Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- // This breaks boost multi index, this is defined by cpprest
- #ifdef U
- #undef U
- #endif
- #include <boost/multi_index_container.hpp>
- #include <boost/multi_index/tag.hpp>
- #include "key.hpp"
- #include <boost/multi_index/member.hpp>
- #include <boost/multi_index/ordered_index.hpp>
- #include <boost/multi_index/identity.hpp>
- namespace ap {
- using namespace boost::multi_index;
- //-----------------------------------------------------------------------------
- /// @details
- /// This is an experimental word store based off boost multi index
- /// and text short allocators
- //-----------------------------------------------------------------------------
- template<size_t StackSize = 1024, size_t GrowByCount = 50>
- class WordStoreBmi {
- public:
- WordStoreBmi() :
- m_table(m_rowArena) {
- }
- WordStoreBmi(WordStoreBmi &&words) = delete;
- WordStoreBmi(const WordStoreBmi &words) = delete;
- private:
- //-----------------------------------------------------------------------------
- /// @details
- /// In order to ensure optimum performance we use a short allocator
- /// for our componentId containers and our words
- //-----------------------------------------------------------------------------
- using CompAllocator = memory::short_alloc<Dword, StackSize>;
- using CompArena = typename CompAllocator::arena_type;
- using Comps = std::vector<Dword, CompAllocator>;
- using iWordStrAllocator = memory::short_alloc<TextChr, StackSize, alignof(std::max_align_t)>;
- using iWordStrArena = typename iWordStrAllocator::arena_type;
- using iWordStr = string::Str<TextChr, string::NoCase<TextChr>, iWordStrAllocator>;
- using iWordStrView = string::StrView<TextChr, string::NoCase<TextChr>>;
- //-----------------------------------------------------------------------------
- /// @details
- /// These empty structures are used as tags in the index,
- /// IdxWordId is the index for the word id itself (Dword), where
- /// IdxWordStr is the index for the case insensitive word value
- //-----------------------------------------------------------------------------
- struct IdxWordId {};
- struct IdxWordStr {};
- //-----------------------------------------------------------------------------
- /// @details
- /// Here we define the word row, think of this like a database, where
- /// indexes are sepearate from the actual row definition
- //-----------------------------------------------------------------------------
- struct Row {
- //-----------------------------------------------------------------
- /// @details
- /// The id for this item, ids always start at 1
- //-----------------------------------------------------------------
- Dword id;
- //-----------------------------------------------------------------
- /// @details
- /// The word itself
- //-----------------------------------------------------------------
- iWordStr word;
- iWordStrView accessWordStr() const noexcept { return word; }
- //-----------------------------------------------------------------
- /// @details
- /// Component ids this word is associated with
- //-----------------------------------------------------------------
- Comps componentIds;
- };
- using RowAllocator = memory::short_alloc<Row, StackSize>;
- using RowArena = typename RowAllocator::arena_type;
- RowArena m_rowArena;
- //-----------------------------------------------------------------------------
- /// @details
- /// Define the word table, a boost multi index with two indexes
- /// one for the word id, the other for the word value
- //-----------------------------------------------------------------------------
- using Table = boost::multi_index_container<
- Row,
- indexed_by<
- ordered_unique<
- tag<IdxWordId>,
- key<&Row::id>
- >,
- ordered_unique<
- tag<IdxWordStr>,
- const_mem_fun<Row, iWordStrView, &Row::accessWordStr>
- >
- >,
- RowAllocator
- >;
- //------------------------------------------------------------------------------
- /// @details
- /// Here is our short allocator for all componentId vectors in all word rows
- //------------------------------------------------------------------------------
- CompArena m_compArena;
- //------------------------------------------------------------------------------
- /// @details
- /// Here is our short allocator for all word strings
- //------------------------------------------------------------------------------
- iWordStrArena m_strArena;
- //------------------------------------------------------------------------------
- /// @details
- /// And here's the actual table of indexes, note the allocator arenas
- /// above must not outlive this so its declared last
- //------------------------------------------------------------------------------
- Table m_table;
- public:
- //-----------------------------------------------------------------------------
- /// @details
- /// Each lookup function below will look up the word by either its
- /// id or its value. They don't add to the store and they all
- /// return optional references which are populated if the word
- /// was found. There are const and non const versions for each, note
- /// it is imperitive the word member of the word row is never
- /// modified as it serves as the index to the table.
- /// @param[in]: wordId/word
- /// Either the word value or the word id
- /// @returns
- /// An optional reference if the word was found
- //-----------------------------------------------------------------------------
- Opt<Ref<const Row>> lookup(Dword wordId) const noexcept {
- const auto &idx = m_table.get<IdxWordId>();
- if (auto entry = idx.find(wordId); entry != idx.end())
- return *entry;
- return {};
- }
- Opt<Ref<const Row>> lookup(iWordStrView word) const noexcept {
- const auto &idx = m_table.get<IdxWordStr>();
- if (auto entry = idx.find(word); entry != idx.end())
- return *entry;
- return {};
- }
- Opt<Ref<Row>> lookup(Dword wordId) noexcept {
- auto &idx = m_table.get<IdxWordId>();
- if (auto entry = idx.find(wordId); entry != idx.end())
- return const_cast<Row &>(*entry);
- return {};
- }
- Opt<Ref<Row>> lookup(iWordStrView word) noexcept {
- auto &idx = m_table.get<IdxWordStr>();
- if (auto entry = idx.find(word); entry != idx.end())
- return const_cast<Row &>(*entry);
- return {};
- }
- //-----------------------------------------------------------------------------
- /// @details
- /// Returns the size of this store, which amounts to the total number
- /// of unique words present
- /// @returns
- /// The total number of stored words
- //-----------------------------------------------------------------------------
- size_t size() const noexcept {
- return m_table.size();
- }
- //-----------------------------------------------------------------------------
- /// @details
- /// Adds a word to the store, optionally associates a componentId to
- /// the located word if specified
- /// @param[in]: word
- /// The word to add
- /// @param[in|opt]: componentId
- /// An optional which if set is added to the component id list in the word
- /// row
- /// @returns
- /// A pair, first entry is the ref, second is a flag indicating if
- /// this word was newly added to the store, or was looked up from a previous
- /// add. If componentId is specified this flag will be true if either
- /// component id was first to encounter it
- //-----------------------------------------------------------------------------
- decltype(auto) add(iWordStrView word, Opt<Dword> componentId = {}) noexcept {
- //-------------------------------------------------------------------------
- // Lookup or add a row and unpackage it
- //-------------------------------------------------------------------------
- Opt<Ref<Row>> wordRow;
- bool unique = false;
- if (!(wordRow = lookup(word))) {
- wordRow = const_cast<Row &>(*m_table.insert(Row{ m_nextWordId++, iWordStr(word, m_strArena), Comps(m_compArena) }).first);
- unique = true;
- }
- auto &row = wordRow->get();
- //---------------------------------------------------------------------
- // Add the component if needed
- //---------------------------------------------------------------------
- if (componentId) {
- if (!util::anyOf(row.componentIds, componentId.value())) {
- unique = true;
- if (!(row.componentIds.capacity() % GrowByCount))
- row.componentIds.reserve(row.componentIds.capacity() + GrowByCount);
- row.componentIds.push_back(componentId.value());
- }
- }
- return std::make_pair(row, unique);
- }
- private:
- //------------------------------------------------------------------------------
- /// @details
- /// We keep tabs on the word ids, and they start at one
- //------------------------------------------------------------------------------
- Dword m_nextWordId = 1;
- };
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement