OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
device_parameter_index.hpp
1#pragma once
2#include <ossia/detail/hash.hpp>
3#include <ossia/network/base/device.hpp>
4#include <ossia/network/base/node.hpp>
5#include <ossia/network/base/osc_address.hpp>
6#include <ossia/network/base/parameter.hpp>
7
8#include <boost/unordered/concurrent_flat_map.hpp>
9
10#include <string>
11#include <string_view>
12
13namespace ossia::net
14{
15
30class device_parameter_index : public Nano::Observer
31{
32public:
34 : m_device{dev}
35 {
36 dev.on_parameter_created.connect<&device_parameter_index::on_parameter_created>(
37 *this);
38 dev.on_parameter_removing.connect<&device_parameter_index::on_parameter_removing>(
39 *this);
40 dev.on_node_removing.connect<&device_parameter_index::on_node_removing>(*this);
41 dev.on_node_renamed.connect<&device_parameter_index::on_node_renamed>(*this);
42
43 index_recursively(dev.get_root_node());
44 }
45
48 device_parameter_index& operator=(const device_parameter_index&) = delete;
50
53 template <typename F>
54 bool apply(std::string_view address, F&& f)
55 {
56 std::string buf;
57 return m_index.visit(normalize(address, buf), [&](const auto& e) { f(*e.second); })
58 > 0;
59 }
60
63 void clear() { m_index.clear(); }
64
65 std::size_t size() const { return m_index.size(); }
66
67private:
70 static std::string_view normalize(std::string_view address, std::string& buf)
71 {
72 while(address.size() > 1 && address.back() == '/')
73 address.remove_suffix(1);
74
75 if(!address.empty() && address.front() == '/')
76 return address;
77
78 buf.reserve(address.size() + 1);
79 buf = "/";
80 buf += address;
81 return buf;
82 }
83
86 static std::string address_of(const ossia::net::node_base& node)
87 {
88 return ossia::net::osc_parameter_string(node);
89 }
90
91 void index_recursively(const ossia::net::node_base& node)
92 {
93 if(auto param = node.get_parameter())
94 m_index.insert_or_assign(address_of(node), param);
95
96 for(const auto& cld : node.children_copy())
97 index_recursively(*cld);
98 }
99
100 void on_parameter_created(const ossia::net::parameter_base& param)
101 {
102 m_index.insert_or_assign(
103 address_of(param.get_node()), const_cast<ossia::net::parameter_base*>(&param));
104 }
105
106 void on_parameter_removing(const ossia::net::parameter_base& param)
107 {
108 m_index.erase(address_of(param.get_node()));
109 }
110
111 void on_node_removing(ossia::net::node_base& node)
112 {
113 // wrapped_node has no remove_parameter(), so a node's own parameter is not
114 // always signalled separately, and a node removed with children takes their
115 // parameters with it: sweep the subtree.
116 const auto prefix = address_of(node);
117
118 m_index.erase_if([&prefix](const auto& e) {
119 const auto& key = e.first;
120 return key == prefix
121 || (key.size() > prefix.size() && key.starts_with(prefix)
122 && key[prefix.size()] == '/');
123 });
124 }
125
126 void on_node_renamed(ossia::net::node_base& node, const std::string& old_name)
127 {
128 // A rename changes the address of a whole subtree, and the node's own cache
129 // has already been updated when this runs.
130 m_index.clear();
131 index_recursively(m_device.get_root_node());
132 }
133
134 ossia::net::device_base& m_device;
135 boost::concurrent_flat_map<
136 std::string, ossia::net::parameter_base*, ossia::string_hash, std::equal_to<>>
137 m_index;
138};
139
140}
Root of a device tree.
Definition ossia/network/base/device.hpp:58
A thread-safe index of a device's parameters, by OSC address.
Definition device_parameter_index.hpp:31
bool apply(std::string_view address, F &&f)
Definition device_parameter_index.hpp:54
void clear()
Definition device_parameter_index.hpp:63
The node_base class.
Definition node.hpp:48
The parameter_base class.
Definition ossia/network/base/parameter.hpp:48