Skip to content

Instantly share code, notes, and snippets.

@mrdomino
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrdomino/f91292a20f3584f0b6f5 to your computer and use it in GitHub Desktop.
Save mrdomino/f91292a20f3584f0b6f5 to your computer and use it in GitHub Desktop.
Registry sketch
#include <iomanip>
#include <iostream>
#include <utility>
#include "registry.h"
using std::cerr;
using std::cin;
using std::endl;
using std::ios_base;
using std::setbase;
using std::showbase;
using std::ws;
struct Foo {
static const int KEY;
virtual char const* thingy() const {
static constexpr char const* thingy = "Foo";
return thingy;
}
};
struct BFoo : Foo {
static const int KEY;
char const* thingy() const override {
static constexpr char const* thingy = "BFoo";
return thingy;
}
};
struct ZFoo : Foo {
static const int KEY;
char const* thingy() const override {
static constexpr char const* thingy = "ZFoo";
return thingy;
}
};
struct YFoo : Foo {
static const int KEY;
char const* thingy() const override {
static constexpr char const* thingy = "YFoo";
return thingy;
}
};
const int Foo::KEY = 0;
const int BFoo::KEY = 1;
const int ZFoo::KEY = 2;
const int YFoo::KEY = 3;
using FooRegistry = Registry<int, Foo, ZFoo,
Foo, BFoo, YFoo>;
int main() {
auto fr = FooRegistry(Foo(), BFoo(), YFoo());
try {
cin.exceptions(cin.failbit | cin.badbit);
while (cin.good()) {
auto k = FooRegistry::key_type();
cin >> ws >> k;
auto f = fr.get(k);
cerr << k << ": " << setbase(16) << showbase << f << endl;
cerr << f->thingy() << endl;
}
} catch (ios_base::failure& e) {
if (!cin.eof())
exit(1);
}
return 0;
}
CXXFLAGS=-Wall -Wextra -std=c++1y
CXXFLAGS+=-DUSE_BOOST
LDFLAGS=-fsanitize=address -fsanitize=undefined
all: example
CORE=.MAKEFILE-VERSION
$(CORE): makefile
touch .MAKEFILE-VERSION
example: registry.o example.o $(CORE)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o example registry.o example.o
%.o: %.cc
$(CXX) $(CXXFLAGS) -o $@ -c $<
example.o registry.o: registry.h $(CORE)
clean:
rm example *.o
.PHONY: all clean
#include "registry.h"
#include <cassert>
#include <memory>
#include <unordered_map>
#include <type_traits>
#ifdef USE_BOOST
#include <boost/concept/assert.hpp>
#else
#define BOOST_CONCEPT_ASSERT(X) (void)0
#endif
#pragma once
template <typename T, typename K>
constexpr auto get_key()
-> typename std::enable_if<
std::is_convertible<decltype(T::KEY), K>::value,
K
>::type
{ return T::KEY; }
template <typename Registry>
struct RegistryConcept {
using Value = typename Registry::value_type;
using Key = typename Registry::key_type;
using Map = typename Registry::map_type;
void constraints() {
m.emplace(get_key<Value, Key>(), std::unique_ptr<Value>());
v = r->get(k);
}
Map& m;
Registry const* r;
Key const& k;
Value const* v;
};
/**
* This class maps Ks to instances of subclasses of V.
*
* Each Memb... is a subclass of V. When get() is called with the key returned
* by get_key<Memb, key_type>(), a pointer to an instance of Memb is returned.
* Each Memb... must have a unique key; this is checked by a runtime assert.
*
* Fail is a subclass of V that is returned if the key passed to get() is not
* in the registry. Fail may also be passed as one of the Memb... . If it is
* not, Fail need not respond to get_key.
*/
template <typename K, typename V, typename Fail, typename... Memb>
class Registry {
public:
using key_type = K;
using value_type = V;
using map_type = std::unordered_map<key_type, std::unique_ptr<value_type>>;
Registry(): Registry(Memb()...) {}
Registry(Memb&&... ms) {
BOOST_CONCEPT_ASSERT((RegistryConcept<Registry>));
addAll(std::make_unique<Memb>(std::forward<Memb>(ms))...);
}
// Callee owns.
value_type const* get(key_type const& k) const {
auto it = map_.find(k);
if (it != map_.end())
return it->second.get();
else
return &fail_;
}
private:
inline void addAll() {}
template <typename M, typename... Ms>
inline void addAll(std::unique_ptr<M>&& m, Ms&&... ms) {
auto r = map_.emplace(get_key<M, key_type>(), std::move(m));
assert(r.second);
addAll(std::forward<Ms>(ms)...);
}
map_type map_;
Fail fail_;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment