Skip to content

Instantly share code, notes, and snippets.

@Shauren
Last active March 27, 2018 16:02
Show Gist options
  • Save Shauren/db335085df33b7620c25648ffd57ec9f to your computer and use it in GitHub Desktop.
Save Shauren/db335085df33b7620c25648ffd57ec9f to your computer and use it in GitHub Desktop.
DB2 autoindexing
https://godbolt.org/g/G8mq4T // cpp14
#include <unordered_map>
#include <vector>
#include <boost/functional/hash.hpp>
#include <cstdint>
#include <cstdio>
template<typename C, typename R, R C::*M>
struct DB2Field {
using type = R;
static R value(void const* row) {
return reinterpret_cast<C const*>(row)->*M;
}
};
struct WMOAreaTableEntry {
uint32_t Id;
uint32_t RootId;
uint32_t GroupId;
uint32_t NameSet;
using Id_t = DB2Field<WMOAreaTableEntry, uint32_t, &WMOAreaTableEntry::Id>;
using RootId_t = DB2Field<WMOAreaTableEntry, uint32_t, &WMOAreaTableEntry::RootId>;
using GroupId_t = DB2Field<WMOAreaTableEntry, uint32_t, &WMOAreaTableEntry::GroupId>;
using NameSet_t = DB2Field<WMOAreaTableEntry, uint32_t, &WMOAreaTableEntry::NameSet>;
};
template<typename T>
struct tuplehash
{
size_t operator()(T const& arg) const noexcept
{
return boost::hash_value(arg);
}
};
template<typename IsUnique, typename... Fields>
struct DB2IndexDefinition {
using Key = std::tuple<typename Fields::type...>;
using Unique = IsUnique;
static Key make_index_value(void const* row)
{
return std::make_tuple(Fields::value(row)...);
}
};
struct DB2IndexType {
using Unique = std::true_type;
using NonUnique = std::false_type;
};
template<typename T, typename FieldList>
class DB2Index {
public:
using Key = typename FieldList::Key;
using StoredValue = std::conditional_t<FieldList::Unique::value, T const*, std::vector<T const*>>;
using NonUniqueValue = std::pair<typename std::vector<T const*>::const_iterator, typename std::vector<T const*>::const_iterator>;
using Unique = typename FieldList::Unique;
auto Lookup(Key&& key) const
{
return Lookup(std::forward<Key>(key), Unique{});
}
void Index(T const* row)
{
Index(row, Unique{});
}
private:
T const* Lookup(Key&& key, DB2IndexType::Unique) const
{
auto itr = _indexTable.find(std::forward<Key>(key));
if (itr != _indexTable.end())
return itr->second;
return nullptr;
}
NonUniqueValue Lookup(Key&& key, DB2IndexType::NonUnique) const
{
auto itr = _indexTable.find(std::forward<Key>(key));
if (itr != _indexTable.end())
return { itr->second.begin(), itr->second.end() };
return { };
}
void Index(T const* row, DB2IndexType::Unique)
{
_indexTable[FieldList::make_index_value(row)] = row;
}
void Index(T const* row, DB2IndexType::NonUnique)
{
_indexTable[FieldList::make_index_value(row)].push_back(row);
}
std::unordered_map<Key, StoredValue, tuplehash<Key>> _indexTable;
};
template<typename T, typename... Indexes>
class DB2Storage
{
public:
template<typename... IndexFields>
T const* LookupEntryByIndex(typename IndexFields::type... keys) const
{
using IndexType = DB2Index<T, DB2IndexDefinition<DB2IndexType::Unique, IndexFields...>>;
auto const& indexTable = std::get<IndexType>(_indexTables);
return indexTable.Lookup(std::make_tuple(keys...));
}
template<typename... IndexFields>
auto LookupEntriesByIndex(typename IndexFields::type... keys) const
{
using IndexType = DB2Index<T, DB2IndexDefinition<DB2IndexType::NonUnique, IndexFields...>>;
auto indexTable = std::get<IndexType>(_indexTables);
return indexTable.Lookup(std::make_tuple(keys...));
}
void Index()
{
for (uint32_t i = 0; i < _numRows; ++i)
IndexRow(&_dataTable[i], std::index_sequence_for<Indexes...>());
}
private:
template <std::size_t...Is>
void IndexRow(T const* row, std::index_sequence<Is...>)
{
int dummy[] = {0, (std::get<Is>(_indexTables).Index(row), void(), 0)...};
static_cast<void>(dummy);
}
std::tuple<DB2Index<T, Indexes>...> _indexTables;
T* _dataTable;
uint32_t _numRows;
};
DB2Storage<WMOAreaTableEntry,
DB2IndexDefinition<DB2IndexType::NonUnique, WMOAreaTableEntry::RootId_t, WMOAreaTableEntry::GroupId_t, WMOAreaTableEntry::NameSet_t>,
DB2IndexDefinition<DB2IndexType::Unique, WMOAreaTableEntry::Id_t>
> sWMOAreaTableStore;
int main()
{
sWMOAreaTableStore.Index();
auto byWmoBounds = sWMOAreaTableStore.LookupEntriesByIndex<WMOAreaTableEntry::RootId_t, WMOAreaTableEntry::GroupId_t, WMOAreaTableEntry::NameSet_t>(1, 1, 1);
WMOAreaTableEntry const* byId = sWMOAreaTableStore.LookupEntryByIndex<WMOAreaTableEntry::Id_t>(1);
for (auto byWmo = byWmoBounds.first; byWmo != byWmoBounds.second; ++byWmo)
printf("byWmo: %u\n", (*byWmo)->Id);
printf("byId: root %u, group %u, name %u\n", byId->RootId, byId->GroupId, byId->NameSet);
return 0;
}
https://godbolt.org/g/FTuFL8
#include <unordered_map>
#include <vector>
#include <boost/functional/hash.hpp>
#include <cstdint>
struct WMOAreaTableEntry {
uint32_t Id;
uint32_t RootId;
uint32_t GroupId;
uint32_t NameSet;
};
template<typename T>
struct tuplehash
{
size_t operator()(T const& arg) const noexcept
{
return boost::hash_value(arg);
}
};
template<class T>
struct remove_member_pointer {
typedef T type;
};
template<class Parent, class T>
struct remove_member_pointer<T Parent::*> {
typedef T type;
};
template<auto... Fields>
struct DB2IndexFieldList {
using keys = std::tuple<typename remove_member_pointer<decltype(Fields)>::type...>;
};
template<typename T, typename FieldsTuple>
class DB2Index {
public:
using KeysTuple = typename FieldsTuple::keys;
std::vector<T const*> const* Lookup(KeysTuple&& keys) const
{
auto itr = _indexTable.find(std::forward<KeysTuple>(keys));
if (itr != _indexTable.end())
return &itr->second;
return nullptr;
}
std::unordered_map<KeysTuple, std::vector<T const*>, tuplehash<KeysTuple>> _indexTable;
};
template<typename T, typename... Indexes>
class DB2Storage
{
public:
template<auto... IndexFields>
T const* LookupEntryByIndex(typename remove_member_pointer<decltype(IndexFields)>::type... keys) const
{
using IndexType = DB2Index<T, DB2IndexFieldList<IndexFields...>>;
auto const& indexTable = std::get<IndexType>(_indexTables);
std::vector<T const*> const* values = indexTable.Lookup(std::make_tuple(keys...));
if (values)
return (*values)[0]; // guaranteed nonempty by loading
return nullptr;
}
template<auto... IndexFields>
std::vector<T const*> const* LookupEntriesByIndex(typename remove_member_pointer<decltype(IndexFields)>::type... keys) const
{
using IndexType = DB2Index<T, DB2IndexFieldList<IndexFields...>>;
auto indexTable = std::get<IndexType>(_indexTables);
return indexTable.Lookup(std::make_tuple(keys...));
}
std::tuple<DB2Index<T, Indexes>...> _indexTables;
};
DB2Storage<WMOAreaTableEntry, DB2IndexFieldList<&WMOAreaTableEntry::RootId, &WMOAreaTableEntry::GroupId, &WMOAreaTableEntry::NameSet>> sWMOAreaTableStore;
int main()
{
sWMOAreaTableStore.LookupEntryByIndex<&WMOAreaTableEntry::RootId, &WMOAreaTableEntry::GroupId, &WMOAreaTableEntry::NameSet>(1, 1, 1);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment