Skip to content

Commit eb44dba

Browse files
author
Daniel Plemmons
authored
Merge pull request #967 from leapmotion/fix-globalenum
Fix global config enumeration
2 parents 2b7b15e + 02a715a commit eb44dba

File tree

6 files changed

+109
-14
lines changed

6 files changed

+109
-14
lines changed

src/autowiring/ConfigRegistry.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,19 @@
44

55
using namespace autowiring;
66

7-
std::atomic<config_registry_entry_base*> autowiring::g_pFirstEntry;
8-
const config_descriptor config_registry_entry_default::desc = {};
7+
config_registry_entry_base* autowiring::config_registry::g_pFirstEntry;
8+
const config_registry_entry_default config_registry_entry_default::entry = {};
99

10-
config_registry_entry_base::config_registry_entry_base(void) {
11-
while (!g_pFirstEntry.compare_exchange_weak(pFlink, this));
10+
config_registry_entry_default::config_registry_entry_default(void) = default;
11+
12+
config_registry_entry_base::config_registry_entry_base(config_descriptor&& descriptor) :
13+
descriptor(std::move(descriptor)),
14+
pFlink(config_registry::Link(*this))
15+
{
16+
}
17+
18+
const config_registry_entry_base* config_registry::Link(config_registry_entry_base& entry) {
19+
config_registry_entry_base* pFlink = g_pFirstEntry;
20+
g_pFirstEntry = &entry;
21+
return pFlink;
1222
}

src/autowiring/ConfigRegistry.h

+75-8
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,22 @@
66
namespace autowiring {
77
struct config_registry_entry_base {
88
protected:
9-
config_registry_entry_base(void);
9+
config_registry_entry_base(config_descriptor&& descriptor);
1010

1111
public:
1212
// Next entry in the registry:
13-
config_registry_entry_base* pFlink = nullptr;
13+
const config_registry_entry_base* const pFlink = nullptr;
14+
15+
// Descriptor proper:
16+
const config_descriptor descriptor;
1417
};
1518

1619
struct config_registry_entry_default {
17-
static const config_descriptor desc;
20+
config_registry_entry_default(void);
21+
22+
config_descriptor descriptor;
23+
24+
static const config_registry_entry_default entry;
1825
};
1926

2027
template<typename T, typename = void>
@@ -26,21 +33,81 @@ namespace autowiring {
2633
struct config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type> :
2734
config_registry_entry_base
2835
{
36+
private:
37+
config_registry_entry(void) :
38+
config_registry_entry_base(T::GetConfigDescriptor())
39+
{}
40+
2941
public:
30-
static const config_descriptor desc;
42+
static const config_registry_entry entry;
3143
};
3244

3345
template<typename T>
34-
const config_descriptor config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type>::desc = T::GetConfigDescriptor();
46+
const config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type>
47+
config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type>::entry;
48+
49+
struct config_registry {
50+
/// <summary>
51+
/// Standard iterator type
52+
/// </summary>
53+
class const_iterator {
54+
public:
55+
typedef std::forward_iterator_tag iterator_category;
56+
typedef std::ptrdiff_t difference_type;
57+
typedef config_registry_entry_base value_type;
58+
typedef const config_descriptor* pointer;
59+
typedef const config_descriptor& reference;
60+
61+
const_iterator(const config_registry_entry_base* entry = nullptr) :
62+
m_cur(entry)
63+
{}
64+
65+
private:
66+
const config_registry_entry_base* m_cur;
3567

36-
extern std::atomic<config_registry_entry_base*> g_pFirstEntry;
68+
public:
69+
pointer operator->(void) const { return &m_cur->descriptor; }
70+
reference operator*(void) { return m_cur->descriptor; }
71+
72+
bool operator==(const const_iterator& rhs) const { return m_cur == rhs.m_cur; }
73+
bool operator!=(const const_iterator& rhs) const { return m_cur != rhs.m_cur; }
74+
75+
// Iterator operator overloads:
76+
const_iterator& operator++(void) {
77+
m_cur = m_cur->pFlink;
78+
return *this;
79+
}
80+
const_iterator operator++(int) {
81+
auto prior = m_cur;
82+
++*this;
83+
return{ prior };
84+
}
85+
};
86+
87+
private:
88+
// Application linked list head
89+
static config_registry_entry_base* g_pFirstEntry;
90+
91+
public:
92+
/// <summary>
93+
/// Adds a link to the specified registry entry
94+
/// </summary>
95+
/// <remarks>
96+
/// This routine is not thread safe, and must be externally synchronized
97+
/// </remarks>
98+
static const config_registry_entry_base* Link(config_registry_entry_base& entry);
99+
100+
// Iterator support logic:
101+
const_iterator begin(void) const { return{ g_pFirstEntry }; }
102+
const_iterator end(void) const { return{ nullptr }; }
103+
};
37104

38105
/// <summary>
39106
/// Gets a string representation of the named configuration value
40107
/// </summary>
41108
template<typename T>
42109
std::string ConfigGet(const char* name, T& obj) {
43-
const config_descriptor& desc = config_registry_entry<T>::desc;
110+
const config_descriptor& desc = config_registry_entry<T>::entry.descriptor;
44111
auto q = desc.fields.find(name);
45112
if (q == desc.fields.end())
46113
throw std::invalid_argument("Configuration name not found in the specified object's configuration descriptor");
@@ -54,7 +121,7 @@ namespace autowiring {
54121
/// </summary>
55122
template<typename T>
56123
void ConfigSet(const char* name, T& obj, const char* value) {
57-
const config_descriptor& desc = config_registry_entry<T>::desc;
124+
const config_descriptor& desc = config_registry_entry<T>::entry.descriptor;
58125
auto q = desc.fields.find(name);
59126
if (q == desc.fields.end())
60127
throw std::invalid_argument("Configuration name not found in the specified object's configuration descriptor");

src/autowiring/CoreObjectDescriptor.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ struct CoreObjectDescriptor {
5252
pBasicThread(autowiring::fast_pointer_cast<::BasicThread>(value)),
5353
pFilter(autowiring::fast_pointer_cast<::ExceptionFilter>(value)),
5454
pBoltBase(autowiring::fast_pointer_cast<::BoltBase>(value)),
55-
pConfigDesc(&config_registry_entry<T>::desc),
55+
pConfigDesc(&config_registry_entry<T>::entry.descriptor),
5656
primitiveOffset(
5757
reinterpret_cast<size_t>(
5858
static_cast<T*>(

src/autowiring/config_descriptor.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ config_descriptor::t_mpType autowiring::config_descriptor::MakeFields(const std:
1111
return retVal;
1212
}
1313

14+
config_descriptor::config_descriptor(void) {}
15+
1416
const config_field& config_descriptor::get(size_t offset) const {
1517
for (const auto& entry : fields)
1618
if (entry.second.offset == offset)

src/autowiring/config_descriptor.h

+4
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,10 @@ namespace autowiring {
309309

310310
static t_mpType MakeFields(const std::initializer_list<config_field>& fields);
311311

312+
config_descriptor(void);
313+
config_descriptor(config_descriptor&& rhs) :
314+
fields(std::move(rhs.fields))
315+
{}
312316
config_descriptor(std::initializer_list<config_field> fields) :
313317
fields(MakeFields(fields))
314318
{}

src/autowiring/test/AutoConfigTest.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <autowiring/config.h>
55
#include <autowiring/ConfigRegistry.h>
66
#include <autowiring/observable.h>
7+
#include <cstring>
78

89
namespace aw = autowiring;
910

@@ -285,7 +286,7 @@ namespace {
285286

286287
static autowiring::config_descriptor GetConfigDescriptor(void) {
287288
return{
288-
aw::config_field { "b", "Field B description", &ClassWithBoundsField::b, 929, slider{}, aw::bounds<int>{ 10, 423 } },
289+
aw::config_field { "crazyjenkins", "Field B description", &ClassWithBoundsField::b, 929, slider{}, aw::bounds<int>{ 10, 423 } },
289290
};
290291
}
291292
};
@@ -297,3 +298,14 @@ TEST_F(AutoConfigTest, WhenFn) {
297298

298299
ASSERT_EQ(1UL, mgr->sliderReg.size()) << "Slider registration count did not match expectations";
299300
}
301+
302+
TEST_F(AutoConfigTest, CanEnumRegistry) {
303+
size_t nFound = 0;
304+
for (const config_descriptor& desc : autowiring::config_registry{}) {
305+
for (const auto& field : desc.fields) {
306+
if (!std::strcmp("crazyjenkins", field.second.name))
307+
nFound++;
308+
}
309+
}
310+
ASSERT_EQ(1, nFound) << "Failed to find a descriptor field in the total descriptor enumeration";
311+
}

0 commit comments

Comments
 (0)