scraps

Abandon all hope, ye who enter here.
git clone https://git.neptards.moe/neptards/scraps.git
Log | Files | Refs | Submodules | README | LICENSE

id_set.hpp (2666B)


      1 #ifndef GUARD_STRONGMINDEDLY_VIRULENT_FOURTEENER_UNHEARS_0129
      2 #define GUARD_STRONGMINDEDLY_VIRULENT_FOURTEENER_UNHEARS_0129
      3 #pragma once
      4 
      5 #include <libshit/container/simple_vector.hpp> // IWYU pragma: export
      6 
      7 #include <algorithm>
      8 #include <cstddef>
      9 
     10 namespace Scraps::Game
     11 {
     12 
     13   /**
     14    * A flat_set like container for storing a set of IDs. Unlike
     15    * boost::container::flat_set, allows direct access to the underlying vector,
     16    * allowing you to push_back a bunch of random items and sort them in one go.
     17    * Limitations: expects T is cheap & noexcept to copy.
     18    */
     19   template <typename T>
     20   class IdSet : public Libshit::SimpleVector<const T>
     21   {
     22   public:
     23     using Libshit::SimpleVector<const T>::SimpleVector;
     24 
     25     void Sort()
     26     {
     27       std::sort(const_cast<T*>(this->begin()), const_cast<T*>(this->end()));
     28       ++mod_count;
     29     }
     30 
     31     bool InsertSorted(T t)
     32     {
     33       auto it = std::lower_bound(this->begin(), this->end(), t);
     34       auto to_insert = it == this->end() || *it != t;
     35       if (to_insert) this->insert(it, t);
     36       ++mod_count;
     37       return to_insert;
     38     }
     39 
     40     bool EraseSorted(T t) noexcept
     41     {
     42       auto it = std::lower_bound(this->begin(), this->end(), t);
     43       auto to_remove = it != this->end() && *it == t;
     44       if (to_remove) this->erase(it);
     45       ++mod_count;
     46       return to_remove;
     47     }
     48 
     49     template <typename Pred>
     50     void EraseIf(Pred p) noexcept(noexcept(p(this->front())))
     51     {
     52       auto it = std::remove_if(
     53         const_cast<T*>(this->begin()), const_cast<T*>(this->end()), p);
     54       this->resize(it - this->begin());
     55       ++mod_count;
     56     }
     57 
     58     // Doesn't do anything when the two containers are the same, so be careful
     59     // with side-effects...
     60     template <typename Pred>
     61     void MoveTo(IdSet& o, Pred p)
     62     {
     63       if (this == &o || this->empty()) return;
     64       IdSet tmp;
     65       tmp.reserve(this->size() + o.size());
     66 
     67       auto wr = const_cast<T*>(this->begin());
     68       auto oit = o.begin();
     69       for (auto& rd : *this)
     70         if (p(rd))
     71         {
     72           while (oit != o.end() && *oit < rd) tmp.push_back(*oit++);
     73           if (oit == o.end() || *oit != rd) tmp.push_back(rd);
     74         }
     75         else *wr++ = rd;
     76       this->resize(wr - this->begin());
     77       ++mod_count;
     78 
     79       while (oit != o.end()) tmp.push_back(*oit++);
     80       static_cast<Libshit::SimpleVector<const T>&>(o) = tmp;
     81       ++o.mod_count;
     82     }
     83 
     84     bool Count(T t) const noexcept
     85     { return std::binary_search(this->begin(), this->end(), t); }
     86 
     87     std::size_t GetModCount() const noexcept { return mod_count; }
     88     void BumpModCount() noexcept { ++mod_count; }
     89 
     90   private:
     91     std::size_t mod_count = 0;
     92   };
     93 
     94 }
     95 
     96 #endif