diff --git a/src/specmicp_common/cached_vector.hpp b/src/specmicp_common/cached_vector.hpp index d258893..07b94bf 100644 --- a/src/specmicp_common/cached_vector.hpp +++ b/src/specmicp_common/cached_vector.hpp @@ -1,448 +1,450 @@ /* ============================================================================= Copyright (c) 2014 - 2016 F. Georget Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================= */ #ifndef SPECMICP_REACTMICP_CACHEDVECTOR_HPP #define SPECMICP_REACTMICP_CACHEDVECTOR_HPP //! \file cached_vector.hpp //! \brief Vector with cache +#include "macros.hpp" + #include #include #include #include #include #include namespace specmicp { namespace utils { //! \brief A vector with cache //! //! This vector is designed to simulate a large vector with only a few different //! values of type T, where T is 'big' //! //! \tparam T must be copyable, assignable, default constructible template -class CachedVector +class SPECMICP_DLL_PUBLIC CachedVector { class CachedIterator; // forward declaration of the iterator class public: using value_type = T; //!< Type of a value using reference = T&; //!< Type a reference to a value using const_reference = const T&; //!< Type of a const reference to a value using size_type = std::size_t; //!< Type for the size of a vector using iterator = CachedIterator; //!< Type of an iterator using const_iterator = const CachedIterator; //!< Type of a const iterator using index_vector = std::vector; //!< Type of the index vector //! \brief Default constructor, an empty vector CachedVector() {} //! \brief Initialize a vector with value T //! //! \param size size of the vector //! \param value initial value for all entry CachedVector(size_type size, T&& value): m_cache({std::forward(value),}), m_indexes(size, 0) {} //! \brief Initialize a vector with default T //! //! \param size size of the vector //! //! \warning This constructor is only available if a default constructor exist for T CachedVector(size_type size, typename std::enable_if::value>::type* = nullptr): m_cache(), m_indexes(size, 0) { m_cache.emplace_back(); } //! \brief Reserve storage //! //! Reserves memory for the vector //! //! \param size_cap the size to reserve in memory for the vector void reserve(size_type size_cap) { m_indexes.reserve(size_cap); } //! \brief Reserve cache storage //! //! Reserves memory for the cache //! //! \param size_cap The cache will be able to store up to 'size_cap' value //! without realllocation void reserve_cache(size_type size_cap) { m_cache.reserve(size_cap); } //! \brief Access an element //! //! No bounds checkoing is performed in this method. //! //! \sa at reference operator[] (size_type pos) { return m_cache[m_indexes[pos]]; } //! \brief Access an element //! //! No bounds checkoing is performed in this method. //! //! \sa at const_reference operator[] (size_type pos) const { return m_cache[m_indexes[pos]]; } //! \brief Access an lement with bounds checking //! //! \sa operator[] reference at(size_type pos) { std::size_t ind = m_indexes.at(pos); return m_cache.at(ind); } //! \brief Access an element with bounds checking //! //! \sa operator[] const_reference at(size_type pos) const { std::size_t ind = m_indexes.at(pos); return m_cache.at(ind); } //! \brief Return a reference to the position in the cache //! //! \sa get size_type& operator() (size_type pos) { return m_indexes[pos]; } //! \brief Return a reference to the position in the cache //! //! \sa get const size_type& operator () (size_type pos) const { return m_indexes[pos]; } //! \brief Return the cached value //! //! \sa operator() reference get(size_t pos_cache) { return m_cache[pos_cache]; } //! \brief Return the cached value //! //! \sa operator() const_reference get(size_t pos_cache) const { return m_cache[pos_cache]; } //! \brief Return the size of the vector size_type size() const { return m_indexes.size(); } //! \brief Return the size of the cache size_type size_cache() const { return m_cache.size(); } //! \brief Push an element to the cache //! //! \param value The element to add //! \return the position of the element in the cache size_type push_back_cache(T&& value) { m_cache.push_back(std::forward(value)); return (m_cache.size() - 1); } //! \brief Emplace a new element to the cache template size_type emplace_back_cache(Args...args) { m_cache.emplace_back(args...); return (m_cache.size() - 1); } //! \brief Adds an element to the end //! //! \param index refers to a position in the cache void push_back(size_type index) { m_indexes.push_back(index); } //! \brief Adds an element to the end and a new value to the cache //! //! \param value a new value void push_back(T&& value) { auto ind = push_back_cache(std::forward(value)); m_indexes.push_back(ind); } //! \brief Add a new element at the end and build a new element to the cache template void emplace_back(Args...args) { auto ind = emplace_back_cache(args...); m_indexes.push_back(ind); } //! \brief Fork the value at the given position reference fork(size_type pos) { m_cache.push_back(m_cache[m_indexes[pos]]); m_indexes[pos] = m_cache.size() - 1; return m_cache.back(); } //! \brief Set the value to another //! //! Don't check the validity of the value ! void set(size_type pos, size_type pos_cache) { m_indexes[pos] = pos_cache; } // Iterator business //! \brief Return an iterator to the beginning iterator begin() { return CachedIterator(m_indexes.begin(), m_cache); } //! \brief Return an iterator to the end iterator end() { return CachedIterator(m_indexes.end(), m_cache); } //! \brief Return an iterator to the beginning const_iterator cbegin() const { return CachedIterator(m_indexes.begin(), m_cache); } //! \brief Return an iterator to the end const_iterator cend() const{ return CachedIterator(m_indexes.end(), m_cache); } //! \brief Return an iterator to the beginning of the indexes index_vector::iterator begin_index() { return m_indexes.begin(); } //! \brief Return an iterator to the end of the indexes index_vector::iterator end_index() { return m_indexes.end(); } //! \brief Return an iterator to the beginning of the indexes index_vector::const_iterator cbegin_index() const { return m_indexes.cbegin(); } //! \brief Return an iterator to the end of the indexes index_vector::const_iterator cend_index() const{ return m_indexes.cend(); } private: //! \brief The iterator class for a cached vector class CachedIterator: public std::vector::iterator { using base = std::vector; using base_iterator = base::iterator; public : //! \param base iterator over the index vector //! \param cache referece to the cache vector CachedIterator( const base_iterator& base, std::vector& cache): base_iterator(base), m_cache(cache) {} //! \param pos position where to start the iterator //! \param cache referece to the cache vector CachedIterator( std::size_t pos, std::vector& cache ): base_iterator(), m_cache(cache) { advance(static_cast(*this), pos-1); } //! \brief Dereference operator //! //! \return a reference to the corresponding value T& operator* () { return m_cache[base_iterator::operator* ()]; } //! \brief Const dereference operator //! //! \return a const reference to the corresponding value const T& operator* () const { return m_cache[base_iterator::operator* ()]; } private: std::vector& m_cache; }; private: std::vector m_cache; std::vector m_indexes; }; //! \brief A named cached vector //! //! Every cache value has an associated name which can be used to obtain the //! values. template -class NameCachedVector: +class SPECMICP_DLL_PUBLIC NameCachedVector: public CachedVector { public: using size_type = typename CachedVector::size_type; //!< Type of the size of a value using reference = typename CachedVector::reference; //!< Type of a reference using const_reference = typename CachedVector::const_reference; //!< Type of a const reference NameCachedVector(): CachedVector() {} //! \brief Initialize a vector with a default value //! //! \param size size of the vector //! \param name name of the default value //! \param value the default value NameCachedVector(size_type size, std::string name, T&& value): CachedVector(size, std::forward(value)), m_names({name, }) {} //! \brief Initialize the vector with the default value //! //! \param size size of the vector //! \param name name of the default value //! //! \warning only exist if the value type has a default constructor NameCachedVector(size_type size, std::string name, typename std::enable_if::value>::type* = nullptr): CachedVector(size), m_names({name, }) {} //! \brief Reserve cache storage void reserve_cache(size_type size_cap) { CachedVector::reserve_cache(size_cap); m_names.reserve(size_cap); } //! \brief Push an element to the cache //! //! \param name label for the value to add //! \param value The element to add //! \return the position of the element in the cache size_type push_back_cache(const std::string& name, T&& value) { m_names.push_back(name); return CachedVector::push_back_cache(std::forward(value)); } //! \brief Emplace a new element to the cache template size_type emplace_back_cache(const std::string& name, Args...args) { m_names.push_back(name); return CachedVector::emplace_back_cache(args...); } //! \brief Adds an element to the end and a new value to the cache //! //! \param name label for the value //! \param value a new value void push_back(const std::string& name, T&& value) { CachedVector::push_back(std::forward(value)); m_names.push_back(name); } //! \brief Add a new element at the end and build a new element to the cache template void emplace_back(const std::string& name, Args...args) { CachedVector::emplace_back(args...); m_names.push_back(name); } //! \brief Return the value stored as "name" reference get(std::string name) { return CachedVector::get(get_cache_position(name)); } //! \brief Return the value stored as "name" const_reference get(std::string name) const { return CachedVector::get(get_cache_position(name)); } //! \brief Return true if the vector ha sa value called "name" bool has_value(std::string name) const { auto it = std::find(m_names.cbegin(), m_names.cend(), name); return (it != m_names.cend()); } //! \brief Fork the value at the given position reference fork(size_type pos, const std::string& name) { m_names.push_back(name); return CachedVector::fork(pos); } //! \brief Fork the value of a given name reference fork(const std::string& old_name, const std::string& new_name) { auto&& val = get(old_name); auto pos = push_back_cache(new_name, std::forward(val)); return CachedVector::get(pos); } //! \brief Set the given node to the value 'name' void set(size_type pos, const std::string& name) { CachedVector::set(pos, get_cache_position(name)); } //! \brief Return the position in the cache size_type get_cache_position(const std::string& name) const { auto it = std::find(m_names.cbegin(), m_names.cend(), name); if (it == m_names.cend()) { throw std::invalid_argument("Unknow value in NamedCachedVector '" + name + "'."); } return (it-m_names.cbegin()); } private: std::vector m_names; }; } //end namespace utils } //end namespace specmicp #endif // SPECMICP_REACTMICP_CACHEDVECTOR_HPP