Program Listing for File static_vector.hpp
↰ Return to documentation for file (/tmp/ws/src/apex_containers/apex_containers/include/apex_containers/static_vector.hpp
)
// Copyright 2018 Apex.AI, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef APEX_CONTAINERS__STATIC_VECTOR_HPP_
#define APEX_CONTAINERS__STATIC_VECTOR_HPP_
#include <algorithm>
#include <vector>
#include <typeinfo>
#include <utility>
#include <memory>
namespace apex
{
namespace _vector_impl
{
template<class U>
class single_allocator
{
public:
using base_type = std::allocator<U>;
using value_type = U;
using propagate_on_container_copy_assignment = std::true_type; // for consistency
using propagate_on_container_move_assignment = std::true_type; // to avoid the pessimization
using propagate_on_container_swap = std::true_type; // to avoid the undefined behavior
explicit single_allocator(const typename base_type::size_type n)
: m_size(n), m_consumed(false)
{
// Checking that we are not trying to allocate more than the base allocator supports.
if (n > m_alloc.max_size()) {
throw std::bad_alloc();
}
}
single_allocator(const single_allocator<U> & other) // NOLINT #2459
: m_size(other.m_size), m_consumed(other.m_consumed), m_alloc(other.m_alloc) {}
single_allocator<U> & operator=(const _vector_impl::single_allocator<U> & other)
{
m_size = other.m_size;
m_consumed = other.m_consumed;
m_alloc = other.m_alloc;
return *this;
}
single_allocator(single_allocator<U> && other) noexcept
: m_size(std::move(other.m_size)),
m_consumed(std::move(other.m_consumed)),
m_alloc(std::move(other.m_alloc)) {}
single_allocator<U> & operator=(single_allocator<U> && other) noexcept
{
m_size = std::move(other.m_size);
m_consumed = std::move(other.m_consumed);
m_alloc = std::move(other.m_alloc);
return *this;
}
typename base_type::pointer allocate(
const typename base_type::size_type n, const void * hint = 0)
{
if (n != m_size || m_consumed) {
throw std::bad_alloc();
}
// Ensuring exception safety by getting the memory before marking the allocator as used.
auto && ret = m_alloc.allocate(n, hint);
m_consumed = true;
return ret;
}
void deallocate(typename base_type::pointer ptr, typename base_type::size_type n)
{
m_alloc.deallocate(ptr, n);
}
typename base_type::size_type max_size() const
{
return m_size;
}
private:
typename base_type::size_type m_size;
bool m_consumed;
base_type m_alloc;
}; // _vector_impl::single_allocator
template<typename T, typename U>
inline bool operator==(const single_allocator<T> &, const single_allocator<U> &)
{
// Memory fom a _vector_impl::single_allocator can always be deallocated by a different
// single_allocator.
return true;
}
template<typename T, typename U>
inline bool operator!=(const single_allocator<T> & a, const single_allocator<U> & b)
{
return !(a == b);
}
} // namespace _vector_impl
#define APEX_STATIC_VECTOR_FWD(member, name) \
decltype(auto) name() {return member.name();} \
decltype(auto) name() const {return member.name();}
#define APEX_STATIC_VECTOR_FWD_PARAM(member, name) \
template<class ... Params> \
decltype(auto) name(Params && ... params) { \
return member.name(std::forward<Params>(params) ...);} \
template<class ... Params> \
decltype(auto) name(Params && ... params) const { \
return member.name(std::forward<Params>(params) ...);}
#define APEX_STATIC_VECTOR_DEFINITIONS_GEN(type, name) \
using name = typename type::name;
template<class T>
class static_vector
{
private:
using vector_type = std::vector<T, _vector_impl::single_allocator<T>>;
std::vector<T, _vector_impl::single_allocator<T>> m_v;
public:
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, value_type)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, allocator_type)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, reference)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, const_reference)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, pointer)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, const_pointer)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, iterator)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, const_iterator)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, reverse_iterator)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, const_reverse_iterator)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, difference_type)
APEX_STATIC_VECTOR_DEFINITIONS_GEN(vector_type, size_type)
explicit static_vector(const size_type capacity)
: m_v(_vector_impl::single_allocator<T>(capacity))
{
m_v.reserve(capacity);
}
template<class IT>
explicit static_vector(
const size_type capacity,
const IT first,
const IT last)
: m_v(_vector_impl::single_allocator<T>(capacity))
{
const auto dist = std::distance(first, last);
if (dist > static_cast<decltype(dist)>(capacity)) {
throw std::length_error("[first, last) range error");
}
m_v.reserve(capacity);
// Distance is positive per above condition.
m_v.resize(std::distance(first, last));
std::copy(first, last, m_v.begin());
}
explicit static_vector(
const size_type capacity,
std::initializer_list<value_type> il)
: m_v(_vector_impl::single_allocator<T>(capacity))
{
if (il.size() > capacity) {
throw std::length_error("initializer list too long");
}
m_v.reserve(capacity);
m_v.resize(il.size());
std::copy(il.begin(), il.end(), m_v.begin());
}
static_vector(const static_vector<T> & other) = delete;
static_vector<T> & operator=(const static_vector<T> & other)
{
m_v = other.m_v;
return *this;
}
static_vector(static_vector<T> && other) noexcept
: m_v(std::move(other.m_v)) {}
static_vector<T> & operator=(static_vector<T> && other) noexcept
{
m_v = std::move(other.m_v);
return *this;
}
void shrink_to_fit()
{
// The C++ standard allows shrink to fit to be a noop which is the case here to prevent any
// reallocation.
}
void swap(static_vector<T> & x)
{
m_v.swap(x.m_v);
}
APEX_STATIC_VECTOR_FWD(m_v, begin)
APEX_STATIC_VECTOR_FWD(m_v, end)
APEX_STATIC_VECTOR_FWD(m_v, rbegin)
APEX_STATIC_VECTOR_FWD(m_v, rend)
APEX_STATIC_VECTOR_FWD(m_v, cbegin)
APEX_STATIC_VECTOR_FWD(m_v, cend)
APEX_STATIC_VECTOR_FWD(m_v, crbegin)
APEX_STATIC_VECTOR_FWD(m_v, crend)
APEX_STATIC_VECTOR_FWD(m_v, size)
APEX_STATIC_VECTOR_FWD(m_v, max_size)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, resize)
APEX_STATIC_VECTOR_FWD(m_v, capacity)
APEX_STATIC_VECTOR_FWD(m_v, empty)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, reserve)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, operator[])
APEX_STATIC_VECTOR_FWD_PARAM(m_v, at)
APEX_STATIC_VECTOR_FWD(m_v, front)
APEX_STATIC_VECTOR_FWD(m_v, back)
APEX_STATIC_VECTOR_FWD(m_v, data)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, assign)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, push_back)
APEX_STATIC_VECTOR_FWD(m_v, pop_back)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, insert)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, erase)
APEX_STATIC_VECTOR_FWD(m_v, clear)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, emplace)
APEX_STATIC_VECTOR_FWD_PARAM(m_v, emplace_back)
template<class K>
friend bool operator==(const static_vector<K> & lhs, const static_vector<K> & rhs);
template<class K>
friend bool operator!=(const static_vector<K> & lhs, const static_vector<K> & rhs);
template<class K>
friend bool operator<(const static_vector<K> & lhs, const static_vector<K> & rhs);
template<class K>
friend bool operator<=(const static_vector<K> & lhs, const static_vector<K> & rhs);
template<class K>
friend bool operator>(const static_vector<K> & lhs, const static_vector<K> & rhs);
template<class K>
friend bool operator>=(const static_vector<K> & lhs, const static_vector<K> & rhs);
};
#define APEX_VECTOR_CMP_OP(op, member) \
template<class K> \
bool operator op( \
const static_vector<K> & lhs, \
const static_vector<K> & rhs) { \
return operator op(lhs.member, rhs.member); \
}
APEX_VECTOR_CMP_OP(==, m_v)
APEX_VECTOR_CMP_OP(!=, m_v)
APEX_VECTOR_CMP_OP(<, m_v) // NOLINT
APEX_VECTOR_CMP_OP(<=, m_v)
APEX_VECTOR_CMP_OP(>, m_v) // NOLINT
APEX_VECTOR_CMP_OP(>=, m_v)
} // namespace apex
namespace std
{
template<class T>
void swap(apex::static_vector<T> & rhs, apex::static_vector<T> & lhs)
{
rhs.swap(lhs);
}
} // namespace std
#endif // APEX_CONTAINERS__STATIC_VECTOR_HPP_