pEpJSONServerAdapter/server/registry.hh

134 lines
2.8 KiB
C++

// A "registry" for arbitrary objects.
// all registered objects have their unique "handle", an arbitrary
// 64 bit number that can also be represented as a base64-encoded string
#include <cstdint>
#include <string>
#include <map>
#include <memory> // for unique ptr
#include <vector>
//////////////////////////////
//
// helper functions
//
/////////////////////////////
// mix the bits of 'value' into a less-
std::uint64_t joggle(std::uint64_t realm, std::uint64_t value);
// unjoggle( joggle(x) ) == x for any 64 bit value
std::uint64_t unjoggle(std::uint64_t realm, std::uint64_t value);
// converts 'x' into a 11-character string
std::string base57(std::uint64_t x);
// does the reverse of base62().
std::uint64_t unbase57(const std::string& s);
// tests the joggle(), unjoggle(), base57(), unbase57() on several values.
// return 0 on succes, >0 on error
unsigned test_joggle();
template<class Resource, class Creator, class Deleter>
class Registry
{
public:
Registry(const Creator& cr, const Deleter& del)
: c(cr), d(del)
{}
Registry(const Registry&) = delete;
~Registry()
{
clear();
}
bool has( std::uint64_t index ) const;
bool has( const std::string& handle ) const;
// throws an exception if there is no such element in the map
Resource get( std::uint64_t handle ) const
{
const auto it = m.find(handle);
if(it == m.end())
{
throw std::runtime_error("There is no element with handle <" + std::to_string(handle) + "> registered.");
}
return it->second;
}
Resource get( const std::string& handle ) const
{
return get(unbase57(handle));
}
// construct & inserts a new element and returns the handle
template<class... Args>
std::uint64_t emplace(Args... args)
{
Resource rsrc = c(args...);
const uint64_t id = joggle( Identifier, intptr_t(rsrc) );
const auto ret = m.insert( std::make_pair(id, rsrc) );
if(ret.second == false)
{
d(rsrc);
throw std::runtime_error("Duplicate entry: id=" + std::to_string(id) + ", rsrc=" + std::to_string( intptr_t(rsrc) ) );
}
return id;
}
void erase( std::uint64_t handle )
{
auto it = m.find(handle);
if(it!=m.end())
{
d(it->second);
m.erase(it);
}else{
throw std::runtime_error("cannot erase: There is no element with handle <" + std::to_string(handle) + "> registered.");
}
}
void erase( const std::string& handle )
{
erase(unbase57(handle));
}
std::vector<std::uint64_t> keys() const
{
std::vector<std::uint64_t> k;
k.reserve(m.size());
for(const auto& e : m)
{
k.push_back(e.first);
}
return k;
}
void clear()
{
for(auto elem : m)
{
d(elem.second);
}
}
std::size_t size() const
{
return m.size();
}
private:
typedef std::map< std::uint64_t, Resource > Map;
const Creator c;
const Deleter d;
Map m;
static const uint64_t Identifier;
};