Last active
August 29, 2015 14:13
-
-
Save mrdomino/f91292a20f3584f0b6f5 to your computer and use it in GitHub Desktop.
Registry sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "registry.h" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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