ivl 679
ivl/details/array/impl/indirect_array.hpp
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 #ifndef IVL_ARRAY_DETAILS_INDIRECT_ARRAY_HPP
00025 #define IVL_ARRAY_DETAILS_INDIRECT_ARRAY_HPP
00026 
00027 namespace ivl {
00028 
00029 template<class A, class B> class indirect_array; // fwd
00030 
00031 namespace array_details {
00032 
00033 // check if the array is already indirect
00034 template <class A, class D>
00035 struct indirect_ref_type_2
00036 {
00037         typedef A type;
00038         typedef types::term idref_type;
00039 };
00040 
00041 template <class A, class AR, class B, class D>
00042 struct indirect_ref_type_2<A, data::indirect<AR, B, D> >
00043 {
00044 //      typedef typename types::apply_const<AR, 
00045 //              typename types::is_const<A>::type>::type type;
00046         typedef AR type;
00047         typedef types::term idref_type;
00048 };
00049 
00050 template <class A, class IS_ARRAY>
00051 struct indirect_ref_type_1
00052 {
00053         typedef A type;
00054         typedef types::term idref_type;
00055 };
00056 
00057 template <class A>
00058 struct indirect_ref_type_1<A, types::t_true>
00059         : public indirect_ref_type_2<A, typename A::data_type>
00060 {
00061 };
00062 
00063 template <class A>
00064 struct indirect_ref_type
00065         : public indirect_ref_type_1<A, typename
00066                 types::is_ivl_array<A>::type>
00067 {
00068 };
00069 
00070 template <class A, class B, class BASE_PLAIN>
00071 struct rebase_indirect_1
00072 {
00073         typedef typename types::bare_type<B>::type b_t;
00074 
00075         //typedef typename b_t::create_new n_t;
00076         typedef typename types::normal_type<b_t>::type n_t;
00077 
00078         typedef typename types::change_elem_type<typename A::elem_type, n_t>::type t1;
00079 
00080         typedef typename types::change_data_class_set<data::indirect<A, B>, t1>::type type;
00081         //typedef array<typename A::elem_type, data::indirect<A, B> > type;
00082 
00083         typedef tuple<A&, const b_t&> data_init_arg;
00084 
00085         static inline A& correct(A& a) { return a; }
00086         static inline const b_t& merge(A& a, const b_t& b) { return b; }
00087 };
00088 
00089 template <class A, class B>
00090 struct rebase_indirect_1<A, B, types::t_false>
00091 {
00092         // This is the case where indices need to be merged.
00093 
00094         typedef typename types::bare_type<B>::type b_t;
00095         // B is either going to be an elem type or a mem type,
00096         // in our case a mem type.
00097         /*
00098         typedef typename types::t_if<types::is_ref<B>,
00099                 typename types::create_similar<b_t>::type, B>
00100                         ::type new_b_t;
00101                 */
00102         typedef typename types::create_similar<b_t>::type new_b_t;
00103 
00104 
00105 
00106         typedef typename types::normal_type<b_t>::type n_t;
00107         typedef typename types::change_elem_type<typename A::elem_type, n_t>::type t1;
00108         typedef typename types::change_data_class_set<data::indirect<typename indirect_ref_type<A>::type, new_b_t>, t1>::type type;
00109 
00110         //typedef indirect_array<typename indirect_ref_type<A>::type, new_b_t> type;
00111 
00112 
00113 
00114         static inline
00115                 typename indirect_ref_type<A>::type& correct(A& a)
00116         {
00117                 return a.get_ref_1();
00118         }
00119         // TODO: (more likely than below)
00120         // instead of elem- solution for merge, differentiate
00121         // indirect<indirect based on whether B is reference.
00122         // when B is stored, use the rebasing and merging approach.
00123         // when B is reference, do not rebase at all, use the original
00124         // data::indirect<data::indirect class that automatically inherits
00125         // and solves merging, even if slower.
00126         // The latter may have its own valid uses, e.g. the indices of
00127         // parent change and the child is dynamically affected.
00128         //
00129         // TODO: should be (in implementation and return type) 
00130         // an elem func to avoid copy
00131         // something like idxmap(b, _[a.get_ref_2()])
00132         // the _[] scalar conversion is to make the second arg scalar.
00133         // maybe when the B type is mem we need mem and when the B type
00134         // is reference we need that elem_func approach.
00135         typedef tuple<typename indirect_ref_type<A>::type&, new_b_t> data_init_arg;
00136 
00137         static inline new_b_t merge(A& a, const b_t& b)
00138                 { return a.merge_idx(b); }       
00139 };
00140 
00141 template <class A, class B>
00142 struct rebase_indirect
00143         : public rebase_indirect_1<A, B, 
00144                 typename types::t_eq<A, typename indirect_ref_type<A>::type>
00145                  ::type>
00146 {
00147 };
00148 
00149 } /* namespace array_details */
00150 
00151 template<class A, class B>
00152 class indirect_array
00153 //: public array<typename A::elem_type, data::indirect<
00154 //      typename array_details::indirect_ref_type<A>::type, B> >
00155 : public array_details::rebase_indirect<A, B>::type
00156 {
00157         typedef typename array_details::indirect_ref_type<A>::type prv_ref_t;
00158         typedef typename array_details::rebase_indirect<A, B>::type prv_base;
00159         typedef typename array_details::rebase_indirect<A, B>::data_init_arg prv_arg;
00160         typedef typename types::bare_type<B>::type b_t;
00161         prv_base& get_prv_base() { return static_cast<prv_base&>(*this); }
00162         const prv_base& get_prv_base() const 
00163                 { return static_cast<const prv_base&>(*this); }
00164         typedef typename types::bare_type<B>::type prv_b;
00165 public:
00166         typedef indirect_array this_type;
00167         typedef typename this_type::array_type base_class;
00168 
00169         base_class& base() { return static_cast<base_class&>(*this); }
00170         const base_class& base() const
00171                 { return static_cast<const base_class&>(*this); }
00172 
00173         // convert temporary object to non-const reference
00174         this_type& ref() { return *this; }
00175 
00176         indirect_array() { }
00177         //indirect_array(const this_type& o) : base_class(o.base()) { }
00178         indirect_array(const this_type& o) : prv_base(o.get_prv_base()) { }
00179 
00180         //indirect_array(const internal::tuple<prv_ref_t&, const B&>& t)
00181         //      : base_class(t.v1, t.v2) { }
00182 
00183         /* nd-spec
00184         template<class I>
00185         indirect_array(const internal::tuple<A&, const I&>& t)
00186                 : prv_base(t.v2.size(), prv_arg(array_details::rebase_indirect<A, B>
00187                                 ::correct(t.v1), 
00188                         array_details::rebase_indirect<A, B>
00189                                 ::merge(t.v1, t.v2))) { }
00190         template<class SZ, class K>
00191         indirect_array(SZ sz, K t) 
00192                 : prv_base(t.v2.size(), prv_arg(array_details::rebase_indirect<A, B>
00193                                 ::correct(t.v1), 
00194                         array_details::rebase_indirect<A, B>
00195                                 ::merge(t.v1, t.v2))) { }
00196 
00197         */
00198 
00199 
00200 
00201         template<class I>
00202         indirect_array(const internal::tuple<A&, I&>& t)
00203                 : prv_base(t.v2.size(), prv_arg(array_details::rebase_indirect<A, B>
00204                                 ::correct(t.v1), 
00205                         array_details::rebase_indirect<A, B>
00206                                 ::merge(t.v1, t.v2))) { }
00207 
00208 
00209         /* old-spec works*/
00210         /*
00211         template<class I>
00212         indirect_array(const internal::tuple<A&, const I&>& t)
00213                 : prv_base(array_details::rebase_indirect<A, B>
00214                                 ::correct(t.v1), 
00215                         array_details::rebase_indirect<A, B>
00216                                 ::merge(t.v1, t.v2)) { }
00217 
00218         indirect_array(A& a, const b_t& b)
00219                 : prv_base(array_details::rebase_indirect<A, B>
00220                                 ::correct(a),
00221                         array_details::rebase_indirect<A, B>
00222                                 ::merge(a, b)) { }
00223                 */
00224         
00225 
00226 
00227 
00228         //template<class P1, class P2>
00229         //template<class T, class I, class J>
00230         //indirect_array(const array<T, data::indirect<A, I, J> >& o)
00231         //      : prv_base(o) { }
00232 
00233         template<class T, class I>
00234         explicit indirect_array(array<T, I>& o) : prv_base(o.derived()) { }
00235 
00236         template<class T, class I>
00237         explicit indirect_array(const array<T, I>& o) : prv_base(o.derived()) { }
00238 
00239 
00240         //indirect_array(A& a)
00241         //      : prv_base(A, 
00242 
00243 
00244         //using base_class::operator=;
00245         this_type& operator=(const this_type& o)
00246         {
00247                 base_class::operator=(o);
00248                 return *this;
00249         }
00250         template<class K>
00251         this_type& operator=(const K& o)
00252         {
00253                 base_class::operator=(o);
00254                 return *this;
00255         }
00256 };
00257 
00258 } /* namespace ivl */
00259 
00260 #endif // IVL_ARRAY_DETAILS_INDIRECT_ARRAY_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations