1 #include "settingvar.hpp"
2 #include "stateobject.hpp"
8 threads::rlock
* global_lock
;
12 std::map
<std::string
, superbase
*> supervars
;
13 std::set
<set::listener
*> callbacks
;
18 std::map
<std::string
, class base
*> settings
;
19 std::set
<struct listener
*> listeners
;
20 std::set
<struct set
*> sets_listened
;
23 typedef stateobject::type
<set
, set_internal
> set_internal_t
;
24 typedef stateobject::type
<group
, group_internal
> group_internal_t
;
27 threads::rlock
& get_setting_lock()
29 if(!global_lock
) global_lock
= new threads::rlock
;
33 listener::~listener() throw()
37 set::listener::~listener()
41 group::group() throw(std::bad_alloc
)
46 group::~group() throw()
48 threads::arlock
h(get_setting_lock());
49 auto state
= group_internal_t::get_soft(this);
51 for(auto i
: state
->settings
)
52 i
.second
->group_died();
53 for(auto i
: state
->sets_listened
)
54 i
->drop_callback(_listener
);
55 group_internal_t::clear(this);
58 std::set
<std::string
> group::get_settings_set() throw(std::bad_alloc
)
60 threads::arlock
h(get_setting_lock());
61 auto state
= group_internal_t::get_soft(this);
62 std::set
<std::string
> x
;
64 for(auto i
: state
->settings
)
69 base
& group::operator[](const std::string
& name
)
71 threads::arlock
h(get_setting_lock());
72 auto state
= group_internal_t::get_soft(this);
73 if(!state
|| !state
->settings
.count(name
))
74 throw std::runtime_error("No such setting");
75 return *state
->settings
[name
];
78 void group::fire_listener(base
& var
) throw()
80 std::set
<listener
*> l
;
82 threads::arlock
h(get_setting_lock());
83 auto state
= group_internal_t::get_soft(this);
85 for(auto i
: state
->listeners
)
90 i
->on_setting_change(*this, var
);
95 void group::add_listener(struct listener
& listener
) throw(std::bad_alloc
)
97 threads::arlock
h(get_setting_lock());
98 auto& state
= group_internal_t::get(this);
99 state
.listeners
.insert(&listener
);
102 void group::remove_listener(struct listener
& listener
) throw(std::bad_alloc
)
104 threads::arlock
h(get_setting_lock());
105 auto state
= group_internal_t::get_soft(this);
107 state
->listeners
.erase(&listener
);
110 void group::do_register(const std::string
& name
, base
& _setting
) throw(std::bad_alloc
)
112 threads::arlock
h(get_setting_lock());
113 auto& state
= group_internal_t::get(this);
114 if(state
.settings
.count(name
)) return;
115 state
.settings
[name
] = &_setting
;
118 void group::do_unregister(const std::string
& name
, base
& _setting
) throw(std::bad_alloc
)
120 threads::arlock
h(get_setting_lock());
121 auto state
= group_internal_t::get_soft(this);
122 if(!state
|| !state
->settings
.count(name
) || state
->settings
[name
] != &_setting
) return;
123 state
->settings
.erase(name
);
126 void group::add_set(set
& s
) throw(std::bad_alloc
)
128 threads::arlock
u(get_setting_lock());
129 auto& state
= group_internal_t::get(this);
130 if(state
.sets_listened
.count(&s
)) return;
132 state
.sets_listened
.insert(&s
);
133 s
.add_callback(_listener
);
135 state
.sets_listened
.erase(&s
);
139 void group::drop_set(set
& s
)
141 threads::arlock
h(get_setting_lock());
142 auto state
= group_internal_t::get_soft(this);
144 //Drop the callback. This unregisters all.
145 s
.drop_callback(_listener
);
146 state
->sets_listened
.erase(&s
);
149 group::xlistener::xlistener(group
& _grp
)
154 group::xlistener::~xlistener()
158 void group::xlistener::create(set
& s
, const std::string
& name
, superbase
& sb
)
160 threads::arlock
h(get_setting_lock());
164 void group::xlistener::destroy(set
& s
, const std::string
& name
)
166 threads::arlock
h(get_setting_lock());
167 auto state
= group_internal_t::get_soft(&grp
);
169 state
->settings
.erase(name
);
172 void group::xlistener::kill(set
& s
)
174 threads::arlock
h(get_setting_lock());
175 auto state
= group_internal_t::get_soft(&grp
);
177 state
->sets_listened
.erase(&s
);
186 auto state
= set_internal_t::get_soft(this);
188 threads::arlock
u(get_setting_lock());
189 //Call all DCBs on all factories.
190 for(auto i
: state
->supervars
)
191 for(auto j
: state
->callbacks
)
192 j
->destroy(*this, i
.first
);
194 for(auto j
: state
->callbacks
)
196 //Notify all factories that base set died.
197 for(auto i
: state
->supervars
)
198 i
.second
->set_died();
199 //We assume factories look after themselves, so we don't destroy those.
200 set_internal_t::clear(this);
203 void set::do_register(const std::string
& name
, superbase
& info
)
205 threads::arlock
u(get_setting_lock());
206 auto& state
= set_internal_t::get(this);
207 if(state
.supervars
.count(name
)) {
208 std::cerr
<< "WARNING: Command collision for " << name
<< "!" << std::endl
;
211 state
.supervars
[name
] = &info
;
212 //Call all CCBs on this.
213 for(auto i
: state
.callbacks
)
214 i
->create(*this, name
, info
);
217 void set::do_unregister(const std::string
& name
, superbase
& info
)
219 threads::arlock
u(get_setting_lock());
220 auto state
= set_internal_t::get_soft(this);
222 if(!state
->supervars
.count(name
) || state
->supervars
[name
] != &info
) return; //Not this.
223 state
->supervars
.erase(name
);
224 //Call all DCBs on this.
225 for(auto i
: state
->callbacks
)
226 i
->destroy(*this, name
);
229 void set::add_callback(set::listener
& listener
) throw(std::bad_alloc
)
231 threads::arlock
u(get_setting_lock());
232 auto& state
= set_internal_t::get(this);
233 state
.callbacks
.insert(&listener
);
234 //To avoid races, call CCBs on all factories for this.
235 for(auto j
: state
.supervars
)
236 listener
.create(*this, j
.first
, *j
.second
);
239 void set::drop_callback(set::listener
& listener
)
241 threads::arlock
u(get_setting_lock());
242 auto state
= set_internal_t::get_soft(this);
244 if(state
->callbacks
.count(&listener
)) {
245 //To avoid races, call DCBs on all factories for this.
246 for(auto j
: state
->supervars
)
247 listener
.destroy(*this, j
.first
);
248 state
->callbacks
.erase(&listener
);
252 base::base(group
& _group
, const std::string
& _iname
, const std::string
& _hname
, bool dynamic
)
253 throw(std::bad_alloc
)
254 : sgroup(&_group
), iname(_iname
), hname(_hname
), is_dynamic(dynamic
)
256 sgroup
->do_register(iname
, *this);
259 base::~base() throw()
261 threads::arlock
u(get_setting_lock());
263 sgroup
->do_unregister(iname
, *this);
266 void base::group_died()
268 threads::arlock
u(get_setting_lock());
270 if(is_dynamic
) delete this;
273 void superbase::_superbase(set
& _s
, const std::string
& _iname
) throw(std::bad_alloc
)
277 s
->do_register(iname
, *this);
280 superbase::~superbase() throw()
282 threads::arlock
u(get_setting_lock());
284 s
->do_unregister(iname
, *this);
287 void superbase::set_died()
292 cache::cache(group
& _grp
)
297 std::map
<std::string
, std::string
> cache::get_all()
299 std::map
<std::string
, std::string
> x
;
300 auto s
= grp
.get_settings_set();
303 for(auto i
: badcache
)
304 x
[i
.first
] = i
.second
;
308 std::set
<std::string
> cache::get_keys()
310 return grp
.get_settings_set();
313 void cache::set(const std::string
& name
, const std::string
& value
, bool allow_invalid
)
314 throw(std::bad_alloc
, std::runtime_error
)
317 grp
[name
].str(value
);
318 threads::arlock
u(get_setting_lock());
319 badcache
.erase(name
);
320 } catch(std::bad_alloc
& e
) {
322 } catch(std::exception
& e
) {
324 threads::arlock
u(get_setting_lock());
325 badcache
[name
] = value
;
331 std::string
cache::get(const std::string
& name
) throw(std::bad_alloc
, std::runtime_error
)
333 return grp
[name
].str();
336 const description
& cache::get_description(const std::string
& name
) throw(std::bad_alloc
,
339 return grp
[name
].get_description();
342 std::string
cache::get_hname(const std::string
& name
) throw(std::bad_alloc
, std::runtime_error
)
344 return grp
[name
].get_hname();
347 const char* yes_no::enable
= "yes";
348 const char* yes_no::disable
= "no";