1 //  synth prototype
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.
13 //
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.
18 
19 #pragma once
20 
21 #include <cassert>
22 #include <cstdint>
23 
24 #include <boost/checked_delete.hpp>
25 #include <boost/intrusive/unordered_set.hpp>
26 
27 #include "utilities/aligned_class.hpp"
28 #include "utilities/named_hash_entry.hpp"
29 #include "utilities/utils.hpp"
30 
31 namespace nova {
32 
33 typedef std::int32_t slot_index_t;
34 typedef symbol slot_identifier_type;
35 
36 namespace detail {
37 
38 /** class to resolve alphanumeric string to slot id */
39 class slot_resolver {
40 protected:
41     struct map_type : public named_hash_entry {
map_typenova::detail::slot_resolver::map_type42         map_type(slot_identifier_type const& name, slot_index_t index, int number_of_values):
43             named_hash_entry(name),
44             index(index),
45             number_of_values(number_of_values) {}
46 
47         const slot_index_t index;
48         const int number_of_values;
49     };
50 
51 private:
52     struct hash_value {
hash_valuenova::detail::slot_resolver::hash_value53         hash_value(std::size_t v): value(v) {}
54 
operator ()nova::detail::slot_resolver::hash_value55         std::size_t operator()(const char*) const { return value; }
56 
57         const std::size_t value;
58     };
59 
exists(const char * str) const60     bool exists(const char* str) const {
61         return slot_resolver_map.find(str, named_hash_hash(), named_hash_equal()) != slot_resolver_map.end();
62     }
63 
64 protected:
slot_resolver(void)65     slot_resolver(void): slot_resolver_map(slot_resolver_map_t::bucket_traits(buckets, resolver_map_bucket_count)) {}
66 
~slot_resolver(void)67     ~slot_resolver(void) { slot_resolver_map.clear_and_dispose(boost::checked_deleter<map_type>()); }
68 
register_slot(symbol const & str,slot_index_t i,int number_of_values)69     void register_slot(symbol const& str, slot_index_t i, int number_of_values) {
70         assert(not exists(str.c_str()));
71         map_type* elem = new map_type(str, i, number_of_values);
72         bool success = slot_resolver_map.insert(*elem).second;
73         assert(success);
74 
75         if (size_t(i) >= slot_names.size())
76             slot_names.resize(i + 1, nullptr);
77         slot_names[i] = elem->name();
78     }
79 
80 public:
81     /*@{*/
82     /** resolve slot by symbolic name
83      *
84      *  \return nonnegative index of slot
85      *          -1, if symbolic name cannot be resolved
86      */
resolve_slot(const char * str) const87     slot_index_t resolve_slot(const char* str) const { return resolve_slot(str, string_hash(str)); }
88 
resolve_slot_with_size(const char * str,int & number_of_values) const89     slot_index_t resolve_slot_with_size(const char* str, int& number_of_values) const {
90         return resolve_slot_with_size(str, string_hash(str), number_of_values);
91     }
92 
resolve_slot(const char * str,std::size_t hashed_value) const93     slot_index_t resolve_slot(const char* str, std::size_t hashed_value) const {
94         auto it = slot_resolver_map.find(str, hash_value(hashed_value), named_hash_equal());
95         if (it == slot_resolver_map.end())
96             return -1;
97         else
98             return it->index;
99     }
100 
resolve_slot_with_size(const char * str,std::size_t hashed_value,int & number_of_values) const101     slot_index_t resolve_slot_with_size(const char* str, std::size_t hashed_value, int& number_of_values) const {
102         auto it = slot_resolver_map.find(str, hash_value(hashed_value), named_hash_equal());
103         if (it == slot_resolver_map.end())
104             return -1;
105 
106         number_of_values = it->number_of_values;
107         return it->index;
108     }
109     /*@}*/
110 
number_of_slots() const111     size_t number_of_slots() const { return slot_names.size(); }
112 
name_of_slot(size_t slot_index) const113     const char* name_of_slot(size_t slot_index) const {
114         assert(slot_index < slot_names.size());
115         return slot_names[slot_index];
116     }
117 
118 private:
119     static const int resolver_map_bucket_count = 512;
120 
121     typedef boost::intrusive::unordered_set<map_type, boost::intrusive::power_2_buckets<true>> slot_resolver_map_t;
122     slot_resolver_map_t::bucket_type buckets[resolver_map_bucket_count];
123     slot_resolver_map_t slot_resolver_map;
124 
125     std::vector<const char*> slot_names;
126 };
127 
128 } /* namespace detail */
129 
130 class abstract_synth;
131 
132 struct synth_definition_deleter {
operator ()nova::synth_definition_deleter133     template <typename T> void operator()(T* ptr) { dispose(static_cast<class synth_definition*>(ptr)); }
134 
135     void dispose(class synth_definition*);
136 };
137 
138 /** prototype of a synth
139  *
140  * - works as a synth factory
141  *
142  * */
143 class synth_definition : public aligned_class,
144                          public named_hash_entry,
145                          public intrusive_refcountable<>,
146                          public detail::slot_resolver {
147 public:
synth_definition(symbol const & name)148     explicit synth_definition(symbol const& name): named_hash_entry(name) {}
149 
150     virtual ~synth_definition(void) = default;
151 
152     virtual abstract_synth* create_instance(int node_id) = 0;
153 
154     template <typename synth_t> static inline synth_t* allocate(void);
155 };
156 
157 typedef boost::intrusive_ptr<synth_definition> synth_definition_ptr;
158 
159 } /* namespace nova */
160