diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarMap.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarMap.hpp')
-rw-r--r-- | source/core/StarMap.hpp | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/source/core/StarMap.hpp b/source/core/StarMap.hpp new file mode 100644 index 0000000..45dd219 --- /dev/null +++ b/source/core/StarMap.hpp @@ -0,0 +1,318 @@ +#ifndef STAR_MAP_HPP +#define STAR_MAP_HPP + +#include <map> +#include <unordered_map> + +#include "StarFlatHashMap.hpp" +#include "StarList.hpp" + +namespace Star { + +STAR_EXCEPTION(MapException, StarException); + +template <typename BaseMap> +class MapMixin : public BaseMap { +public: + typedef BaseMap Base; + + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + typedef typename Base::key_type key_type; + typedef typename Base::mapped_type mapped_type; + typedef typename Base::value_type value_type; + + typedef typename std::decay<mapped_type>::type* mapped_ptr; + typedef typename std::decay<mapped_type>::type const* mapped_const_ptr; + + template <typename MapType> + static MapMixin from(MapType const& m); + + using Base::Base; + + List<key_type> keys() const; + List<mapped_type> values() const; + List<pair<key_type, mapped_type>> pairs() const; + + bool contains(key_type const& k) const; + + // Removes the item with key k and returns true if contains(k) is true, + // false otherwise. + bool remove(key_type const& k); + + // Removes *all* items that have a value matching the given one. Returns + // true if any elements were removed. + bool removeValues(mapped_type const& v); + + // Throws exception if key not found + mapped_type take(key_type const& k); + + Maybe<mapped_type> maybeTake(key_type const& k); + + // Throws exception if key not found + mapped_type& get(key_type const& k); + mapped_type const& get(key_type const& k) const; + + // Return d if key not found + mapped_type value(key_type const& k, mapped_type d = mapped_type()) const; + + Maybe<mapped_type> maybe(key_type const& k) const; + + mapped_const_ptr ptr(key_type const& k) const; + mapped_ptr ptr(key_type const& k); + + // Finds first value matching the given value and returns its key. + key_type keyOf(mapped_type const& v) const; + + // Finds all of the values matching the given value and returns their keys. + List<key_type> keysOf(mapped_type const& v) const; + + bool hasValue(mapped_type const& v) const; + + using Base::insert; + + // Same as insert(value_type), returns the iterator to either the newly + // inserted value or the existing value, and then a bool that is true if the + // new element was inserted. + pair<iterator, bool> insert(key_type k, mapped_type v); + + // Add a key / value pair, throw if the key already exists + mapped_type& add(key_type k, mapped_type v); + + // Set a key to a value, always override if it already exists + mapped_type& set(key_type k, mapped_type v); + + // Appends all values of given map into this map. If overwite is false, then + // skips values that already exist in this map. Returns false if any keys + // previously existed. + template <typename MapType> + bool merge(MapType const& m, bool overwrite = false); + + bool operator==(MapMixin const& m) const; +}; + +template <typename BaseMap> +std::ostream& operator<<(std::ostream& os, MapMixin<BaseMap> const& m); + +template <typename Key, typename Value, typename Compare = std::less<Key>, typename Allocator = std::allocator<pair<Key const, Value>>> +using Map = MapMixin<std::map<Key, Value, Compare, Allocator>>; + +template <typename Key, typename Value, typename Hash = hash<Key>, typename Equals = std::equal_to<Key>, typename Allocator = std::allocator<pair<Key const, Value>>> +using HashMap = MapMixin<FlatHashMap<Key, Value, Hash, Equals, Allocator>>; + +template <typename Key, typename Value, typename Hash = hash<Key>, typename Equals = std::equal_to<Key>, typename Allocator = std::allocator<pair<Key const, Value>>> +using StableHashMap = MapMixin<std::unordered_map<Key, Value, Hash, Equals, Allocator>>; + +template <typename BaseMap> +template <typename MapType> +auto MapMixin<BaseMap>::from(MapType const& m) -> MapMixin { + return MapMixin(m.begin(), m.end()); +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::keys() const -> List<key_type> { + List<key_type> klist; + for (const_iterator i = Base::begin(); i != Base::end(); ++i) + klist.push_back(i->first); + return klist; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::values() const -> List<mapped_type> { + List<mapped_type> vlist; + for (const_iterator i = Base::begin(); i != Base::end(); ++i) + vlist.push_back(i->second); + return vlist; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::pairs() const -> List<pair<key_type, mapped_type>> { + List<pair<key_type, mapped_type>> plist; + for (const_iterator i = Base::begin(); i != Base::end(); ++i) + plist.push_back(*i); + return plist; +} + +template <typename BaseMap> +bool MapMixin<BaseMap>::contains(key_type const& k) const { + return Base::find(k) != Base::end(); +} + +template <typename BaseMap> +bool MapMixin<BaseMap>::remove(key_type const& k) { + return Base::erase(k) != 0; +} + +template <typename BaseMap> +bool MapMixin<BaseMap>::removeValues(mapped_type const& v) { + bool removed = false; + const_iterator i = Base::begin(); + while (i != Base::end()) { + if (i->second == v) { + Base::erase(i++); + removed = true; + } else { + ++i; + } + } + return removed; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::take(key_type const& k) -> mapped_type { + if (auto v = maybeTake(k)) + return v.take(); + throw MapException(strf("Key '%s' not found in Map::take()", outputAny(k))); +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::maybeTake(key_type const& k) -> Maybe<mapped_type> { + const_iterator i = Base::find(k); + if (i != Base::end()) { + mapped_type v = std::move(i->second); + Base::erase(i); + return move(v); + } + + return {}; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::get(key_type const& k) -> mapped_type& { + iterator i = Base::find(k); + if (i == Base::end()) + throw MapException(strf("Key '%s' not found in Map::get()", outputAny(k))); + return i->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::get(key_type const& k) const -> mapped_type const& { + const_iterator i = Base::find(k); + if (i == Base::end()) + throw MapException(strf("Key '%s' not found in Map::get()", outputAny(k))); + return i->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::value(key_type const& k, mapped_type d) const -> mapped_type { + const_iterator i = Base::find(k); + if (i == Base::end()) + return std::move(d); + else + return i->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::maybe(key_type const& k) const -> Maybe<mapped_type> { + auto i = Base::find(k); + if (i == Base::end()) + return {}; + else + return i->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::ptr(key_type const& k) const -> mapped_const_ptr { + auto i = Base::find(k); + if (i == Base::end()) + return nullptr; + else + return &i->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::ptr(key_type const& k) -> mapped_ptr { + auto i = Base::find(k); + if (i == Base::end()) + return nullptr; + else + return &i->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::keyOf(mapped_type const& v) const -> key_type { + for (const_iterator i = Base::begin(); i != Base::end(); ++i) { + if (i->second == v) + return i->first; + } + throw MapException(strf("Value '%s' not found in Map::keyOf()", outputAny(v))); +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::keysOf(mapped_type const& v) const -> List<key_type> { + List<key_type> keys; + for (const_iterator i = Base::begin(); i != Base::end(); ++i) { + if (i->second == v) + keys.append(i->first); + } + return keys; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::hasValue(mapped_type const& v) const -> bool { + for (const_iterator i = Base::begin(); i != Base::end(); ++i) { + if (i->second == v) + return true; + } + return false; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::insert(key_type k, mapped_type v) -> pair<iterator, bool> { + return Base::insert(value_type(move(k), move(v))); +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::add(key_type k, mapped_type v) -> mapped_type& { + auto pair = Base::insert(value_type(move(k), move(v))); + if (!pair.second) + throw MapException(strf("Entry with key '%s' already present.", outputAny(k))); + else + return pair.first->second; +} + +template <typename BaseMap> +auto MapMixin<BaseMap>::set(key_type k, mapped_type v) -> mapped_type& { + auto i = Base::find(k); + if (i != Base::end()) { + i->second = move(v); + return i->second; + } else { + return Base::insert(value_type(move(k), move(v))).first->second; + } +} + +template <typename BaseMap> +template <typename OtherMapType> +bool MapMixin<BaseMap>::merge(OtherMapType const& m, bool overwrite) { + return mapMerge(*this, m, overwrite); +} + +template <typename BaseMap> +bool MapMixin<BaseMap>::operator==(MapMixin const& m) const { + return this == &m || mapsEqual(*this, m); +} + +template <typename MapType> +void printMap(std::ostream& os, MapType const& m) { + os << "{ "; + for (auto i = m.begin(); i != m.end(); ++i) { + if (m.begin() == i) + os << "\""; + else + os << ", \""; + os << i->first << "\" : \"" << i->second << "\""; + } + os << " }"; +} + +template <typename BaseMap> +std::ostream& operator<<(std::ostream& os, MapMixin<BaseMap> const& m) { + printMap(os, m); + return os; +} + +} + +#endif |