Skip to content
Snippets Groups Projects
Commit 14766f4f authored by Simon Praetorius's avatar Simon Praetorius
Browse files

Merge branch 'issue/reserved-vector-incomplete' into 'master'

Fillin missing functionality in ReservedVector and make it constexpr

See merge request !1158
parents 8038be95 bfd85ab0
No related branches found
No related tags found
1 merge request!1158Fillin missing functionality in ReservedVector and make it constexpr
Pipeline #53188 passed
Pipeline: Dune Nightly Test

#53189

    ......@@ -32,6 +32,9 @@ In order to build the DUNE core modules you need at least the following software
    - Add `python -m dune [info|configure|list|remove|dunetype|fix-dunepy]` command to manage just-in-time generated python modules in dune-py
    - The storage type `ReservedVector` is extended to follow more closely the `std::vector` and
    `std::array` interfaces.
    ## Build System
    - Improve the the function `dune_add_library` by separating the target types normal, interface, and
    ......
    ......@@ -9,9 +9,10 @@
    #include <algorithm>
    #include <array>
    #include <cassert>
    #include <iostream>
    #include <iterator>
    #include <cstddef>
    #include <dune/common/genericiterator.hh>
    #include <initializer_list>
    #include <dune/common/hash.hh>
    ......@@ -35,194 +36,414 @@ namespace Dune
    This implies that the vector cannot grow bigger than the predefined
    maximum size.
    \tparam T The data type ReservedVector stores.
    \tparam T The value type ReservedVector stores.
    \tparam n The maximum number of objects the ReservedVector can store.
    */
    template<class T, int n>
    class ReservedVector
    {
    using storage_type = std::array<T,n>;
    public:
    /** @{ Typedefs */
    //! The type of object, T, stored in the vector.
    typedef T value_type;
    typedef typename storage_type::value_type value_type;
    //! Pointer to T.
    typedef T* pointer;
    typedef typename storage_type::pointer pointer;
    //! Const pointer to T.
    typedef typename storage_type::const_pointer const_pointer;
    //! Reference to T
    typedef T& reference;
    typedef typename storage_type::reference reference;
    //! Const reference to T
    typedef const T& const_reference;
    typedef typename storage_type::const_reference const_reference;
    //! An unsigned integral type.
    typedef size_t size_type;
    typedef typename storage_type::size_type size_type;
    //! A signed integral type.
    typedef std::ptrdiff_t difference_type;
    typedef typename storage_type::difference_type difference_type;
    //! Iterator used to iterate through a vector.
    typedef Dune::GenericIterator<ReservedVector, value_type> iterator;
    typedef typename storage_type::iterator iterator;
    //! Const iterator used to iterate through a vector.
    typedef Dune::GenericIterator<const ReservedVector, const value_type> const_iterator;
    typedef typename storage_type::const_iterator const_iterator;
    //! Reverse iterator
    typedef std::reverse_iterator<iterator> reverse_iterator;
    //! Const reverse iterator
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
    /** @} */
    /** @{ Constructors */
    //! Constructor
    ReservedVector() = default;
    //! Constructs an empty vector
    constexpr ReservedVector()
    noexcept(std::is_nothrow_default_constructible_v<value_type>)
    : storage_()
    , size_(0)
    {}
    //! Constructs the vector with `count` elements that will be default-initialized.
    explicit constexpr ReservedVector(size_type count)
    noexcept(std::is_nothrow_default_constructible_v<value_type>)
    : storage_()
    , size_(count)
    {
    assert(count <= n);
    }
    //! Constructs the vector with `count` copies of elements with value `value`.
    constexpr ReservedVector(size_type count, const value_type& value)
    noexcept(std::is_nothrow_copy_assignable_v<value_type> &&
    noexcept(ReservedVector(count)))
    : ReservedVector(count)
    {
    for (size_type i=0; i<count; ++i)
    storage_[i] = value;
    }
    ReservedVector(std::initializer_list<T> const &l)
    //! Constructs the vector from an iterator range `[first,last)`
    template<class InputIt,
    std::enable_if_t<std::is_convertible_v<typename std::iterator_traits<InputIt>::value_type, value_type>, int> = 0>
    constexpr ReservedVector(InputIt first, InputIt last)
    noexcept(std::is_nothrow_copy_assignable_v<value_type> &&
    noexcept(ReservedVector()))
    : ReservedVector()
    {
    assert(l.size() <= n);// Actually, this is not needed any more!
    sz = l.size();
    std::copy_n(l.begin(), sz, data.data());
    for (size_type i=0; i<n && first!=last; ++i,++size_)
    storage_[i] = *first++;
    assert(first == last);
    }
    //! Constructs the vector from an initializer list
    constexpr ReservedVector(std::initializer_list<value_type> const& l)
    noexcept(std::is_nothrow_copy_assignable_v<value_type> &&
    noexcept(ReservedVector(l.begin(),l.end())))
    : ReservedVector(l.begin(),l.end())
    {}
    /** @} */
    bool operator == (const ReservedVector & other) const
    /** @{ Comparison */
    //! Compares the values in the vector `this` with `that` for equality
    constexpr bool operator== (const ReservedVector& that) const noexcept
    {
    bool eq = (sz == other.sz);
    for (size_type i=0; i<sz && eq; ++i)
    eq = eq && (data[i] == other.data[i]);
    return eq;
    if (size() != that.size())
    return false;
    for (size_type i=0; i<size(); ++i)
    if (!(storage_[i]==that.storage_[i]))
    return false;
    return true;
    }
    /** @{ Data access operations */
    //! Compares the values in the vector `this` with `that` for not equality
    constexpr bool operator!= (const ReservedVector& that) const noexcept
    {
    return !(*this == that);
    }
    //! Lexicographically compares the values in the vector `this` with `that`
    constexpr bool operator< (const ReservedVector& that) const noexcept
    {
    for (size_type i=0; i<std::min(size(),that.size()); ++i) {
    if (storage_[i] < that.storage_[i]) return true;
    if (that.storage_[i] < storage_[i]) return false;
    }
    return size() < that.size();
    }
    //! Lexicographically compares the values in the vector `this` with `that`
    constexpr bool operator> (const ReservedVector& that) const noexcept
    {
    return that < *this;
    }
    //! Lexicographically compares the values in the vector `this` with `that`
    constexpr bool operator<= (const ReservedVector& that) const noexcept
    {
    return !(*this > that);
    }
    //! Lexicographically compares the values in the vector `this` with `that`
    constexpr bool operator>= (const ReservedVector& that) const noexcept
    {
    return !(*this < that);
    }
    /** @} */
    /** @{ Modifiers */
    //! Erases all elements.
    void clear()
    constexpr void clear() noexcept
    {
    sz = 0;
    size_ = 0;
    }
    //! Specifies a new size for the vector.
    void resize(size_t s)
    constexpr void resize(size_type s) noexcept
    {
    CHECKSIZE(s<=n);
    sz = s;
    size_ = s;
    }
    //! Appends an element to the end of a vector, up to the maximum size n, O(1) time.
    void push_back(const T& t)
    constexpr void push_back(const value_type& t)
    noexcept(std::is_nothrow_copy_assignable_v<value_type>)
    {
    CHECKSIZE(size_<n);
    storage_[size_++] = t;
    }
    //! Appends an element to the end of a vector by moving the value, up to the maximum size n, O(1) time.
    constexpr void push_back(value_type&& t)
    noexcept(std::is_nothrow_move_assignable_v<value_type>)
    {
    CHECKSIZE(sz<n);
    data[sz++] = t;
    CHECKSIZE(size_<n);
    storage_[size_++] = std::move(t);
    }
    //! Appends an element to the end of a vector by constructing it in place
    template<class... Args>
    reference emplace_back(Args&&... args)
    noexcept(std::is_nothrow_constructible_v<value_type,decltype(args)...>)
    {
    CHECKSIZE(size_<n);
    value_type* p = &storage_[size_++];
    // first destroy any previously (default) constructed element at that location
    p->~value_type();
    // construct the value_type in place
    // NOTE: This is not an integral constant expression.
    // With c++20 we could use std::construct_at
    ::new (const_cast<void*>(static_cast<const volatile void*>(p)))
    value_type(std::forward<Args>(args)...);
    return *p;
    }
    //! Erases the last element of the vector, O(1) time.
    void pop_back()
    constexpr void pop_back() noexcept
    {
    if (! empty()) sz--;
    if (! empty()) size_--;
    }
    /** @} */
    /** @{ Iterators */
    //! Returns a iterator pointing to the beginning of the vector.
    iterator begin(){
    return iterator(*this, 0);
    constexpr iterator begin() noexcept
    {
    return storage_.begin();
    }
    //! Returns a const_iterator pointing to the beginning of the vector.
    constexpr const_iterator begin() const noexcept
    {
    return storage_.begin();
    }
    //! Returns a const_iterator pointing to the beginning of the vector.
    const_iterator begin() const {
    return const_iterator(*this, 0);
    constexpr const_iterator cbegin() const noexcept
    {
    return storage_.cbegin();
    }
    //! Returns a const reverse-iterator pointing to the end of the vector.
    constexpr reverse_iterator rbegin() noexcept
    {
    return reverse_iterator{begin()+size()};
    }
    //! Returns a const reverse-iterator pointing to the end of the vector.
    constexpr const_reverse_iterator rbegin() const noexcept
    {
    return const_reverse_iterator{begin()+size()};
    }
    //! Returns a const reverse-iterator pointing to the end of the vector.
    constexpr const_reverse_iterator crbegin() const noexcept
    {
    return const_reverse_iterator{begin()+size()};
    }
    //! Returns an iterator pointing to the end of the vector.
    iterator end(){
    return iterator(*this, sz);
    constexpr iterator end() noexcept
    {
    return storage_.begin()+size();
    }
    //! Returns a const_iterator pointing to the end of the vector.
    constexpr const_iterator end() const noexcept
    {
    return storage_.begin()+size();
    }
    //! Returns a const_iterator pointing to the end of the vector.
    const_iterator end() const {
    return const_iterator(*this, sz);
    constexpr const_iterator cend() const noexcept
    {
    return storage_.cbegin()+size();
    }
    //! Returns a const reverse-iterator pointing to the begin of the vector.
    constexpr reverse_iterator rend() noexcept
    {
    return reverse_iterator{begin()};
    }
    //! Returns a const reverse-iterator pointing to the begin of the vector.
    constexpr const_reverse_iterator rend() const noexcept
    {
    return const_reverse_iterator{begin()};
    }
    //! Returns a const reverse-iterator pointing to the begin of the vector.
    constexpr const_reverse_iterator crend() const noexcept
    {
    return const_reverse_iterator{begin()};
    }
    /** @} */
    /** @{ Element access */
    //! Returns reference to the i'th element.
    reference operator[] (size_type i)
    constexpr reference at(size_type i)
    {
    CHECKSIZE(sz>i);
    return data[i];
    if (!(i < size()))
    throw std::out_of_range("Index out of range");
    return storage_[i];
    }
    //! Returns a const reference to the i'th element.
    const_reference operator[] (size_type i) const
    constexpr const_reference at(size_type i) const
    {
    CHECKSIZE(sz>i);
    return data[i];
    if (!(i < size()))
    throw std::out_of_range("Index out of range");
    return storage_[i];
    }
    //! Returns reference to the i'th element.
    constexpr reference operator[] (size_type i) noexcept
    {
    CHECKSIZE(size_>i);
    return storage_[i];
    }
    //! Returns a const reference to the i'th element.
    constexpr const_reference operator[] (size_type i) const noexcept
    {
    CHECKSIZE(size_>i);
    return storage_[i];
    }
    //! Returns reference to first element of vector.
    reference front()
    constexpr reference front() noexcept
    {
    CHECKSIZE(sz>0);
    return data[0];
    CHECKSIZE(size_>0);
    return storage_[0];
    }
    //! Returns const reference to first element of vector.
    const_reference front() const
    constexpr const_reference front() const noexcept
    {
    CHECKSIZE(sz>0);
    return data[0];
    CHECKSIZE(size_>0);
    return storage_[0];
    }
    //! Returns reference to last element of vector.
    reference back()
    constexpr reference back() noexcept
    {
    CHECKSIZE(sz>0);
    return data[sz-1];
    CHECKSIZE(size_>0);
    return storage_[size_-1];
    }
    //! Returns const reference to last element of vector.
    const_reference back() const
    constexpr const_reference back() const noexcept
    {
    CHECKSIZE(size_>0);
    return storage_[size_-1];
    }
    //! Returns pointer to the underlying memory.
    constexpr pointer data() noexcept
    {
    return storage_.data();
    }
    //! Returns const pointer to the underlying memory.
    constexpr const_pointer data() const noexcept
    {
    CHECKSIZE(sz>0);
    return data[sz-1];
    return storage_.data();
    }
    /** @} */
    /** @{ Informative Methods */
    /** @{ Capacity */
    //! Returns number of elements in the vector.
    size_type size () const
    constexpr size_type size() const noexcept
    {
    return sz;
    return size_;
    }
    //! Returns true if vector has no elements.
    bool empty() const
    constexpr bool empty() const noexcept
    {
    return sz==0;
    return size_==0;
    }
    //! Returns current capacity (allocated memory) of the vector.
    static constexpr size_type capacity()
    static constexpr size_type capacity() noexcept
    {
    return n;
    }
    //! Returns the maximum length of the vector.
    static constexpr size_type max_size()
    static constexpr size_type max_size() noexcept
    {
    return n;
    }
    /** @} */
    /** @{ Operations */
    //! Fill the container with the value
    constexpr void fill(const value_type& value)
    noexcept(std::is_nothrow_copy_assignable_v<value_type>)
    {
    for (size_type i=0; i<size(); ++i)
    storage_[i] = value;
    }
    //! Swap the content with another vector
    void swap(ReservedVector& other)
    noexcept(std::is_nothrow_swappable_v<value_type>)
    {
    using std::swap;
    swap(storage_, other.storage_);
    swap(size_, other.size_);
    }
    /** @} */
    //! Send ReservedVector to an output stream
    friend std::ostream& operator<< (std::ostream& s, const ReservedVector& v)
    {
    for (size_t i=0; i<v.size(); i++)
    for (size_type i=0; i<v.size(); i++)
    s << v[i] << " ";
    return s;
    }
    inline friend std::size_t hash_value(const ReservedVector& v) noexcept
    {
    return hash_range(v.data.data(),v.data.data()+v.sz);
    return hash_range(v.storage_.data(),v.storage_.data()+v.size_);
    }
    private:
    std::array<T,n> data = {};
    size_type sz = 0;
    storage_type storage_;
    size_type size_;
    };
    }
    ......
    ......@@ -12,6 +12,46 @@
    #include <dune/common/classname.hh>
    #include <dune/common/reservedvector.hh>
    struct A
    {
    explicit A(int s = 42)
    : data_(s > 0 ? new double[s] : nullptr)
    , size_(s) {};
    A(const A& other)
    : A(other.size_) {}
    A(A&& other) {
    std::swap(data_, other.data_);
    std::swap(size_, other.size_);
    }
    A& operator=(A other) {
    std::swap(data_, other.data_);
    std::swap(size_, other.size_);
    return *this;
    }
    ~A() { delete[] data_; }
    double* data_ = nullptr;
    int size_ = 0;
    };
    struct NoCopy
    {
    NoCopy() = default;
    NoCopy(const NoCopy&) = delete;
    NoCopy(NoCopy&&) = default;
    NoCopy& operator= (const NoCopy&) = delete;
    NoCopy& operator= (NoCopy&&) = default;
    };
    struct NoMove
    {
    NoMove() = default;
    NoMove(const NoMove&) = default;
    NoMove(NoMove&&) = delete;
    NoMove& operator= (const NoMove&) = default;
    NoMove& operator= (NoMove&&) = delete;
    };
    int main() {
    Dune::TestSuite test;
    // check that make_array works
    ......@@ -31,6 +71,12 @@ int main() {
    test.check(rv.size() == 5);
    test.check(rv.back() == 5);
    // check emplace_back
    test.check(rv.emplace_back(6) == 6);
    test.check(rv.size() == 6);
    test.check(rv.back() == 6);
    rv.pop_back();
    // check copy constructor
    Dune::ReservedVector<unsigned int, 8> rv2 = rv;
    test.check(rv2[0] == 1 &&
    ......@@ -39,6 +85,16 @@ int main() {
    rv2[3] == 4 &&
    rv2[4] == 5);
    // check size constructor
    Dune::ReservedVector<unsigned int, 8> rv3(7);
    test.check(rv3.size() == 7);
    test.check(rv3[6] == 0);
    // check size and value constructor
    Dune::ReservedVector<unsigned int, 8> rv4(5, 42);
    test.check(rv4.size() == 5);
    test.check(rv4[3] == 42);
    // check pop_back
    rv2.pop_back();
    test.check(rv2.size() == 4);
    ......@@ -58,5 +114,50 @@ int main() {
    // try and try again with a const ReservedVector
    std::unordered_map< const Dune::ReservedVector<unsigned int, 8>, double> const_rv_map;
    rv = {1,2,3,4};
    { // check forward iterators
    unsigned int i = 1;
    for (auto it = rv.begin(); it != rv.end(); ++it)
    test.check( *it == i++ );
    // check backward iterators
    i = 4;
    for (auto it = rv.rbegin(); it != rv.rend(); ++it)
    test.check( *it == i-- );
    // check raw data
    i = 1;
    for (auto* it = rv.data(); it != rv.data()+rv.size(); ++it)
    test.check( *it == i++ );
    }
    { // check non-trivial types
    Dune::ReservedVector<A, 8> rvA;
    rvA.push_back(A(5));
    rvA.emplace_back(A(5));
    rvA.emplace_back(5);
    test.check( rvA.size() == 3 );
    }
    { // check non-copyable types
    Dune::ReservedVector<NoCopy, 8> rv;
    rv.push_back(NoCopy{});
    rv.emplace_back();
    test.check( rv.size() == 2 );
    }
    { // check non-movable types
    Dune::ReservedVector<NoMove, 8> rv;
    NoMove x;
    rv.push_back(x);
    rv.emplace_back();
    test.check( rv.size() == 2 );
    }
    { // check constexpr
    constexpr Dune::ReservedVector<unsigned int, 8> crv{3,2,1};
    static_assert(crv.size() == 3);
    static_assert(crv.at(2) == 1);
    }
    return 0;
    }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment