LCOV - code coverage report
Current view: top level - src - util.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 78 117 66.7 %
Date: 2020-10-15 20:26:03 Functions: 63 95 66.3 %

          Line data    Source code
       1             : #ifndef util_hpp
       2             : #define util_hpp
       3             : 
       4             : #include <algorithm>
       5             : #include <cassert>
       6             : #include <cstdint>
       7             : #include <initializer_list>
       8             : #include <random>
       9             : #include <sstream>
      10             : #include <string>
      11             : #include <unordered_map>
      12             : 
      13             : // reference to an entity or component
      14             : struct ident {
      15             : public:
      16        1214 :     constexpr explicit ident(uint32_t i) : i_{i} {}
      17             : 
      18           0 :     operator bool() { return i_ != 0; }
      19             : 
      20        5843 :     bool operator==(const ident& other) const { return i_ == other.i_; }
      21           0 :     bool operator!=(const ident& other) const { return !(*this == other); }
      22             : 
      23        1194 :     ident operator++(int) {
      24        1194 :         uint32_t old = i_++;
      25        1194 :         return ident{old};
      26             :     }
      27             : 
      28             : protected:
      29             :     uint32_t i_;
      30             :     friend std::hash<ident>;
      31             :     friend std::string to_string(const ident& id);
      32             : };
      33             : 
      34             : constexpr ident invalid_id{0};
      35             : 
      36             : inline std::string to_string(const ident& id) { return std::string("#") + std::to_string(id.i_); }
      37             : 
      38             : namespace std {
      39             : // for std::unordered_map<id, ...>
      40             : template <> struct hash<::ident> {
      41        4335 :     size_t operator()(::ident i) const noexcept { return hash<uint32_t>()(i.i_); }
      42             : };
      43             : }; // namespace std
      44             : 
      45             : // packed-array map for components
      46          20 : template <typename T> class container {
      47             : public:
      48             :     using key_type = ident;
      49             :     using value_type = T;
      50             : 
      51          20 :     container() {
      52          20 :         const int initialElems = 4096;
      53          20 :         values_.reserve(initialElems);
      54          20 :     }
      55             : 
      56             :     value_type& add(value_type value = {}) {
      57             :         key_type key = nextKey_++;
      58             :         size_t index = values_.size();
      59             :         values_.push_back(std::move(value));
      60             :         values_.back().id = key;
      61             :         indices_[key] = index;
      62             :         return values_.back();
      63             :     }
      64             : 
      65          10 :     value_type& operator[](key_type key) {
      66          10 :         auto it = indices_.find(key);
      67          10 :         if (it == indices_.end())
      68           0 :             return nullElement_;
      69             :         else
      70          10 :             return values_[it->second];
      71             :     }
      72             : 
      73           0 :     void remove(key_type key) {
      74           0 :         auto it = indices_.find(key);
      75           0 :         assert(it != indices_.end());
      76           0 :         size_t index = it->second;
      77           0 :         auto& back = values_.back();
      78           0 :         indices_[back.id] = index;
      79           0 :         values_[index] = std::move(back);
      80           0 :         values_.pop_back();
      81           0 :         indices_.erase(it);
      82           0 :     }
      83             : 
      84          50 :     std::vector<T>& values() { return values_; }
      85             : 
      86             : protected:
      87             :     std::unordered_map<key_type, size_t> indices_;
      88             :     std::vector<T> values_;
      89             :     key_type nextKey_{1};
      90             :     T nullElement_{};
      91             : 
      92             :     template <typename U> friend std::string to_string(const container<U>& container);
      93             : };
      94             : 
      95             : template <typename T> std::string to_string(const container<T>& container) {
      96             :     std::ostringstream oss;
      97             :     oss << "[";
      98             :     for (const auto& v : container.values_) {
      99             :         oss << "(" << container.indices_.at(v.id) << ":" << to_string(v) << ") ";
     100             :     }
     101             :     oss << "]";
     102             :     return oss.str();
     103             : }
     104             : 
     105             : // a buffered, safer version of container
     106             : // preserves references to elements until sync() is called
     107          20 : template <typename T> class buffered_container : public container<T> {
     108             :     using super = container<T>;
     109             : 
     110             : public:
     111             :     using key_type = typename super::key_type;
     112             :     using value_type = typename super::value_type;
     113             : 
     114          20 :     buffered_container() {
     115          20 :         add_.reserve(max_size());
     116          20 :         remove_.reserve(max_size());
     117             : 
     118          20 :         remove_.clear();
     119          20 :         add_.clear();
     120          20 :     }
     121             : 
     122        1234 :     constexpr int max_size() const { return 1024; }
     123             : 
     124           0 :     int size() const { return (int)add_.size(); }
     125             : 
     126        1194 :     value_type& add(value_type value = {}) {
     127        1194 :         if (add_.size() >= max_size()) {
     128           0 :             throw std::runtime_error("Exceeded buffer capacity");
     129             :         }
     130             : 
     131        1194 :         buffered_ = true;
     132        1194 :         key_type key = super::nextKey_++;
     133        1194 :         add_.push_back(std::move(value));
     134        1194 :         add_.back().id = key;
     135        1194 :         return add_.back();
     136             :     }
     137             : 
     138           0 :     void remove(key_type key) {
     139           0 :         bool inContainer = super::indices_.find(key) != super::indices_.end();
     140           0 :         bool inBuffer = std::find_if(add_.begin(), add_.end(),
     141           0 :                                      [key](T& value) { return value.id == key; }) != add_.end();
     142           0 :         assert(inContainer || inBuffer);
     143             : 
     144           0 :         buffered_ = true;
     145           0 :         remove_.push_back(key);
     146           0 :     }
     147             : 
     148         212 :     value_type& operator[](key_type key) {
     149         212 :         if (buffered_) {
     150         202 :             auto remove_it = std::find(remove_.begin(), remove_.end(), key);
     151         202 :             if (remove_it != remove_.end())
     152         202 :                 return super::nullElement_;
     153             : 
     154         202 :             if (super::indices_.count(key) == 0) {
     155         202 :                 auto add_it = std::find_if(add_.begin(), add_.end(),
     156        5717 :                                            [key](const T& t) { return t.id == key; });
     157         202 :                 if (add_it != add_.end())
     158         202 :                     return *add_it;
     159             :             }
     160             :         }
     161          10 :         return super::operator[](key);
     162             :     }
     163             : 
     164         100 :     void sync() {
     165        1294 :         for (auto& value : add_) {
     166        1194 :             size_t index = super::values_.size();
     167        1194 :             super::values_.push_back(std::move(value));
     168        1194 :             super::indices_[value.id] = index;
     169             :         }
     170             : 
     171         100 :         for (auto& id : remove_) {
     172           0 :             super::remove(id);
     173             :         }
     174             : 
     175         100 :         add_.clear();
     176         100 :         remove_.clear();
     177         100 :         buffered_ = false;
     178         100 :     }
     179             : 
     180             : protected:
     181             :     bool buffered_ = false;
     182             :     std::vector<T> add_{};
     183             :     std::vector<ident> remove_{};
     184             : };
     185             : 
     186             : // Mathematics
     187             : 
     188             : template <typename T> struct vec2 {
     189             :     T x, y;
     190             : 
     191           0 :     template <typename U> explicit operator vec2<U>() {
     192           0 :         return vec2<U>{static_cast<U>(x), static_cast<U>(y)};
     193             :     }
     194             : };
     195             : 
     196             : using vec2i = vec2<int32_t>;
     197             : using vec2d = vec2<double>;
     198             : 
     199             : template <typename T> inline vec2<T> operator-(vec2<T> a) { return {-a.x, -a.y}; }
     200     1020828 : template <typename T> inline vec2<T> operator+(vec2<T> a, vec2<T> b) {
     201     1020828 :     return {a.x + b.x, a.y + b.y};
     202             : }
     203      327680 : template <typename T> inline vec2<T> operator-(vec2<T> a, vec2<T> b) {
     204      327680 :     return {a.x - b.x, a.y - b.y};
     205             : }
     206           0 : template <typename T> inline vec2<T> operator*(vec2<T> a, T m) { return {a.x * m, a.y * m}; }
     207      674153 : template <typename T> inline vec2<T> operator/(vec2<T> a, T m) { return {a.x / m, a.y / m}; }
     208           0 : template <typename T> inline vec2<T>& operator+=(vec2<T>& a, vec2<T> b) { return a = a + b; }
     209             : template <typename T> inline vec2<T>& operator-=(vec2<T>& a, vec2<T> b) { return a = a + b; }
     210           0 : template <typename T> inline vec2<T>& operator*=(vec2<T>& a, T b) { return a = a * b; }
     211             : template <typename T> inline vec2<T>& operator/=(vec2<T>& a, T b) { return a = a / b; }
     212           0 : template <typename T> inline bool operator==(vec2<T> a, vec2<T> b) {
     213           0 :     return a.x == b.x && a.y == b.y;
     214             : }
     215          10 : template <typename T> inline bool operator!=(vec2<T> a, vec2<T> b) {
     216          10 :     return a.x != b.x || a.y != b.y;
     217             : }
     218             : 
     219             : struct recti {
     220             :     int32_t left, top, width, height;
     221      665255 :     inline bool contains(const vec2i& p) const {
     222      665255 :         return p.x >= left && p.x < left + width && p.y <= top && p.y > top - height;
     223             :     }
     224             : };
     225             : 
     226             : template <typename T> inline std::string to_string(const vec2<T>& vec) {
     227             :     using namespace std::string_literals;
     228             :     return "{"s + std::to_string(vec.x) + ", "s + std::to_string(vec.y) + "}"s;
     229             : }
     230             : 
     231           0 : template <typename T> T sign(T t) {
     232           0 :     if (t > 0)
     233           0 :         return 1;
     234           0 :     else if (t < 0)
     235           0 :         return -1;
     236             :     else
     237           0 :         return 0;
     238             : }
     239             : 
     240             : // Helpful containers
     241             : 
     242          10 : template <typename T> struct Array2D {
     243             : public:
     244          10 :     Array2D(int width, int height, T nullVal = {})
     245          10 :         : nullVal_(nullVal), width_(width), height_(height), data_(width * height, nullVal) {}
     246             : 
     247             :     void resize(int newWidth, int newHeight) {
     248             :         width_ = newWidth;
     249             :         height_ = newHeight;
     250             :         data_.resize(width_ * height_, nullVal_);
     251             :         data_.shrink_to_fit();
     252             :     }
     253             : 
     254      135840 :     int width() const { return width_; }
     255             : 
     256      135840 :     int height() const { return height_; }
     257             : 
     258           5 :     void fill(T val) { std::fill(data_.begin(), data_.end(), val); }
     259             : 
     260      170980 :     T& operator()(int x, int y) { return inBounds(x, y) ? data_[x + y * width_] : nullVal_; }
     261             : 
     262       35140 :     T& operator()(vec2i p) { return (*this)(p.x, p.y); }
     263             : 
     264             :     const T& operator()(int x, int y) const {
     265             :         return inBounds(x, y) ? data_[x + y * width_] : nullVal_;
     266             :     }
     267             : 
     268             :     const T& operator()(vec2i p) const { return (*this)(p.x, p.y); }
     269             : 
     270      170980 :     bool inBounds(int x, int y) const { return x >= 0 && x < width_ && y >= 0 && y < height_; }
     271             : 
     272             :     bool inBounds(vec2i p) const { return p.x >= 0 && p.x < width_ && p.y >= 0 && p.y < height_; }
     273             : 
     274             :     // Raw data access
     275          10 :     std::vector<T>& data() { return data_; }
     276             : 
     277             : private:
     278             :     T nullVal_{};
     279             :     int width_ = 0;
     280             :     int height_ = 0;
     281             :     std::vector<T> data_;
     282             : };
     283             : 
     284             : // Random number generation
     285             : 
     286       58738 : inline std::default_random_engine& engine() {
     287       58738 :     static std::default_random_engine engine_;
     288       58738 :     return engine_;
     289             : }
     290             : 
     291       58738 : inline int32_t randInt(int32_t from, int32_t to) {
     292       58738 :     return std::uniform_int_distribution<>(from, to)(engine());
     293             : }
     294             : 
     295           0 : inline double random(double from = 0.0, double to = 1.0) {
     296           0 :     return std::uniform_real_distribution<>(from, to)(engine());
     297             : }
     298             : 
     299             : inline vec2i randVec2i(vec2i from, vec2i to) {
     300             :     return {randInt(from.x, to.x), randInt(from.y, to.y)};
     301             : }
     302             : 
     303             : template <typename T> T choose(const std::vector<T>& values) {
     304             :     return values[randInt(0, values.size() - 1)];
     305             : }
     306             : 
     307        4615 : template <typename T> T choose(std::initializer_list<T> values) {
     308        4615 :     return *(values.begin() + randInt(0, (int)values.size() - 1));
     309             : }
     310             : 
     311             : #endif

Generated by: LCOV version 1.13