storage_sparse.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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. // FIXME should use ALLOC for map but std::allocator of std::pair<const I, T> and std::pair<I,T> fail to compile
  180. template<class I, class T, class ALLOC>
  181. class map_std : public std::map<I, T /*, ALLOC */> {
  182. public:
  183. // Serialization
  184. template<class Archive>
  185. void serialize(Archive & ar, const unsigned int /* file_version */){
  186. ar & serialization::make_nvp("base", boost::serialization::base_object< std::map<I, T /*, ALLOC */> >(*this));
  187. }
  188. };
  189. // Map array
  190. // Implementation requires pair<I, T> allocator definition (without const)
  191. template<class I, class T, class ALLOC>
  192. class map_array {
  193. public:
  194. typedef ALLOC allocator_type;
  195. typedef typename ALLOC::size_type size_type;
  196. typedef typename ALLOC::difference_type difference_type;
  197. typedef std::pair<I,T> value_type;
  198. typedef I key_type;
  199. typedef T mapped_type;
  200. typedef const value_type &const_reference;
  201. typedef value_type &reference;
  202. typedef const value_type *const_pointer;
  203. typedef value_type *pointer;
  204. // Iterators simply are pointers.
  205. typedef const_pointer const_iterator;
  206. typedef pointer iterator;
  207. typedef const T &data_const_reference;
  208. #ifndef BOOST_UBLAS_STRICT_MAP_ARRAY
  209. typedef T &data_reference;
  210. #else
  211. typedef sparse_storage_element<map_array> data_reference;
  212. #endif
  213. // Construction and destruction
  214. BOOST_UBLAS_INLINE
  215. map_array (const ALLOC &a = ALLOC()):
  216. alloc_(a), capacity_ (0), size_ (0) {
  217. data_ = 0;
  218. }
  219. BOOST_UBLAS_INLINE
  220. map_array (const map_array &c):
  221. alloc_ (c.alloc_), capacity_ (c.size_), size_ (c.size_) {
  222. if (capacity_) {
  223. data_ = alloc_.allocate (capacity_);
  224. std::uninitialized_copy (data_, data_ + capacity_, c.data_);
  225. // capacity != size_ requires uninitialized_fill (size_ to capacity_)
  226. }
  227. else
  228. data_ = 0;
  229. }
  230. BOOST_UBLAS_INLINE
  231. ~map_array () {
  232. if (capacity_) {
  233. std::for_each (data_, data_ + capacity_, static_destroy);
  234. alloc_.deallocate (data_, capacity_);
  235. }
  236. }
  237. private:
  238. // Resizing - implicitly exposses uninitialized (but default constructed) mapped_type
  239. BOOST_UBLAS_INLINE
  240. void resize (size_type size) {
  241. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  242. if (size > capacity_) {
  243. const size_type capacity = size << 1;
  244. BOOST_UBLAS_CHECK (capacity, internal_logic ());
  245. pointer data = alloc_.allocate (capacity);
  246. std::uninitialized_copy (data_, data_ + (std::min) (size, size_), data);
  247. std::uninitialized_fill (data + (std::min) (size, size_), data + capacity, value_type ());
  248. if (capacity_) {
  249. std::for_each (data_, data_ + capacity_, static_destroy);
  250. alloc_.deallocate (data_, capacity_);
  251. }
  252. capacity_ = capacity;
  253. data_ = data;
  254. }
  255. size_ = size;
  256. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  257. }
  258. public:
  259. // Reserving
  260. BOOST_UBLAS_INLINE
  261. void reserve (size_type capacity) {
  262. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  263. // Reduce capacity_ if size_ allows
  264. BOOST_UBLAS_CHECK (capacity >= size_, bad_size ());
  265. pointer data;
  266. if (capacity) {
  267. data = alloc_.allocate (capacity);
  268. std::uninitialized_copy (data_, data_ + size_, data);
  269. std::uninitialized_fill (data + size_, data + capacity, value_type ());
  270. }
  271. else
  272. data = 0;
  273. if (capacity_) {
  274. std::for_each (data_, data_ + capacity_, static_destroy);
  275. alloc_.deallocate (data_, capacity_);
  276. }
  277. capacity_ = capacity;
  278. data_ = data;
  279. BOOST_UBLAS_CHECK (size_ <= capacity_, internal_logic ());
  280. }
  281. // Random Access Container
  282. BOOST_UBLAS_INLINE
  283. size_type size () const {
  284. return size_;
  285. }
  286. BOOST_UBLAS_INLINE
  287. size_type capacity () const {
  288. return capacity_;
  289. }
  290. BOOST_UBLAS_INLINE
  291. size_type max_size () const {
  292. return 0; //TODO
  293. }
  294. BOOST_UBLAS_INLINE
  295. bool empty () const {
  296. return size_ == 0;
  297. }
  298. // Element access
  299. BOOST_UBLAS_INLINE
  300. data_reference operator [] (key_type i) {
  301. #ifndef BOOST_UBLAS_STRICT_MAP_ARRAY
  302. pointer it = find (i);
  303. if (it == end ())
  304. it = insert (end (), value_type (i, mapped_type (0)));
  305. BOOST_UBLAS_CHECK (it != end (), internal_logic ());
  306. return it->second;
  307. #else
  308. return data_reference (*this, i);
  309. #endif
  310. }
  311. // Assignment
  312. BOOST_UBLAS_INLINE
  313. map_array &operator = (const map_array &a) {
  314. if (this != &a) {
  315. resize (a.size_);
  316. std::copy (a.data_, a.data_ + a.size_, data_);
  317. }
  318. return *this;
  319. }
  320. BOOST_UBLAS_INLINE
  321. map_array &assign_temporary (map_array &a) {
  322. swap (a);
  323. return *this;
  324. }
  325. // Swapping
  326. BOOST_UBLAS_INLINE
  327. void swap (map_array &a) {
  328. if (this != &a) {
  329. std::swap (capacity_, a.capacity_);
  330. std::swap (data_, a.data_);
  331. std::swap (size_, a.size_);
  332. }
  333. }
  334. BOOST_UBLAS_INLINE
  335. friend void swap (map_array &a1, map_array &a2) {
  336. a1.swap (a2);
  337. }
  338. // Element insertion and deletion
  339. // From Back Insertion Sequence concept
  340. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  341. iterator push_back (iterator it, const value_type &p) {
  342. if (size () == 0 || (it = end () - 1)->first < p.first) {
  343. resize (size () + 1);
  344. *(it = end () - 1) = p;
  345. return it;
  346. }
  347. external_logic ().raise ();
  348. return it;
  349. }
  350. // Form Unique Associative Container concept
  351. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  352. std::pair<iterator,bool> insert (const value_type &p) {
  353. iterator it = detail::lower_bound (begin (), end (), p, detail::less_pair<value_type> ());
  354. if (it != end () && it->first == p.first)
  355. return std::make_pair (it, false);
  356. difference_type n = it - begin ();
  357. resize (size () + 1);
  358. it = begin () + n; // allow for invalidation
  359. std::copy_backward (it, end () - 1, end ());
  360. *it = p;
  361. return std::make_pair (it, true);
  362. }
  363. // Form Sorted Associative Container concept
  364. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  365. iterator insert (iterator hint, const value_type &p) {
  366. return insert (p).first;
  367. }
  368. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  369. void erase (iterator it) {
  370. BOOST_UBLAS_CHECK (begin () <= it && it < end (), bad_index ());
  371. std::copy (it + 1, end (), it);
  372. resize (size () - 1);
  373. }
  374. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  375. void erase (iterator it1, iterator it2) {
  376. if (it1 == it2) return /* nothing to erase */;
  377. BOOST_UBLAS_CHECK (begin () <= it1 && it1 < it2 && it2 <= end (), bad_index ());
  378. std::copy (it2, end (), it1);
  379. resize (size () - (it2 - it1));
  380. }
  381. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  382. void clear () {
  383. resize (0);
  384. }
  385. // Element lookup
  386. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  387. const_iterator find (key_type i) const {
  388. const_iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ()));
  389. if (it == end () || it->first != i)
  390. it = end ();
  391. return it;
  392. }
  393. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  394. iterator find (key_type i) {
  395. iterator it (detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ()));
  396. if (it == end () || it->first != i)
  397. it = end ();
  398. return it;
  399. }
  400. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  401. const_iterator lower_bound (key_type i) const {
  402. return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ());
  403. }
  404. // BOOST_UBLAS_INLINE This function seems to be big. So we do not let the compiler inline it.
  405. iterator lower_bound (key_type i) {
  406. return detail::lower_bound (begin (), end (), value_type (i, mapped_type (0)), detail::less_pair<value_type> ());
  407. }
  408. BOOST_UBLAS_INLINE
  409. const_iterator begin () const {
  410. return data_;
  411. }
  412. BOOST_UBLAS_INLINE
  413. const_iterator end () const {
  414. return data_ + size_;
  415. }
  416. BOOST_UBLAS_INLINE
  417. iterator begin () {
  418. return data_;
  419. }
  420. BOOST_UBLAS_INLINE
  421. iterator end () {
  422. return data_ + size_;
  423. }
  424. // Reverse iterators
  425. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  426. typedef std::reverse_iterator<iterator> reverse_iterator;
  427. BOOST_UBLAS_INLINE
  428. const_reverse_iterator rbegin () const {
  429. return const_reverse_iterator (end ());
  430. }
  431. BOOST_UBLAS_INLINE
  432. const_reverse_iterator rend () const {
  433. return const_reverse_iterator (begin ());
  434. }
  435. BOOST_UBLAS_INLINE
  436. reverse_iterator rbegin () {
  437. return reverse_iterator (end ());
  438. }
  439. BOOST_UBLAS_INLINE
  440. reverse_iterator rend () {
  441. return reverse_iterator (begin ());
  442. }
  443. // Allocator
  444. allocator_type get_allocator () {
  445. return alloc_;
  446. }
  447. // Serialization
  448. template<class Archive>
  449. void serialize(Archive & ar, const unsigned int /* file_version */){
  450. serialization::collection_size_type s (size_);
  451. ar & serialization::make_nvp("size",s);
  452. if (Archive::is_loading::value) {
  453. resize(s);
  454. }
  455. ar & serialization::make_array(data_, s);
  456. }
  457. private:
  458. // Provide destroy as a non member function
  459. BOOST_UBLAS_INLINE
  460. static void static_destroy (reference p) {
  461. (&p) -> ~value_type ();
  462. }
  463. ALLOC alloc_;
  464. size_type capacity_;
  465. pointer data_;
  466. size_type size_;
  467. };
  468. namespace detail {
  469. template<class A, class T>
  470. struct map_traits {
  471. typedef typename A::mapped_type &reference;
  472. };
  473. template<class I, class T, class ALLOC>
  474. struct map_traits<map_array<I, T, ALLOC>, T > {
  475. typedef typename map_array<I, T, ALLOC>::data_reference reference;
  476. };
  477. // reserve helpers for map_array and generic maps
  478. // ISSUE should be in map_traits but want to use on all compilers
  479. template<class M>
  480. BOOST_UBLAS_INLINE
  481. void map_reserve (M &/* m */, typename M::size_type /* capacity */) {
  482. }
  483. template<class I, class T, class ALLOC>
  484. BOOST_UBLAS_INLINE
  485. void map_reserve (map_array<I, T, ALLOC> &m, typename map_array<I, T, ALLOC>::size_type capacity) {
  486. m.reserve (capacity);
  487. }
  488. template<class M>
  489. struct map_capacity_traits {
  490. typedef typename M::size_type type ;
  491. type operator() ( M const& m ) const {
  492. return m.size ();
  493. }
  494. } ;
  495. template<class I, class T, class ALLOC>
  496. struct map_capacity_traits< map_array<I, T, ALLOC> > {
  497. typedef typename map_array<I, T, ALLOC>::size_type type ;
  498. type operator() ( map_array<I, T, ALLOC> const& m ) const {
  499. return m.capacity ();
  500. }
  501. } ;
  502. template<class M>
  503. BOOST_UBLAS_INLINE
  504. typename map_capacity_traits<M>::type map_capacity (M const& m) {
  505. return map_capacity_traits<M>() ( m );
  506. }
  507. }
  508. }}}
  509. #endif