/* * Copyright (C) 2023 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_GEOM_BREP_ATTRIBUTE_MAP_HPP #define ANTKEEPER_GEOM_BREP_ATTRIBUTE_MAP_HPP #include #include #include #include #include #include #include #include namespace geom { /** * Maps names to B-rep attributes. */ class brep_attribute_map { public: template class iterator_template { public: using iterator_type = Iter; using iterator_category = std::bidirectional_iterator_tag; using iterator_concept = std::bidirectional_iterator_tag; using difference_type = std::iter_difference_t; using value_type = brep_attribute_base; using pointer = std::conditional::type; using reference = std::conditional::type; [[nodiscard]] inline constexpr reference operator*() const noexcept { return *m_it->second; } [[nodiscard]] inline constexpr pointer operator->() const noexcept { return &(*m_it->second); } [[nodiscard]] inline constexpr reference operator[](difference_type i) const noexcept { return *(m_it[i]); } inline iterator_template& operator++() noexcept { ++m_it; return *this; } [[nodiscard]] inline iterator_template operator++(int) noexcept { iterator_template tmp = *this; ++(*this); return tmp; } inline iterator_template& operator--() noexcept { --m_it; return *this; } [[nodiscard]] inline iterator_template operator--(int) noexcept { iterator_template tmp = *this; --(*this); return tmp; } inline iterator_template& operator+=(difference_type n) noexcept { m_it += n; return *this; } inline iterator_template& operator-=(difference_type n) noexcept { m_it -= n; return *this; } [[nodiscard]] inline bool operator==(const iterator_template& other) const noexcept { return m_it == other.m_it; }; [[nodiscard]] inline std::weak_ordering operator<=>(const iterator_template& other) const noexcept { return m_it <=> other.m_it; } [[nodiscard]] inline difference_type operator-(const iterator_template& rhs) const noexcept { return m_it - rhs.m_it; } [[nodiscard]] inline iterator_template operator+(difference_type n) const noexcept { return iterator_template{m_it + n}; } [[nodiscard]] inline iterator_template operator-(difference_type n) const noexcept { return iterator_template{m_it - n}; } [[nodiscard]] friend iterator_template operator+(difference_type lhs, const iterator_template& rhs) noexcept { return iterator_template{lhs + rhs.m_it}; } [[nodiscard]] friend iterator_template operator-(difference_type lhs, const iterator_template& rhs) noexcept { return iterator_template{lhs - rhs.m_it}; } private: friend class brep_attribute_map; iterator_type m_it; }; using iterator = iterator_template>::iterator, false>; using const_iterator = iterator_template>::const_iterator, true>; /// @name Iterators /// @{ /// Returns an iterator to the first attribute. /// @{ [[nodiscard]] inline const_iterator begin() const noexcept { const_iterator it; it.m_it = m_attributes.begin(); return it; } [[nodiscard]] inline iterator begin() noexcept { iterator it; it.m_it = m_attributes.begin(); return it; } [[nodiscard]] inline const_iterator cbegin() const noexcept { return begin(); } /// @} /// Returns an iterator to the attribute following the last attribute. /// @{ [[nodiscard]] inline const_iterator end() const noexcept { const_iterator it; it.m_it = m_attributes.end(); return it; } [[nodiscard]] inline iterator end() noexcept { iterator it; it.m_it = m_attributes.end(); return it; } [[nodiscard]] inline const_iterator cend() const noexcept { return end(); } /// @} /// @} /// @name Capacity /// @{ /// Returns `true` if the container is empty, `false` otherwise. [[nodiscard]] inline bool empty() const noexcept { return m_attributes.empty(); } /// Returns the number of attributes in the container. [[nodiscard]] inline std::size_t size() const noexcept { return m_attributes.size(); } /// @} /// @name Modifiers /// @{ /** * Removes all attributes from the container. */ inline void clear() noexcept { m_attributes.clear(); } /** * Constructs a new attribute. If an attribute with the given name exists, it will be replaced. * * @tparam T Attribute data type. * * @param name Name of the new attribute. * * @return Iterator to the new attribute. */ template iterator emplace(hash::fnv1a32_t name) { if (auto i = m_attributes.find(name); i != m_attributes.end()) { i->second.reset(); i->second = std::make_unique>(name, m_element_count); iterator it; it.m_it = i; return it; } iterator it; it.m_it = m_attributes.emplace(name, std::make_unique>(name, m_element_count)).first; return it; } /** * Removes an attribute from the container. * * @param pos Iterator to the attribute to remove. * * @return Iterator following the erased attribute. */ inline iterator erase(iterator pos) { iterator it; it.m_it = m_attributes.erase(pos.m_it); return it; } /** * Removes an attribute from the container. * * @param name Name of the attribute to remove. * * @return Number of attributes removed (0 or 1). */ inline std::size_t erase(hash::fnv1a32_t name) { return m_attributes.erase(name); } /** * Constructs a new attribute if an attribute with the given name does not exist. * * @tparam T Attribute data type. * * @param name Name of the new attribute. * * @return Pair consisting of an iterator to the new or pre-existing attribute, and a Boolean value that's `true` if the new attribute was constructed, or `false` if an attribute with the given name pre-existed. */ template std::pair try_emplace(hash::fnv1a32_t name) { if (auto i = m_attributes.find(name); i != m_attributes.end()) { iterator it; it.m_it = i; return {it, false}; } auto pair = m_attributes.emplace(name, std::make_unique>(name, m_element_count)); iterator it; it.m_it = pair.first; return {it, pair.second}; } /// @} /// @name Lookup /// @{ /** * Returns a reference to the attribute with the given name. If no such attribute exists, an exception of type std::out_of_range is thrown. * * @tparam T Attribute data type. * * @return Reference to the attribute with the given name. * * @except std::out_of_range B-rep attribute not found. */ /// @{ template [[nodiscard]] const brep_attribute& at(hash::fnv1a32_t name) const { auto it = find(name); if (it == end()) { throw std::out_of_range("B-rep attribute not found"); } return static_cast&>(*it); } template [[nodiscard]] brep_attribute& at(hash::fnv1a32_t name) { auto it = find(name); if (it == end()) { throw std::out_of_range("B-rep attribute not found"); } return static_cast&>(*it); } /// @} /** * Finds an attribute with the given name. * * @param name Name of an attribute. * * @return Iterator to the attribute with the given name. If no such attribute is found, an end iterator is returned. */ /// @{ [[nodiscard]] inline const_iterator find(hash::fnv1a32_t name) const { const_iterator it; it.m_it = m_attributes.find(name); return it; } [[nodiscard]] inline iterator find(hash::fnv1a32_t name) { iterator it; it.m_it = m_attributes.find(name); return it; } /// @} /** * Checks if there is an attribute with a given name in the container. * * @param name Attribute name. * * @return `true` if an attribute with the given name was found, `false` otherwise. */ [[nodiscard]] inline bool contains(hash::fnv1a32_t name) const { return m_attributes.contains(name); } /// @} private: template friend class brep_element_container; friend class brep_mesh; brep_attribute_map& operator=(const brep_attribute_map& other) { m_element_count = other.m_element_count; m_attributes.clear(); for (const auto& [key, value]: other.m_attributes) { m_attributes.emplace(key, value->clone()); } return *this; } std::size_t m_element_count{}; std::unordered_map> m_attributes; }; } // namespace geom #endif // ANTKEEPER_GEOM_BREP_ATTRIBUTE_MAP_HPP