Program Listing for File bounded_vector.hpp
↰ Return to documentation for file (include/rosidl_runtime_cpp/bounded_vector.hpp
)
// Copyright 2016 Open Source Robotics Foundation, 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 ROSIDL_RUNTIME_CPP__BOUNDED_VECTOR_HPP_
#define ROSIDL_RUNTIME_CPP__BOUNDED_VECTOR_HPP_
#include <algorithm>
#include <memory>
#include <stdexcept>
#include <utility>
#include <vector>
namespace rosidl_runtime_cpp
{
template<typename Tp, std::size_t UpperBound, typename Alloc = std::allocator<Tp>>
class BoundedVector
: protected std::vector<Tp, Alloc>
{
using Base = std::vector<Tp, Alloc>;
public:
using typename Base::value_type;
using typename Base::pointer;
using typename Base::const_pointer;
using typename Base::reference;
using typename Base::const_reference;
using typename Base::iterator;
using typename Base::const_iterator;
using typename Base::const_reverse_iterator;
using typename Base::reverse_iterator;
using typename Base::size_type;
using typename Base::difference_type;
using typename Base::allocator_type;
BoundedVector()
noexcept (std::is_nothrow_default_constructible<Alloc>::value)
: Base()
{}
explicit
BoundedVector(
const typename Base::allocator_type & a)
noexcept
: Base(a)
{}
explicit
BoundedVector(
typename Base::size_type n,
const typename Base::allocator_type & a = allocator_type())
: Base(n, a)
{
if (n > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
}
BoundedVector(
typename Base::size_type n,
const typename Base::value_type & value,
const typename Base::allocator_type & a = allocator_type())
: Base(n, value, a)
{
if (n > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
}
BoundedVector(
const BoundedVector & x)
: Base(x)
{}
BoundedVector(BoundedVector && x) noexcept
: Base(std::move(x))
{}
BoundedVector(const BoundedVector & x, const typename Base::allocator_type & a)
: Base(x, a)
{}
BoundedVector(
std::initializer_list<typename Base::value_type> l,
const typename Base::allocator_type & a = typename Base::allocator_type())
: Base(l, a)
{
if (l.size() > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
}
template<
typename InputIterator
>
BoundedVector(
InputIterator first,
InputIterator last,
const typename Base::allocator_type & a = allocator_type())
: Base(first, last, a)
{
if (size() > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
}
~BoundedVector() noexcept
{}
BoundedVector &
operator=(const BoundedVector & x)
{
(void)Base::operator=(x);
return *this;
}
BoundedVector &
operator=(BoundedVector && x)
{
(void)Base::operator=(std::move(x));
return *this;
}
BoundedVector &
operator=(std::initializer_list<typename Base::value_type> l)
{
if (l.size() > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::operator=(l);
return *this;
}
void
assign(
typename Base::size_type n,
const typename Base::value_type & val)
{
if (n > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::assign(n, val);
}
template<
typename InputIterator
>
void
assign(InputIterator first, InputIterator last)
{
using cat = typename std::iterator_traits<InputIterator>::iterator_category;
do_assign(first, last, cat());
}
void
assign(std::initializer_list<typename Base::value_type> l)
{
if (l.size() > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::assign(l);
}
using Base::begin;
using Base::end;
using Base::rbegin;
using Base::rend;
using Base::cbegin;
using Base::cend;
using Base::crbegin;
using Base::crend;
using Base::size;
typename Base::size_type
max_size() const noexcept
{
return std::min(UpperBound, Base::max_size());
}
void
resize(typename Base::size_type new_size)
{
if (new_size > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::resize(new_size);
}
void
resize(
typename Base::size_type new_size,
const typename Base::value_type & x)
{
if (new_size > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::resize(new_size, x);
}
using Base::shrink_to_fit;
using Base::capacity;
using Base::empty;
void
reserve(typename Base::size_type n)
{
if (n > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::reserve(n);
}
using Base::operator[];
using Base::at;
using Base::front;
using Base::back;
template<
typename T,
typename std::enable_if<
!std::is_same<T, Tp>::value &&
!std::is_same<T, bool>::value
>::type * = nullptr
>
T *
data() noexcept
{
return Base::data();
}
template<
typename T,
typename std::enable_if<
!std::is_same<T, Tp>::value &&
!std::is_same<T, bool>::value
>::type * = nullptr
>
const T *
data() const noexcept
{
return Base::data();
}
void
push_back(const typename Base::value_type & x)
{
if (size() >= UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::push_back(x);
}
void
push_back(typename Base::value_type && x)
{
if (size() >= UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::push_back(x);
}
template<typename ... Args>
auto
emplace_back(Args && ... args)
{
if (size() >= UpperBound) {
throw std::length_error("Exceeded upper bound");
}
return Base::emplace_back(std::forward<Args>(args)...);
}
template<typename ... Args>
typename Base::iterator
emplace(
typename Base::const_iterator position,
Args && ... args)
{
if (size() >= UpperBound) {
throw std::length_error("Exceeded upper bound");
}
return Base::emplace(position, std::forward<Args>(args) ...);
}
typename Base::iterator
insert(
typename Base::const_iterator position,
const typename Base::value_type & x)
{
if (size() >= UpperBound) {
throw std::length_error("Exceeded upper bound");
}
return Base::insert(position, x);
}
typename Base::iterator
insert(
typename Base::const_iterator position,
typename Base::value_type && x)
{
if (size() >= UpperBound) {
throw std::length_error("Exceeded upper bound");
}
return Base::insert(position, x);
}
typename Base::iterator
insert(
typename Base::const_iterator position,
std::initializer_list<typename Base::value_type> l)
{
if (size() + l.size() > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
return Base::insert(position, l);
}
typename Base::iterator
insert(
typename Base::const_iterator position,
typename Base::size_type n,
const typename Base::value_type & x)
{
if (size() + n > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
return Base::insert(position, n, x);
}
template<
typename InputIterator
>
typename Base::iterator
insert(
typename Base::const_iterator position,
InputIterator first,
InputIterator last)
{
using cat = typename std::iterator_traits<InputIterator>::iterator_category;
return do_insert(position, first, last, cat());
}
using Base::erase;
using Base::pop_back;
using Base::clear;
private:
template<
typename InputIterator
>
void
do_assign(InputIterator first, InputIterator last, std::input_iterator_tag)
{
BoundedVector(first, last).swap(*this);
}
template<
typename FwdIterator
>
void
do_assign(FwdIterator first, FwdIterator last, std::forward_iterator_tag)
{
if (static_cast<std::size_t>(std::distance(first, last)) > UpperBound) {
throw std::length_error("Exceeded upper bound");
}
Base::assign(first, last);
}
// Insert each value at the end and then rotate them to the desired position.
// If the bound is exceeded, the inserted elements are removed again.
template<
typename InputIterator
>
typename Base::iterator
do_insert(
typename Base::const_iterator position,
InputIterator first,
InputIterator last,
std::input_iterator_tag)
{
const auto orig_size = size();
const auto idx = position - cbegin();
try {
while (first != last) {
push_back(*first++);
}
} catch (const std::length_error &) {
Base::resize(orig_size);
throw;
}
auto pos = begin() + idx;
std::rotate(pos, begin() + orig_size, end());
return begin() + idx;
}
template<
typename FwdIterator
>
typename Base::iterator
do_insert(
typename Base::const_iterator position,
FwdIterator first,
FwdIterator last,
std::forward_iterator_tag)
{
auto dist = std::distance(first, last);
if ((dist < 0) || (size() + static_cast<size_t>(dist) > UpperBound)) {
throw std::length_error("Exceeded upper bound");
}
return Base::insert(position, first, last);
}
friend bool
operator==(
const BoundedVector & x,
const BoundedVector & y)
{
return static_cast<const Base &>(x) == static_cast<const Base &>(y);
}
friend bool
operator<(
const BoundedVector & x,
const BoundedVector & y)
{
return static_cast<const Base &>(x) < static_cast<const Base &>(y);
}
friend bool
operator!=(
const BoundedVector & x,
const BoundedVector & y)
{
return static_cast<const Base &>(x) != static_cast<const Base &>(y);
}
friend bool
operator>(
const BoundedVector & x,
const BoundedVector & y)
{
return static_cast<const Base &>(x) > static_cast<const Base &>(y);
}
friend bool
operator<=(
const BoundedVector & x,
const BoundedVector & y)
{
return static_cast<const Base &>(x) <= static_cast<const Base &>(y);
}
friend bool
operator>=(
const BoundedVector & x,
const BoundedVector & y)
{
return static_cast<const Base &>(x) >= static_cast<const Base &>(y);
}
};
template<typename Tp, std::size_t UpperBound, typename Alloc>
inline void
swap(BoundedVector<Tp, UpperBound, Alloc> & x, BoundedVector<Tp, UpperBound, Alloc> & y)
{
x.swap(y);
}
} // namespace rosidl_runtime_cpp
#endif // ROSIDL_RUNTIME_CPP__BOUNDED_VECTOR_HPP_