Chris@16: // Chris@16: // Copyright (c) 2000-2002 Chris@16: // Joerg Walter, Mathias Koch Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // The authors gratefully acknowledge the support of Chris@16: // GeNeSys mbH & Co. KG in producing this work. Chris@16: // Chris@16: Chris@16: #ifndef _BOOST_UBLAS_STORAGE_SPARSE_ Chris@16: #define _BOOST_UBLAS_STORAGE_SPARSE_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: Chris@16: namespace boost { namespace numeric { namespace ublas { Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: I lower_bound (const I &begin, const I &end, const T &t, C compare) { Chris@16: // t <= *begin <=> ! (*begin < t) Chris@16: if (begin == end || ! compare (*begin, t)) Chris@16: return begin; Chris@16: if (compare (*(end - 1), t)) Chris@16: return end; Chris@16: return std::lower_bound (begin, end, t, compare); Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: I upper_bound (const I &begin, const I &end, const T &t, C compare) { Chris@16: if (begin == end || compare (t, *begin)) Chris@16: return begin; Chris@16: // (*end - 1) <= t <=> ! (t < *end) Chris@16: if (! compare (t, *(end - 1))) Chris@16: return end; Chris@16: return std::upper_bound (begin, end, t, compare); Chris@16: } Chris@16: Chris@16: template Chris@16: struct less_pair { Chris@16: BOOST_UBLAS_INLINE Chris@16: bool operator () (const P &p1, const P &p2) { Chris@16: return p1.first < p2.first; Chris@16: } Chris@16: }; Chris@16: template Chris@16: struct less_triple { Chris@16: BOOST_UBLAS_INLINE Chris@16: bool operator () (const T &t1, const T &t2) { Chris@16: return t1.first.first < t2.first.first || Chris@16: (t1.first.first == t2.first.first && t1.first.second < t2.first.second); Chris@16: } Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: #ifdef BOOST_UBLAS_STRICT_MAP_ARRAY Chris@16: template Chris@16: class sparse_storage_element: Chris@16: public container_reference { Chris@16: public: Chris@16: typedef A array_type; Chris@16: typedef typename A::key_type index_type; Chris@16: typedef typename A::mapped_type data_value_type; Chris@16: // typedef const data_value_type &data_const_reference; Chris@16: typedef typename type_traits::const_reference data_const_reference; Chris@16: typedef data_value_type &data_reference; Chris@16: typedef typename A::value_type value_type; Chris@16: typedef value_type *pointer; Chris@16: Chris@16: // Construction and destruction Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element (array_type &a, pointer it): Chris@16: container_reference (a), it_ (it), i_ (it->first), d_ (it->second), dirty_ (false) {} Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element (array_type &a, index_type i): Chris@16: container_reference (a), it_ (), i_ (i), d_ (), dirty_ (false) { Chris@16: pointer it = (*this) ().find (i_); Chris@16: if (it == (*this) ().end ()) Chris@16: it = (*this) ().insert ((*this) ().end (), value_type (i_, d_)); Chris@16: d_ = it->second; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: ~sparse_storage_element () { Chris@16: if (dirty_) { Chris@16: if (! it_) Chris@16: it_ = (*this) ().find (i_); Chris@16: BOOST_UBLAS_CHECK (it_ != (*this) ().end (), internal_logic ()); Chris@16: it_->second = d_; Chris@16: } Chris@16: } Chris@16: Chris@16: // Element access - only if data_const_reference is defined Chris@16: BOOST_UBLAS_INLINE Chris@16: typename data_value_type::data_const_reference Chris@16: operator [] (index_type i) const { Chris@16: return d_ [i]; Chris@16: } Chris@16: Chris@16: // Assignment Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element &operator = (const sparse_storage_element &p) { Chris@16: // Overide the implict copy assignment Chris@16: d_ = p.d_; Chris@16: dirty_ = true; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element &operator = (const D &d) { Chris@16: d_ = d; Chris@16: dirty_ = true; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element &operator += (const D &d) { Chris@16: d_ += d; Chris@16: dirty_ = true; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element &operator -= (const D &d) { Chris@16: d_ -= d; Chris@16: dirty_ = true; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element &operator *= (const D &d) { Chris@16: d_ *= d; Chris@16: dirty_ = true; Chris@16: return *this; Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: sparse_storage_element &operator /= (const D &d) { Chris@16: d_ /= d; Chris@16: dirty_ = true; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Comparison Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: bool operator == (const D &d) const { Chris@16: return d_ == d; Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: bool operator != (const D &d) const { Chris@16: return d_ != d; Chris@16: } Chris@16: Chris@16: // Conversion Chris@16: BOOST_UBLAS_INLINE Chris@16: operator data_const_reference () const { Chris@16: return d_; Chris@16: } Chris@16: Chris@16: // Swapping Chris@16: BOOST_UBLAS_INLINE Chris@16: void swap (sparse_storage_element p) { Chris@16: if (this != &p) { Chris@16: dirty_ = true; Chris@16: p.dirty_ = true; Chris@16: std::swap (d_, p.d_); Chris@16: } Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: friend void swap (sparse_storage_element p1, sparse_storage_element p2) { Chris@16: p1.swap (p2); Chris@16: } Chris@16: Chris@16: private: Chris@16: pointer it_; Chris@16: index_type i_; Chris@16: data_value_type d_; Chris@16: bool dirty_; Chris@16: }; Chris@16: #endif Chris@16: Chris@16: Chris@16: // Default map type is simply forwarded to std::map Chris@16: // FIXME should use ALLOC for map but std::allocator of std::pair and std::pair fail to compile Chris@16: template Chris@16: class map_std : public std::map { Chris@16: public: Chris@16: // Serialization Chris@16: template Chris@16: void serialize(Archive & ar, const unsigned int /* file_version */){ Chris@16: ar & serialization::make_nvp("base", boost::serialization::base_object< std::map >(*this)); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: // Map array Chris@16: // Implementation requires pair allocator definition (without const) Chris@16: template Chris@16: class map_array { Chris@16: public: Chris@16: typedef ALLOC allocator_type; Chris@16: typedef typename ALLOC::size_type size_type; Chris@16: typedef typename ALLOC::difference_type difference_type; Chris@16: typedef std::pair value_type; Chris@16: typedef I key_type; Chris@16: typedef T mapped_type; Chris@16: typedef const value_type &const_reference; Chris@16: typedef value_type &reference; Chris@16: typedef const value_type *const_pointer; Chris@16: typedef value_type *pointer; Chris@16: // Iterators simply are pointers. Chris@16: typedef const_pointer const_iterator; Chris@16: typedef pointer iterator; Chris@16: Chris@16: typedef const T &data_const_reference; Chris@16: #ifndef BOOST_UBLAS_STRICT_MAP_ARRAY Chris@16: typedef T &data_reference; Chris@16: #else Chris@16: typedef sparse_storage_element data_reference; Chris@16: #endif Chris@16: Chris@16: // Construction and destruction Chris@16: BOOST_UBLAS_INLINE Chris@16: map_array (const ALLOC &a = ALLOC()): Chris@16: alloc_(a), capacity_ (0), size_ (0) { Chris@16: data_ = 0; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: map_array (const map_array &c): Chris@16: alloc_ (c.alloc_), capacity_ (c.size_), size_ (c.size_) { Chris@16: if (capacity_) { Chris@16: data_ = alloc_.allocate (capacity_); Chris@16: std::uninitialized_copy (data_, data_ + capacity_, c.data_); Chris@16: // capacity != size_ requires uninitialized_fill (size_ to capacity_) Chris@16: } Chris@16: else Chris@16: data_ = 0; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: ~map_array () { Chris@16: if (capacity_) { Chris@16: std::for_each (data_, data_ + capacity_, static_destroy); Chris@16: alloc_.deallocate (data_, capacity_); Chris@16: } Chris@16: } Chris@16: Chris@16: private: Chris@16: // Resizing - implicitly exposses uninitialized (but default constructed) mapped_type Chris@16: BOOST_UBLAS_INLINE Chris@16: void resize (size_type size) { Chris@16: BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ()); Chris@16: if (size > capacity_) { Chris@16: const size_type capacity = size << 1; Chris@16: BOOST_UBLAS_CHECK (capacity, internal_logic ()); Chris@16: pointer data = alloc_.allocate (capacity); Chris@16: std::uninitialized_copy (data_, data_ + (std::min) (size, size_), data); Chris@16: std::uninitialized_fill (data + (std::min) (size, size_), data + capacity, value_type ()); Chris@16: Chris@16: if (capacity_) { Chris@16: std::for_each (data_, data_ + capacity_, static_destroy); Chris@16: alloc_.deallocate (data_, capacity_); Chris@16: } Chris@16: capacity_ = capacity; Chris@16: data_ = data; Chris@16: } Chris@16: size_ = size; Chris@16: BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ()); Chris@16: } Chris@16: public: Chris@16: Chris@16: // Reserving Chris@16: BOOST_UBLAS_INLINE Chris@16: void reserve (size_type capacity) { Chris@16: BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ()); Chris@16: // Reduce capacity_ if size_ allows Chris@16: BOOST_UBLAS_CHECK (capacity >= size_, bad_size ()); Chris@16: pointer data; Chris@16: if (capacity) { Chris@16: data = alloc_.allocate (capacity); Chris@16: std::uninitialized_copy (data_, data_ + size_, data); Chris@16: std::uninitialized_fill (data + size_, data + capacity, value_type ()); Chris@16: } Chris@16: else Chris@16: data = 0; Chris@16: Chris@16: if (capacity_) { Chris@16: std::for_each (data_, data_ + capacity_, static_destroy); Chris@16: alloc_.deallocate (data_, capacity_); Chris@16: } Chris@16: capacity_ = capacity; Chris@16: data_ = data; Chris@16: BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ()); Chris@16: } Chris@16: Chris@16: // Random Access Container Chris@16: BOOST_UBLAS_INLINE Chris@16: size_type size () const { Chris@16: return size_; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: size_type capacity () const { Chris@16: return capacity_; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: size_type max_size () const { Chris@16: return 0; //TODO Chris@16: } Chris@16: Chris@16: BOOST_UBLAS_INLINE Chris@16: bool empty () const { Chris@16: return size_ == 0; Chris@16: } Chris@16: Chris@16: // Element access Chris@16: BOOST_UBLAS_INLINE Chris@16: data_reference operator [] (key_type i) { Chris@16: #ifndef BOOST_UBLAS_STRICT_MAP_ARRAY Chris@16: pointer it = find (i); Chris@16: if (it == end ()) Chris@16: it = insert (end (), value_type (i, mapped_type (0))); Chris@16: BOOST_UBLAS_CHECK (it != end (), internal_logic ()); Chris@16: return it->second; Chris@16: #else Chris@16: return data_reference (*this, i); Chris@16: #endif Chris@16: } Chris@16: Chris@16: // Assignment Chris@16: BOOST_UBLAS_INLINE Chris@16: map_array &operator = (const map_array &a) { Chris@16: if (this != &a) { Chris@16: resize (a.size_); Chris@16: std::copy (a.data_, a.data_ + a.size_, data_); Chris@16: } Chris@16: return *this; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: map_array &assign_temporary (map_array &a) { Chris@16: swap (a); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // Swapping Chris@16: BOOST_UBLAS_INLINE Chris@16: void swap (map_array &a) { Chris@16: if (this != &a) { Chris@16: std::swap (capacity_, a.capacity_); Chris@16: std::swap (data_, a.data_); Chris@16: std::swap (size_, a.size_); Chris@16: } Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: friend void swap (map_array &a1, map_array &a2) { Chris@16: a1.swap (a2); Chris@16: } Chris@16: Chris@16: // Element insertion and deletion Chris@16: Chris@16: // From Back Insertion Sequence concept Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: iterator push_back (iterator it, const value_type &p) { Chris@16: if (size () == 0 || (it = end () - 1)->first < p.first) { Chris@16: resize (size () + 1); Chris@16: *(it = end () - 1) = p; Chris@16: return it; Chris@16: } Chris@16: external_logic ().raise (); Chris@16: return it; Chris@16: } Chris@16: // Form Unique Associative Container concept Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: std::pair insert (const value_type &p) { Chris@16: iterator it = detail::lower_bound (begin (), end (), p, detail::less_pair ()); Chris@16: if (it != end () && it->first == p.first) Chris@16: return std::make_pair (it, false); Chris@16: difference_type n = it - begin (); Chris@16: resize (size () + 1); Chris@16: it = begin () + n; // allow for invalidation Chris@16: std::copy_backward (it, end () - 1, end ()); Chris@16: *it = p; Chris@16: return std::make_pair (it, true); Chris@16: } Chris@16: // Form Sorted Associative Container concept Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: iterator insert (iterator hint, const value_type &p) { Chris@16: return insert (p).first; Chris@16: } Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: void erase (iterator it) { Chris@16: BOOST_UBLAS_CHECK (begin () <= it && it < end (), bad_index ()); Chris@16: std::copy (it + 1, end (), it); Chris@16: resize (size () - 1); Chris@16: } Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: void erase (iterator it1, iterator it2) { Chris@16: if (it1 == it2) return /* nothing to erase */; Chris@16: BOOST_UBLAS_CHECK (begin () <= it1 && it1 < it2 && it2 <= end (), bad_index ()); Chris@16: std::copy (it2, end (), it1); Chris@16: resize (size () - (it2 - it1)); Chris@16: } Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: void clear () { Chris@16: resize (0); Chris@16: } Chris@16: Chris@16: // Element lookup Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: const_iterator find (key_type i) const { Chris@16: const_iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair ())); Chris@16: if (it == end () || it->first != i) Chris@16: it = end (); Chris@16: return it; Chris@16: } Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: iterator find (key_type i) { Chris@16: iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair ())); Chris@16: if (it == end () || it->first != i) Chris@16: it = end (); Chris@16: return it; Chris@16: } Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: const_iterator lower_bound (key_type i) const { Chris@16: return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair ()); Chris@16: } Chris@16: // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it. Chris@16: iterator lower_bound (key_type i) { Chris@16: return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair ()); Chris@16: } Chris@16: Chris@16: BOOST_UBLAS_INLINE Chris@16: const_iterator begin () const { Chris@16: return data_; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@101: const_iterator cbegin () const { Chris@101: return begin (); Chris@101: } Chris@101: BOOST_UBLAS_INLINE Chris@16: const_iterator end () const { Chris@16: return data_ + size_; Chris@16: } Chris@101: BOOST_UBLAS_INLINE Chris@101: const_iterator cend () const { Chris@101: return end (); Chris@101: } Chris@16: Chris@16: BOOST_UBLAS_INLINE Chris@16: iterator begin () { Chris@16: return data_; Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: iterator end () { Chris@16: return data_ + size_; Chris@16: } Chris@16: Chris@16: // Reverse iterators Chris@16: typedef std::reverse_iterator const_reverse_iterator; Chris@16: typedef std::reverse_iterator reverse_iterator; Chris@16: Chris@16: BOOST_UBLAS_INLINE Chris@16: const_reverse_iterator rbegin () const { Chris@16: return const_reverse_iterator (end ()); Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@101: const_reverse_iterator crbegin () const { Chris@101: return rbegin (); Chris@101: } Chris@101: BOOST_UBLAS_INLINE Chris@16: const_reverse_iterator rend () const { Chris@16: return const_reverse_iterator (begin ()); Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@101: const_reverse_iterator crend () const { Chris@101: return rend (); Chris@101: } Chris@101: Chris@101: BOOST_UBLAS_INLINE Chris@16: reverse_iterator rbegin () { Chris@16: return reverse_iterator (end ()); Chris@16: } Chris@16: BOOST_UBLAS_INLINE Chris@16: reverse_iterator rend () { Chris@16: return reverse_iterator (begin ()); Chris@16: } Chris@16: Chris@16: // Allocator Chris@16: allocator_type get_allocator () { Chris@16: return alloc_; Chris@16: } Chris@16: Chris@16: // Serialization Chris@16: template Chris@16: void serialize(Archive & ar, const unsigned int /* file_version */){ Chris@16: serialization::collection_size_type s (size_); Chris@16: ar & serialization::make_nvp("size",s); Chris@16: if (Archive::is_loading::value) { Chris@16: resize(s); Chris@16: } Chris@16: ar & serialization::make_array(data_, s); Chris@16: } Chris@16: Chris@16: private: Chris@16: // Provide destroy as a non member function Chris@16: BOOST_UBLAS_INLINE Chris@16: static void static_destroy (reference p) { Chris@16: (&p) -> ~value_type (); Chris@16: } Chris@16: ALLOC alloc_; Chris@16: size_type capacity_; Chris@16: pointer data_; Chris@16: size_type size_; Chris@16: }; Chris@16: Chris@16: Chris@16: namespace detail { Chris@16: template Chris@16: struct map_traits { Chris@16: typedef typename A::mapped_type &reference; Chris@16: }; Chris@16: template Chris@16: struct map_traits, T > { Chris@16: typedef typename map_array::data_reference reference; Chris@16: }; Chris@16: Chris@16: // reserve helpers for map_array and generic maps Chris@16: // ISSUE should be in map_traits but want to use on all compilers Chris@16: Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: void map_reserve (M &/* m */, typename M::size_type /* capacity */) { Chris@16: } Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: void map_reserve (map_array &m, typename map_array::size_type capacity) { Chris@16: m.reserve (capacity); Chris@16: } Chris@16: Chris@16: template Chris@16: struct map_capacity_traits { Chris@16: typedef typename M::size_type type ; Chris@16: type operator() ( M const& m ) const { Chris@16: return m.size (); Chris@16: } Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct map_capacity_traits< map_array > { Chris@16: typedef typename map_array::size_type type ; Chris@16: type operator() ( map_array const& m ) const { Chris@16: return m.capacity (); Chris@16: } Chris@16: } ; Chris@16: Chris@16: template Chris@16: BOOST_UBLAS_INLINE Chris@16: typename map_capacity_traits::type map_capacity (M const& m) { Chris@16: return map_capacity_traits() ( m ); Chris@16: } Chris@16: } Chris@16: Chris@16: }}} Chris@16: Chris@16: #endif