Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 09:58:12

0001 // SPDX-License-Identifier: MIT
0002 // Copyright 2019 Moritz Kiehn
0003 //
0004 // Permission is hereby granted, free of charge, to any person obtaining a copy
0005 // of this software and associated documentation files (the "Software"), to deal
0006 // in the Software without restriction, including without limitation the rights
0007 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0008 // copies of the Software, and to permit persons to whom the Software is
0009 // furnished to do so, subject to the following conditions:
0010 //
0011 // The above copyright notice and this permission notice shall be included in
0012 // all copies or substantial portions of the Software.
0013 //
0014 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0017 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0018 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0019 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0020 // SOFTWARE.
0021 
0022 /// \file
0023 /// \brief   Minimal associative containers based on continous storage
0024 /// \author  Moritz Kiehn <msmk@cern.ch>
0025 /// \date    2019-02-27, Initial version
0026 
0027 #pragma once
0028 
0029 #include <algorithm>
0030 #include <functional>
0031 #include <stdexcept>
0032 #include <vector>
0033 
0034 namespace dfe {
0035 
0036 /// An container adaptor to store a set of elements in a sequential container.
0037 ///
0038 /// \tparam T         Stored element type
0039 /// \tparam Compare   Function satisfying the `Compare` named requirement
0040 /// \tparam Container Sequential container
0041 ///
0042 /// Supports access by equivalence, iteration over all elements, removing all
0043 /// elements, adding elements while maintaining uniqueness, and membership
0044 /// checks. By using a sequential container, memory allocation is greatly
0045 /// simplified and lookups benefit from higher memory locality at the expense of
0046 /// slower insertion of elements. Should work best for smaller sets with
0047 /// frequent lookups.
0048 ///
0049 /// The set elements can not be modified on purpose. With a non-standard
0050 /// `Compare` function modifying a contained object might change its identity
0051 /// and thus its position in the set. This would break the internal sorting.
0052 template<
0053   typename T, typename Compare = std::less<T>,
0054   typename Container = std::vector<T>>
0055 class FlatSet {
0056 public:
0057   using value_type = T;
0058   using size_type = typename Container::size_type;
0059   using const_iterator = typename Container::const_iterator;
0060 
0061   /// Access the equivalent element or throw if it does not exists.
0062   template<typename U>
0063   const value_type& at(U&& u) const;
0064 
0065   const_iterator begin() const { return m_items.begin(); }
0066   const_iterator end() const { return m_items.end(); }
0067 
0068   /// Return true if there are no elements in the set.
0069   bool empty() const { return m_items.empty(); }
0070   /// Return the number of elements in the set.
0071   size_type size() const { return m_items.size(); }
0072 
0073   /// Remove all elements from the container.
0074   void clear() { m_items.clear(); }
0075   /// Add the element to the set or replace the existing equivalent element.
0076   ///
0077   /// Depending on the `Compare` function we might have elements with different
0078   /// values but the same identity with respect to the chosen `Compare`
0079   /// function. Only one can be kept and this function replaces the existing
0080   /// element with the new one in such a case.
0081   void insert_or_assign(const T& t);
0082 
0083   /// Return an interator to the equivalent element or `.end()` if not found.
0084   template<typename U>
0085   const_iterator find(U&& u) const;
0086   /// Return true if the equivalent element is in the set.
0087   template<typename U>
0088   bool contains(U&& u) const;
0089 
0090 private:
0091   Container m_items;
0092 };
0093 
0094 /// A key-value map that stores keys and values in sequential containers.
0095 ///
0096 /// \tparam Key     Stored element key type
0097 /// \tparam T       Stored element value type
0098 /// \tparam Compare Function satisfying the `Compare` name requirements for keys
0099 ///
0100 /// Supports access by key, clearing all elements, adding or replacing the
0101 /// stored value for a given key, and membership checks. Keys and values are
0102 /// stored in separate sequential containers to simplify allocation and benefit
0103 /// from greater memory locality.
0104 template<typename Key, typename T, typename Compare = std::less<Key>>
0105 class FlatMap {
0106 public:
0107   using key_type = Key;
0108   using value_type = T;
0109   using size_type = std::size_t;
0110 
0111   /// Writable access to an element or throw if it does not exists.
0112   value_type& at(const Key& key) { return m_items[m_keys.at(key).index]; }
0113   /// Read-only access to an element or throw if it does not exists.
0114   const value_type& at(const Key& key) const {
0115     return m_items[m_keys.at(key).index];
0116   }
0117 
0118   /// Return true if there are no elements in the map.
0119   bool empty() const { return m_keys.empty(); }
0120   /// Return the number of elements in the container.
0121   size_type size() const { return m_keys.size(); }
0122 
0123   /// Remove all elements from the container.
0124   void clear() { m_keys.clear(), m_items.clear(); }
0125   /// Add the element under the given key or replace an existing element.
0126   ///
0127   /// New elements are constructed or assigned in-place with the parameters
0128   /// forwarded to a `T(...)` constructor call.
0129   template<typename... Params>
0130   void emplace(const Key& key, Params&&... params);
0131 
0132   /// Return true if an element exists for the given key
0133   bool contains(const Key& key) const { return m_keys.contains(key); }
0134 
0135 private:
0136   struct KeyIndex {
0137     Key key;
0138     size_type index;
0139   };
0140   struct KeyCompare {
0141     constexpr bool operator()(const KeyIndex& lhs, const KeyIndex& rhs) const {
0142       return Compare()(lhs.key, rhs.key);
0143     }
0144     constexpr bool operator()(const KeyIndex& lhs, const Key& rhs_key) const {
0145       return Compare()(lhs.key, rhs_key);
0146     }
0147     constexpr bool operator()(const Key& lhs_key, const KeyIndex& rhs) const {
0148       return Compare()(lhs_key, rhs.key);
0149     }
0150   };
0151 
0152   FlatSet<KeyIndex, KeyCompare> m_keys;
0153   std::vector<T> m_items;
0154 };
0155 
0156 // implementation FlatSet
0157 
0158 template<typename T, typename Compare, typename Container>
0159 template<typename U>
0160 inline const typename FlatSet<T, Compare, Container>::value_type&
0161 FlatSet<T, Compare, Container>::at(U&& u) const {
0162   auto pos = find(std::forward<U>(u));
0163   if (pos == end()) {
0164     throw std::out_of_range("The requested element does not exists");
0165   }
0166   return *pos;
0167 }
0168 
0169 template<typename T, typename Compare, typename Container>
0170 inline void
0171 FlatSet<T, Compare, Container>::insert_or_assign(const T& t) {
0172   auto pos = std::lower_bound(m_items.begin(), m_items.end(), t, Compare());
0173   if (((pos != m_items.end()) and !Compare()(t, *pos))) {
0174     *pos = t;
0175   } else {
0176     m_items.emplace(pos, t);
0177   }
0178 }
0179 
0180 template<typename T, typename Compare, typename Container>
0181 template<typename U>
0182 inline typename FlatSet<T, Compare, Container>::const_iterator
0183 FlatSet<T, Compare, Container>::find(U&& u) const {
0184   auto end = m_items.end();
0185   auto pos =
0186     std::lower_bound(m_items.begin(), end, std::forward<U>(u), Compare());
0187   return ((pos != end) and !Compare()(std::forward<U>(u), *pos)) ? pos : end;
0188 }
0189 
0190 template<typename T, typename Compare, typename Container>
0191 template<typename U>
0192 inline bool
0193 FlatSet<T, Compare, Container>::contains(U&& u) const {
0194   return std::binary_search(
0195     m_items.begin(), m_items.end(), std::forward<U>(u), Compare());
0196 }
0197 
0198 // implementation FlatMap
0199 
0200 template<typename Key, typename T, typename Compare>
0201 template<typename... Params>
0202 inline void
0203 FlatMap<Key, T, Compare>::emplace(const Key& key, Params&&... params) {
0204   auto idx = m_keys.find(key);
0205   if (idx != m_keys.end()) {
0206     m_items[idx->index] = T(std::forward<Params>(params)...);
0207   } else {
0208     m_items.emplace_back(std::forward<Params>(params)...);
0209     m_keys.insert_or_assign(KeyIndex{key, m_items.size() - 1});
0210   }
0211 }
0212 
0213 } // namespace dfe