• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / libossia / 31275445545

08 Aug 2026 07:50PM UTC coverage: 50.828% (+2.5%) from 48.367%
31275445545

push

github

jcelerier
build: version Boost.Asio's global symbols on Windows

Since 1.91, Asio names its global symbols through BOOST_ASIO_VERSIONED_NAME,
which with no version namespace expands to the bare asio_ prefix - byte for
byte the names standalone Asio uses. Before 1.91 they carried a boost_asio_
prefix and could not collide.

Where Asio is compiled separately we emit strong definitions of them, so
anything else in the link carrying its own standalone Asio collides with us.
score's LSL addon bundles Asio and compiles asio/impl/src.hpp, and the two meet
as

  lld-link : error : duplicate symbol: asio_signal_handler
    >>> defined at ossia_x64.lib(unity_0_cxx.obj)
    >>> defined at lsl.lib(asio_objects.obj)

which is what stopped score's MSVC job linking as soon as our Boost floor moved
to 1.91.

Enabling the version namespace renames ours - asio_v103801_bdemo_signal_handler
- and leaves standalone Asio's alone. It holds together only with the
_WIN32_WINNT pin above: the namespace tag encodes the Asio configuration, so
without a fixed configuration it varies per translation unit and the duplicate
symbol merely becomes an undefined one. It also requires that nothing declare
an Asio type outside that namespace, which is what the libremidi update in the
previous commit settles.

Set both at the top level, so that the dependencies we build as subdirectories
are configured the same way, and PUBLIC on the ossia target, because this is
part of our ABI rather than only of how we are built. The namespace is an
inline namespace, so it is baked into the mangled name of every Asio type our
headers expose: resolve.cpp explicitly instantiates resolve_sync_v4 for
boost::asio::ip::udp and ::tcp, and a consumer that disagrees about the
namespace names a different specialisation and does not link.

Verified against Boost 1.91: libossia builds clean with VS2026, ossia_x64.lib
exports asio_v103801_bdemo_signal_handler and no longer contains the bare
asio_signal_handler at all; and sco... (continued)

29314 of 57673 relevant lines covered (50.83%)

182772.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.02
/src/ossia/dataflow/graph_node.cpp
1
// This is an open source non-commercial project. Dear PVS-Studio, please check
2
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
#include <ossia/dataflow/dataflow.hpp>
4
#include <ossia/dataflow/execution_state.hpp>
5
#include <ossia/dataflow/for_each_port.hpp>
6
#include <ossia/dataflow/fx_node.hpp>
7
#include <ossia/dataflow/graph_edge.hpp>
8
#include <ossia/dataflow/graph_node.hpp>
9
#include <ossia/dataflow/node_process.hpp>
10
#include <ossia/detail/algorithms.hpp>
11
#include <ossia/detail/logger.hpp>
12

