mirror of
https://github.com/boostorg/stl_interfaces.git
synced 2026-01-19 04:42:12 +00:00
Add an initial sketch of a container_interface example.
This commit is contained in:
@@ -37,6 +37,9 @@
|
||||
[/ View Examples ]
|
||||
[import ../example/drop_while_view.cpp]
|
||||
|
||||
[/ Container Examples ]
|
||||
[import ../example/static_vector.cpp]
|
||||
|
||||
[/ Images ]
|
||||
|
||||
[def __note__ [$images/note.png]]
|
||||
|
||||
@@ -26,3 +26,5 @@ add_sample(back_insert_iterator)
|
||||
add_sample(reverse_iterator)
|
||||
|
||||
add_sample(drop_while_view)
|
||||
|
||||
add_sample(static_vector)
|
||||
|
||||
202
example/static_vector.cpp
Normal file
202
example/static_vector.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright (C) 2019 T. Zachary Laine
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/stl_interfaces/container_interface.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
//[ static_vector_defn
|
||||
template<typename T, std::size_t N>
|
||||
struct static_vector : boost::stl_interfaces::container_interface<
|
||||
static_vector<T, N>,
|
||||
boost::stl_interfaces::contiguous>
|
||||
{
|
||||
// types
|
||||
using value_type = T;
|
||||
using pointer = T *;
|
||||
using const_pointer = T const *;
|
||||
using reference = value_type &;
|
||||
using const_reference = value_type const &;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator = T *;
|
||||
using const_iterator = T const *;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
// [vector.cons], construct/copy/destroy
|
||||
static_vector() noexcept : size_(0) {}
|
||||
explicit static_vector(size_type n) { this->assign(n, T()); }
|
||||
static_vector(size_type n, T const & value) { this->assign(n, value); }
|
||||
template<typename InputIterator>
|
||||
static_vector(InputIterator first, InputIterator last)
|
||||
{
|
||||
this->assign(first, last);
|
||||
}
|
||||
static_vector(static_vector const & other)
|
||||
{
|
||||
// TODO this->assign(other.begin(), other.end());
|
||||
}
|
||||
static_vector(static_vector && other) noexcept
|
||||
{
|
||||
for (auto & element : other) {
|
||||
emplace_back(std::move(element));
|
||||
}
|
||||
other.clear();
|
||||
}
|
||||
static_vector(std::initializer_list<T> il)
|
||||
{
|
||||
// TODO this->assign(il.begin(), il.end());
|
||||
}
|
||||
~static_vector() { this->clear(); }
|
||||
static_vector & operator=(static_vector const & other)
|
||||
{
|
||||
this->clear();
|
||||
// TODO this->assign(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
static_vector & operator=(static_vector && other)
|
||||
{
|
||||
this->clear();
|
||||
for (auto & element : other) {
|
||||
emplace_back(std::move(element));
|
||||
}
|
||||
other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// iterators (2 members, skipped 10)
|
||||
iterator begin() noexcept { return reinterpret_cast<T *>(buf_); }
|
||||
iterator end() noexcept
|
||||
{
|
||||
return reinterpret_cast<T *>(buf_ + size_ * sizeof(T));
|
||||
}
|
||||
|
||||
// [vector.capacity], capacity (6 members, skipped 2)
|
||||
size_type max_size() const noexcept { return N; }
|
||||
size_type capacity() const noexcept { return N; }
|
||||
void resize(size_type sz) { resize(sz, T()); }
|
||||
void resize(size_type sz, T const & x)
|
||||
{
|
||||
if (sz < this->size())
|
||||
erase(begin() + sz, end());
|
||||
if (this->size() < sz)
|
||||
std::uninitialized_fill(end(), begin() + sz, x);
|
||||
}
|
||||
void reserve(size_type n) {}
|
||||
void shrink_to_fit() {}
|
||||
|
||||
// element access (skipped 8 members)
|
||||
// [vector.data], data access (skipped 2 members)
|
||||
|
||||
// [vector.modifiers], modifiers (6 members, skipped 8)
|
||||
template<typename... Args>
|
||||
reference emplace_back(Args &&... args)
|
||||
{
|
||||
assert(this->size() < capacity());
|
||||
auto ptr =
|
||||
new (buf_ + size_ * sizeof(T)) T(std::forward<Args>(args)...);
|
||||
++size_;
|
||||
return *ptr;
|
||||
}
|
||||
template<typename... Args>
|
||||
iterator emplace(const_iterator pos, Args &&... args)
|
||||
{
|
||||
auto position = const_cast<T *>(pos);
|
||||
if (position < end()) {
|
||||
auto last = end();
|
||||
emplace_back(std::move(this->back()));
|
||||
std::move_backward(position, last - 1, last);
|
||||
}
|
||||
new (position) T(std::forward<Args>(args)...);
|
||||
++size_;
|
||||
return position;
|
||||
}
|
||||
// Note: This iterator category was upgraded to ForwardIterator (instead
|
||||
// of vector's InputIterator), to ensure linear time complexity.
|
||||
template<typename ForwardIterator>
|
||||
iterator
|
||||
insert(const_iterator pos, ForwardIterator first, ForwardIterator last)
|
||||
{
|
||||
auto position = const_cast<T *>(pos);
|
||||
auto const insertions = std::distance(first, last);
|
||||
assert(this->size() + insertions < capacity());
|
||||
std::uninitialized_fill_n(end(), insertions, T());
|
||||
std::move_backward(position, end(), begin() + insertions);
|
||||
auto retval = std::copy(first, last, position);
|
||||
size_ += insertions;
|
||||
return retval;
|
||||
}
|
||||
iterator erase(const_iterator pos)
|
||||
{
|
||||
auto position = const_cast<T *>(pos);
|
||||
std::move(position + 1, end(), position);
|
||||
this->back().~T();
|
||||
--size_;
|
||||
return position;
|
||||
}
|
||||
iterator erase(const_iterator f, const_iterator last)
|
||||
{
|
||||
auto first = const_cast<T *>(f);
|
||||
#if 0 // TODO
|
||||
auto const end_ = this->cend();
|
||||
auto it = std::move(last, end_, first);
|
||||
for (; it != end_; ++it) {
|
||||
it->~T();
|
||||
}
|
||||
size_ -= last - first;
|
||||
#endif
|
||||
return first;
|
||||
}
|
||||
void swap(static_vector & other)
|
||||
{
|
||||
size_type short_size, long_size;
|
||||
std::tie(short_size, long_size) =
|
||||
std::minmax(this->size(), other.size());
|
||||
for (auto i = size_type(0); i < short_size; ++i) {
|
||||
using std::swap;
|
||||
swap((*this)[i], other[i]);
|
||||
}
|
||||
|
||||
static_vector * longer = this;
|
||||
static_vector * shorter = this;
|
||||
if (this->size() < other.size())
|
||||
longer = &other;
|
||||
else
|
||||
shorter = &other;
|
||||
|
||||
for (auto it = longer->begin() + short_size, last = longer->end();
|
||||
it != last;
|
||||
++it) {
|
||||
shorter->emplace_back(std::move(*it));
|
||||
}
|
||||
|
||||
longer->resize(short_size);
|
||||
shorter->size_ = long_size;
|
||||
}
|
||||
|
||||
// TODO: Remove!
|
||||
void clear() noexcept { erase(begin(), end()); }
|
||||
|
||||
private:
|
||||
alignas(T) unsigned char buf_[N * sizeof(T)];
|
||||
size_type size_;
|
||||
};
|
||||
//]
|
||||
|
||||
// TODO
|
||||
template struct static_vector<int, 1024>;
|
||||
|
||||
int main()
|
||||
{
|
||||
//[ static_vector_usage
|
||||
static_vector<int, 1024> sv;
|
||||
//]
|
||||
}
|
||||
@@ -109,6 +109,22 @@ namespace boost { namespace stl_interfaces {
|
||||
template<typename Derived, bool Contiguous = discontiguous>
|
||||
struct container_interface : view_interface<Derived, Contiguous, true>
|
||||
{
|
||||
#ifndef BOOST_STL_INTERFACES_DOXYGEN
|
||||
private:
|
||||
constexpr Derived & derived() noexcept
|
||||
{
|
||||
return static_cast<Derived &>(*this);
|
||||
}
|
||||
constexpr const Derived & derived() const noexcept
|
||||
{
|
||||
return static_cast<Derived const &>(*this);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
// TODO: size() from view_interface is actually returning a
|
||||
// difference_type, nto a size_type.
|
||||
|
||||
template<typename D = Derived>
|
||||
constexpr auto begin() const
|
||||
noexcept(noexcept(std::declval<D &>().begin()))
|
||||
@@ -141,7 +157,7 @@ namespace boost { namespace stl_interfaces {
|
||||
|
||||
template<
|
||||
typename D = Derived,
|
||||
typename Enable = std::enable_if_t<detail::common_range<D>>>
|
||||
typename Enable = std::enable_if_t<detail::common_range<D>::value>>
|
||||
constexpr auto rbegin() noexcept(noexcept(
|
||||
stl_interfaces::make_reverse_iterator(std::declval<D &>().end())))
|
||||
-> decltype(
|
||||
@@ -153,7 +169,7 @@ namespace boost { namespace stl_interfaces {
|
||||
}
|
||||
template<
|
||||
typename D = Derived,
|
||||
typename Enable = std::enable_if_t<detail::common_range<D>>>
|
||||
typename Enable = std::enable_if_t<detail::common_range<D>::value>>
|
||||
constexpr auto rend() noexcept(noexcept(
|
||||
stl_interfaces::make_reverse_iterator(std::declval<D &>().begin())))
|
||||
-> decltype(
|
||||
@@ -229,7 +245,7 @@ namespace boost { namespace stl_interfaces {
|
||||
pos, detail::make_n_iter(x, n), detail::make_n_iter_end(x, n)))
|
||||
{
|
||||
return derived().insert(
|
||||
pos, detail::make_n_iter(x, n), detail::make_n_iter_end(x, n)));
|
||||
pos, detail::make_n_iter(x, n), detail::make_n_iter_end(x, n));
|
||||
}
|
||||
|
||||
template<typename D = Derived>
|
||||
@@ -355,16 +371,28 @@ namespace boost { namespace stl_interfaces {
|
||||
noexcept(std::declval<D &>().size(), std::declval<D &>()[i]))
|
||||
-> decltype(std::declval<D &>().size(), std::declval<D &>()[i])
|
||||
{
|
||||
if (derived.size() <= i)
|
||||
throw TODO;
|
||||
if (derived().size() <= i) {
|
||||
throw std::out_of_range(
|
||||
"Bounds check failed in static_vector::at()");
|
||||
}
|
||||
return derived()[i];
|
||||
}
|
||||
|
||||
template<typename D = Derived>
|
||||
constexpr auto clear(typename D::size_type i) noexcept(
|
||||
noexcept(std::declval<D &>().erase(
|
||||
std::declval<D &>().begin(), std::declval<D &>().end())))
|
||||
-> decltype((void)std::declval<D &>().erase(
|
||||
std::declval<D &>().begin(), std::declval<D &>().end()))
|
||||
{
|
||||
return derived().erase(derived().begin(), derived().end());
|
||||
}
|
||||
};
|
||||
|
||||
/** Implementation of free function `swap()` for all containers derived
|
||||
from `container_interface`. */
|
||||
template<typename ContainerInterface>
|
||||
friend constexpr auto swap(
|
||||
constexpr auto swap(
|
||||
ContainerInterface & lhs,
|
||||
ContainerInterface & rhs) noexcept(noexcept(lhs.swap(rhs)))
|
||||
-> decltype(
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_STL_INTERFACES_REVERSE_ITERATOR_HPP
|
||||
#define BOOST_STL_INTERFACES_REVERSE_ITERATOR_HPP
|
||||
|
||||
#include <boost/stl_interfaces/fwd.hpp>
|
||||
#include <boost/stl_interfaces/iterator_interface.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace stl_interfaces {
|
||||
|
||||
@@ -216,5 +216,118 @@ namespace boost { namespace stl_interfaces {
|
||||
}
|
||||
|
||||
}}
|
||||
#if 0
|
||||
namespace std {
|
||||
template<class T, class Allocator = allocator<T>>
|
||||
class vector {
|
||||
public:
|
||||
// types
|
||||
using value_type = T;
|
||||
using allocator_type = Allocator;
|
||||
using pointer = typename allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename allocator_traits<Allocator>::const_pointer;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = implementation-defined; // see [container.requirements]
|
||||
using difference_type = implementation-defined; // see [container.requirements]
|
||||
using iterator = implementation-defined; // see [container.requirements]
|
||||
using const_iterator = implementation-defined; // see [container.requirements]
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
// [vector.cons], construct/copy/destroy
|
||||
constexpr vector() noexcept(noexcept(Allocator())) : vector(Allocator()) { }
|
||||
constexpr explicit vector(const Allocator&) noexcept;
|
||||
constexpr explicit vector(size_type n, const Allocator& = Allocator());
|
||||
constexpr vector(size_type n, const T& value, const Allocator& = Allocator());
|
||||
template<class InputIterator>
|
||||
constexpr vector(InputIterator first, InputIterator last, const Allocator& = Allocator());
|
||||
constexpr vector(const vector& x);
|
||||
constexpr vector(vector&&) noexcept;
|
||||
constexpr vector(const vector&, const Allocator&);
|
||||
constexpr vector(vector&&, const Allocator&);
|
||||
constexpr vector(initializer_list<T>, const Allocator& = Allocator());
|
||||
constexpr ~vector();
|
||||
constexpr vector& operator=(const vector& x);
|
||||
constexpr vector& operator=(vector&& x)
|
||||
noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value ||
|
||||
allocator_traits<Allocator>::is_always_equal::value);
|
||||
constexpr vector& operator=(initializer_list<T>);
|
||||
template<class InputIterator>
|
||||
constexpr void assign(InputIterator first, InputIterator last);
|
||||
constexpr void assign(size_type n, const T& u);
|
||||
constexpr void assign(initializer_list<T>);
|
||||
constexpr allocator_type get_allocator() const noexcept;
|
||||
|
||||
// iterators
|
||||
constexpr iterator begin() noexcept;
|
||||
constexpr const_iterator begin() const noexcept;
|
||||
constexpr iterator end() noexcept;
|
||||
constexpr const_iterator end() const noexcept;
|
||||
constexpr reverse_iterator rbegin() noexcept;
|
||||
constexpr const_reverse_iterator rbegin() const noexcept;
|
||||
constexpr reverse_iterator rend() noexcept;
|
||||
constexpr const_reverse_iterator rend() const noexcept;
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept;
|
||||
constexpr const_iterator cend() const noexcept;
|
||||
constexpr const_reverse_iterator crbegin() const noexcept;
|
||||
constexpr const_reverse_iterator crend() const noexcept;
|
||||
|
||||
// [vector.capacity], capacity
|
||||
[[nodiscard]] constexpr bool empty() const noexcept;
|
||||
constexpr size_type size() const noexcept;
|
||||
constexpr size_type max_size() const noexcept;
|
||||
constexpr size_type capacity() const noexcept;
|
||||
constexpr void resize(size_type sz);
|
||||
constexpr void resize(size_type sz, const T& c);
|
||||
constexpr void reserve(size_type n);
|
||||
constexpr void shrink_to_fit();
|
||||
|
||||
// element access
|
||||
constexpr reference operator[](size_type n);
|
||||
constexpr const_reference operator[](size_type n) const;
|
||||
constexpr const_reference at(size_type n) const;
|
||||
constexpr reference at(size_type n);
|
||||
constexpr reference front();
|
||||
constexpr const_reference front() const;
|
||||
constexpr reference back();
|
||||
constexpr const_reference back() const;
|
||||
|
||||
// [vector.data], data access
|
||||
constexpr T* data() noexcept;
|
||||
constexpr const T* data() const noexcept;
|
||||
|
||||
// [vector.modifiers], modifiers
|
||||
template<class... Args> constexpr reference emplace_back(Args&&... args);
|
||||
constexpr void push_back(const T& x);
|
||||
constexpr void push_back(T&& x);
|
||||
constexpr void pop_back();
|
||||
|
||||
template<class... Args> constexpr iterator emplace(const_iterator position, Args&&... args);
|
||||
constexpr iterator insert(const_iterator position, const T& x);
|
||||
constexpr iterator insert(const_iterator position, T&& x);
|
||||
constexpr iterator insert(const_iterator position, size_type n, const T& x);
|
||||
template<class InputIterator>
|
||||
constexpr iterator insert(const_iterator position,
|
||||
InputIterator first, InputIterator last);
|
||||
constexpr iterator insert(const_iterator position, initializer_list<T> il);
|
||||
constexpr iterator erase(const_iterator position);
|
||||
constexpr iterator erase(const_iterator first, const_iterator last);
|
||||
constexpr void swap(vector&)
|
||||
noexcept(allocator_traits<Allocator>::propagate_on_container_swap::value ||
|
||||
allocator_traits<Allocator>::is_always_equal::value);
|
||||
constexpr void clear() noexcept;
|
||||
};
|
||||
|
||||
template<class InputIterator, class Allocator = allocator<iter-value-type<InputIterator>>>
|
||||
vector(InputIterator, InputIterator, Allocator = Allocator())
|
||||
-> vector<iter-value-type<InputIterator>, Allocator>;
|
||||
|
||||
// swap
|
||||
template<class T, class Allocator>
|
||||
constexpr void swap(vector<T, Allocator>& x, vector<T, Allocator>& y)
|
||||
noexcept(noexcept(x.swap(y)));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user