Last active
March 27, 2018 16:02
-
-
Save Shauren/db335085df33b7620c25648ffd57ec9f to your computer and use it in GitHub Desktop.
DB2 autoindexing
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
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; | |
} |
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
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