Page MenuHomec4science

cached_vector.hpp
No OneTemporary

File Metadata

Created
Sun, Aug 25, 06:58

cached_vector.hpp

/* =============================================================================
Copyright (c) 2014 - 2016
F. Georget <fabieng@princeton.edu> 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 utils/cached_vector.hpp
//! \brief Vector with cache
#include <vector>
#include <string>
#include <utility>
#include <stdexcept>
#include <algorithm>
#include <type_traits>
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 <typename T>
class CachedVector
{
class CachedIterator;
public:
using value_type = T;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using iterator = CachedIterator;
using const_iterator = const CachedIterator;
using index_vector = std::vector<size_type>;
//! \brief Default constructor, an empty vector
CachedVector() {}
//! \brief Initialize a 'size' vector with value T
CachedVector(size_type size, T&& value):
m_cache({std::forward<T>(value),}),
m_indexes(size, 0)
{}
//! \brief Initialize a 'size' vector with default T
CachedVector(size_type size,
typename std::enable_if<std::is_default_constructible<T>::value>::type* = nullptr):
m_cache(),
m_indexes(size, 0)
{
m_cache.emplace_back();
}
//! \brief Reserve storage
void reserve(size_type size_cap) {
m_indexes.reserve(size_cap);
}
//! \brief Reserve cache storage
void reserve_cache(size_type size_cap) {
m_cache.reserve(size_cap);
}
//! \brief Access specified element
reference operator[] (size_type pos) {
return m_cache[m_indexes[pos]];
}
//! \brief Access specified element
const_reference operator[] (size_type pos) const {
return m_cache[m_indexes[pos]];
}
//! \brief Access specified element with bounds checking
reference at(size_type pos) {
std::size_t ind = m_indexes.at(pos);
return m_cache.at(ind);
}
//! \brief Access specified element with bounds checking
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
size_type& operator() (size_type pos) {
return m_indexes[pos];
}
//! \brief Return a reference to the position in the cache
const size_type& operator () (size_type pos) const {
return m_indexes[pos];
}
//! \brief Return the cached value
reference get(size_t pos_cache) {
return m_cache[pos_cache];
}
//! \brief Return the cached value
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<T>(value));
return (m_cache.size() - 1);
}
//! \brief Emplace a new element to the cache
template <typename ...Args>
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_t 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<T>(value));
m_indexes.push_back(ind);
}
//! \brief Add a new element at the end and build a new element to the cache
template <typename ...Args>
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 CachedIterator: public std::vector<size_type>::iterator
{
using base = std::vector<size_type>;
using base_iterator = base::iterator;
public :
CachedIterator(
const base_iterator& base,
std::vector<T>& cache):
base_iterator(base),
m_cache(cache)
{}
CachedIterator(
std::size_t pos,
std::vector<T>& cache
):
base_iterator(pos),
m_cache(cache)
{}
T& operator* () {
return m_cache[base_iterator::operator* ()];
}
const T& operator* () const {
return m_cache[base_iterator::operator* ()];
}
private:
std::vector<T>& m_cache;
};
private:
std::vector<T> m_cache;
std::vector<size_type> m_indexes;
};
//! \brief A name cached vector
//!
//! Every cache value has an associated name
template <typename T>
class NameCachedVector: public CachedVector<T>
{
public:
using size_type = typename CachedVector<T>::size_type;
using reference = typename CachedVector<T>::reference;
using const_reference = typename CachedVector<T>::const_reference;
NameCachedVector():
CachedVector<T>()
{}
NameCachedVector(size_type size, std::string name, T&& value):
CachedVector<T>(size, std::forward<T>(value)),
m_names({name, })
{}
NameCachedVector(size_type size, std::string name,
typename std::enable_if<std::is_default_constructible<T>::value>::type* = nullptr):
CachedVector<T>(size),
m_names({name, })
{}
//! \brief Reserve cache storage
void reserve_cache(size_type size_cap) {
CachedVector<T>::reserve_cache(size_cap);
m_names.reserve(size_cap);
}
//! \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(const std::string& name, T&& value) {
m_names.push_back(name);
return CachedVector<T>::push_back_cache(std::forward<T>(value));
}
//! \brief Emplace a new element to the cache
template <typename ...Args>
size_type emplace_back_cache(const std::string& name, Args...args) {
m_names.push_back(name);
return CachedVector<T>::emplace_back_cache(args...);
}
//! \brief Adds an element to the end and a new value to the cache
//!
//! \param value a new value
void push_back(const std::string& name, T&& value) {
CachedVector<T>::push_back(std::forward<T>(value));
m_names.push_back(name);
}
//! \brief Add a new element at the end and build a new element to the cache
template <typename ...Args>
void emplace_back(const std::string& name, Args...args) {
CachedVector<T>::emplace_back(args...);
m_names.push_back(name);
}
//! \brief Return the value stored as "name"
reference get(std::string name) {
return CachedVector<T>::get(get_cache_position(name));
}
//! \brief Return the value stored as "name"
const_reference get(std::string name) const {
return CachedVector<T>::get(get_cache_position(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<T>::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<T>(val));
return CachedVector<T>::get(pos);
}
//! \brief Set the given node to the value 'name'
void set(size_type pos, const std::string& name) {
CachedVector<T>::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<std::string> m_names;
};
} //end namespace utils
} //end namespace specmicp
#endif // SPECMICP_REACTMICP_CACHEDVECTOR_HPP

Event Timeline