From 7252b2d68b354ffe7731743243efb40e19f38b6f Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Wed, 13 Dec 2017 21:22:50 +0100 Subject: [PATCH 1/5] added xtiny and tests --- include/xtensor/xtiny.hpp | 1983 +++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/test_xtiny.cpp | 307 ++++++ 3 files changed, 2291 insertions(+) create mode 100644 include/xtensor/xtiny.hpp create mode 100644 test/test_xtiny.cpp diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp new file mode 100644 index 000000000..f66addaf9 --- /dev/null +++ b/include/xtensor/xtiny.hpp @@ -0,0 +1,1983 @@ +/*************************************************************************** +* Copyright (c) 2017, Ullrich Koethe * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_XTINY_HPP +#define XTENSOR_XTINY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include // std::ignore + +#include "xconcepts.hpp" +#include "xexception.hpp" +#include "xutils.hpp" +#include "xbuffer_adaptor.hpp" +#include "xstorage.hpp" + +namespace xt +{ + /*****************/ + /* prerequisites */ + /*****************/ + + using index_t = std::ptrdiff_t; + + static const index_t runtime_size = -1; + + namespace tags + { + struct xtiny_tag {}; + + struct skip_initialization_tag {}; + } + + namespace + { + tags::skip_initialization_tag dont_init; + } + + template + struct xtiny_concept + : public std::integral_constant>::value> + { + }; + + /****************/ + /* declarations */ + /****************/ + + template + class xtiny_impl; + + template + class xtiny; + + /*********/ + /* xtiny */ + /*********/ + + /* Adds common functionality to the respective xtiny_impl */ + template + class xtiny + : public xtiny_impl + { + public: + + using self_type = xtiny; + using base_type = xtiny_impl; + using value_type = typename base_type::value_type; + using const_value_type = typename base_type::const_value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using reverse_iterator = typename base_type::reverse_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + using index_type = typename base_type::index_type; + + using base_type::owns_memory; + using base_type::has_fixed_size; + using base_type::static_size; + + using base_type::base_type; + + xtiny(); + xtiny(xtiny const & rhs); + xtiny(xtiny && rhs); + + template + xtiny(xtiny const & rhs); + + template + xtiny(std::vector const & v); + + template + xtiny(std::array const & v); + + xtiny & operator=(xtiny const & rhs); + xtiny & operator=(xtiny && rhs); + + xtiny & operator=(value_type const & v); + + template + xtiny & operator=(std::vector const & v); + + template + xtiny & operator=(std::array const & v); + + template + xtiny & operator=(xtiny const & rhs); + + using base_type::assign; + + template + void assign(std::initializer_list v); + + using base_type::data; + + using base_type::operator[]; + reference at(size_type i); + constexpr const_reference at(size_type i) const; + + reference front(); + reference back(); + constexpr const_reference front() const; + constexpr const_reference back() const; + + template + auto subarray(); + template + auto subarray() const; + auto subarray(size_type FROM, size_type TO); + auto subarray(size_type FROM, size_type TO) const; + + auto erase(size_type m) const; + auto pop_front() const; + auto pop_back() const; + + auto insert(size_type m, value_type v) const; + auto push_front(value_type v) const; + auto push_back(value_type v) const; + + using base_type::begin; + constexpr const_iterator cbegin() const; + iterator end(); + constexpr const_iterator end() const; + constexpr const_iterator cend() const; + + using base_type::rbegin; + constexpr const_reverse_iterator crbegin() const; + reverse_iterator rend(); + constexpr const_reverse_iterator rend() const; + constexpr const_reverse_iterator crend() const; + + using base_type::size; + using base_type::max_size; + using base_type::shape; + constexpr bool empty() const; + + using base_type::swap; + }; + + /******************************/ + /* default dynamic xtiny_impl */ + /******************************/ + + template + class xtiny_impl + : public xtiny_impl + { + using base_type = xtiny_impl; + public: + using base_type::base_type; + }; + + /******************************************/ + /* xtiny_impl: dynamic shape, owns memory */ + /******************************************/ + + template + class xtiny_impl + : public tags::xtiny_tag + { + public: + using self_type = xtiny_impl; + using representation_type = VALUETYPE *; + using buffer_type = VALUETYPE[BUFFER_SIZE < 1 ? 1 : BUFFER_SIZE]; + using allocator_type = std::allocator; + + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = value_type &; + using const_reference = const_value_type &; + using pointer = value_type *; + using const_pointer = const_value_type *; + using iterator = value_type *; + using const_iterator = const_value_type *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = std::array; + + static const bool owns_memory = true; + static const bool has_fixed_size = false; + static const index_t static_size = runtime_size; + static const index_t buffer_size = BUFFER_SIZE; + + template + using rebind = xtiny; + + xtiny_impl(); + ~xtiny_impl(); + + explicit xtiny_impl(size_type n); + xtiny_impl(size_type n, const value_type& v); + xtiny_impl(size_type n, tags::skip_initialization_tag); + + template > + xtiny_impl(IT begin, IT end); + + template + xtiny_impl(std::initializer_list const & v); + + xtiny_impl(xtiny_impl const & v); + xtiny_impl(xtiny_impl && v); + + xtiny_impl & operator=(xtiny_impl const & v); + xtiny_impl & operator=(xtiny_impl && v); + + void assign(size_type n, const value_type& v); + + template > + void assign(IT other_begin, IT other_end); + + reference operator[](size_type i); + constexpr const_reference operator[](size_type i) const; + + pointer data(); + constexpr const_pointer data() const; + + void resize(size_type n); + + size_type capacity() const; + size_type size() const; + size_type max_size() const; + index_type shape() const; + bool on_stack() const; + + iterator begin(); + const_iterator begin() const; + + reverse_iterator rbegin(); + const_reverse_iterator rbegin() const; + + void swap(xtiny_impl & other); + + protected: + static const bool may_use_uninitialized_memory = xtrivially_default_constructible::value; + + /* allocate() assumes that m_size is already set, + but no memory has been allocated yet */ + void allocate(value_type const & v = value_type()); + void allocate(tags::skip_initialization_tag); + template > + void allocate(IT other_begin); + + void deallocate(); + + allocator_type m_allocator; + size_type m_size; + representation_type m_data; + buffer_type m_buffer; + }; + + /**********************************/ + /* default fixed shape xtiny_impl */ + /**********************************/ + + template + class xtiny_impl + : public xtiny_impl> + { + using base_type = xtiny_impl>; + public: + using base_type::base_type; + }; + + /****************************************/ + /* xtiny_impl: fixed shape, owns memory */ + /****************************************/ + + template + class xtiny_impl> + : public std::array + , public tags::xtiny_tag + { + public: + using base_type = std::array; + using self_type = xtiny_impl; + + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using reverse_iterator = typename base_type::reverse_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = std::array; + + static const bool owns_memory = true; + static const bool has_fixed_size = true; + static const index_t static_size = N; + + template + using rebind = xtiny>; + + template + using rebind_size = xtiny>; + + xtiny_impl(); + + explicit xtiny_impl(size_type n); + xtiny_impl(size_type n, const value_type& v); + xtiny_impl(size_type n, tags::skip_initialization_tag); + + template > + xtiny_impl(IT begin); + + template > + xtiny_impl(IT begin, IT end); + + template + xtiny_impl(std::initializer_list const & v); + + xtiny_impl(xtiny_impl const & v); + xtiny_impl(xtiny_impl && v); + + xtiny_impl & operator=(xtiny_impl const & v); + xtiny_impl & operator=(xtiny_impl && v); + + void assign(size_type n, const value_type& v); + + template > + void assign(IT other_begin, IT other_end); + + using base_type::operator[]; + using base_type::data; + + using base_type::size; + using base_type::max_size; + constexpr size_type capacity() const; + constexpr index_type shape() const; + + using base_type::begin; + using base_type::cbegin; + using base_type::rbegin; + using base_type::crbegin; + using base_type::end; + using base_type::cend; + using base_type::rend; + using base_type::crend; + + using base_type::swap; + }; + + /******************************/ + /* representation type traits */ + /******************************/ + + namespace xtiny_detail + { + + template + struct test_value_type + { + static void test(...); + + template + static typename U::value_type test(U *, typename U::value_type * = 0); + + static const bool value = !std::is_same::value; + }; + + template ::value, + bool is_iterator=iterator_concept::value> + struct representation_type_traits; + + template + struct representation_type_traits // T is a container + { + using value_type = typename T::value_type; + using iterator = typename T::iterator; + using const_iterator = typename T::const_iterator; + using reverse_iterator = typename T::reverse_iterator; + using const_reverse_iterator = typename T::const_reverse_iterator; + }; + + template + struct representation_type_traits // T is an iterator + { + using value_type = typename T::value_type; + using iterator = T; + using const_iterator = T; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + }; + + template + struct representation_type_traits + { + using value_type = T; + using iterator = value_type *; + using const_iterator = value_type const *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + }; + + template + struct representation_type_traits + { + using value_type = T const; + using iterator = value_type *; + using const_iterator = value_type *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + }; + } + + /********************************************/ + /* xtiny_impl: fixed shape, borrowed memory */ + /********************************************/ + + template + class xtiny_impl + : public tags::xtiny_tag + { + using traits = xtiny_detail::representation_type_traits; + using deduced_value_type = std::remove_const_t; + static_assert(std::is_same, deduced_value_type>::value, + "xtiny_impl: type mismatch between VALUETYPE and REPRESENTATION."); + + public: + using representation_type = REPRESENTATION; + using self_type = xtiny_impl; + + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = value_type &; + using const_reference = const_value_type &; + using pointer = value_type *; + using const_pointer = const_value_type *; + using iterator = typename traits::iterator; + using const_iterator = typename traits::const_iterator; + using reverse_iterator = typename traits::reverse_iterator; + using const_reverse_iterator = typename traits::const_reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = std::array; + + static const bool owns_memory = false; + static const bool has_fixed_size = true; + static const index_t static_size = N; + + xtiny_impl(); + + explicit xtiny_impl(representation_type const & begin); + xtiny_impl(representation_type const & begin, representation_type const & end); + + template > + xtiny_impl(IT begin, IT end); + + xtiny_impl(xtiny_impl const & v) = default; + xtiny_impl(xtiny_impl && v) = default; + + xtiny_impl & operator=(xtiny_impl const & v) = default; + xtiny_impl & operator=(xtiny_impl && v) = default; + + void reset(representation_type const & begin); + + void assign(size_type n, const value_type& v); + + template > + void assign(IT other_begin, IT other_end); + + reference operator[](size_type i); + constexpr const_reference operator[](size_type i) const; + + pointer data(); + constexpr const_pointer data() const; + + constexpr size_type size() const; + constexpr size_type max_size() const; + constexpr size_type capacity() const; + constexpr index_type shape() const; + + iterator begin(); + constexpr const_iterator begin() const; + + reverse_iterator rbegin(); + constexpr const_reverse_iterator rbegin() const; + + void swap(xtiny_impl &); + + protected: + + representation_type m_data; + }; + + /**********************************************/ + /* xtiny_impl: dynamic shape, borrowed memory */ + /**********************************************/ + + template + class xtiny_impl + : public tags::xtiny_tag + { + using traits = xtiny_detail::representation_type_traits; + using deduced_value_type = std::remove_const_t; + static_assert(std::is_same, deduced_value_type>::value, + "xtiny_impl: type mismatch between VALUETYPE and REPRESENTATION."); + + public: + using representation_type = REPRESENTATION; + using self_type = xtiny_impl; + + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = value_type &; + using const_reference = const_value_type &; + using pointer = value_type *; + using const_pointer = const_value_type *; + using iterator = typename traits::iterator; + using const_iterator = typename traits::const_iterator; + using reverse_iterator = typename traits::reverse_iterator; + using const_reverse_iterator = typename traits::const_reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = std::array; + + static const bool owns_memory = false; + static const bool has_fixed_size = false; + static const index_t static_size = runtime_size; + + xtiny_impl(); + + xtiny_impl(representation_type const & begin, representation_type const & end); + + template > + xtiny_impl(IT begin, IT end); + + xtiny_impl(xtiny_impl const & v) = default; + xtiny_impl(xtiny_impl && v) = default; + + xtiny_impl & operator=(xtiny_impl const & v) = default; + xtiny_impl & operator=(xtiny_impl && v) = default; + + void reset(representation_type const & begin, representation_type const & end); + + void assign(size_type n, const value_type& v); + + template > + void assign(IT other_begin, IT other_end); + + reference operator[](size_type i); + constexpr const_reference operator[](size_type i) const; + + pointer data(); + constexpr const_pointer data() const; + + constexpr size_type size() const; + constexpr size_type max_size() const; + constexpr size_type capacity() const; + constexpr index_type shape() const; + + iterator begin(); + constexpr const_iterator begin() const; + + reverse_iterator rbegin(); + constexpr const_reverse_iterator rbegin() const; + + void swap(xtiny_impl &); + + protected: + + size_type m_size; + representation_type m_data; + }; + + /**********************************************/ + /* xtiny_impl: dynamic shape, xbuffer_adaptor */ + /**********************************************/ + + template + class xtiny_impl> + : public xbuffer_adaptor + , public tags::xtiny_tag + { + using deduced_value_type = typename xbuffer_adaptor::value_type; + static_assert(std::is_same::value, + "tiny_array_base: type mismatch between VALUETYPE and REPRESENTATION."); + public: + using base_type = xbuffer_adaptor; + using self_type = xtiny_impl; + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = value_type &; + using const_reference = const_value_type &; + using pointer = value_type *; + using const_pointer = const_value_type *; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using reverse_iterator = typename base_type::reverse_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = std::array; + + static const bool owns_memory = false; + static const bool has_fixed_size = false; + static const index_t static_size = runtime_size; + + using base_type::base_type; + + void assign(size_type n, const value_type& v); + + template > + void assign(IT other_begin, IT other_end); + + using base_type::operator[]; + using base_type::data; + using base_type::size; + + constexpr size_type max_size() const; + constexpr size_type capacity() const; + constexpr index_type shape() const; + + using base_type::begin; + using base_type::cbegin; + using base_type::rbegin; + using base_type::crbegin; + using base_type::end; + using base_type::cend; + using base_type::rend; + using base_type::crend; + + using base_type::swap; + void swap(xtiny_impl &); + }; + + /****************/ + /* xtiny output */ + /****************/ + + template + std::ostream & operator<<(std::ostream & o, xtiny const & v) + { + o << "{"; + if(v.size() > 0) + o << promote_type_t(v[0]); + for(index_t i=1; i < (index_t)v.size(); ++i) + o << ", " << promote_type_t(v[i]); + o << "}"; + return o; + } + + /********************/ + /* xtiny comparison */ + /********************/ + + template + inline bool + operator==(xtiny const & l, + xtiny const & r) + { + if(l.size() != r.size()) + return false; + for(index_t k=0; k < (index_t)l.size(); ++k) + if(l[k] != r[k]) + return false; + return true; + } + + template ::value && + std::is_convertible::value> > + inline bool + operator==(xtiny const & l, + V2 const & r) + { + for(index_t k=0; k < (index_t)l.size(); ++k) + if(l[k] != r) + return false; + return true; + } + + template ::value && + std::is_convertible::value> > + inline bool + operator==(V1 const & l, + xtiny const & r) + { + for(index_t k=0; k < (index_t)r.size(); ++k) + if(l != r[k]) + return false; + return true; + } + + template + inline bool + operator!=(xtiny const & l, + xtiny const & r) + { + if(l.size() != r.size()) + return true; + for(index_t k=0; k < (index_t)l.size(); ++k) + if(l[k] != r[k]) + return true; + return false; + } + + template ::value && + std::is_convertible::value> > + inline bool + operator!=(xtiny const & l, + V2 const & r) + { + for(index_t k=0; k < (index_t)l.size(); ++k) + if(l[k] != r) + return true; + return false; + } + + template ::value && + std::is_convertible::value> > + inline bool + operator!=(V1 const & l, + xtiny const & r) + { + for(index_t k=0; k < (index_t)r.size(); ++k) + if(l != r[k]) + return true; + return false; + } + + /************************/ + /* xtiny implementation */ + /************************/ + + template + inline + xtiny::xtiny() + : base_type() + { + } + + template + inline + xtiny::xtiny(xtiny const & v) + : base_type(v) + { + } + + template + inline + xtiny::xtiny(xtiny && v) + : base_type(std::forward(v)) + { + } + + template + template + inline + xtiny::xtiny(xtiny const & v) + : base_type(v.begin(), v.end()) + { + } + + template + template + inline + xtiny::xtiny(std::vector const & v) + : base_type(v.begin(), v.end()) + { + } + + template + template + inline + xtiny::xtiny(std::array const & v) + : base_type(v.begin(), v.end()) + { + } + + template + inline auto + xtiny::operator=(xtiny const & v) -> xtiny & + { + base_type::operator=(v); + return *this; + } + + template + inline auto + xtiny::operator=(xtiny && v) -> xtiny & + { + base_type::operator=(v); + return *this; + } + + template + inline auto + xtiny::operator=(value_type const & v) -> xtiny & + { + base_type::assign(size(), v); + return *this; + } + + template + template + inline auto + xtiny::operator=(std::vector const & v) -> xtiny & + { + base_type::assign(v.begin(), v.end()); + return *this; + } + + template + template + inline auto + xtiny::operator=(std::array const & v) -> xtiny & + { + base_type::assign(v.begin(), v.end()); + return *this; + } + + template + template + inline auto + xtiny::operator=(xtiny const & v) -> xtiny & + { + base_type::assign(v.begin(), v.end()); + return *this; + } + + template + template + inline void + xtiny::assign(std::initializer_list v) + { + base_type::assign(v.begin(), v.end()); + } + + template + inline auto + xtiny::at(size_type i) -> reference + { + if(i < 0 || i >= size()) + throw std::out_of_range("xtiny::at()"); + return (*this)[i]; + } + + template + constexpr inline auto + xtiny::at(size_type i) const -> const_reference + { + if(i < 0 || i >= size()) + throw std::out_of_range("xtiny::at()"); + return (*this)[i]; + } + + template + inline auto + xtiny::front() -> reference + { + return (*this)[0]; + } + + template + inline auto + xtiny::back() -> reference + { + return (*this)[size()-1]; + } + + template + constexpr inline auto + xtiny::front() const -> const_reference + { + return (*this)[0]; + } + + template + constexpr inline auto + xtiny::back() const -> const_reference + { + return (*this)[size()-1]; + } + + template + template + inline auto + xtiny::subarray() + { + static_assert(FROM >= 0 && FROM < TO, + "xtiny::subarray(): range out of bounds."); + XTENSOR_PRECONDITION(TO <= size(), + "xtiny::subarray(): range out of bounds."); + return xtiny(begin()+FROM); + } + + template + template + inline auto + xtiny::subarray() const + { + static_assert(FROM >= 0 && FROM < TO, + "xtiny::subarray(): range out of bounds."); + XTENSOR_PRECONDITION(TO <= size(), + "xtiny::subarray(): range out of bounds."); + return xtiny(begin()+FROM); + } + + template + inline auto + xtiny::subarray(size_type FROM, size_type TO) + { + XTENSOR_PRECONDITION(FROM >= 0 && FROM < TO && TO <= size(), + "xtiny::subarray(): range out of bounds."); + return xtiny(begin()+FROM, begin()+TO); + } + + template + inline auto + xtiny::subarray(size_type FROM, size_type TO) const + { + XTENSOR_PRECONDITION(FROM >= 0 && FROM < TO && TO <= size(), + "xtiny::subarray(): range out of bounds."); + return xtiny(begin()+FROM, begin()+TO); + } + + template + inline auto + xtiny::erase(size_type m) const + { + XTENSOR_PRECONDITION(m >= 0 && m < size(), "xtiny::erase(): " + "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); + static const index_t res_size = has_fixed_size + ? static_size-1 + : runtime_size; + xtiny res(size()-1, dont_init); + for(size_type k=0; k + inline auto + xtiny::pop_front() const + { + return erase(0); + } + + template + inline auto + xtiny::pop_back() const + { + return erase(size()-1); + } + + template + inline auto + xtiny::insert(size_type m, value_type v) const + { + XTENSOR_PRECONDITION(m >= 0 && m <= size(), "xtiny::insert(): " + "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); + static const index_t res_size = has_fixed_size + ? static_size+1 + : runtime_size; + xtiny res(size()+1, dont_init); + for(size_type k=0; k + inline auto + xtiny::push_front(value_type v) const + { + return insert(0, v); + } + + template + inline auto + xtiny::push_back(value_type v) const + { + return insert(size(), v); + } + + template + constexpr inline auto + xtiny::cbegin() const -> const_iterator + { + return base_type::begin(); + } + + template + inline auto + xtiny::end() -> iterator + { + return begin() + size(); + } + + template + constexpr inline auto + xtiny::end() const -> const_iterator + { + return begin() + size(); + } + + template + constexpr inline auto + xtiny::cend() const -> const_iterator + { + return cbegin() + size(); + } + + template + constexpr inline auto + xtiny::crbegin() const -> const_reverse_iterator + { + return base_type::rbegin(); + } + + template + inline auto + xtiny::rend() -> reverse_iterator + { + return rbegin() + size(); + } + + template + constexpr inline auto + xtiny::rend() const -> const_reverse_iterator + { + return rbegin() + size(); + } + + template + constexpr inline auto + xtiny::crend() const -> const_reverse_iterator + { + return crbegin() + size(); + } + + template + constexpr bool + xtiny::empty() const + { + return size() == 0; + } + + /*******************************************/ + /* xtiny_impl dynamic shape implementation */ + /*******************************************/ + + template + inline + xtiny_impl::xtiny_impl() + : m_size(0) + , m_data(m_buffer) + { + } + + template + inline + xtiny_impl::~xtiny_impl() + { + deallocate(); + } + + template + inline + xtiny_impl::xtiny_impl(size_type n) + : m_size(n) + , m_data(m_buffer) + { + allocate(); + } + + template + inline + xtiny_impl::xtiny_impl(size_type n, const value_type& v) + : m_size(n) + , m_data(m_buffer) + { + allocate(v); + } + + template + inline + xtiny_impl::xtiny_impl(size_type n, tags::skip_initialization_tag) + : m_size(n) + , m_data(m_buffer) + { + allocate(dont_init); + } + + template + template + inline + xtiny_impl::xtiny_impl(IT begin, IT end) + : m_size(0) + , m_data(m_buffer) + { + assign(begin, end); + } + + template + template + inline + xtiny_impl::xtiny_impl(std::initializer_list const & v) + : m_size(0) + , m_data(m_buffer) + { + assign(v.begin(), v.end()); + } + + template + inline + xtiny_impl::xtiny_impl(xtiny_impl const & v) + : xtiny_impl(v.begin(), v.begin()+v.size()) + { + } + + template + inline + xtiny_impl::xtiny_impl(xtiny_impl && v) + : m_size(0) + , m_data(m_buffer) + { + v.swap(*this); + } + + template + inline auto + xtiny_impl::operator=(xtiny_impl const & v) -> xtiny_impl & + { + if(this != &v) + { + assign(v.begin(), v.begin()+v.size()); + } + return *this; + } + + template + inline auto + xtiny_impl::operator=(xtiny_impl && v) -> xtiny_impl & + { + if(this != &v) + { + assign(v.begin(), v.begin() + v.size()); + } + return *this; + } + + template + inline void + xtiny_impl::assign(size_type n, const value_type& v) + { + if(m_size == n) + { + std::fill(begin(), begin()+size(), v); + } + else + { + deallocate(); + m_size = n; + allocate(v); + } + } + + template + template + inline void + xtiny_impl::assign(IT begin, IT end) + { + size_type n = std::distance(begin, end); + if(m_size == n) + { + for (size_type k = 0; k < m_size; ++k, ++begin) + { + m_data[k] = static_cast(*begin); + } + } + else + { + deallocate(); + m_size = n; + allocate(begin); + } + } + + template + inline auto + xtiny_impl::data() -> pointer + { + return m_data; + } + + template + constexpr inline auto + xtiny_impl::data() const -> const_pointer + { + return m_data; + } + + template + inline auto + xtiny_impl::operator[](size_type i) -> reference + { + return m_data[i]; + } + + template + constexpr inline auto + xtiny_impl::operator[](size_type i) const -> const_reference + { + return m_data[i]; + } + + template + inline void + xtiny_impl::resize(size_type n) + { + if(n != m_size) + { + deallocate(); + m_size = n; + allocate(); + } + } + + template + inline auto + xtiny_impl::capacity() const -> size_type + { + return std::max(m_size, buffer_size); + } + + template + inline auto + xtiny_impl::size() const -> size_type + { + return m_size; + } + + template + inline auto + xtiny_impl::max_size() const -> size_type + { + return std::max_size(m_allocator); + } + + template + inline auto + xtiny_impl::shape() const -> index_type + { + return {m_size}; + } + + template + inline bool + xtiny_impl::on_stack() const + { + return m_data == m_buffer; + } + + template + inline auto + xtiny_impl::begin() -> iterator + { + return m_data; + } + + template + inline auto + xtiny_impl::begin() const -> const_iterator + { + return m_data; + } + + template + inline auto + xtiny_impl::rbegin() -> reverse_iterator + { + return reverse_iterator(m_data + m_size); + } + + template + inline auto + xtiny_impl::rbegin() const -> const_reverse_iterator + { + return const_reverse_iterator(m_data + m_size); + } + + template + inline void + xtiny_impl::swap(xtiny_impl & other) + { + using std::swap; + if(this == &other) + { + return; + } + if(m_size == 0 || m_size > buffer_size) + { + if(other.m_size == 0 || other.m_size > buffer_size) + { + // both use allocated memory (or no memory at all) + swap(m_data, other.m_data); + } + else + { + // self uses allocated memory, other the buffer + for(size_type k=0; k buffer_size) + { + // self uses the buffer, other allocated memory + for(size_type k=0; k + inline void + xtiny_impl::allocate(value_type const & v) + { + if(m_size > buffer_size) + { + m_data = m_allocator.allocate(m_size); + std::uninitialized_fill(m_data, m_data+m_size, v); + } + else + { + std::fill(m_data, m_data+m_size, v); + } + } + + template + inline void + xtiny_impl::allocate(tags::skip_initialization_tag) + { + if(m_size > buffer_size) + { + m_data = m_allocator.allocate(m_size); + if(!may_use_uninitialized_memory) + std::uninitialized_fill(m_data, m_data+m_size, value_type()); + } + } + + template + template + inline void + xtiny_impl::allocate(IT begin) + { + if(m_size > buffer_size) + { + m_data = m_allocator.allocate(m_size); + for(size_type k=0; k(*begin)); + } + else + { + for(size_type k=0; k(*begin); + } + } + + template + inline void + xtiny_impl::deallocate() + { + if(m_size > buffer_size) + { + if(!may_use_uninitialized_memory) + { + for(size_type k=0; k + inline + xtiny_impl>::xtiny_impl() + : base_type{} + { + } + + template + inline + xtiny_impl>::xtiny_impl(size_type n) + : xtiny_impl() + { + std::ignore = n; + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl(n): size mismatch"); + } + + template + inline + xtiny_impl>::xtiny_impl(size_type n, const value_type& v) + { + std::ignore = n; + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl(n): size mismatch"); + base_type::fill(v); + } + + template + inline + xtiny_impl>::xtiny_impl(size_type n, tags::skip_initialization_tag) + { + std::ignore = n; + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl(n): size mismatch."); + } + + template + template + inline + xtiny_impl>::xtiny_impl(IT begin) + { + assign(begin, begin+N); + } + + template + template + inline + xtiny_impl>::xtiny_impl(IT begin, IT end) + { + assign(begin, end); + } + + template + template + inline + xtiny_impl>::xtiny_impl(std::initializer_list const & v) + { + const size_t n = v.size(); + if(n == 1) + { + assign(N, static_cast(*v.begin())); + } + else if(n == N) + { + assign(v.begin(), v.end()); + } + else + { + XTENSOR_ASSERT_MSG(false, "xtiny_impl::xtiny_impl(std::initializer_list): size mismatch."); + } + } + + template + inline + xtiny_impl>::xtiny_impl(xtiny_impl const & v) + : base_type(v) + { + } + + template + inline + xtiny_impl>::xtiny_impl(xtiny_impl && v) + : base_type(std::forward(v)) + { + } + + template + inline auto + xtiny_impl>::operator=(xtiny_impl const & v) -> xtiny_impl & + { + base_type::operator=(v); + return *this; + } + + template + inline auto + xtiny_impl>::operator=(xtiny_impl && v) -> xtiny_impl & + { + base_type::operator=(std::forward(v)); + return *this; + } + + template + inline void + xtiny_impl>::assign(size_type n, const value_type& v) + { + std::ignore = n; + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl::assign(n, v): size mismatch."); + base_type::fill(v); + } + + template + template + inline void + xtiny_impl>::assign(IT begin, IT end) + { + std::ignore = end; + XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + for(size_type k=0; k(*begin); + } + } + + template + constexpr inline auto + xtiny_impl>::capacity() const -> size_type + { + return N; + } + + template + constexpr inline auto + xtiny_impl>::shape() const -> index_type + { + return {N}; + } + + /**********************************************/ + /* xtiny_impl fixed shape view implementation */ + /**********************************************/ + + template + inline + xtiny_impl::xtiny_impl() + : m_data() + { + } + + template + inline + xtiny_impl::xtiny_impl(representation_type const & begin) + : m_data(begin) + { + } + + template + inline + xtiny_impl::xtiny_impl(representation_type const & begin, representation_type const & end) + : m_data(begin) + { + std::ignore = end; + XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl(begin, end): size mismatch"); + } + + template + template + inline + xtiny_impl::xtiny_impl(IT begin, IT end) + : m_data(const_cast(&*begin)) + { + std::ignore = end; + XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + } + + template + inline void + xtiny_impl::reset(representation_type const & begin) + { + m_data = begin; + } + + template + inline void + xtiny_impl::assign(size_type n, const value_type& v) + { + std::ignore = n; + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl::assign(n, v): size mismatch."); + for(size_type k=0; k + template + inline void + xtiny_impl::assign(IT begin, IT end) + { + std::ignore = end; + XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + for(size_type k=0; k(*begin); + } + } + + template + inline auto + xtiny_impl::operator[](size_type i) -> reference + { + return m_data[i]; + } + + template + constexpr inline auto + xtiny_impl::operator[](size_type i) const -> const_reference + { + return m_data[i]; + } + + template + inline auto + xtiny_impl::data() -> pointer + { + return &m_data[0]; + } + + template + constexpr inline auto + xtiny_impl::data() const -> const_pointer + { + return &m_data[0]; + } + + template + constexpr inline auto + xtiny_impl::size() const -> size_type + { + return N; + } + + template + constexpr inline auto + xtiny_impl::max_size() const -> size_type + { + return N; + } + + template + constexpr inline auto + xtiny_impl::capacity() const -> size_type + { + return N; + } + + template + constexpr inline auto + xtiny_impl::shape() const -> index_type + { + return {N}; + } + + template + inline auto + xtiny_impl::begin() -> iterator + { + return m_data; + } + + template + constexpr inline auto + xtiny_impl::begin() const -> const_iterator + { + return m_data; + } + + template + inline auto + xtiny_impl::rbegin() -> reverse_iterator + { + return reverse_iterator(m_data+N); + } + + template + constexpr inline auto + xtiny_impl::rbegin() const -> const_reverse_iterator + { + return const_reverse_iterator(m_data+N); + } + + template + inline void + xtiny_impl::swap(xtiny_impl & other) + { + using std::swap; + swap(m_data, other.m_data); + } + + /************************************************/ + /* xtiny_impl dynamic shape view implementation */ + /************************************************/ + + template + inline + xtiny_impl::xtiny_impl() + : m_size(0) + , m_data() + { + } + + template + inline + xtiny_impl::xtiny_impl(representation_type const & begin, representation_type const & end) + : m_size(std::distance(begin, end)) + , m_data(begin) + { + } + + template + template + inline + xtiny_impl::xtiny_impl(IT begin, IT end) + : m_size(std::distance(begin, end)) + , m_data(const_cast(&*begin)) + { + } + + template + inline void + xtiny_impl::reset(representation_type const & begin, representation_type const & end) + { + m_size = std::distance(begin, end); + m_data = begin; + } + + template + inline void + xtiny_impl::assign(size_type n, const value_type& v) + { + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl::assign(n, v): size mismatch."); + for(size_type k=0; k + template + inline void + xtiny_impl::assign(IT begin, IT end) + { + std::ignore = end; + XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + for(size_type k=0; k(*begin); + } + } + + template + inline auto + xtiny_impl::operator[](size_type i) -> reference + { + return m_data[i]; + } + + template + constexpr inline auto + xtiny_impl::operator[](size_type i) const -> const_reference + { + return m_data[i]; + } + + template + inline auto + xtiny_impl::data() -> pointer + { + return &m_data[0]; + } + + template + constexpr inline auto + xtiny_impl::data() const -> const_pointer + { + return &m_data[0]; + } + + template + constexpr inline auto + xtiny_impl::size() const -> size_type + { + return m_size; + } + + template + constexpr inline auto + xtiny_impl::max_size() const -> size_type + { + return m_size; + } + + template + constexpr inline auto + xtiny_impl::capacity() const -> size_type + { + return m_size; + } + + template + constexpr inline auto + xtiny_impl::shape() const -> index_type + { + return {m_size}; + } + + template + inline auto + xtiny_impl::begin() -> iterator + { + return m_data; + } + + template + constexpr inline auto + xtiny_impl::begin() const -> const_iterator + { + return m_data; + } + + template + inline auto + xtiny_impl::rbegin() -> reverse_iterator + { + return reverse_iterator(m_data+N); + } + + template + constexpr inline auto + xtiny_impl::rbegin() const -> const_reverse_iterator + { + return const_reverse_iterator(m_data+N); + } + + template + inline void + xtiny_impl::swap(xtiny_impl & other) + { + using std::swap; + swap(m_size, other.m_size); + swap(m_data, other.m_data); + } + + + /**************************************************/ + /* xtiny_impl xbuffer_adaptor view implementation */ + /**************************************************/ + + template + inline void + xtiny_impl>::assign(size_type n, const value_type& v) + { + XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl::assign(n, v): size mismatch."); + for(size_type k=0; k + template + inline void + xtiny_impl>::assign(IT begin, IT end) + { + std::ignore = end; + XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + for(size_type k=0; k(*begin); + } + } + + template + constexpr inline auto + xtiny_impl>::max_size() const -> size_type + { + return size(); + } + + template + constexpr inline auto + xtiny_impl>::capacity() const -> size_type + { + return size(); + } + + template + constexpr inline auto + xtiny_impl>::shape() const -> index_type + { + return {size()}; + } + +} // namespace xt + +#endif // XTENSOR_XTINY_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b5d2f3a07..760e81742 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -122,6 +122,7 @@ set(XTENSOR_TESTS test_xtensor.cpp test_xtensor_adaptor.cpp test_xtensor_semantic.cpp + test_xtiny.cpp test_xvectorize.cpp test_xview.cpp test_xview_semantic.cpp diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp new file mode 100644 index 000000000..38018cf9a --- /dev/null +++ b/test/test_xtiny.cpp @@ -0,0 +1,307 @@ +/*************************************************************************** +* Copyright (c) 2017, Ullrich Koethe * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ENABLE_ASSERT +#define XTENSOR_ENABLE_ASSERT +#endif + +#include +#include +#include + +#include +#include + +namespace xt +{ + static const int SIZE = 3; + using BV = xtiny; + using IV = xtiny; + using FV = xtiny; + + static float di[] = { 1, 2, 4}; + static float df[] = { 1.2f, 2.4f, 3.6f}; + BV bv0, bv1{1}, bv3(di); + IV iv0, iv1{1}, iv3(di); + FV fv0, fv1{1.0f}, fv3(df); + + TEST(xtiny, construction) + { + EXPECT_EQ(bv0.size(), SIZE); + EXPECT_EQ(iv0.size(), SIZE); + EXPECT_EQ(fv0.size(), SIZE); + EXPECT_FALSE(bv0.empty()); + EXPECT_FALSE(iv0.empty()); + EXPECT_FALSE(fv0.empty()); + EXPECT_EQ(bv0.shape(), (std::array{SIZE})); + EXPECT_EQ(iv0.shape(), (std::array{SIZE})); + EXPECT_EQ(fv0.shape(), (std::array{SIZE})); + + auto iv3iter = iv3.begin(); + auto iv3citer = iv3.cbegin(); + auto iv3riter = iv3.rbegin(); + auto iv3criter = iv3.crbegin(); + for(int k=0; k{1, 2, 4})); + EXPECT_EQ(iv1, IV(std::vector(SIZE, 1))); + + IV iv; + iv.assign(SIZE, 0); + EXPECT_EQ(iv0, iv); + iv.assign(SIZE, 1); + EXPECT_EQ(iv1, iv); + iv.assign({1,2,4}); + EXPECT_EQ(iv3, iv); + + FV fv(iv3); + EXPECT_EQ(fv, iv3); + fv = fv3; + EXPECT_EQ(fv, fv3); + fv = bv3; + EXPECT_EQ(fv, bv3); + + EXPECT_EQ(iv3, (iv3.template subarray<0, SIZE>())); + EXPECT_EQ(2, (iv3.template subarray<0, 2>().size())); + EXPECT_EQ(iv3[0], (iv3.template subarray<0, 2>()[0])); + EXPECT_EQ(iv3[1], (iv3.template subarray<0, 2>()[1])); + EXPECT_EQ(2, (iv3.template subarray<1, 3>().size())); + EXPECT_EQ(iv3[1], (iv3.template subarray<1, 3>()[0])); + EXPECT_EQ(iv3[2], (iv3.template subarray<1, 3>()[1])); + EXPECT_EQ(1, (iv3.template subarray<1, 2>().size())); + EXPECT_EQ(iv3[1], (iv3.template subarray<1, 2>()[0])); + EXPECT_EQ(1, (iv3.subarray(1, 2).size())); + EXPECT_EQ(iv3[1], (iv3.subarray(1, 2)[0])); + IV const & civ3 = iv3; + EXPECT_EQ(1, (civ3.template subarray<1, 2>().size())); + EXPECT_EQ(iv3[1], (civ3.template subarray<1, 2>()[0])); + EXPECT_EQ(1, (civ3.subarray(1, 2).size())); + EXPECT_EQ(iv3[1], (civ3.subarray(1, 2)[0])); + + using FV1 = FV::rebind_size; + FV1 fv10(fv3.begin()); + EXPECT_EQ(fv10, fv3.erase(SIZE - 1)); + EXPECT_EQ(fv3, fv10.insert(SIZE - 1, fv3[SIZE - 1])); + EXPECT_EQ(fv10, fv3.pop_back()); + EXPECT_EQ(fv3, fv10.push_back(fv3[SIZE - 1])); + FV1 fv11(fv3.begin() + 1); + EXPECT_EQ(fv11, fv3.erase(0)); + EXPECT_EQ(fv3, fv11.insert(0, fv3[0])); + EXPECT_EQ(fv11, fv3.pop_front()); + EXPECT_EQ(fv3, fv11.push_front(fv3[0])); + + BV bv2(bv1), bv4(bv3); + swap(bv2, bv4); + EXPECT_EQ(bv3, bv2); + EXPECT_EQ(bv1, bv4); + } + + TEST(xtiny, comparison) + { + EXPECT_TRUE(bv0 == bv0); + EXPECT_TRUE(bv0 == 0); + EXPECT_TRUE(0 == bv0); + EXPECT_TRUE(iv0 == iv0); + EXPECT_TRUE(fv0 == fv0); + EXPECT_TRUE(fv0 == 0); + EXPECT_TRUE(0 == fv0); + EXPECT_TRUE(iv0 == bv0); + EXPECT_TRUE(iv0 == fv0); + EXPECT_TRUE(fv0 == bv0); + + EXPECT_TRUE(bv3 == bv3); + EXPECT_TRUE(iv3 == iv3); + EXPECT_TRUE(fv3 == fv3); + EXPECT_TRUE(iv3 == bv3); + EXPECT_TRUE(iv3 != fv3); + EXPECT_TRUE(iv3 != 0); + EXPECT_TRUE(0 != iv3); + EXPECT_TRUE(fv3 != bv3); + EXPECT_TRUE(fv3 != 0); + EXPECT_TRUE(0 != fv3); + } + + TEST(xtiny, ostream) + { + std::ostringstream out; + out << iv3; + std::string expected("{1, 2, 4}"); + EXPECT_EQ(expected, out.str()); + out << "Testing.." << fv3 << 42; + out << bv3 << std::endl; + } + + TEST(xtiny, runtime_size) + { + using A = xtiny; + using V1 = xtiny; + + EXPECT_TRUE(typeid(A) == typeid(xtiny)); + + A a{ 1,2,3 }, b{ 1,2,3 }, c = a, e(3, 0); + EXPECT_EQ(a.size(), 3); + EXPECT_EQ(b.size(), 3); + EXPECT_EQ(c.size(), 3); + EXPECT_EQ(e.size(), 3); + EXPECT_EQ(a, b); + EXPECT_EQ(a, c); + EXPECT_TRUE(a != e); + EXPECT_EQ(e, (A{ 0,0,0 })); + + EXPECT_EQ(iv3, (A{ 1, 2, 4 })); + EXPECT_EQ(iv3, (A{ 1.1, 2.2, 4.4 })); + EXPECT_EQ(iv3, (A({ 1, 2, 4 }))); + EXPECT_EQ(iv3, (A({ 1.1, 2.2, 4.4 }))); + EXPECT_EQ(V1{1}, (A{ 1 })); + EXPECT_EQ(V1{1}, (A{ 1.1 })); + EXPECT_EQ(V1{1}, (A({ 1 }))); + EXPECT_EQ(V1{1}, (A({ 1.1 }))); + EXPECT_EQ(iv0, A(SIZE, 0)); + EXPECT_EQ(iv1, A(SIZE, 1)); + + c.assign({ 1,2,3 }); + EXPECT_EQ(a, c); + + EXPECT_EQ(a.erase(1), (A{ 1,3 })); + EXPECT_EQ(a.insert(3, 4), (A{ 1,2,3,4 })); + + // testing move constructor and assignment + EXPECT_EQ(std::move(A{ 1,2,3 }), (A{ 1,2,3 })); + EXPECT_EQ(A(a.insert(3, 4)), (A{ 1,2,3,4 })); + a = a.insert(3, 4); + EXPECT_EQ(a, (A{ 1,2,3,4 })); + + A r{ 2,3,4,5 }; + EXPECT_EQ(r, (A{ 2,3,4,5 })); + EXPECT_EQ(r.subarray(1, 3).size(), 2); + EXPECT_EQ(r.subarray(1, 3), (A{ 3,4 })); + EXPECT_EQ((r.template subarray<1, 3>().size()), 2); + EXPECT_EQ((r.template subarray<1, 3>()), (A{ 3,4 })); + } + + TEST(xtiny, interoperability) + { + using A = xtiny; + using B = xtiny; + using C = xtiny; + using D = xtiny; + using E = xtiny>; + + EXPECT_TRUE(xtiny_concept::value); + EXPECT_TRUE(xtiny_concept::value); + EXPECT_TRUE(xtiny_concept::value); + EXPECT_TRUE(xtiny_concept::value); + EXPECT_TRUE(xtiny_concept::value); + + static const size_t s = 4; + std::array data{1,2,3,4}; + A a(data.begin()); + B b(a); + C c(a); + D d(a); + E e(data.data(), s); + std::vector v(data.begin(), data.end()); + + EXPECT_EQ(b, a); + EXPECT_EQ(c, a); + EXPECT_EQ(d, a); + EXPECT_EQ(e, a); + + EXPECT_EQ(A(data), a); + EXPECT_EQ(B(data), a); + EXPECT_EQ(C(data), a); + EXPECT_EQ(D(data), a); + + EXPECT_EQ(A(v), a); + EXPECT_EQ(B(v), a); + EXPECT_EQ(C(v), a); + EXPECT_EQ(D(v), a); + + EXPECT_EQ((A{1,2,3,4}), a); + EXPECT_EQ((B{1,2,3,4}), a); + + data[0] = 0; + EXPECT_EQ(e, (B{0,2,3,4})); + EXPECT_EQ((a = e), e); + EXPECT_EQ((b = e), e); + EXPECT_EQ((c = e), e); + EXPECT_EQ((d = e), e); + + EXPECT_EQ((a = 1), A{1}); + EXPECT_EQ((b = 1), A{1}); + EXPECT_EQ((c = 1), A{1}); + EXPECT_EQ((d = 1), A{1}); + EXPECT_EQ((e = 1), A{1}); + + EXPECT_EQ((a = v), (A{1,2,3,4})); + EXPECT_EQ((b = v), a); + EXPECT_EQ((c = v), a); + EXPECT_EQ((d = v), a); + EXPECT_EQ((e = v), a); + + b[s-1] = 5; + EXPECT_EQ(b, (A{1,2,3,5})); + EXPECT_EQ((a = b), b); + EXPECT_EQ((c = b), b); + EXPECT_EQ((d = b), b); + EXPECT_EQ((e = b), b); + + data[0] = 0; + EXPECT_EQ((c = data), (A{0,2,3,5})); + EXPECT_EQ((a = data), c); + EXPECT_EQ((b = data), c); + EXPECT_EQ((d = data), c); + EXPECT_EQ((e = data), c); + + d.assign(v.begin(), v.end()); + EXPECT_EQ(d, (A{1,2,3,4})); + a.assign(v.begin(), v.end()); + EXPECT_EQ(a, d); + b.assign(v.begin(), v.end()); + EXPECT_EQ(b, d); + c.assign(v.begin(), v.end()); + EXPECT_EQ(c, d); + e.assign(v.begin(), v.end()); + EXPECT_EQ(e, d); + } +} // namespace xt \ No newline at end of file From 86c62470f2bd6591c7b35ca683b28591790c3c87 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Fri, 15 Dec 2017 16:51:29 +0100 Subject: [PATCH 2/5] improved xtiny tests --- test/test_xtiny.cpp | 404 ++++++++++++++++++++++++-------------------- 1 file changed, 224 insertions(+), 180 deletions(-) diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 38018cf9a..908f25e5a 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -20,196 +20,158 @@ namespace xt { static const int SIZE = 3; - using BV = xtiny; - using IV = xtiny; - using FV = xtiny; - static float di[] = { 1, 2, 4}; - static float df[] = { 1.2f, 2.4f, 3.6f}; - BV bv0, bv1{1}, bv3(di); - IV iv0, iv1{1}, iv3(di); - FV fv0, fv1{1.0f}, fv3(df); + template + struct xtiny_test_data + { + static T data[SIZE]; + }; + + template + T xtiny_test_data::data[SIZE] = {1, 2, 4}; + + template <> + float xtiny_test_data::data[SIZE] = { 1.2f, 2.4f, 4.6f}; - TEST(xtiny, construction) + template + class xtiny_test : public testing::Test { - EXPECT_EQ(bv0.size(), SIZE); - EXPECT_EQ(iv0.size(), SIZE); - EXPECT_EQ(fv0.size(), SIZE); - EXPECT_FALSE(bv0.empty()); - EXPECT_FALSE(iv0.empty()); - EXPECT_FALSE(fv0.empty()); - EXPECT_EQ(bv0.shape(), (std::array{SIZE})); - EXPECT_EQ(iv0.shape(), (std::array{SIZE})); - EXPECT_EQ(fv0.shape(), (std::array{SIZE})); - - auto iv3iter = iv3.begin(); - auto iv3citer = iv3.cbegin(); - auto iv3riter = iv3.rbegin(); - auto iv3criter = iv3.crbegin(); - for(int k=0; k, + xtiny, + xtiny, + xtiny, // buffer_size > SIZE + xtiny // buffer_size < SIZE + > xtiny_types; + + TYPED_TEST_CASE(xtiny_test, xtiny_types); + + TYPED_TEST(xtiny_test, construction) + { + using V = TypeParam; + using T = typename V::value_type; + using size_type = typename V::size_type; + const bool fixed = V::has_fixed_size; + + T * data = xtiny_test_data::data; + + V v0, + v1(SIZE, 1), + v3(data, data+SIZE); + + EXPECT_EQ(v0.size(), fixed ? SIZE : 0); + EXPECT_EQ(v1.size(), SIZE); + EXPECT_EQ(v3.size(), SIZE); + EXPECT_EQ(v0.empty(), !fixed); + EXPECT_FALSE(v1.empty()); + EXPECT_FALSE(v3.empty()); + EXPECT_EQ(v0.shape(), (std::array{fixed ? SIZE : 0})); + EXPECT_EQ(v1.shape(), (std::array{SIZE})); + EXPECT_EQ(v3.shape(), (std::array{SIZE})); + + EXPECT_EQ(v3.front(), data[0]); + EXPECT_EQ(v3.back(), data[SIZE-1]); + V const & cv3 = v3; + EXPECT_EQ(cv3.front(), data[0]); + EXPECT_EQ(cv3.back(), data[SIZE-1]); + + auto v3iter = v3.begin(); + auto v3citer = v3.cbegin(); + auto v3riter = v3.rbegin(); + auto v3criter = v3.crbegin(); + for(size_type k=0; k{1, 2, 4})); - EXPECT_EQ(iv1, IV(std::vector(SIZE, 1))); - - IV iv; - iv.assign(SIZE, 0); - EXPECT_EQ(iv0, iv); - iv.assign(SIZE, 1); - EXPECT_EQ(iv1, iv); - iv.assign({1,2,4}); - EXPECT_EQ(iv3, iv); - - FV fv(iv3); - EXPECT_EQ(fv, iv3); - fv = fv3; - EXPECT_EQ(fv, fv3); - fv = bv3; - EXPECT_EQ(fv, bv3); - - EXPECT_EQ(iv3, (iv3.template subarray<0, SIZE>())); - EXPECT_EQ(2, (iv3.template subarray<0, 2>().size())); - EXPECT_EQ(iv3[0], (iv3.template subarray<0, 2>()[0])); - EXPECT_EQ(iv3[1], (iv3.template subarray<0, 2>()[1])); - EXPECT_EQ(2, (iv3.template subarray<1, 3>().size())); - EXPECT_EQ(iv3[1], (iv3.template subarray<1, 3>()[0])); - EXPECT_EQ(iv3[2], (iv3.template subarray<1, 3>()[1])); - EXPECT_EQ(1, (iv3.template subarray<1, 2>().size())); - EXPECT_EQ(iv3[1], (iv3.template subarray<1, 2>()[0])); - EXPECT_EQ(1, (iv3.subarray(1, 2).size())); - EXPECT_EQ(iv3[1], (iv3.subarray(1, 2)[0])); - IV const & civ3 = iv3; - EXPECT_EQ(1, (civ3.template subarray<1, 2>().size())); - EXPECT_EQ(iv3[1], (civ3.template subarray<1, 2>()[0])); - EXPECT_EQ(1, (civ3.subarray(1, 2).size())); - EXPECT_EQ(iv3[1], (civ3.subarray(1, 2)[0])); - - using FV1 = FV::rebind_size; - FV1 fv10(fv3.begin()); - EXPECT_EQ(fv10, fv3.erase(SIZE - 1)); - EXPECT_EQ(fv3, fv10.insert(SIZE - 1, fv3[SIZE - 1])); - EXPECT_EQ(fv10, fv3.pop_back()); - EXPECT_EQ(fv3, fv10.push_back(fv3[SIZE - 1])); - FV1 fv11(fv3.begin() + 1); - EXPECT_EQ(fv11, fv3.erase(0)); - EXPECT_EQ(fv3, fv11.insert(0, fv3[0])); - EXPECT_EQ(fv11, fv3.pop_front()); - EXPECT_EQ(fv3, fv11.push_front(fv3[0])); - - BV bv2(bv1), bv4(bv3); - swap(bv2, bv4); - EXPECT_EQ(bv3, bv2); - EXPECT_EQ(bv1, bv4); - } - TEST(xtiny, comparison) - { - EXPECT_TRUE(bv0 == bv0); - EXPECT_TRUE(bv0 == 0); - EXPECT_TRUE(0 == bv0); - EXPECT_TRUE(iv0 == iv0); - EXPECT_TRUE(fv0 == fv0); - EXPECT_TRUE(fv0 == 0); - EXPECT_TRUE(0 == fv0); - EXPECT_TRUE(iv0 == bv0); - EXPECT_TRUE(iv0 == fv0); - EXPECT_TRUE(fv0 == bv0); - - EXPECT_TRUE(bv3 == bv3); - EXPECT_TRUE(iv3 == iv3); - EXPECT_TRUE(fv3 == fv3); - EXPECT_TRUE(iv3 == bv3); - EXPECT_TRUE(iv3 != fv3); - EXPECT_TRUE(iv3 != 0); - EXPECT_TRUE(0 != iv3); - EXPECT_TRUE(fv3 != bv3); - EXPECT_TRUE(fv3 != 0); - EXPECT_TRUE(0 != fv3); - } + if(std::is_integral::value) + { + EXPECT_EQ(v3, (V{1, 2, 4})); + } + else + { + EXPECT_EQ(v3, (V{1.2f, 2.4f, 4.6f})); + } + if(fixed) + { + EXPECT_EQ(v1, (V{1})); + } + else + { + EXPECT_EQ((xtiny(1,1)), (V{1})); + } - TEST(xtiny, ostream) - { - std::ostringstream out; - out << iv3; - std::string expected("{1, 2, 4}"); - EXPECT_EQ(expected, out.str()); - out << "Testing.." << fv3 << 42; - out << bv3 << std::endl; - } + V v; + v.assign(SIZE, 1); + EXPECT_EQ(v1, v); + v.assign({1.2f, 2.4f, 4.6f}); + EXPECT_EQ(v3, v); - TEST(xtiny, runtime_size) - { - using A = xtiny; - using V1 = xtiny; - - EXPECT_TRUE(typeid(A) == typeid(xtiny)); - - A a{ 1,2,3 }, b{ 1,2,3 }, c = a, e(3, 0); - EXPECT_EQ(a.size(), 3); - EXPECT_EQ(b.size(), 3); - EXPECT_EQ(c.size(), 3); - EXPECT_EQ(e.size(), 3); - EXPECT_EQ(a, b); - EXPECT_EQ(a, c); - EXPECT_TRUE(a != e); - EXPECT_EQ(e, (A{ 0,0,0 })); - - EXPECT_EQ(iv3, (A{ 1, 2, 4 })); - EXPECT_EQ(iv3, (A{ 1.1, 2.2, 4.4 })); - EXPECT_EQ(iv3, (A({ 1, 2, 4 }))); - EXPECT_EQ(iv3, (A({ 1.1, 2.2, 4.4 }))); - EXPECT_EQ(V1{1}, (A{ 1 })); - EXPECT_EQ(V1{1}, (A{ 1.1 })); - EXPECT_EQ(V1{1}, (A({ 1 }))); - EXPECT_EQ(V1{1}, (A({ 1.1 }))); - EXPECT_EQ(iv0, A(SIZE, 0)); - EXPECT_EQ(iv1, A(SIZE, 1)); - - c.assign({ 1,2,3 }); - EXPECT_EQ(a, c); - - EXPECT_EQ(a.erase(1), (A{ 1,3 })); - EXPECT_EQ(a.insert(3, 4), (A{ 1,2,3,4 })); + v = 1; + EXPECT_EQ(v, v1); + v = v3; + EXPECT_EQ(v, v3); + + V v2(v1), v4(v3); + swap(v2, v4); + EXPECT_EQ(v3, v2); + EXPECT_EQ(v1, v4); // testing move constructor and assignment - EXPECT_EQ(std::move(A{ 1,2,3 }), (A{ 1,2,3 })); - EXPECT_EQ(A(a.insert(3, 4)), (A{ 1,2,3,4 })); - a = a.insert(3, 4); - EXPECT_EQ(a, (A{ 1,2,3,4 })); + v4 = v3.push_back(0).pop_back(); + EXPECT_EQ(v4, v3); + EXPECT_EQ(V(v3.push_back(0).pop_back()), v3); + } + + TYPED_TEST(xtiny_test, subarray) + { + using V = TypeParam; + using A = typename V::rebind_size; + using T = typename V::value_type; + + T * data = xtiny_test_data::data; + V v3(data, data+SIZE); + V const & cv3 = v3; + + EXPECT_EQ(v3, (v3.template subarray<0, SIZE>())); + EXPECT_EQ(2, (v3.template subarray<0, 2>().size())); + EXPECT_EQ(v3[0], (v3.template subarray<0, 2>()[0])); + EXPECT_EQ(v3[1], (v3.template subarray<0, 2>()[1])); + EXPECT_EQ(2, (v3.template subarray<1, 3>().size())); + EXPECT_EQ(v3[1], (v3.template subarray<1, 3>()[0])); + EXPECT_EQ(v3[2], (v3.template subarray<1, 3>()[1])); + EXPECT_EQ(1, (v3.template subarray<1, 2>().size())); + EXPECT_EQ(v3[1], (v3.template subarray<1, 2>()[0])); + EXPECT_EQ(1, (v3.subarray(1, 2).size())); + EXPECT_EQ(v3[1], (v3.subarray(1, 2)[0])); + EXPECT_EQ(1, (cv3.template subarray<1, 2>().size())); + EXPECT_EQ(v3[1], (cv3.template subarray<1, 2>()[0])); + EXPECT_EQ(1, (cv3.subarray(1, 2).size())); + EXPECT_EQ(v3[1], (cv3.subarray(1, 2)[0])); A r{ 2,3,4,5 }; EXPECT_EQ(r, (A{ 2,3,4,5 })); @@ -219,6 +181,88 @@ namespace xt EXPECT_EQ((r.template subarray<1, 3>()), (A{ 3,4 })); } + TYPED_TEST(xtiny_test, erase_insert) + { + using V = TypeParam; + using V1 = V::rebind_size; + using T = typename V::value_type; + + T * data = xtiny_test_data::data; + V v3(data, data+SIZE); + V1 v10(v3.begin(), v3.begin()+SIZE-1); + + EXPECT_EQ(v10, v3.erase(SIZE - 1)); + EXPECT_EQ(v3, v10.insert(SIZE - 1, v3[SIZE - 1])); + EXPECT_EQ(v10, v3.pop_back()); + EXPECT_EQ(v3, v10.push_back(v3[SIZE - 1])); + V1 v11(v3.begin() + 1, v3.begin() + SIZE); + EXPECT_EQ(v11, v3.erase(0)); + EXPECT_EQ(v3, v11.insert(0, v3[0])); + EXPECT_EQ(v11, v3.pop_front()); + EXPECT_EQ(v3, v11.push_front(v3[0])); + } + + TYPED_TEST(xtiny_test, comparison) + { + using V = TypeParam; + using T = typename V::value_type; + + T * data = xtiny_test_data::data; + + V v1{1}, + v2(SIZE, 1), + v3(data, data+SIZE); + + EXPECT_TRUE(v3 == v3); + EXPECT_EQ(v1 == v2, V::has_fixed_size); + EXPECT_TRUE(v1 == v1); + EXPECT_TRUE(v1 == 1); + EXPECT_TRUE(1 == v1); + EXPECT_TRUE(v1 != v3); + EXPECT_TRUE(v2 != v3); + EXPECT_TRUE(v1 != 0); + EXPECT_TRUE(0 != v1); + EXPECT_TRUE(v2 != 0); + EXPECT_TRUE(0 != v2); + } + + TYPED_TEST(xtiny_test, ostream) + { + using V = TypeParam; + using T = typename V::value_type; + + T * data = xtiny_test_data::data; + V v3(data, data+SIZE); + + std::ostringstream out; + out << v3; + if(std::is_integral::value) + { + std::string expected("{1, 2, 4}"); + EXPECT_EQ(expected, out.str()); + } + } + + TEST(xtiny, conversion) + { + using IV = xtiny; + using FV = xtiny; + IV iv{1,2,3}, + iv1(SIZE, 1); + FV fv{1.1f,2.2f,3.3f}, + fv1{1.0}; + + EXPECT_TRUE(iv1 == fv1); + EXPECT_TRUE(fv1 == iv1); + EXPECT_TRUE(iv != fv); + EXPECT_TRUE(fv != iv); + EXPECT_TRUE(iv == IV(fv)); + EXPECT_TRUE(iv == (IV{1.1f,2.2f,3.3f})); + EXPECT_TRUE(iv1 == IV{1.2}); + iv1 = fv; + EXPECT_TRUE(iv1 == iv); + } + TEST(xtiny, interoperability) { using A = xtiny; From a9354d001d2cadc7f3178b1b95c2e28179513374 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Fri, 15 Dec 2017 16:52:49 +0100 Subject: [PATCH 3/5] minor fixes in xtiny --- include/xtensor/xtiny.hpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index f66addaf9..0a00b95db 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -223,6 +223,9 @@ namespace xt template using rebind = xtiny; + template + using rebind_size = xtiny; + xtiny_impl(); ~xtiny_impl(); @@ -335,10 +338,10 @@ namespace xt static const index_t static_size = N; template - using rebind = xtiny>; + using rebind = xtiny; template - using rebind_size = xtiny>; + using rebind_size = xtiny; xtiny_impl(); @@ -679,6 +682,13 @@ namespace xt void swap(xtiny_impl &); }; + template + inline void + swap(xtiny & l, xtiny & r) + { + l.swap(r); + } + /****************/ /* xtiny output */ /****************/ @@ -1284,7 +1294,7 @@ namespace xt inline auto xtiny_impl::capacity() const -> size_type { - return std::max(m_size, buffer_size); + return std::max(m_size, buffer_size); } template @@ -1298,7 +1308,7 @@ namespace xt inline auto xtiny_impl::max_size() const -> size_type { - return std::max_size(m_allocator); + return m_allocator.max_size(); } template @@ -1909,14 +1919,14 @@ namespace xt inline auto xtiny_impl::rbegin() -> reverse_iterator { - return reverse_iterator(m_data+N); + return reverse_iterator(m_data+m_size); } template constexpr inline auto xtiny_impl::rbegin() const -> const_reverse_iterator { - return const_reverse_iterator(m_data+N); + return const_reverse_iterator(m_data+m_size); } template From 9718594f663336cbfd2a818aab902d63583475e2 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Fri, 15 Dec 2017 18:37:44 +0100 Subject: [PATCH 4/5] gcc compatibility fixes --- include/xtensor/xtiny.hpp | 64 +++++++++++++++++++++------------------ test/test_xtiny.cpp | 25 +++++++-------- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 0a00b95db..8aa6838d0 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -101,13 +101,13 @@ namespace xt xtiny(xtiny && rhs); template - xtiny(xtiny const & rhs); + explicit xtiny(xtiny const & rhs); template - xtiny(std::vector const & v); + explicit xtiny(std::vector const & v); template - xtiny(std::array const & v); + explicit xtiny(std::array const & v); xtiny & operator=(xtiny const & rhs); xtiny & operator=(xtiny && rhs); @@ -238,7 +238,7 @@ namespace xt xtiny_impl(IT begin, IT end); template - xtiny_impl(std::initializer_list const & v); + explicit xtiny_impl(std::initializer_list const & v); xtiny_impl(xtiny_impl const & v); xtiny_impl(xtiny_impl && v); @@ -351,14 +351,14 @@ namespace xt template > - xtiny_impl(IT begin); + explicit xtiny_impl(IT begin); template > xtiny_impl(IT begin, IT end); template - xtiny_impl(std::initializer_list const & v); + explicit xtiny_impl(std::initializer_list const & v); xtiny_impl(xtiny_impl const & v); xtiny_impl(xtiny_impl && v); @@ -699,7 +699,7 @@ namespace xt o << "{"; if(v.size() > 0) o << promote_type_t(v[0]); - for(index_t i=1; i < (index_t)v.size(); ++i) + for(decltype(v.size()) i=1; i < v.size(); ++i) o << ", " << promote_type_t(v[i]); o << "}"; return o; @@ -716,7 +716,7 @@ namespace xt { if(l.size() != r.size()) return false; - for(index_t k=0; k < (index_t)l.size(); ++k) + for(decltype(l.size()) k=0; k < l.size(); ++k) if(l[k] != r[k]) return false; return true; @@ -729,7 +729,7 @@ namespace xt operator==(xtiny const & l, V2 const & r) { - for(index_t k=0; k < (index_t)l.size(); ++k) + for(decltype(l.size()) k=0; k < l.size(); ++k) if(l[k] != r) return false; return true; @@ -742,7 +742,7 @@ namespace xt operator==(V1 const & l, xtiny const & r) { - for(index_t k=0; k < (index_t)r.size(); ++k) + for(decltype(r.size()) k=0; k < r.size(); ++k) if(l != r[k]) return false; return true; @@ -755,7 +755,7 @@ namespace xt { if(l.size() != r.size()) return true; - for(index_t k=0; k < (index_t)l.size(); ++k) + for(decltype(l.size()) k=0; k < l.size(); ++k) if(l[k] != r[k]) return true; return false; @@ -768,7 +768,7 @@ namespace xt operator!=(xtiny const & l, V2 const & r) { - for(index_t k=0; k < (index_t)l.size(); ++k) + for(decltype(l.size()) k=0; k < l.size(); ++k) if(l[k] != r) return true; return false; @@ -781,7 +781,7 @@ namespace xt operator!=(V1 const & l, xtiny const & r) { - for(index_t k=0; k < (index_t)r.size(); ++k) + for(decltype(r.size()) k=0; k < r.size(); ++k) if(l != r[k]) return true; return false; @@ -1057,21 +1057,21 @@ namespace xt inline auto xtiny::end() -> iterator { - return begin() + size(); + return begin() + static_cast(size()); } template constexpr inline auto xtiny::end() const -> const_iterator { - return begin() + size(); + return begin() + static_cast(size()); } template constexpr inline auto xtiny::cend() const -> const_iterator { - return cbegin() + size(); + return cbegin() + static_cast(size()); } template @@ -1085,21 +1085,21 @@ namespace xt inline auto xtiny::rend() -> reverse_iterator { - return rbegin() + size(); + return rbegin() + static_cast(size()); } template constexpr inline auto xtiny::rend() const -> const_reverse_iterator { - return rbegin() + size(); + return rbegin() + static_cast(size()); } template constexpr inline auto xtiny::crend() const -> const_reverse_iterator { - return crbegin() + size(); + return crbegin() + static_cast(size()); } template @@ -1234,7 +1234,7 @@ namespace xt inline void xtiny_impl::assign(IT begin, IT end) { - size_type n = std::distance(begin, end); + size_type n = static_cast(std::distance(begin, end)); if(m_size == n) { for (size_type k = 0; k < m_size; ++k, ++begin) @@ -1602,7 +1602,8 @@ namespace xt xtiny_impl>::assign(IT begin, IT end) { std::ignore = end; - XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + XTENSOR_ASSERT_MSG(std::distance(begin, end) == static_cast(size()), + "xtiny_impl::assign(begin, end): size mismatch."); for(size_type k=0; k(*begin); @@ -1647,7 +1648,8 @@ namespace xt : m_data(begin) { std::ignore = end; - XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl(begin, end): size mismatch"); + XTENSOR_ASSERT_MSG(std::distance(begin, end) == static_cast(size()), + "xtiny_impl(begin, end): size mismatch"); } template @@ -1657,7 +1659,8 @@ namespace xt : m_data(const_cast(&*begin)) { std::ignore = end; - XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + XTENSOR_ASSERT_MSG(std::distance(begin, end) == static_cast(size()), + "xtiny_impl::assign(begin, end): size mismatch."); } template @@ -1685,7 +1688,8 @@ namespace xt xtiny_impl::assign(IT begin, IT end) { std::ignore = end; - XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + XTENSOR_ASSERT_MSG(std::distance(begin, end) == static_cast(size()), + "xtiny_impl::assign(begin, end): size mismatch."); for(size_type k=0; k(*begin); @@ -1799,7 +1803,7 @@ namespace xt template inline xtiny_impl::xtiny_impl(representation_type const & begin, representation_type const & end) - : m_size(std::distance(begin, end)) + : m_size(static_cast(std::distance(begin, end))) , m_data(begin) { } @@ -1808,7 +1812,7 @@ namespace xt template inline xtiny_impl::xtiny_impl(IT begin, IT end) - : m_size(std::distance(begin, end)) + : m_size(static_cast(std::distance(begin, end))) , m_data(const_cast(&*begin)) { } @@ -1817,7 +1821,7 @@ namespace xt inline void xtiny_impl::reset(representation_type const & begin, representation_type const & end) { - m_size = std::distance(begin, end); + m_size = static_cast(std::distance(begin, end)); m_data = begin; } @@ -1838,7 +1842,8 @@ namespace xt xtiny_impl::assign(IT begin, IT end) { std::ignore = end; - XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + XTENSOR_ASSERT_MSG(std::distance(begin, end) == static_cast(size()), + "xtiny_impl::assign(begin, end): size mismatch."); for(size_type k=0; k(*begin); @@ -1960,7 +1965,8 @@ namespace xt xtiny_impl>::assign(IT begin, IT end) { std::ignore = end; - XTENSOR_ASSERT_MSG(std::distance(begin, end) == size(), "xtiny_impl::assign(begin, end): size mismatch."); + XTENSOR_ASSERT_MSG(std::distance(begin, end) == static_cast(size()), + "xtiny_impl::assign(begin, end): size mismatch."); for(size_type k=0; k(*begin); diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 908f25e5a..5c6bd9a9d 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -19,7 +19,7 @@ namespace xt { - static const int SIZE = 3; + static const unsigned SIZE = 3; template struct xtiny_test_data @@ -150,7 +150,7 @@ namespace xt TYPED_TEST(xtiny_test, subarray) { using V = TypeParam; - using A = typename V::rebind_size; + using A = typename V::template rebind_size; using T = typename V::value_type; T * data = xtiny_test_data::data; @@ -158,33 +158,33 @@ namespace xt V const & cv3 = v3; EXPECT_EQ(v3, (v3.template subarray<0, SIZE>())); - EXPECT_EQ(2, (v3.template subarray<0, 2>().size())); + EXPECT_EQ(2u, (v3.template subarray<0, 2>().size())); EXPECT_EQ(v3[0], (v3.template subarray<0, 2>()[0])); EXPECT_EQ(v3[1], (v3.template subarray<0, 2>()[1])); - EXPECT_EQ(2, (v3.template subarray<1, 3>().size())); + EXPECT_EQ(2u, (v3.template subarray<1, 3>().size())); EXPECT_EQ(v3[1], (v3.template subarray<1, 3>()[0])); EXPECT_EQ(v3[2], (v3.template subarray<1, 3>()[1])); - EXPECT_EQ(1, (v3.template subarray<1, 2>().size())); + EXPECT_EQ(1u, (v3.template subarray<1, 2>().size())); EXPECT_EQ(v3[1], (v3.template subarray<1, 2>()[0])); - EXPECT_EQ(1, (v3.subarray(1, 2).size())); + EXPECT_EQ(1u, (v3.subarray(1, 2).size())); EXPECT_EQ(v3[1], (v3.subarray(1, 2)[0])); - EXPECT_EQ(1, (cv3.template subarray<1, 2>().size())); + EXPECT_EQ(1u, (cv3.template subarray<1, 2>().size())); EXPECT_EQ(v3[1], (cv3.template subarray<1, 2>()[0])); - EXPECT_EQ(1, (cv3.subarray(1, 2).size())); + EXPECT_EQ(1u, (cv3.subarray(1, 2).size())); EXPECT_EQ(v3[1], (cv3.subarray(1, 2)[0])); A r{ 2,3,4,5 }; EXPECT_EQ(r, (A{ 2,3,4,5 })); - EXPECT_EQ(r.subarray(1, 3).size(), 2); + EXPECT_EQ(r.subarray(1, 3).size(), 2u); EXPECT_EQ(r.subarray(1, 3), (A{ 3,4 })); - EXPECT_EQ((r.template subarray<1, 3>().size()), 2); + EXPECT_EQ((r.template subarray<1, 3>().size()), 2u); EXPECT_EQ((r.template subarray<1, 3>()), (A{ 3,4 })); } TYPED_TEST(xtiny_test, erase_insert) { using V = TypeParam; - using V1 = V::rebind_size; + using V1 = typename V::template rebind_size; using T = typename V::value_type; T * data = xtiny_test_data::data; @@ -206,6 +206,7 @@ namespace xt { using V = TypeParam; using T = typename V::value_type; + const bool fixed = V::has_fixed_size; T * data = xtiny_test_data::data; @@ -214,7 +215,7 @@ namespace xt v3(data, data+SIZE); EXPECT_TRUE(v3 == v3); - EXPECT_EQ(v1 == v2, V::has_fixed_size); + EXPECT_EQ(v1 == v2, fixed); EXPECT_TRUE(v1 == v1); EXPECT_TRUE(v1 == 1); EXPECT_TRUE(1 == v1); From e8c4672dc25b4add662aebe181bf7d86003dd880 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 18 Dec 2017 12:15:08 +0100 Subject: [PATCH 5/5] implemented suggestions by @wolfv --- include/xtensor/xtiny.hpp | 206 ++++++++++++-------------------------- test/test_xtiny.cpp | 27 ++--- 2 files changed, 76 insertions(+), 157 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 8aa6838d0..b75d1bf11 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -32,7 +32,7 @@ namespace xt using index_t = std::ptrdiff_t; - static const index_t runtime_size = -1; + constexpr static index_t runtime_size = -1; namespace tags { @@ -88,7 +88,6 @@ namespace xt using const_reverse_iterator = typename base_type::const_reverse_iterator; using size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; - using index_type = typename base_type::index_type; using base_type::owns_memory; using base_type::has_fixed_size; @@ -125,8 +124,7 @@ namespace xt using base_type::assign; - template - void assign(std::initializer_list v); + void assign(std::initializer_list v); using base_type::data; @@ -168,7 +166,6 @@ namespace xt using base_type::size; using base_type::max_size; - using base_type::shape; constexpr bool empty() const; using base_type::swap; @@ -213,12 +210,11 @@ namespace xt using const_reverse_iterator = std::reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = std::array; - static const bool owns_memory = true; - static const bool has_fixed_size = false; - static const index_t static_size = runtime_size; - static const index_t buffer_size = BUFFER_SIZE; + constexpr static bool owns_memory = true; + constexpr static bool has_fixed_size = false; + constexpr static index_t static_size = runtime_size; + constexpr static index_t buffer_size = BUFFER_SIZE; template using rebind = xtiny; @@ -237,8 +233,7 @@ namespace xt class = detail::require_input_iter> xtiny_impl(IT begin, IT end); - template - explicit xtiny_impl(std::initializer_list const & v); + explicit xtiny_impl(std::initializer_list const & v); xtiny_impl(xtiny_impl const & v); xtiny_impl(xtiny_impl && v); @@ -263,7 +258,6 @@ namespace xt size_type capacity() const; size_type size() const; size_type max_size() const; - index_type shape() const; bool on_stack() const; iterator begin(); @@ -275,7 +269,7 @@ namespace xt void swap(xtiny_impl & other); protected: - static const bool may_use_uninitialized_memory = xtrivially_default_constructible::value; + constexpr static bool may_use_uninitialized_memory = xtrivially_default_constructible::value; /* allocate() assumes that m_size is already set, but no memory has been allocated yet */ @@ -331,11 +325,10 @@ namespace xt using const_reverse_iterator = typename base_type::const_reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = std::array; - static const bool owns_memory = true; - static const bool has_fixed_size = true; - static const index_t static_size = N; + constexpr static bool owns_memory = true; + constexpr static bool has_fixed_size = true; + constexpr static index_t static_size = N; template using rebind = xtiny; @@ -357,8 +350,7 @@ namespace xt class = detail::require_input_iter> xtiny_impl(IT begin, IT end); - template - explicit xtiny_impl(std::initializer_list const & v); + explicit xtiny_impl(std::initializer_list const & v); xtiny_impl(xtiny_impl const & v); xtiny_impl(xtiny_impl && v); @@ -378,7 +370,6 @@ namespace xt using base_type::size; using base_type::max_size; constexpr size_type capacity() const; - constexpr index_type shape() const; using base_type::begin; using base_type::cbegin; @@ -407,7 +398,7 @@ namespace xt template static typename U::value_type test(U *, typename U::value_type * = 0); - static const bool value = !std::is_same::value; + constexpr static bool value = !std::is_same::value; }; template ; - static const bool owns_memory = false; - static const bool has_fixed_size = true; - static const index_t static_size = N; + constexpr static bool owns_memory = false; + constexpr static bool has_fixed_size = true; + constexpr static index_t static_size = N; xtiny_impl(); @@ -523,7 +513,6 @@ namespace xt constexpr size_type size() const; constexpr size_type max_size() const; constexpr size_type capacity() const; - constexpr index_type shape() const; iterator begin(); constexpr const_iterator begin() const; @@ -567,11 +556,10 @@ namespace xt using const_reverse_iterator = typename traits::const_reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = std::array; - static const bool owns_memory = false; - static const bool has_fixed_size = false; - static const index_t static_size = runtime_size; + constexpr static bool owns_memory = false; + constexpr static bool has_fixed_size = false; + constexpr static index_t static_size = runtime_size; xtiny_impl(); @@ -604,7 +592,6 @@ namespace xt constexpr size_type size() const; constexpr size_type max_size() const; constexpr size_type capacity() const; - constexpr index_type shape() const; iterator begin(); constexpr const_iterator begin() const; @@ -647,11 +634,10 @@ namespace xt using const_reverse_iterator = typename base_type::const_reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = std::array; - static const bool owns_memory = false; - static const bool has_fixed_size = false; - static const index_t static_size = runtime_size; + constexpr static bool owns_memory = false; + constexpr static bool has_fixed_size = false; + constexpr static index_t static_size = runtime_size; using base_type::base_type; @@ -667,7 +653,6 @@ namespace xt constexpr size_type max_size() const; constexpr size_type capacity() const; - constexpr index_type shape() const; using base_type::begin; using base_type::cbegin; @@ -714,12 +699,7 @@ namespace xt operator==(xtiny const & l, xtiny const & r) { - if(l.size() != r.size()) - return false; - for(decltype(l.size()) k=0; k < l.size(); ++k) - if(l[k] != r[k]) - return false; - return true; + return l.size() == r.size() && std::equal(l.cbegin(), l.cend(), r.cbegin()); } template const & l, V2 const & r) { - for(decltype(l.size()) k=0; k < l.size(); ++k) - if(l[k] != r) + auto i = l.cbegin(); + for(decltype(l.size()) k=0; k < l.size(); ++k, ++i) + { + if(*i != r) + { return false; + } + } return true; } @@ -742,36 +727,15 @@ namespace xt operator==(V1 const & l, xtiny const & r) { - for(decltype(r.size()) k=0; k < r.size(); ++k) - if(l != r[k]) - return false; - return true; + return r == l; } - template - inline bool - operator!=(xtiny const & l, - xtiny const & r) - { - if(l.size() != r.size()) - return true; - for(decltype(l.size()) k=0; k < l.size(); ++k) - if(l[k] != r[k]) - return true; - return false; - } - - template ::value && - std::is_convertible::value> > + template inline bool operator!=(xtiny const & l, V2 const & r) { - for(decltype(l.size()) k=0; k < l.size(); ++k) - if(l[k] != r) - return true; - return false; + return !(l == r); } template const & r) { - for(decltype(r.size()) k=0; k < r.size(); ++k) - if(l != r[k]) - return true; - return false; + return !(r == l); } /************************/ @@ -816,7 +777,7 @@ namespace xt template inline xtiny::xtiny(xtiny const & v) - : base_type(v.begin(), v.end()) + : base_type(v.cbegin(), v.cend()) { } @@ -824,7 +785,7 @@ namespace xt template inline xtiny::xtiny(std::vector const & v) - : base_type(v.begin(), v.end()) + : base_type(v.cbegin(), v.cend()) { } @@ -832,7 +793,7 @@ namespace xt template inline xtiny::xtiny(std::array const & v) - : base_type(v.begin(), v.end()) + : base_type(v.cbegin(), v.cend()) { } @@ -865,7 +826,7 @@ namespace xt inline auto xtiny::operator=(std::vector const & v) -> xtiny & { - base_type::assign(v.begin(), v.end()); + base_type::assign(v.cbegin(), v.cend()); return *this; } @@ -874,7 +835,7 @@ namespace xt inline auto xtiny::operator=(std::array const & v) -> xtiny & { - base_type::assign(v.begin(), v.end()); + base_type::assign(v.cbegin(), v.cend()); return *this; } @@ -883,14 +844,13 @@ namespace xt inline auto xtiny::operator=(xtiny const & v) -> xtiny & { - base_type::assign(v.begin(), v.end()); + base_type::assign(v.cbegin(), v.cend()); return *this; } template - template inline void - xtiny::assign(std::initializer_list v) + xtiny::assign(std::initializer_list v) { base_type::assign(v.begin(), v.end()); } @@ -900,7 +860,9 @@ namespace xt xtiny::at(size_type i) -> reference { if(i < 0 || i >= size()) + { throw std::out_of_range("xtiny::at()"); + } return (*this)[i]; } @@ -909,7 +871,9 @@ namespace xt xtiny::at(size_type i) const -> const_reference { if(i < 0 || i >= size()) + { throw std::out_of_range("xtiny::at()"); + } return (*this)[i]; } @@ -989,14 +953,12 @@ namespace xt { XTENSOR_PRECONDITION(m >= 0 && m < size(), "xtiny::erase(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); - static const index_t res_size = has_fixed_size + constexpr static index_t res_size = has_fixed_size ? static_size-1 : runtime_size; xtiny res(size()-1, dont_init); - for(size_type k=0; k= 0 && m <= size(), "xtiny::insert(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); - static const index_t res_size = has_fixed_size + constexpr static index_t res_size = has_fixed_size ? static_size+1 : runtime_size; xtiny res(size()+1, dont_init); - for(size_type k=0; k - template inline - xtiny_impl::xtiny_impl(std::initializer_list const & v) + xtiny_impl::xtiny_impl(std::initializer_list const & v) : m_size(0) , m_data(m_buffer) { @@ -1311,13 +1270,6 @@ namespace xt return m_allocator.max_size(); } - template - inline auto - xtiny_impl::shape() const -> index_type - { - return {m_size}; - } - template inline bool xtiny_impl::on_stack() const @@ -1445,7 +1397,9 @@ namespace xt { m_data = m_allocator.allocate(m_size); if(!may_use_uninitialized_memory) + { std::uninitialized_fill(m_data, m_data+m_size, value_type()); + } } } @@ -1458,12 +1412,16 @@ namespace xt { m_data = m_allocator.allocate(m_size); for(size_type k=0; k(*begin)); + } } else { for(size_type k=0; k(*begin); + } } } @@ -1476,7 +1434,9 @@ namespace xt if(!may_use_uninitialized_memory) { for(size_type k=0; k - template inline - xtiny_impl>::xtiny_impl(std::initializer_list const & v) + xtiny_impl>::xtiny_impl(std::initializer_list const & v) { const size_t n = v.size(); if(n == 1) @@ -1553,7 +1512,7 @@ namespace xt } else { - XTENSOR_ASSERT_MSG(false, "xtiny_impl::xtiny_impl(std::initializer_list): size mismatch."); + XTENSOR_ASSERT_MSG(false, "xtiny_impl::xtiny_impl(std::initializer_list): size mismatch."); } } @@ -1617,13 +1576,6 @@ namespace xt return N; } - template - constexpr inline auto - xtiny_impl>::shape() const -> index_type - { - return {N}; - } - /**********************************************/ /* xtiny_impl fixed shape view implementation */ /**********************************************/ @@ -1745,13 +1697,6 @@ namespace xt return N; } - template - constexpr inline auto - xtiny_impl::shape() const -> index_type - { - return {N}; - } - template inline auto xtiny_impl::begin() -> iterator @@ -1829,11 +1774,9 @@ namespace xt inline void xtiny_impl::assign(size_type n, const value_type& v) { + std::ignore = n; XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl::assign(n, v): size mismatch."); - for(size_type k=0; k @@ -1899,13 +1842,6 @@ namespace xt return m_size; } - template - constexpr inline auto - xtiny_impl::shape() const -> index_type - { - return {m_size}; - } - template inline auto xtiny_impl::begin() -> iterator @@ -1952,11 +1888,9 @@ namespace xt inline void xtiny_impl>::assign(size_type n, const value_type& v) { + std::ignore = n; XTENSOR_ASSERT_MSG(n == size(), "xtiny_impl::assign(n, v): size mismatch."); - for(size_type k=0; k @@ -1986,14 +1920,6 @@ namespace xt { return size(); } - - template - constexpr inline auto - xtiny_impl>::shape() const -> index_type - { - return {size()}; - } - } // namespace xt #endif // XTENSOR_XTINY_HPP diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 5c6bd9a9d..0c198670a 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -55,9 +55,11 @@ namespace xt const bool fixed = V::has_fixed_size; T * data = xtiny_test_data::data; + int * idata = xtiny_test_data::data; V v0, v1(SIZE, 1), + v2(idata, idata+SIZE), v3(data, data+SIZE); EXPECT_EQ(v0.size(), fixed ? SIZE : 0); @@ -66,9 +68,6 @@ namespace xt EXPECT_EQ(v0.empty(), !fixed); EXPECT_FALSE(v1.empty()); EXPECT_FALSE(v3.empty()); - EXPECT_EQ(v0.shape(), (std::array{fixed ? SIZE : 0})); - EXPECT_EQ(v1.shape(), (std::array{SIZE})); - EXPECT_EQ(v3.shape(), (std::array{SIZE})); EXPECT_EQ(v3.front(), data[0]); EXPECT_EQ(v3.back(), data[SIZE-1]); @@ -112,10 +111,6 @@ namespace xt { EXPECT_EQ(v3, (V{1, 2, 4})); } - else - { - EXPECT_EQ(v3, (V{1.2f, 2.4f, 4.6f})); - } if(fixed) { EXPECT_EQ(v1, (V{1})); @@ -128,22 +123,22 @@ namespace xt V v; v.assign(SIZE, 1); EXPECT_EQ(v1, v); - v.assign({1.2f, 2.4f, 4.6f}); - EXPECT_EQ(v3, v); + v.assign({1, 2, 4}); + EXPECT_EQ(v2, v); v = 1; EXPECT_EQ(v, v1); v = v3; EXPECT_EQ(v, v3); - V v2(v1), v4(v3); - swap(v2, v4); - EXPECT_EQ(v3, v2); - EXPECT_EQ(v1, v4); + V v4(v1), v5(v3); + swap(v4, v5); + EXPECT_EQ(v3, v4); + EXPECT_EQ(v1, v5); // testing move constructor and assignment - v4 = v3.push_back(0).pop_back(); - EXPECT_EQ(v4, v3); + v5 = v3.push_back(0).pop_back(); + EXPECT_EQ(v5, v3); EXPECT_EQ(V(v3.push_back(0).pop_back()), v3); } @@ -258,8 +253,6 @@ namespace xt EXPECT_TRUE(iv != fv); EXPECT_TRUE(fv != iv); EXPECT_TRUE(iv == IV(fv)); - EXPECT_TRUE(iv == (IV{1.1f,2.2f,3.3f})); - EXPECT_TRUE(iv1 == IV{1.2}); iv1 = fv; EXPECT_TRUE(iv1 == iv); }