// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_ISTL_BASEARRAY_HH #define DUNE_ISTL_BASEARRAY_HH #include <cassert> #include <cmath> #include <cstddef> #include <memory> #include <algorithm> #include <type_traits> #include "istlexception.hh" #include <dune/common/iteratorfacades.hh> /** \file \brief Implements several basic array containers. */ namespace Dune { /** \brief Everything in this namespace is internal to dune-istl, and may change without warning */ namespace Imp { /** \brief A simple array container for objects of type B Implement. - iterator access - const_iterator access - random access This container has *NO* memory management at all, copy constructor, assignment and destructor are all default. The constructor is made protected to emphasize that objects are only usable in derived classes. Error checking: no error checking is provided normally. Setting the compile time switch DUNE_ISTL_WITH_CHECKING enables error checking. \internal This class is an implementation detail, and should not be used outside of dune-istl. */ template<class B, class ST=std::size_t > class base_array_unmanaged { public: //===== type definitions and constants //! export the type representing the components typedef B member_type; //! the type for the index access typedef ST size_type; //! the type used for references using reference = B&; //! the type used for const references using const_reference = const B&; //===== access to components //! random access to blocks reference operator[] (size_type i) { #ifdef DUNE_ISTL_WITH_CHECKING if (i>=n) DUNE_THROW(ISTLError,"index out of range"); #endif return p[i]; } //! same for read only access const_reference operator[] (size_type i) const { #ifdef DUNE_ISTL_WITH_CHECKING if (i>=n) DUNE_THROW(ISTLError,"index out of range"); #endif return p[i]; } /** \brief Iterator implementation class */ template<class T> class RealIterator : public RandomAccessIteratorFacade<RealIterator<T>, T> { public: //! \brief The unqualified value type typedef typename std::remove_const<T>::type ValueType; friend class RandomAccessIteratorFacade<RealIterator<const ValueType>, const ValueType>; friend class RandomAccessIteratorFacade<RealIterator<ValueType>, ValueType>; friend class RealIterator<const ValueType>; friend class RealIterator<ValueType>; //! constructor RealIterator () = default; RealIterator (const B* _p, B* _i) : p(_p), i(_i) {} template <class T_, std::enable_if_t<std::is_same_v<std::remove_const_t<T>, std::remove_const_t<T_>>, int> = 0> RealIterator (const RealIterator<T_>& other) : p(other.p), i(other.i) {} template <class T_, std::enable_if_t<std::is_same_v<std::remove_const_t<T>, std::remove_const_t<T_>>, int> = 0> RealIterator& operator= (const RealIterator<T_>& other) { p = other.p; i = other.i; return *this; } //! return index size_type index () const { return i-p; } //! equality bool equals (const RealIterator<ValueType>& other) const { assert(other.p==p); return i==other.i; } //! equality bool equals (const RealIterator<const ValueType>& other) const { assert(other.p==p); return i==other.i; } std::ptrdiff_t distanceTo(const RealIterator& o) const { return o.i-i; } private: //! prefix increment void increment() { ++i; } //! prefix decrement void decrement() { --i; } // Needed for operator[] of the iterator reference elementAt (std::ptrdiff_t offset) const { return *(i+offset); } //! dereferencing reference dereference () const { return *i; } void advance(std::ptrdiff_t d) { i+=d; } const B* p = nullptr; B* i = nullptr; }; //! iterator type for sequential access typedef RealIterator<B> iterator; //! begin iterator iterator begin () { return iterator(p,p); } //! end iterator iterator end () { return iterator(p,p+n); } //! @returns an iterator that is positioned before //! the end iterator of the vector, i.e. at the last entry. iterator beforeEnd () { return iterator(p,p+n-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. iterator beforeBegin () { return iterator(p,p-1); } //! random access returning iterator (end if not contained) iterator find (size_type i) { return iterator(p,p+std::min(i,n)); } //! iterator class for sequential access typedef RealIterator<const B> const_iterator; //! begin const_iterator const_iterator begin () const { return const_iterator(p,p+0); } //! end const_iterator const_iterator end () const { return const_iterator(p,p+n); } //! @returns an iterator that is positioned before //! the end iterator of the vector. i.e. at the last element. const_iterator beforeEnd () const { return const_iterator(p,p+n-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. const_iterator beforeBegin () const { return const_iterator(p,p-1); } //! random access returning iterator (end if not contained) const_iterator find (size_type i) const { return const_iterator(p,p+std::min(i,n)); } //===== sizes //! number of blocks in the array (are of size 1 here) size_type size () const { return n; } //! Returns pointer to the underlying array const B* data() const { return p; } //! Returns pointer to the underlying array B* data() { return p; } protected: //! makes empty array base_array_unmanaged () : n(0), p(0) {} //! make an initialized array base_array_unmanaged (size_type n_, B* p_) : n(n_), p(p_) {} size_type n; // number of elements in array B *p; // pointer to dynamically allocated built-in array }; /** \brief A simple array container with non-consecutive index set. Elements in the array are of type B. This class provides - iterator access - const_iterator access - random access in log(n) steps using binary search - find returning iterator This container has *NO* memory management at all, copy constructor, assignment and destructor are all default. The constructor is made protected to emphasize that objects are only usably in derived classes. Error checking: no error checking is provided normally. Setting the compile time switch DUNE_ISTL_WITH_CHECKING enables error checking. \internal This class is an implementation detail, and should not be used outside of dune-istl. */ template<class B, class ST=std::size_t > class compressed_base_array_unmanaged { public: //===== type definitions and constants //! export the type representing the components typedef B member_type; //! The type used for the index access typedef ST size_type; //! the type used for references using reference = B&; //! the type used for const references using const_reference = const B&; //===== access to components //! random access to blocks, assumes ascending ordering reference operator[] (size_type i) { const size_type* lb = std::lower_bound(j, j+n, i); if (lb == j+n || *lb != i) DUNE_THROW(ISTLError,"index "<<i<<" not in compressed array"); return p[lb-j]; } //! same for read only access, assumes ascending ordering const_reference operator[] (size_type i) const { const size_type* lb = std::lower_bound(j, j+n, i); if (lb == j+n || *lb != i) DUNE_THROW(ISTLError,"index "<<i<<" not in compressed array"); return p[lb-j]; } //! iterator class for sequential access template<class T> class RealIterator : public BidirectionalIteratorFacade<RealIterator<T>, T> { public: //! \brief The unqualified value type typedef typename std::remove_const<T>::type ValueType; friend class BidirectionalIteratorFacade<RealIterator<const ValueType>, const ValueType>; friend class BidirectionalIteratorFacade<RealIterator<ValueType>, ValueType>; friend class RealIterator<const ValueType>; friend class RealIterator<ValueType>; //! constructor RealIterator () = default; //! constructor RealIterator (B* _p, size_type* _j, size_type _i) : p(_p), j(_j), i(_i) {} template <class T_, std::enable_if_t<std::is_same_v<std::remove_const_t<T>, std::remove_const_t<T_>>, int> = 0> RealIterator (const RealIterator<T_>& other) : p(other.p), j(other.j), i(other.i) {} template <class T_, std::enable_if_t<std::is_same_v<std::remove_const_t<T>, std::remove_const_t<T_>>, int> = 0> RealIterator& operator= (const RealIterator<T_>& other) { p = other.p; j = other.j; i = other.i; return *this; } //! equality bool equals (const RealIterator<ValueType>& it) const { assert(p==it.p); return (i)==(it.i); } //! equality bool equals (const RealIterator<const ValueType>& it) const { assert(p==it.p); return (i)==(it.i); } //! return index corresponding to pointer size_type index () const { return j[i]; } //! Set index corresponding to pointer void setindex (size_type k) { return j[i] = k; } /** * @brief offset from the first entry. * * An iterator positioned at the beginning * has to be increment this amount of times to * the same position. */ size_type offset () const { return i; } private: //! prefix increment void increment() { ++i; } //! prefix decrement void decrement() { --i; } //! dereferencing reference dereference () const { return p[i]; } B* p = nullptr; size_type* j = nullptr; size_type i = 0; }; /** @brief The iterator type. */ typedef RealIterator<B> iterator; //! begin iterator iterator begin () { return iterator(p,j,0); } //! end iterator iterator end () { return iterator(p,j,n); } //! @returns an iterator that is positioned before //! the end iterator of the vector, i.e. at the last entry. iterator beforeEnd () { return iterator(p,j,n-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. iterator beforeBegin () { return iterator(p,j,-1); } //! random access returning iterator (end if not contained) iterator find (size_type i) { const size_type* lb = std::lower_bound(j, j+n, i); return (lb != j+n && *lb == i) ? iterator(p,j,lb-j) : end(); } //! const_iterator class for sequential access typedef RealIterator<const B> const_iterator; //! begin const_iterator const_iterator begin () const { return const_iterator(p,j,0); } //! end const_iterator const_iterator end () const { return const_iterator(p,j,n); } //! @returns an iterator that is positioned before //! the end iterator of the vector. i.e. at the last element. const_iterator beforeEnd () const { return const_iterator(p,j,n-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. const_iterator beforeBegin () const { return const_iterator(p,j,-1); } //! random access returning iterator (end if not contained) const_iterator find (size_type i) const { const size_type* lb = std::lower_bound(j, j+n, i); return (lb != j+n && *lb == i) ? const_iterator(p,j,lb-j) : end(); } //===== sizes //! number of blocks in the array (are of size 1 here) size_type size () const { return n; } protected: //! makes empty array compressed_base_array_unmanaged () : n(0), p(0), j(0) {} size_type n; // number of elements in array B *p; // pointer to dynamically allocated built-in array size_type* j; // the index set }; } // end namespace Imp } // end namespace #endif