Skip to content

Commit

Permalink
Merge pull request #967 from leapmotion/fix-globalenum
Browse files Browse the repository at this point in the history
Fix global config enumeration
  • Loading branch information
Daniel Plemmons authored Jul 11, 2016
2 parents 2b7b15e + 02a715a commit eb44dba
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 14 deletions.
18 changes: 14 additions & 4 deletions src/autowiring/ConfigRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

using namespace autowiring;

std::atomic<config_registry_entry_base*> autowiring::g_pFirstEntry;
const config_descriptor config_registry_entry_default::desc = {};
config_registry_entry_base* autowiring::config_registry::g_pFirstEntry;
const config_registry_entry_default config_registry_entry_default::entry = {};

config_registry_entry_base::config_registry_entry_base(void) {
while (!g_pFirstEntry.compare_exchange_weak(pFlink, this));
config_registry_entry_default::config_registry_entry_default(void) = default;

config_registry_entry_base::config_registry_entry_base(config_descriptor&& descriptor) :
descriptor(std::move(descriptor)),
pFlink(config_registry::Link(*this))
{
}

const config_registry_entry_base* config_registry::Link(config_registry_entry_base& entry) {
config_registry_entry_base* pFlink = g_pFirstEntry;
g_pFirstEntry = &entry;
return pFlink;
}
83 changes: 75 additions & 8 deletions src/autowiring/ConfigRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@
namespace autowiring {
struct config_registry_entry_base {
protected:
config_registry_entry_base(void);
config_registry_entry_base(config_descriptor&& descriptor);

public:
// Next entry in the registry:
config_registry_entry_base* pFlink = nullptr;
const config_registry_entry_base* const pFlink = nullptr;

// Descriptor proper:
const config_descriptor descriptor;
};

struct config_registry_entry_default {
static const config_descriptor desc;
config_registry_entry_default(void);

config_descriptor descriptor;

static const config_registry_entry_default entry;
};

template<typename T, typename = void>
Expand All @@ -26,21 +33,81 @@ namespace autowiring {
struct config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type> :
config_registry_entry_base
{
private:
config_registry_entry(void) :
config_registry_entry_base(T::GetConfigDescriptor())
{}

public:
static const config_descriptor desc;
static const config_registry_entry entry;
};

template<typename T>
const config_descriptor config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type>::desc = T::GetConfigDescriptor();
const config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type>
config_registry_entry<T, typename std::enable_if<has_getconfigdescriptor<T>::value>::type>::entry;

struct config_registry {
/// <summary>
/// Standard iterator type
/// </summary>
class const_iterator {
public:
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
typedef config_registry_entry_base value_type;
typedef const config_descriptor* pointer;
typedef const config_descriptor& reference;

const_iterator(const config_registry_entry_base* entry = nullptr) :
m_cur(entry)
{}

private:
const config_registry_entry_base* m_cur;

extern std::atomic<config_registry_entry_base*> g_pFirstEntry;
public:
pointer operator->(void) const { return &m_cur->descriptor; }
reference operator*(void) { return m_cur->descriptor; }

bool operator==(const const_iterator& rhs) const { return m_cur == rhs.m_cur; }
bool operator!=(const const_iterator& rhs) const { return m_cur != rhs.m_cur; }

// Iterator operator overloads:
const_iterator& operator++(void) {
m_cur = m_cur->pFlink;
return *this;
}
const_iterator operator++(int) {
auto prior = m_cur;
++*this;
return{ prior };
}
};

private:
// Application linked list head
static config_registry_entry_base* g_pFirstEntry;

public:
/// <summary>
/// Adds a link to the specified registry entry
/// </summary>
/// <remarks>
/// This routine is not thread safe, and must be externally synchronized
/// </remarks>
static const config_registry_entry_base* Link(config_registry_entry_base& entry);

// Iterator support logic:
const_iterator begin(void) const { return{ g_pFirstEntry }; }
const_iterator end(void) const { return{ nullptr }; }
};

/// <summary>
/// Gets a string representation of the named configuration value
/// </summary>
template<typename T>
std::string ConfigGet(const char* name, T& obj) {
const config_descriptor& desc = config_registry_entry<T>::desc;
const config_descriptor& desc = config_registry_entry<T>::entry.descriptor;
auto q = desc.fields.find(name);
if (q == desc.fields.end())
throw std::invalid_argument("Configuration name not found in the specified object's configuration descriptor");
Expand All @@ -54,7 +121,7 @@ namespace autowiring {
/// </summary>
template<typename T>
void ConfigSet(const char* name, T& obj, const char* value) {
const config_descriptor& desc = config_registry_entry<T>::desc;
const config_descriptor& desc = config_registry_entry<T>::entry.descriptor;
auto q = desc.fields.find(name);
if (q == desc.fields.end())
throw std::invalid_argument("Configuration name not found in the specified object's configuration descriptor");
Expand Down
2 changes: 1 addition & 1 deletion src/autowiring/CoreObjectDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ struct CoreObjectDescriptor {
pBasicThread(autowiring::fast_pointer_cast<::BasicThread>(value)),
pFilter(autowiring::fast_pointer_cast<::ExceptionFilter>(value)),
pBoltBase(autowiring::fast_pointer_cast<::BoltBase>(value)),
pConfigDesc(&config_registry_entry<T>::desc),
pConfigDesc(&config_registry_entry<T>::entry.descriptor),
primitiveOffset(
reinterpret_cast<size_t>(
static_cast<T*>(
Expand Down
2 changes: 2 additions & 0 deletions src/autowiring/config_descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ config_descriptor::t_mpType autowiring::config_descriptor::MakeFields(const std:
return retVal;
}

config_descriptor::config_descriptor(void) {}

const config_field& config_descriptor::get(size_t offset) const {
for (const auto& entry : fields)
if (entry.second.offset == offset)
Expand Down
4 changes: 4 additions & 0 deletions src/autowiring/config_descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ namespace autowiring {

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

config_descriptor(void);
config_descriptor(config_descriptor&& rhs) :
fields(std::move(rhs.fields))
{}
config_descriptor(std::initializer_list<config_field> fields) :
fields(MakeFields(fields))
{}
Expand Down
14 changes: 13 additions & 1 deletion src/autowiring/test/AutoConfigTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <autowiring/config.h>
#include <autowiring/ConfigRegistry.h>
#include <autowiring/observable.h>
#include <cstring>

namespace aw = autowiring;

Expand Down Expand Up @@ -285,7 +286,7 @@ namespace {

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

ASSERT_EQ(1UL, mgr->sliderReg.size()) << "Slider registration count did not match expectations";
}

TEST_F(AutoConfigTest, CanEnumRegistry) {
size_t nFound = 0;
for (const config_descriptor& desc : autowiring::config_registry{}) {
for (const auto& field : desc.fields) {
if (!std::strcmp("crazyjenkins", field.second.name))
nFound++;
}
}
ASSERT_EQ(1, nFound) << "Failed to find a descriptor field in the total descriptor enumeration";
}

0 comments on commit eb44dba

Please sign in to comment.