13
namespace ossia
14
{
15
audio_buffer_pool::audio_buffer_pool() = default;
9✔
16
audio_buffer_pool::~audio_buffer_pool() = default;
9✔
17

18
audio_buffer_pool& audio_buffer_pool::instance() noexcept
248,550✔
19
{
20
  static audio_buffer_pool p;
248,550✔
21
  return p;
248,550✔
22
}
23

24
#if defined(OSSIA_SCENARIO_DATAFLOW)
25
node_process::node_process(node_ptr n)
1,059✔
26
{
27
  assert(n);
1,059✔
28
  node = std::move(n);
1,059✔
29
}
1,059✔
30

31
void node_process::offset_impl(time_value date) { }
×
32

33
void node_process::transport_impl(time_value date) { }
320✔
34

35
void node_process::start()
1,409✔
36
{
37
  // TODO reset all delay buffer positions
38
}
1,409✔
39

40
void node_process::stop()
2,253✔
41
{
42
  if(node)
2,253✔
43
    node->all_notes_off();
2,253✔
44
}
2,253✔
45

46
void node_process::pause() { }
×
47

48
void node_process::resume() { }
×
49

50
void node_process::mute_impl(bool) { }
×
51

52
node_process::~node_process() = default;
1,059✔
53
#endif
54
/*
55
graph_edge::graph_edge(
56
    connection c, std::size_t pout, std::size_t pin, node_ptr pout_node,
57
    node_ptr pin_node) noexcept
58
    : graph_edge{c, pout_node->outputs()[pout], pin_node->inputs()[pin],
59
                 std::move(pout_node), std::move(pin_node)}
60
{
61
}
62
*/
63
graph_edge::graph_edge(
34✔
64
    connection c, outlet_ptr pout, inlet_ptr pin, node_ptr pout_node,
65
    node_ptr pin_node) noexcept
34✔
66
    : con{c}
34✔
67
    , out{std::move(pout)}
34✔
68
    , in{std::move(pin)}
34✔
69
    , out_node{std::move(pout_node)}
34✔
70
    , in_node{std::move(pin_node)}
34✔
71
{
72
  assert(out_node);
34✔
73
  assert(in_node);
34✔
74
}
34✔
75

76
template <typename T>
77
struct alloc_observer
78
{
79
  std::allocator<T> alloc;
80
  std::size_t& request;
81
  template <typename U>
82
  using rebind = alloc_observer<U>;
83
  using value_type = T;
84

85
  alloc_observer(std::size_t& request) noexcept
21✔
86
      : request(request)
21✔
87
  {
88
    // Tricky note: std::make/allocate_shared store the allocator. Thus the allocated size depend on alloc_observer / edge_pool_alloc size.
89
    // To get the correct size, we have to make sure that sizeof(alloc_observer) == sizeof(edge_pool_alloc) (which is just a shared_ptr)
90

91
    static_assert(sizeof(alloc_observer<T>) == sizeof(std::shared_ptr<int>));
92
  }
21✔
93

94
  template <typename U>
95
  alloc_observer(alloc_observer<U> const& other) noexcept
42✔
96
      : request(other.request)
42✔
97
  {
98
    static_assert(sizeof(alloc_observer<T>) == sizeof(std::shared_ptr<int>));
99
    static_assert(sizeof(alloc_observer<U>) == sizeof(std::shared_ptr<int>));
100
  }
42✔
101

102
  T* allocate(const std::size_t n) noexcept
21✔
103
  {
104
    request = sizeof(T);
21✔
105
    return alloc.allocate(n);
42✔
106
  }
107
  void deallocate(T* ptr, const size_t n) noexcept { return alloc.deallocate(ptr, n); }
42✔
108
};
109

110
std::size_t graph_edge::size_of_allocated_memory_by_make_shared() noexcept
21✔
111
{
112
  struct private_bypass : graph_edge
113
  {
114
  public:
115
    private_bypass() = default;
21✔
116
  };
117
  std::size_t request{};
21✔
118
  alloc_observer<private_bypass> alloc{request};
21✔
119

120
  std::allocate_shared<private_bypass, alloc_observer<private_bypass>>(alloc);
21✔
121

122
  return request;
42✔
123
}
21✔
124

125
void graph_edge::init() noexcept
23✔
126
{
127
  if(in && out && in_node && out_node)
23✔
128
  {
129
    bool found_in = false;
22✔
130
    bool found_out = false;
22✔
131
    ossia::for_each_inlet(*in_node, [&](ossia::inlet& e) { found_in |= &e == in; });
22✔
132
    ossia::for_each_outlet(*out_node, [&](ossia::outlet& e) { found_out |= &e == out; });
22✔
133
    if(!found_in || !found_out)
22✔
134
    {
135
      ossia::logger().error("Trying to connect missing inlets / outlets");
×
136
      return;
×
137
    }
138
    out->connect(this);
22✔
139
    in->connect(this);
22✔
140

141
    if(auto delay = con.target<delayed_glutton_connection>())
44✔
142
    {
143
      out->visit(init_delay_line{delay->buffer});
1✔
144
    }
145
    else if(auto sdelay = con.target<delayed_strict_connection>())
42✔
146
    {
147
      out->visit(init_delay_line{sdelay->buffer});
1✔
148
    }
149
  }
150
  else
151
  {
152
    ossia::logger().error("Missing in_node / out_node");
1✔
153
  }
154
}
155

156
graph_edge::~graph_edge()
55✔
157
{
158
  clear();
55✔
159
}
55✔
160

161
void graph_edge::clear() noexcept
78✔
162
{
163
  if(in && out && in_node && out_node)
78✔
164
  {
165
    bool found_in = false;
26✔
166
    bool found_out = false;
26✔
167
    ossia::for_each_inlet(*in_node, [&](ossia::inlet& e) { found_in |= &e == in; });
26✔
168
    ossia::for_each_outlet(*out_node, [&](ossia::outlet& e) { found_out |= &e == out; });
26✔
169
    if(found_in && found_out)
26✔
170
    {
171
      out->disconnect(this);
26✔
172
      in->disconnect(this);
26✔
173
    }
174
    else
175
    {
176
      ossia::logger().error("Trying to disconnect missing inlets / outlets");
×
177
    }
178
  }
179

180
  con = connection{};
78✔
181
  out = {};
78✔
182
  in = {};
78✔
183
  out_node.reset();
78✔
184
  in_node.reset();
78✔
185
}
78✔
186

187
graph_node::~graph_node()
2,351✔
188
{
189
  for(auto inl : m_inlets)
2,829✔
190
    delete inl;
478✔
191
  for(auto outl : m_outlets)
2,829✔
192
    delete outl;
478✔
193
}
2,351✔
194

195
void graph_node::prepare(const execution_state& st) noexcept
×
196
{
197
  struct
198
  {
199
    std::size_t buffer_size{};
200
    void operator()(ossia::audio_port& p) const noexcept
×
201
    {
202
      if(p.empty())
×
203
        p.set_channels(2);
×
204

205
      for(auto& c : p.get())
×
206
      {
207
        c.shrink_to_fit();
×
208
        c.reserve(buffer_size);
×
209
      }
210
    }
×
211
    void operator()(ossia::midi_port& p) const noexcept { }
×
212
    void operator()(ossia::value_port& p) const noexcept { }
×
213
    void operator()(ossia::geometry_port& p) const noexcept { }
×
214
  } vis;
×
215
  for(auto& in : this->m_inlets)
×
216
  {
217
    in->visit(vis);
×
218
  }
219
  for(auto& out : this->m_outlets)
×
220
  {
221
    out->visit(vis);
×
222
  }
223
}
×
224

225
graph_node::graph_node() noexcept = default;
2,351✔
226

227
bool graph_node::consumes(const execution_state&) const noexcept
×
228
{
229
  return false;
×
230
}
231

232
void graph_node::run(const token_request& t, exec_state_facade) noexcept { }
×
233

234
std::string graph_node::label() const noexcept
×
235
{
236
  return {};
×
237
}
238

239
bool graph_node::has_port_inputs() const noexcept
×
240
{
241
  return any_of_inlet(*this, [](const inlet& inlet) { return !inlet.sources.empty(); });
×
242
}
243

244
bool graph_node::has_global_inputs() const noexcept
×
245
{
246
  return any_of_inlet(*this, [&](const inlet& inlet) {
×
247
    return (inlet.scope & port::scope_t::global) && bool(inlet.address);
×
248
  });
×
249
}
250

251
bool graph_node::has_local_inputs(const execution_state& st) const noexcept
×
252
{
253
  return any_of_inlet(*this, [&](const inlet& inlet) {
×
254
    if(inlet.scope & port::scope_t::local)
×
255
    {
256
      bool b = false;
×
257

258
      // TODO optimize by stopping when found
259
      apply_to_destination(
×
260
          inlet.address, st.exec_devices(),
×
261
          [&](ossia::net::parameter_base* addr, bool) {
×
262
        if(!b || st.in_local_scope(*addr))
×
263
          b = true;
×
264
          },
×
265
          do_nothing_for_nodes{});
266

267
      if(b)
×
268
        return true;
×
269

270
      if(consumes(st))
×
271
        return true;
×
272
    }
273
    return false;
×
274
  });
×
275
}
276

277
void graph_node::clear() noexcept
38✔
278
{
279
  for_each_inlet(*this, [](auto& port) {
76✔
280
    for(ossia::graph_edge* e : port.cables())
38✔
281
    {
282
      e->clear();
×
283
    }
284
  });
38✔
285
  for_each_outlet(*this, [](auto& port) {
38✔
286
    for(ossia::graph_edge* e : port.cables())
38✔
287
    {
288
      e->clear();
×
289
    }
290
  });
38✔
291

292
  for(auto outl : m_outlets)
76✔
293
  {
294
    delete outl;
38✔
295
  }
296
  for(auto inl : m_inlets)
76✔
297
  {
298
    delete inl;
38✔
299
  }
300
  m_inlets.clear();
38✔
301
  m_outlets.clear();
38✔
302
}
38✔
303

304
void graph_node::request(const token_request& req) noexcept
169,342✔
305
{
306
  /*
307
  if(std::abs(req.date - req.prev_date) > 1000)
308
  {
309
    std::cerr << typeid(this).name() << " " << req.prev_date << " => " <<
310
  req.date << std::endl;
311
  }
312
  */
313

314
  requested_tokens.push_back(std::move(req));
169,342✔
315
}
169,342✔
316

317
void graph_node::process_time(
103✔
318
    const ossia::token_request& req, execution_state& st) noexcept
319
{
320
  auto [s, d] = exec_state_facade{&st}.timings(req);
103✔
321
  this->m_processed_frames += d;
103✔
322

323
  // A span length is never negative, so the counter above cannot follow a
324
  // rewind. The playhead can: map the date of the tick's first sample through
325
  // the same model -> sample map the spans are taken from.
326
  if(req.speed != 0.)
103✔
327
    this->m_transport_frames = req.start_date_to_physical(st.modelToSamplesRatio);
103✔
328
}
103✔
329

330
void graph_node::all_notes_off() noexcept { }
2,253✔
331

332
nonowning_graph_node::~nonowning_graph_node()
1,263✔
333
{
334
  m_inlets.clear();
1,263✔
335
  m_outlets.clear();
1,263✔
336
}
1,263✔
337

338
void nonowning_graph_node::clear() noexcept
8✔
339
{
340
  for(auto inl : m_inlets)
12✔
341
  {
342
    for(ossia::graph_edge* e : inl->sources)
4✔
343
    {
344
      e->clear();
×
345
    }
346
  }
347
  for(auto outl : m_outlets)
16✔
348
  {
349
    for(ossia::graph_edge* e : outl->targets)
8✔
350
    {
351
      e->clear();
×
352
    }
353
  }
354
}
8✔
355
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc