storage_sparse.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. //
  2. // Copyright (c) 2000-2002
  3. // Joerg Walter, Mathias Koch
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // The authors gratefully acknowledge the support of
  10. // GeNeSys mbH & Co. KG in producing this work.
  11. //
  12. #ifndef _BOOST_UBLAS_STORAGE_SPARSE_
  13. #define _BOOST_UBLAS_STORAGE_SPARSE_
  14. #include <map>
  15. #include <boost/serialization/collection_size_type.hpp>
  16. #include <boost/serialization/nvp.hpp>
  17. #include <boost/serialization/array.hpp>
  18. #include <boost/serialization/map.hpp>
  19. #include <boost/serialization/base_object.hpp>
  20. #include <boost/numeric/ublas/storage.hpp>
  21. namespace boost { namespace numeric { namespace ublas {
  22. namespace detail {
  23. template<class I, class T, class C>
  24. BOOST_UBLAS_INLINE
  25. I lower_bound (const I &begin, const I &end, const T &t, C compare) {
  26. // t <= *begin <=> ! (*begin < t)
  27. if (begin == end || ! compare (*begin, t))
  28. return begin;
  29. if (compare (*(end - 1), t))
  30. return end;
  31. return std::lower_bound (begin, end, t, compare);
  32. }
  33. template<class I, class T, class C>
  34. BOOST_UBLAS_INLINE
  35. I upper_bound (const I &begin, const I &end, const T &t, C compare) {
  36. if (begin == end || compare (t, *begin))
  37. return begin;
  38. // (*end - 1) <= t <=> ! (t < *end)
  39. if (! compare (t, *(end - 1)))
  40. return end;
  41. return std::upper_bound (begin, end, t, compare);
  42. }
  43. template<class P>
  44. struct less_pair {
  45. BOOST_UBLAS_INLINE
  46. bool operator () (const P &p1, const P &p2) {
  47. return p1.first < p2.first;
  48. }
  49. };
  50. template<class T>
  51. struct less_triple {
  52. BOOST_UBLAS_INLINE
  53. bool operator () (const T &t1, const T &t2) {
  54. return t1.first.first < t2.first.first ||
  55. (t1.first.first == t2.first.first && t1.first.second < t2.first.second);
  56. }
  57. };
  58. }
  59. #ifdef BOOST_UBLAS_STRICT_MAP_ARRAY
  60. template<class A>
  61. class sparse_storage_element:
  62. public container_reference<A> {
  63. public:
  64. typedef A array_type;
  65. typedef typename A::key_type index_type;
  66. typedef typename A::mapped_type data_value_type;
  67. // typedef const data_value_type &data_const_reference;
  68. typedef typename type_traits<data_value_type>::const_reference data_const_reference;
  69. typedef data_value_type &data_reference;
  70. typedef typename A::value_type value_type;
  71. typedef value_type *pointer;
  72. // Construction and destruction
  73. BOOST_UBLAS_INLINE
  74. sparse_storage_element (array_type &a, pointer it):
  75. container_reference<array_type> (a), it_ (it), i_ (it->first), d_ (it->second), dirty_ (false) {}
  76. BOOST_UBLAS_INLINE
  77. sparse_storage_element (array_type &a, index_type i):
  78. container_reference<array_type> (a), it_ (), i_ (i), d_ (), dirty_ (false) {
  79. pointer it = (*this) ().find (i_);
  80. if (it == (*this) ().end ())
  81. it = (*this) ().insert ((*this) ().end (), value_type (i_, d_));
  82. d_ = it->second;
  83. }
  84. BOOST_UBLAS_INLINE
  85. ~sparse_storage_element () {
  86. if (dirty_) {
  87. if (! it_)
  88. it_ = (*this) ().find (i_);
  89. BOOST_UBLAS_CHECK (it_ != (*this) ().end (), internal_logic ());
  90. it_->second = d_;
  91. }
  92. }
  93. // Element access - only if data_const_reference is defined
  94. BOOST_UBLAS_INLINE
  95. typename data_value_type::data_const_reference
  96. operator [] (index_type i) const {
  97. return d_ [i];
  98. }
  99. // Assignment
  100. BOOST_UBLAS_INLINE
  101. sparse_storage_element &operator = (const sparse_storage_element &p) {
  102. // Overide the implict copy assignment
  103. d_ = p.d_;
  104. dirty_ = true;
  105. return *this;
  106. }
  107. template<class D>
  108. BOOST_UBLAS_INLINE
  109. sparse_storage_element &operator = (const D &d) {
  110. d_ = d;
  111. dirty_ = true;
  112. return *this;
  113. }
  114. template<class D>
  115. BOOST_UBLAS_INLINE
  116. sparse_storage_element &operator += (const D &d) {
  117. d_ += d;
  118. dirty_ = true;
  119. return *this;
  120. }
  121. template<class D>
  122. BOOST_UBLAS_INLINE
  123. sparse_storage_element &operator -= (const D &d) {
  124. d_ -= d;
  125. dirty_ = true;
  126. return *this;
  127. }
  128. template<class D>
  129. BOOST_UBLAS_INLINE
  130. sparse_storage_element &operator *= (const D &d) {
  131. d_ *= d;
  132. dirty_ = true;
  133. return *this;
  134. }
  135. template<class D>
  136. BOOST_UBLAS_INLINE
  137. sparse_storage_element &operator /= (const D &d) {
  138. d_ /= d;
  139. dirty_ = true;
  140. return *this;
  141. }
  142. // Comparison
  143. template<class D>
  144. BOOST_UBLAS_INLINE
  145. bool operator == (const D &d) const {
  146. return d_ == d;
  147. }
  148. template<class D>
  149. BOOST_UBLAS_INLINE
  150. bool operator != (const D &d) const {
  151. return d_ != d;
  152. }
  153. // Conversion
  154. BOOST_UBLAS_INLINE
  155. operator data_const_reference () const {
  156. return d_;
  157. }
  158. // Swapping
  159. BOOST_UBLAS_INLINE
  160. void swap (sparse_storage_element p) {
  161. if (this != &p) {
  162. dirty_ = true;
  163. p.dirty_ = true;
  164. std::swap (d_, p.d_);
  165. }
  166. }
  167. BOOST_UBLAS_INLINE
  168. friend void swap (sparse_storage_element p1, sparse_storage_element p2) {
  169. p1.swap (p2);
  170. }
  171. private:
  172. pointer it_;
  173. index_type i_;
  174. data_value_type d_;
  175. bool dirty_;
  176. };
  177. #endif
  178. // Default map type is simply forwarded to std::map
  179. template<class I, class T, class ALLOC>
  180. class map_std : public std::map<I, T, std::less<I>, ALLOC> {
  181. public:
  182. // Serialization
  183. template<class Archive>
  184. void serialize(Archive & ar, const unsigned int /* file_version */){
  185. ar & serialization::make_nvp("base", boost::serialization::base_object< std::map<I, T, std::less<I>, ALLOC> >(*this));
  186. }
  187. };
  188. // Map array
  189. // Implementation requires pair<I, T> allocator definition (without const)
  190. template<class I, class T, class ALLOC>
  191. class map_array {
  192. public:
  193. typedef ALLOC allocator_type;
  194. typedef typename boost::allocator_size_type<ALLOC>::type size_type;
  195. typedef typename boost::allocator_difference_type<ALLOC>::type difference_type;
  196. typedef std::pair<I,T> value_type;
  197. typedef I key_type;
  198. typedef T mapped_type;
  199. typedef const value_type &const_reference;
  200. typedef value_type &reference;
  201. typedef const value_type *const_pointer;
  202. typedef value_type *pointer;
  203. // Iterators simply are pointers.
  204. typedef const_pointer const_iterator;
  205. typedef pointer iterator;
  206. typedef const T &data_const_reference;
  207. #ifndef BOOST_UBLAS_STRICT_MAP_ARRAY
  208. typedef T &data_reference;
  209. #else
  210. typedef sparse_storage_element<map_array> data_reference;
  211. #endif
  212. // Construction and destruction
  213. BOOST_UBLAS_INLINE
  214. map_array (const ALLOC &a = ALLOC()):
  215. alloc_(a), capacity_ (0), size_ (0) {
  216. data_ = 0;
  217. }
  218. BOOST_UBLAS_INLINE
  219. map_array (const map_array &c):
  220. alloc_ (c.alloc_), capacity_ (c.size_), size_ (c.size_) {
  221. if (capacity_) {
  222. data_ = alloc_.allocate (capacity_);
  223. std::uninitialized_copy (data_, data_ + capacity_, c.data_);
  224. // capacity != size_ requires uninitialized_fill (size_ to capacity_)
  225. }
  226. else
  227. data_ = 0;
  228. }
  229. BOOST_UBLAS_INLINE
  230. ~map_array () {
  231. if (capacity_) {
  232. std::for_each (data_, data_ + capacity_, static_destroy);
  233. alloc_.deallocate (data_, capacity_);
  234. }
  235. }
  236. private:
  237. // Resizing - implicitly exposses uninitialized (but default constructed) mapped_type
  238. BOOST_UBLAS_INLINE
  239. void resize (size_type size) {
  240. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  241. if (size > capacity_) {
  242. const size_type capacity = size << 1;
  243. BOOST_UBLAS_CHECK (capacity, internal_logic ());
  244. pointer data = alloc_.allocate (capacity);
  245. std::uninitialized_copy (data_, data_ + (std::min) (size, size_), data);
  246. std::uninitialized_fill (data + (std::min) (size, size_), data + capacity, value_type ());
  247. if (capacity_) {
  248. std::for_each (data_, data_ + capacity_, static_destroy);
  249. alloc_.deallocate (data_, capacity_);
  250. }
  251. capacity_ = capacity;
  252. data_ = data;
  253. }
  254. size_ = size;
  255. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  256. }
  257. public:
  258. // Reserving
  259. BOOST_UBLAS_INLINE
  260. void reserve (size_type capacity) {
  261. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  262. // Reduce capacity_ if size_ allows
  263. BOOST_UBLAS_CHECK (capacity >= size_, bad_size ());
  264. pointer data;
  265. if (capacity) {
  266. data = alloc_.allocate (capacity);
  267. std::uninitialized_copy (data_, data_ + size_, data);
  268. std::uninitialized_fill (data + size_, data + capacity, value_type ());
  269. }
  270. else
  271. data = 0;
  272. if (capacity_) {
  273. std::for_each (data_, data_ + capacity_, static_destroy);
  274. alloc_.deallocate (data_, capacity_);
  275. }
  276. capacity_ = capacity;
  277. data_ = data;
  278. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  279. }
  280. // Random Access Container
  281. BOOST_UBLAS_INLINE
  282. size_type size () const {
  283. return size_;
  284. }
  285. BOOST_UBLAS_INLINE
  286. size_type capacity () const {
  287. return capacity_;
  288. }
  289. BOOST_UBLAS_INLINE
  290. size_type max_size () const {
  291. return 0; //TODO
  292. }
  293. BOOST_UBLAS_INLINE
  294. bool empty () const {
  295. return size_ == 0;
  296. }
  297. // Element access
  298. BOOST_UBLAS_INLINE
  299. data_reference operator [] (key_type i) {
  300. #ifndef BOOST_UBLAS_STRICT_MAP_ARRAY
  301. pointer it = find (i);
  302. if (it == end ())
  303. it = insert (end (), value_type (i, mapped_type (0)));
  304. BOOST_UBLAS_CHECK (it != end (), internal_logic ());
  305. return it->second;
  306. #else
  307. return data_reference (*this, i);
  308. #endif
  309. }
  310. // Assignment
  311. BOOST_UBLAS_INLINE
  312. map_array &operator = (const map_array &a) {
  313. if (this != &a) {
  314. resize (a.size_);
  315. std::copy (a.data_, a.data_ + a.size_, data_);
  316. }
  317. return *this;
  318. }
  319. BOOST_UBLAS_INLINE
  320. map_array &assign_temporary (map_array &a) {
  321. swap (a);
  322. return *this;
  323. }
  324. // Swapping
  325. BOOST_UBLAS_INLINE
  326. void swap (map_array &a) {
  327. if (this != &a) {
  328. std::swap (capacity_, a.capacity_);
  329. std::swap (data_, a.data_);
  330. std::swap (size_, a.size_);
  331. }
  332. }
  333. BOOST_UBLAS_INLINE
  334. friend void swap (map_array &a1, map_array &a2) {
  335. a1.swap (a2);
  336. }
  337. // Element insertion and deletion
  338. // From Back Insertion Sequence concept
  339. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  340. iterator push_back (iterator it, const value_type &p) {
  341. if (size () == 0 || (it = end () - 1)->first < p.first) {
  342. resize (size () + 1);
  343. *(it = end () - 1) = p;
  344. return it;
  345. }
  346. external_logic ().raise ();
  347. return it;
  348. }
  349. // Form Unique Associative Container concept
  350. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  351. std::pair<iterator,bool> insert (const value_type &p) {
  352. iterator it = detail::lower_bound (begin (), end (), p, detail::less_pair<value_type> ());
  353. if (it != end () && it->first == p.first)
  354. return std::make_pair (it, false);
  355. difference_type n = it - begin ();
  356. resize (size () + 1);
  357. it = begin () + n; // allow for invalidation
  358. std::copy_backward (it, end () - 1, end ());
  359. *it = p;
  360. return std::make_pair (it, true);
  361. }
  362. // Form Sorted Associative Container concept
  363. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  364. iterator insert (iterator /*hint*/, const value_type &p) {
  365. return insert (p).first;
  366. }
  367. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  368. void erase (iterator it) {
  369. BOOST_UBLAS_CHECK (begin () <= it && it < end (), bad_index ());
  370. std::copy (it + 1, end (), it);
  371. resize (size () - 1);
  372. }
  373. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  374. void erase (iterator it1, iterator it2) {
  375. if (it1 == it2) return /* nothing to erase */;
  376. BOOST_UBLAS_CHECK (begin () <= it1 && it1 < it2 && it2 <= end (), bad_index ());
  377. std::copy (it2, end (), it1);
  378. resize (size () - (it2 - it1));
  379. }
  380. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  381. void clear () {
  382. resize (0);
  383. }
  384. // Element lookup
  385. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  386. const_iterator find (key_type i) const {
  387. const_iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ()));
  388. if (it == end () || it->first != i)
  389. it = end ();
  390. return it;
  391. }
  392. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  393. iterator find (key_type i) {
  394. iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ()));
  395. if (it == end () || it->first != i)
  396. it = end ();
  397. return it;
  398. }
  399. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  400. const_iterator lower_bound (key_type i) const {
  401. return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ());
  402. }
  403. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  404. iterator lower_bound (key_type i) {
  405. return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ());
  406. }
  407. BOOST_UBLAS_INLINE
  408. const_iterator begin () const {
  409. return data_;
  410. }
  411. BOOST_UBLAS_INLINE
  412. const_iterator cbegin () const {
  413. return begin ();
  414. }
  415. BOOST_UBLAS_INLINE
  416. const_iterator end () const {
  417. return data_ + size_;
  418. }
  419. BOOST_UBLAS_INLINE
  420. const_iterator cend () const {
  421. return end ();
  422. }
  423. BOOST_UBLAS_INLINE
  424. iterator begin () {
  425. return data_;
  426. }
  427. BOOST_UBLAS_INLINE
  428. iterator end () {
  429. return data_ + size_;
  430. }
  431. // Reverse iterators
  432. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  433. typedef std::reverse_iterator<iterator> reverse_iterator;
  434. BOOST_UBLAS_INLINE
  435. const_reverse_iterator rbegin () const {
  436. return const_reverse_iterator (end ());
  437. }
  438. BOOST_UBLAS_INLINE
  439. const_reverse_iterator crbegin () const {
  440. return rbegin ();
  441. }
  442. BOOST_UBLAS_INLINE
  443. const_reverse_iterator rend () const {
  444. return const_reverse_iterator (begin ());
  445. }
  446. BOOST_UBLAS_INLINE
  447. const_reverse_iterator crend () const {
  448. return rend ();
  449. }
  450. BOOST_UBLAS_INLINE
  451. reverse_iterator rbegin () {
  452. return reverse_iterator (end ());
  453. }
  454. BOOST_UBLAS_INLINE
  455. reverse_iterator rend () {
  456. return reverse_iterator (begin ());
  457. }
  458. // Allocator
  459. allocator_type get_allocator () {
  460. return alloc_;
  461. }
  462. // Serialization
  463. template<class Archive>
  464. void serialize(Archive & ar, const unsigned int /* file_version */){
  465. serialization::collection_size_type s (size_);
  466. ar & serialization::make_nvp("size",s);
  467. if (Archive::is_loading::value) {
  468. resize(s);
  469. }
  470. ar & serialization::make_array(data_, s);
  471. }
  472. private:
  473. // Provide destroy as a non member function
  474. BOOST_UBLAS_INLINE
  475. static void static_destroy (reference p) {
  476. (&p) -> ~value_type ();
  477. }
  478. ALLOC alloc_;
  479. size_type capacity_;
  480. pointer data_;
  481. size_type size_;
  482. };
  483. namespace detail {
  484. template<class A, class T>
  485. struct map_traits {
  486. typedef typename A::mapped_type &reference;
  487. };
  488. template<class I, class T, class ALLOC>
  489. struct map_traits<map_array<I, T, ALLOC>, T > {
  490. typedef typename map_array<I, T, ALLOC>::data_reference reference;
  491. };
  492. // reserve helpers for map_array and generic maps
  493. // ISSUE should be in map_traits but want to use on all compilers
  494. template<class M>
  495. BOOST_UBLAS_INLINE
  496. void map_reserve (M &/* m */, typename M::size_type /* capacity */) {
  497. }
  498. template<class I, class T, class ALLOC>
  499. BOOST_UBLAS_INLINE
  500. void map_reserve (map_array<I, T, ALLOC> &m, typename map_array<I, T, ALLOC>::size_type capacity) {
  501. m.reserve (capacity);
  502. }
  503. template<class M>
  504. struct map_capacity_traits {
  505. typedef typename M::size_type type ;
  506. type operator() ( M const& m ) const {
  507. return m.size ();
  508. }
  509. } ;
  510. template<class I, class T, class ALLOC>
  511. struct map_capacity_traits< map_array<I, T, ALLOC> > {
  512. typedef typename map_array<I, T, ALLOC>::size_type type ;
  513. type operator() ( map_array<I, T, ALLOC> const& m ) const {
  514. return m.capacity ();
  515. }
  516. } ;
  517. template<class M>
  518. BOOST_UBLAS_INLINE
  519. typename map_capacity_traits<M>::type map_capacity (M const& m) {
  520. return map_capacity_traits<M>() ( m );
  521. }
  522. }
  523. }}}
  524. #endif