ivl 679
|
00001 /* This file is part of the ivl C++ library <http://image.ntua.gr/ivl>. 00002 A C++ template library extending syntax towards mathematical notation. 00003 00004 Copyright (C) 2012 Yannis Avrithis <iavr@image.ntua.gr> 00005 Copyright (C) 2012 Kimon Kontosis <kimonas@image.ntua.gr> 00006 00007 ivl is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU Lesser General Public License 00009 version 3 as published by the Free Software Foundation. 00010 00011 Alternatively, you can redistribute it and/or modify it under the terms 00012 of the GNU General Public License version 2 as published by the Free 00013 Software Foundation. 00014 00015 ivl is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00018 See the GNU General Public License for more details. 00019 00020 You should have received a copy of the GNU General Public License 00021 and a copy of the GNU Lesser General Public License along 00022 with ivl. If not, see <http://www.gnu.org/licenses/>. */ 00023 00024 00025 namespace array_details { 00026 00027 template<bool IS_CONTENT_RESIZEABLE> 00028 struct slice_tools 00029 { 00030 template<class A> 00031 static void shrink(A& a, size_t j) { } 00032 00033 template<class A_IT> 00034 static size_t cut(A_IT a, size_t, ptrdiff_t, size_t) { return 0; } 00035 }; 00036 00037 template<> 00038 struct slice_tools<true> 00039 { 00040 template<class A> 00041 static void shrink(A& a, size_t j) 00042 { 00043 a.resize(j); 00044 } 00045 00046 template<class A_IT> 00047 static size_t cut(A_IT a, size_t first, ptrdiff_t step, size_t len); 00048 }; 00049 00050 template<class A_IT> 00051 size_t slice_tools<true>::cut(A_IT a, size_t first, ptrdiff_t step, size_t len) 00052 { 00053 // len:length after cut. these specs are not same across specializations. 00054 size_t i = 0; 00055 size_t j = 0; 00056 00057 for(size_t i = 0; j < len && i != first; ++i, ++a) { ++j; } 00058 first += step; 00059 00060 A_IT wa = a; 00061 00062 for(++i, ++a; j < len; ++i, ++a) { 00063 if(i != first) { 00064 *wa = *a; 00065 ++wa; 00066 ++j; 00067 } 00068 else { 00069 first += step; 00070 } 00071 } 00072 00073 return len; 00074 } 00075 00076 } /* namespace array_details */ 00077 00083 template <class T, 00084 class A, 00085 class DERIVED_INFO 00086 > 00087 class array<T, data::slice<A, DERIVED_INFO> > 00088 : 00089 public array_common_base<array<T, 00090 data::slice<A, DERIVED_INFO> > >, 00091 00092 public data::referer<typename types::derive< 00093 array<T, data::slice<A, DERIVED_INFO> > >::type> 00094 { 00095 00096 private: 00097 typedef array_common_base<array<T, 00098 data::slice<A, DERIVED_INFO> > > common_base_class; 00099 00100 typedef typename types::t_if<typename array::is_writeable, 00101 typename A::iterator, 00102 typename A::const_iterator>::type a_best_iterator; 00103 00104 // used to disable some types. TODO: test that not_a_type actually throws an error and 00105 // consider explicitly making the default constructor private. 00106 class not_a_type { }; 00107 00108 typedef typename types::t_and_3< 00109 types::t_not<types::is_const<A> >, 00110 typename A::is_writeable, 00111 typename A::is_resizeable> 00112 ::type is_content_resizeable; 00113 00114 typedef typename array_details:: 00115 slice_tools<array::is_content_resizeable::value> slice_tool; 00116 00117 A* a; 00118 ivl::slice b; 00119 size_t end_el; 00120 00121 protected: 00122 template <class J, class D> 00123 void copy_or_cut(const array<J, D>& o) 00124 { 00125 if(is_content_resizeable::value && 00126 o.begin() == o.end() && b.length > 0) { 00127 00128 size_t newlen_a; 00129 00130 if(b.stride < 0) 00131 newlen_a = slice_tool::cut(a->begin(), 00132 end_el, -b.stride, a->length() - b.length); 00133 else 00134 newlen_a = slice_tool::cut(a->begin(), 00135 b.start, b.stride, a->length() - b.length); 00136 00137 slice_tool::shrink(*a, newlen_a); 00138 00139 b.length = 0; 00140 end_el = b.start; 00141 00142 } else { 00143 static_cast<common_base_class&>(*this).assign_array(o); 00144 } 00145 } 00146 public: 00147 typedef array this_type; 00148 00149 typedef this_type this_array_type; 00150 00151 typedef this_type array_type; 00152 00153 typedef T elem_type; 00154 00155 typedef typename a_best_iterator::reference reference; 00156 typedef typename A::const_reference const_reference; 00157 00158 typedef typename common_base_class::derived_type derived_type; 00159 00160 typedef typename common_base_class::base_class base_class; 00161 00163 typedef size_t size_type; 00164 00165 using base_class::derived; 00166 00168 typename types::t_and_3< 00169 types::t_not<types::is_const<A> >, 00170 typename A::is_writeable, 00171 typename A::is_resizeable> 00172 ::type is_cuttable; 00173 00174 00175 template <bool CONST> 00176 class iterator_type 00177 : public data::data_details:: 00178 rnd_iter_operator_expander<iterator_type<CONST>, T, CONST, 00179 typename types::remove_const< 00180 typename a_best_iterator::reference>::type> 00181 { 00182 private: 00183 template <bool C> friend class iterator_type; 00184 00185 template <class X, class Y, bool C, class Z> 00186 friend class data::data_details::rnd_iter_operator_expander; 00187 00188 template <class X, class Y, bool C, class Z> 00189 friend class data::data_details::iter_operator_expander; 00190 00191 00192 typedef typename types::apply_const<T, types::t_expr<CONST> > 00193 ::type best_value_type; 00194 00195 typedef typename types::apply_const< 00196 typename a_best_iterator::reference, types::t_expr<CONST> > 00197 ::type best_ref_type; 00198 00199 // this class is used to disable specific specialization members 00200 class not_a_type { }; 00201 00202 typedef typename types::t_if<types::t_expr<CONST>, not_a_type, 00203 types::code_word<> >::type invalid_if_const; 00204 00205 typedef typename types::t_if<types::t_expr<CONST>, 00206 typename A::const_iterator, typename A::iterator>::type a_iterator; 00207 00208 a_iterator a; 00209 ptrdiff_t step; 00210 00211 protected: 00212 inline typename types::apply_const<best_ref_type>::type base( 00213 types::code_word<> ok = types::code_word<>()) const 00214 { return (*a); } 00215 //TODO!!!! make it random access only if b is random access 00216 // otherwise make it non-random access. 00217 // make it complain if a is non-random access. 00218 inline best_ref_type base( 00219 invalid_if_const disable = invalid_if_const()) 00220 { return (*a); } 00221 00222 inline typename types::apply_const<best_ref_type>::type base(size_t j, 00223 types::code_word<> ok = types::code_word<>()) const 00224 { return (a[j * step]); } 00225 00226 inline best_ref_type base(size_t j, 00227 invalid_if_const disable = invalid_if_const()) 00228 { return (a[j * step]); } 00229 00230 public: 00231 typedef iterator_type<CONST> this_type; 00232 00233 // iterator_traits 00234 typedef std::random_access_iterator_tag iterator_category; 00235 typedef T value_type; 00236 typedef ptrdiff_t difference_type; 00237 typedef best_value_type* pointer; 00238 typedef best_ref_type reference; 00239 00240 // constructors 00241 iterator_type() { } 00242 iterator_type(const this_type& it) 00243 : a(it.a), step(it.step) { } 00244 template <bool C> 00245 iterator_type(const iterator_type<C>& it) 00246 : a(it.a), step(it.step) { } 00247 iterator_type(const a_iterator& a, ptrdiff_t step) 00248 : a(a), step(step) { } 00249 00250 // members 00251 00252 // increment-decrement 00253 this_type& operator++() { a += step; return *this; } 00254 this_type& operator--() { a -= step; return *this; } 00255 00256 this_type operator++(int) { this_type t(*this); ++(*this); return t; } 00257 this_type operator--(int) { this_type t(*this); --(*this); return t; } 00258 00259 // random access. 00260 00261 // X can be either size_t or B::iter_bound_mover 00262 template<class X> 00263 this_type& operator +=(X j) { a += j * step; return *this; } 00264 00265 template<class X> 00266 this_type& operator -=(X j) { a -= j * step; return *this; } 00267 00268 template<class X> 00269 inline this_type operator +(X j) const 00270 { 00271 this_type tmp(*this); 00272 tmp += j; 00273 return tmp; 00274 } 00275 template<class X> 00276 inline this_type operator -(X j) const 00277 { 00278 this_type tmp(*this); 00279 tmp -= j; 00280 return tmp; 00281 } 00282 00283 // difference. 00284 ptrdiff_t operator-(const this_type& it) 00285 { 00286 return (a - it.a) / step; 00287 } 00288 00289 //copy same type iterator 00290 this_type& operator=(const this_type& it) 00291 { 00292 a = it.a; step = it.step; 00293 return *this; 00294 } 00295 //copy relevant type iterator 00296 template<bool C> 00297 this_type& operator=(const iterator_type<C>& it) 00298 { 00299 a = it.a; step = it.step; 00300 return *this; 00301 } 00302 00303 bool operator==(const this_type& it) const { return (a == it.a); } 00304 bool operator!=(const this_type& it) const { return (a != it.a); } 00305 bool operator<(const this_type& it) const { return (a < it.a); } 00306 bool operator<=(const this_type& it) const { return (a <= it.a); } 00307 bool operator>(const this_type& it) const { return (a > it.a); } 00308 bool operator>=(const this_type& it) const { return (a >= it.a); } 00309 00310 }; 00311 00312 // typedefs for class iterators 00313 typedef typename types::t_if<typename array::is_writeable, 00314 iterator_type<false>, not_a_type>::type iterator; 00315 00316 typedef iterator_type<true> const_iterator; 00317 00318 typedef typename types::t_if<types::t_eq<iterator, not_a_type>, 00319 const_iterator, iterator>::type best_iterator; 00320 00321 typedef std::reverse_iterator<iterator> reverse_iterator; 00322 00323 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 00324 00325 typedef ptrdiff_t iter_border_walker; 00326 00327 iterator begin() 00328 { return best_iterator(a->begin() + b.start, b.stride); } 00329 00330 iterator end() 00331 { return best_iterator(a->begin() + end_el, b.stride); } 00332 00333 const_iterator begin() const 00334 { return const_iterator(a->begin() + b.start, b.stride); } 00335 00336 const_iterator end() const 00337 { return const_iterator(a->begin() + end_el, b.stride); } 00338 00339 // reverse iterator defs 00340 reverse_iterator rbegin() { return reverse_iterator(end()); } 00341 00342 reverse_iterator rend() { return reverse_iterator(begin()); } 00343 00344 const_reverse_iterator rbegin() const 00345 { return const_reverse_iterator(end()); } 00346 00347 const_reverse_iterator rend() const 00348 { return const_reverse_iterator(begin()); } 00349 00350 00351 using common_base_class::operator[]; 00352 00353 // todo: resolve when b has no random access 00354 typename best_iterator::reference operator[](size_t j) 00355 { 00356 return (*a)[b.start + j * b.stride]; 00357 } 00358 typename const_iterator::reference operator[](size_t j) const 00359 { 00360 return (*a)[b.start + j * b.stride]; 00361 } 00362 00365 //TODO: explain this better. 00367 size_t length() const { return b.length; } 00369 size_type size() const { return length(); } 00371 size_t numel() const { return length(); } 00374 iter_border_walker first_to_last() { return b.length - 1; } 00375 iter_border_walker begin_to_end() { return b.length; } 00376 00377 void init(A& a0, const slice& b0) 00378 { 00379 a = &a0; 00380 b = b0; 00381 end_el = b0.start + b0.stride * b0.length; 00382 } 00383 00384 void init(const array& o) 00385 { 00386 a = o.a; 00387 b = o.b; 00388 end_el = o.end_el; 00389 } 00390 00393 00394 array(A& a, const ivl::slice& b) 00395 : a(&a), b(b), end_el(b.start + b.stride * b.length) { } 00396 00398 array(const this_type& o) : a(o.a), b(o.b), end_el(o.end_el) {} 00399 00402 00403 ~array() { } 00404 00405 00409 template <class J, class P> 00410 derived_type& assign_array(const array<J, data::empty<P> >& o) 00411 { 00412 copy_or_cut(o); // will always fallback to cut 00413 return this->derived(); 00414 } 00415 00416 template<class D> 00417 derived_type& assign_array(const D& o) 00418 { 00419 copy_or_cut(o); 00420 return this->derived(); 00421 } 00422 00423 template <class D> 00424 bool overlap(const D& d) const 00425 { 00426 return a->overlap(d); 00427 } 00428 00429 template <class D> 00430 bool self_overlap(const D& d) const 00431 { 00432 return d.overlap(*a); 00433 } 00434 00441 using common_base_class::operator=; 00442 00443 this_type& operator=(const this_type& o) // copy operator 00444 { 00445 copy_or_cut(o); 00446 return *this; 00447 } 00448 00451 }; 00452