Advertisement
Guest User

Untitled

a guest
Jan 17th, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.67 KB | None | 0 0
  1. #pragma once
  2. // This breaks boost multi index, this is defined by cpprest
  3. #ifdef U
  4. #undef U
  5. #endif
  6. #include <boost/multi_index_container.hpp>
  7. #include <boost/multi_index/tag.hpp>
  8. #include "key.hpp"
  9. #include <boost/multi_index/member.hpp>
  10. #include <boost/multi_index/ordered_index.hpp>
  11. #include <boost/multi_index/identity.hpp>
  12.  
  13. namespace ap {
  14.  
  15. using namespace boost::multi_index;
  16.  
  17. //-----------------------------------------------------------------------------
  18. /// @details
  19. ///     This is an experimental word store based off boost multi index
  20. ///     and text short allocators
  21. //-----------------------------------------------------------------------------
  22. template<size_t StackSize = 1024, size_t GrowByCount = 50>
  23. class WordStoreBmi {
  24.  
  25. public:
  26.     WordStoreBmi() :
  27.         m_table(m_rowArena) {
  28.     }
  29.  
  30.     WordStoreBmi(WordStoreBmi &&words) = delete;
  31.     WordStoreBmi(const WordStoreBmi &words) = delete;
  32.  
  33. private:
  34.  
  35.     //-----------------------------------------------------------------------------
  36.     /// @details
  37.     ///     In order to ensure optimum performance we use a short allocator
  38.     ///     for our componentId containers and our words
  39.     //-----------------------------------------------------------------------------
  40.     using CompAllocator = memory::short_alloc<Dword, StackSize>;
  41.     using CompArena = typename CompAllocator::arena_type;
  42.     using Comps = std::vector<Dword, CompAllocator>;
  43.  
  44.     using iWordStrAllocator = memory::short_alloc<TextChr, StackSize, alignof(std::max_align_t)>;
  45.     using iWordStrArena = typename iWordStrAllocator::arena_type;
  46.     using iWordStr = string::Str<TextChr, string::NoCase<TextChr>, iWordStrAllocator>;
  47.     using iWordStrView = string::StrView<TextChr, string::NoCase<TextChr>>;
  48.  
  49.     //-----------------------------------------------------------------------------
  50.     /// @details
  51.     ///     These empty structures are used as tags in the index,
  52.     ///     IdxWordId is the index for the word id itself (Dword), where
  53.     ///     IdxWordStr is the index for the case insensitive word value
  54.     //-----------------------------------------------------------------------------
  55.     struct IdxWordId {};
  56.     struct IdxWordStr {};
  57.  
  58.     //-----------------------------------------------------------------------------
  59.     /// @details
  60.     ///     Here we define the word row, think of this like a database, where
  61.     ///     indexes are sepearate from the actual row definition
  62.     //-----------------------------------------------------------------------------
  63.     struct Row {
  64.         //-----------------------------------------------------------------
  65.         /// @details
  66.         ///     The id for this item, ids always start at 1
  67.         //-----------------------------------------------------------------
  68.         Dword id;
  69.  
  70.         //-----------------------------------------------------------------
  71.         /// @details
  72.         ///     The word itself
  73.         //-----------------------------------------------------------------
  74.         iWordStr word;
  75.         iWordStrView accessWordStr() const noexcept { return word; }
  76.  
  77.         //-----------------------------------------------------------------
  78.         /// @details
  79.         ///     Component ids this word is associated with
  80.         //-----------------------------------------------------------------
  81.         Comps componentIds;
  82.     };
  83.  
  84.     using RowAllocator = memory::short_alloc<Row, StackSize>;
  85.     using RowArena = typename RowAllocator::arena_type;
  86.  
  87.     RowArena m_rowArena;
  88.  
  89.     //-----------------------------------------------------------------------------
  90.     /// @details
  91.     ///     Define the word table, a boost multi index with two indexes
  92.     ///     one for the word id, the other for the word value
  93.     //-----------------------------------------------------------------------------
  94.     using Table = boost::multi_index_container<
  95.         Row,
  96.         indexed_by<
  97.             ordered_unique<
  98.                 tag<IdxWordId>,
  99.                 key<&Row::id>
  100.             >,
  101.             ordered_unique<
  102.                 tag<IdxWordStr>,
  103.                 const_mem_fun<Row, iWordStrView, &Row::accessWordStr>
  104.             >
  105.         >,
  106.         RowAllocator
  107.     >;
  108.  
  109.     //------------------------------------------------------------------------------
  110.     /// @details
  111.     ///     Here is our short allocator for all componentId vectors in all word rows
  112.     //------------------------------------------------------------------------------
  113.     CompArena m_compArena;
  114.  
  115.     //------------------------------------------------------------------------------
  116.     /// @details
  117.     ///     Here is our short allocator for all word strings
  118.     //------------------------------------------------------------------------------
  119.     iWordStrArena m_strArena;
  120.  
  121.     //------------------------------------------------------------------------------
  122.     /// @details
  123.     ///     And here's the actual table of indexes, note the allocator arenas
  124.     ///     above must not outlive this so its declared last
  125.     //------------------------------------------------------------------------------
  126.     Table m_table;
  127.  
  128. public:
  129.     //-----------------------------------------------------------------------------
  130.     /// @details
  131.     ///     Each lookup function below will look up the word by either its
  132.     ///     id or its value. They don't add to the store and they all
  133.     ///     return optional references which are populated if the word
  134.     ///     was found. There are const and non const versions for each, note
  135.     ///     it is imperitive the word member of the word row is never
  136.     ///     modified as it serves as the index to the table.
  137.     /// @param[in]: wordId/word
  138.     ///     Either the word value or the word id
  139.     /// @returns
  140.     ///     An optional reference if the word was found
  141.     //-----------------------------------------------------------------------------
  142.     Opt<Ref<const Row>> lookup(Dword wordId) const noexcept {
  143.         const auto &idx = m_table.get<IdxWordId>();
  144.         if (auto entry = idx.find(wordId); entry != idx.end())
  145.             return *entry;
  146.         return {};
  147.     }
  148.  
  149.     Opt<Ref<const Row>> lookup(iWordStrView word) const noexcept {
  150.         const auto &idx = m_table.get<IdxWordStr>();
  151.         if (auto entry = idx.find(word); entry != idx.end())
  152.             return *entry;
  153.         return {};
  154.     }
  155.  
  156.     Opt<Ref<Row>> lookup(Dword wordId) noexcept {
  157.         auto &idx = m_table.get<IdxWordId>();
  158.         if (auto entry = idx.find(wordId); entry != idx.end())
  159.             return const_cast<Row &>(*entry);
  160.         return {};
  161.     }
  162.  
  163.     Opt<Ref<Row>> lookup(iWordStrView word) noexcept {
  164.         auto &idx = m_table.get<IdxWordStr>();
  165.         if (auto entry = idx.find(word); entry != idx.end())
  166.             return const_cast<Row &>(*entry);
  167.         return {};
  168.     }
  169.  
  170.     //-----------------------------------------------------------------------------
  171.     /// @details
  172.     ///     Returns the size of this store, which amounts to the total number
  173.     ///     of unique words present
  174.     /// @returns
  175.     ///     The total number of stored words
  176.     //-----------------------------------------------------------------------------
  177.     size_t size() const noexcept {
  178.         return m_table.size();
  179.     }
  180.  
  181.     //-----------------------------------------------------------------------------
  182.     /// @details
  183.     ///     Adds a word to the store, optionally associates a componentId to
  184.     ///     the located word if specified
  185.     /// @param[in]: word
  186.     ///     The word to add
  187.     /// @param[in|opt]: componentId
  188.     ///     An optional which if set is added to the component id list in the word
  189.     ///     row
  190.     /// @returns
  191.     ///     A pair, first entry is the ref, second is a flag indicating if
  192.     ///     this word was newly added to the store, or was looked up from a previous
  193.     ///     add. If componentId is specified this flag will be true if either
  194.     ///     component id was first to encounter it
  195.     //-----------------------------------------------------------------------------
  196.     decltype(auto) add(iWordStrView word, Opt<Dword> componentId = {}) noexcept {
  197.         //-------------------------------------------------------------------------
  198.         // Lookup or add a row and unpackage it
  199.         //-------------------------------------------------------------------------
  200.         Opt<Ref<Row>> wordRow;
  201.         bool unique = false;
  202.         if (!(wordRow = lookup(word))) {
  203.             wordRow = const_cast<Row &>(*m_table.insert(Row{ m_nextWordId++, iWordStr(word, m_strArena), Comps(m_compArena) }).first);
  204.             unique = true;
  205.         }
  206.         auto &row = wordRow->get();
  207.  
  208.         //---------------------------------------------------------------------
  209.         // Add the component if needed
  210.         //---------------------------------------------------------------------
  211.         if (componentId) {
  212.             if (!util::anyOf(row.componentIds, componentId.value())) {
  213.                 unique = true;
  214.                 if (!(row.componentIds.capacity() % GrowByCount))
  215.                     row.componentIds.reserve(row.componentIds.capacity() + GrowByCount);
  216.                 row.componentIds.push_back(componentId.value());
  217.             }
  218.         }
  219.  
  220.         return std::make_pair(row, unique);
  221.     }
  222.  
  223. private:
  224.     //------------------------------------------------------------------------------
  225.     /// @details
  226.     ///     We keep tabs on the word ids, and they start at one
  227.     //------------------------------------------------------------------------------
  228.     Dword m_nextWordId = 1;
  229. };
  230.  
  231. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement