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