bumping version to 3.5-rc1
[supercollider.git] / server / supernova / utilities / osc_dispatcher.hpp
blobbf2b8601d772938038f607d6a3fe4d6faf5d94ff
1 // osc responder class
2 // Copyright (C) 2008 Tim Blechmann
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #ifndef OSC_RESPONDER_HPP
20 #define OSC_RESPONDER_HPP
22 #include <string>
23 #include <map>
24 #include "exists.hpp"
25 #include "branch_hints.hpp"
27 #include <boost/tuple/tuple.hpp>
29 #include "osc/OscReceivedElements.h"
31 namespace nova
35 class osc_responder
37 public:
38 virtual ~osc_responder()
41 virtual void run(osc::ReceivedMessageArgumentIterator begin,
42 osc::ReceivedMessageArgumentIterator const & end) = 0;
46 class osc_dispatcher
48 typedef std::string string;
49 typedef std::size_t size_t;
50 typedef std::multimap<string, osc_responder*> responder_map_t;
52 public:
53 static bool is_pattern(const char * pattern)
55 for(;;)
57 if (unlikely(*pattern == 0))
58 return false;
59 if (unlikely((*pattern == '?') or (*pattern == '*')))
60 return true;
61 ++pattern;
65 static unsigned int first_pattern_char(const char * pattern)
67 assert(is_pattern(pattern));
69 unsigned int ret = 0;
70 for(;;)
72 if (unlikely((*pattern == '?') or (*pattern == '*')))
73 return ret;
74 ++ret;
75 ++pattern;
77 assert(false);
80 static bool match_pattern(const char * pattern, const char * address)
82 const char pc = *pattern;
83 const char ac = *address;
85 if ((pc == 0) and (ac == 0))
86 return true;
88 if ((pc == 0) or (ac == 0))
89 return false;
91 if (pc == '?')
92 return match_pattern(++pattern, ++address);
94 if (pc == '*')
96 for(;;)
98 if (match_pattern(pattern+1, address+1))
99 return true;
100 ++address;
101 if (*address == 0)
102 return *(pattern+1) == 0;
106 if (pc != ac)
107 return false;
108 else
109 return match_pattern(++pattern, ++address);
112 void add_responder(string const & address, osc_responder * resp)
114 responder_map.insert(std::make_pair(address, resp));
117 void remove_responder(string const & address, osc_responder * resp)
119 assert(exists(responder_map, address));
121 responder_map_t::iterator it, end;
122 boost::tie(it, end) = responder_map.equal_range(address);
124 for(; it != end; ++it)
126 if (it->second == resp)
128 responder_map.erase(it);
129 return;
132 assert(false);
135 void handle_packet(const char * data, size_t length)
137 assert(length);
138 if (data[0] == '#')
139 handle_bundle(data, length);
140 else
141 handle_message(data, length);
144 private:
145 void handle_message(const char * data, size_t length)
147 osc::ReceivedMessage msg(osc::ReceivedPacket(data, length));
148 handle_message(msg.AddressPattern(), msg.ArgumentsBegin(), msg.ArgumentsEnd());
151 void handle_bundle(const char * data, size_t length)
153 osc::ReceivedBundle bundle(osc::ReceivedPacket(data, length));
154 handle_bundle(bundle.ElementsBegin(), bundle.ElementsEnd());
157 void handle_bundle(osc::ReceivedBundleElementIterator const & begin,
158 osc::ReceivedBundleElementIterator const & end)
160 for (osc::ReceivedBundleElementIterator it = begin; it != end; ++it)
162 if (it->IsBundle())
164 osc::ReceivedBundle bundle(*it);
165 handle_bundle(bundle.ElementsBegin(), bundle.ElementsEnd());
167 else
169 osc::ReceivedMessage msg(*it);
170 handle_message(msg.AddressPattern(), msg.ArgumentsBegin(), msg.ArgumentsEnd());
175 void handle_message(char const * pattern, osc::ReceivedMessageArgumentIterator const & begin,
176 osc::ReceivedMessageArgumentIterator const & end)
178 if (is_pattern(pattern))
179 handle_pattern(pattern, begin, end);
180 else
181 handle_address(pattern, begin, end);
185 void handle_pattern(const char * pattern, osc::ReceivedMessageArgumentIterator const & begin,
186 osc::ReceivedMessageArgumentIterator const & end)
188 responder_map_t::iterator it;
189 const unsigned int pattern_begin = first_pattern_char(pattern);
191 const string pattern_root(pattern, pattern_begin);
193 it = responder_map.lower_bound(pattern_root);
195 for(; it != responder_map.end(); ++it)
197 if (match_pattern(pattern, it->first.c_str()))
199 osc_responder * resp = it->second;
200 resp->run(begin, end);
201 continue;
204 if (it->first.compare(0, pattern_begin, pattern_root))
205 return;
209 void handle_address(const char * address, osc::ReceivedMessageArgumentIterator const & begin,
210 osc::ReceivedMessageArgumentIterator const & end)
212 responder_map_t::iterator it, it_end;
213 boost::tie(it, it_end) = responder_map.equal_range(address);
215 for(; it != it_end; ++it)
217 osc_responder * resp = it->second;
218 resp->run(begin, end);
222 responder_map_t responder_map;
225 } /* namespace nova */
227 #endif /* OSC_RESPONDER_HPP */