summaryrefslogtreecommitdiff
path: root/boost/poly_collection/detail/segment.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/poly_collection/detail/segment.hpp')
-rw-r--r--boost/poly_collection/detail/segment.hpp296
1 files changed, 296 insertions, 0 deletions
diff --git a/boost/poly_collection/detail/segment.hpp b/boost/poly_collection/detail/segment.hpp
new file mode 100644
index 0000000000..52aa4d4a66
--- /dev/null
+++ b/boost/poly_collection/detail/segment.hpp
@@ -0,0 +1,296 @@
+/* Copyright 2016-2017 Joaquin M Lopez Munoz.
+ * 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)
+ *
+ * See http://www.boost.org/libs/poly_collection for library home page.
+ */
+
+#ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
+#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
+
+#if defined(_MSC_VER)
+#pragma once
+#endif
+
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace boost{
+
+namespace poly_collection{
+
+namespace detail{
+
+/* segment<Model,Allocator> encapsulates implementations of
+ * Model::segment_backend virtual interface under a value-semantics type for
+ * use by poly_collection. The techique is described by Sean Parent at slides
+ * 157-205 of
+ * https://github.com/sean-parent/sean-parent.github.com/wiki/
+ * presentations/2013-09-11-cpp-seasoning/cpp-seasoning.pdf
+ * with one twist: when the type of the implementation can be known at compile
+ * time, a downcast is done and non-virtual member functions (named with a nv_
+ * prefix) are used: this increases the performance of some operations.
+ */
+
+template<typename Model,typename Allocator>
+class segment
+{
+public:
+ using value_type=typename Model::value_type;
+ using base_iterator=typename Model::base_iterator;
+ using const_base_iterator=typename Model::const_base_iterator;
+ using base_sentinel=typename Model::base_sentinel;
+ using const_base_sentinel=typename Model::const_base_sentinel;
+ template<typename T>
+ using iterator=typename Model::template iterator<T>;
+ template<typename T>
+ using const_iterator=typename Model::template const_iterator<T>;
+
+ template<typename T>
+ static segment make(const Allocator& al)
+ {
+ return Model::template make<T>(al);
+ }
+
+ /* clones the implementation of x with no elements */
+
+ static segment make_from_prototype(const segment& x)
+ {
+ return {from_prototype{},x};
+ }
+
+ segment(const segment& x):pimpl{x.impl().copy()}{set_sentinel();}
+ segment(segment&& x)=default;
+ segment& operator=(segment x) // TODO: Why do we need this?
+ {
+ pimpl=std::move(x.pimpl);
+ snt=x.snt;
+ return *this;
+ }
+
+ friend bool operator==(const segment& x,const segment& y)
+ {
+ if(typeid(*(x.pimpl))!=typeid(*(y.pimpl)))return false;
+ else return x.impl().equal(y.impl());
+ }
+
+ friend bool operator!=(const segment& x,const segment& y){return !(x==y);}
+
+ base_iterator begin()const noexcept{return impl().begin();}
+ template<typename U>
+ base_iterator begin()const noexcept{return impl<U>().nv_begin();}
+ base_iterator end()const noexcept{return impl().end();}
+ template<typename U>
+ base_iterator end()const noexcept{return impl<U>().nv_end();}
+ base_sentinel sentinel()const noexcept{return snt;}
+ bool empty()const noexcept{return impl().empty();}
+ template<typename U>
+ bool empty()const noexcept{return impl<U>().nv_empty();}
+ std::size_t size()const noexcept{return impl().size();}
+ template<typename U>
+ std::size_t size()const noexcept{return impl<U>().nv_size();}
+ std::size_t max_size()const noexcept{return impl().max_size();}
+ template<typename U>
+ std::size_t max_size()const noexcept
+ {return impl<U>().nv_max_size();}
+ void reserve(std::size_t n){filter(impl().reserve(n));}
+ template<typename U>
+ void reserve(std::size_t n){filter(impl<U>().nv_reserve(n));}
+ std::size_t capacity()const noexcept{return impl().capacity();}
+ template<typename U>
+ std::size_t capacity()const noexcept
+ {return impl<U>().nv_capacity();}
+ void shrink_to_fit(){filter(impl().shrink_to_fit());}
+ template<typename U>
+ void shrink_to_fit(){filter(impl<U>().nv_shrink_to_fit());}
+
+ template<typename U,typename Iterator,typename... Args>
+ base_iterator emplace(Iterator it,Args&&... args)
+ {
+ return filter(impl<U>().nv_emplace(it,std::forward<Args>(args)...));
+ }
+
+ template<typename U,typename... Args>
+ base_iterator emplace_back(Args&&... args)
+ {
+ return filter(impl<U>().nv_emplace_back(std::forward<Args>(args)...));
+ }
+
+ template<typename T>
+ base_iterator push_back(const T& x)
+ {
+ return filter(impl().push_back(subaddress(x)));
+ }
+
+ template<
+ typename T,
+ typename std::enable_if<
+ !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
+ >::type* =nullptr
+ >
+ base_iterator push_back(T&& x)
+ {
+ return filter(impl().push_back_move(subaddress(x)));
+ }
+
+ template<typename U>
+ base_iterator push_back_terminal(U&& x)
+ {
+ return filter(
+ impl<typename std::decay<U>::type>().nv_push_back(std::forward<U>(x)));
+ }
+
+ template<typename T>
+ base_iterator insert(const_base_iterator it,const T& x)
+ {
+ return filter(impl().insert(it,subaddress(x)));
+ }
+
+ template<typename U,typename T>
+ base_iterator insert(const_iterator<U> it,const T& x)
+ {
+ return filter(
+ impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));
+ }
+
+ template<
+ typename T,
+ typename std::enable_if<
+ !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
+ >::type* =nullptr
+ >
+ base_iterator insert(const_base_iterator it,T&& x)
+ {
+ return filter(impl().insert_move(it,subaddress(x)));
+ }
+
+ template<
+ typename U,typename T,
+ typename std::enable_if<
+ !std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
+ >::type* =nullptr
+ >
+ base_iterator insert(const_iterator<U> it,T&& x)
+ {
+ return filter(
+ impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));
+ }
+
+ template<typename InputIterator>
+ base_iterator insert(InputIterator first,InputIterator last)
+ {
+ return filter(
+ impl<typename std::iterator_traits<InputIterator>::value_type>().
+ nv_insert(first,last));
+ }
+
+ template<typename InputIterator>
+ base_iterator insert(
+ const_base_iterator it,InputIterator first,InputIterator last)
+ {
+ return insert(
+ const_iterator<
+ typename std::iterator_traits<InputIterator>::value_type>(it),
+ first,last);
+ }
+
+ template<typename U,typename InputIterator>
+ base_iterator insert(
+ const_iterator<U> it,InputIterator first,InputIterator last)
+ {
+ return filter(impl<U>().nv_insert(it,first,last));
+ }
+
+ base_iterator erase(const_base_iterator it)
+ {
+ return filter(impl().erase(it));
+ }
+
+ template<typename U>
+ base_iterator erase(const_iterator<U> it)
+ {
+ return filter(impl<U>().nv_erase(it));
+ }
+
+ base_iterator erase(const_base_iterator f,const_base_iterator l)
+ {
+ return filter(impl().erase(f,l));
+ }
+
+ template<typename U>
+ base_iterator erase(const_iterator<U> f,const_iterator<U> l)
+ {
+ return filter(impl<U>().nv_erase(f,l));
+ }
+
+ template<typename Iterator>
+ base_iterator erase_till_end(Iterator f)
+ {
+ return filter(impl().erase_till_end(f));
+ }
+
+ template<typename Iterator>
+ base_iterator erase_from_begin(Iterator l)
+ {
+ return filter(impl().erase_from_begin(l));
+ }
+
+ void clear()noexcept{filter(impl().clear());}
+ template<typename U>
+ void clear()noexcept{filter(impl<U>().nv_clear());}
+
+private:
+ using segment_backend=typename Model::segment_backend;
+ template<typename Concrete>
+ using segment_backend_implementation=typename Model::
+ template segment_backend_implementation<Concrete,Allocator>;
+ using segment_backend_unique_ptr=
+ typename segment_backend::segment_backend_unique_ptr;
+ using range=typename segment_backend::range;
+
+ struct from_prototype{};
+
+ segment(segment_backend_unique_ptr&& pimpl):
+ pimpl{std::move(pimpl)}{set_sentinel();}
+ segment(from_prototype,const segment& x):
+ pimpl{x.impl().empty_copy()}{set_sentinel();}
+
+ segment_backend& impl()noexcept{return *pimpl;}
+ const segment_backend& impl()const noexcept{return *pimpl;}
+
+ template<typename Concrete>
+ segment_backend_implementation<Concrete>& impl()noexcept
+ {
+ return static_cast<segment_backend_implementation<Concrete>&>(impl());
+ }
+
+ template<typename Concrete>
+ const segment_backend_implementation<Concrete>& impl()const noexcept
+ {
+ return
+ static_cast<const segment_backend_implementation<Concrete>&>(impl());
+ }
+
+ template<typename T>
+ static void* subaddress(T& x){return Model::subaddress(x);}
+ template<typename T>
+ static const void* subaddress(const T& x){return Model::subaddress(x);}
+
+ void set_sentinel(){filter(impl().end());}
+ void filter(base_sentinel x){snt=x;}
+ base_iterator filter(const range& x){snt=x.second;return x.first;}
+
+ segment_backend_unique_ptr pimpl;
+ base_sentinel snt;
+};
+
+} /* namespace poly_collection::detail */
+
+} /* namespace poly_collection */
+
+} /* namespace boost */
+
+#endif