File: iterator_zipper.h

package info (click to toggle)
polymake 4.14-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 35,888 kB
  • sloc: cpp: 168,933; perl: 43,407; javascript: 31,575; ansic: 3,007; java: 2,654; python: 632; sh: 268; xml: 117; makefile: 61
file content (400 lines) | stat: -rw-r--r-- 15,706 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/* Copyright (c) 1997-2024
   Ewgenij Gawrilow, Michael Joswig, and the polymake team
   Technische Universität Berlin, Germany
   https://polymake.org

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
--------------------------------------------------------------------------------
*/

#pragma once

#include "polymake/internal/comparators_basic_defs.h"
#include "polymake/ContainerUnion.h"
#include "polymake/internal/operations.h"

namespace pm {

enum {
   zipper_lt = 1, zipper_eq = 2, zipper_gt = 4,       // correspond to 1<<cmp_XX+1
   zipper_cmp = zipper_lt + zipper_eq + zipper_gt,    // mask for all of them
   zipper_first = (zipper_lt << 6),                   // first iterator is in a dereferenceable position
   zipper_second = (zipper_gt << 3),                  // second iterator is ...
   zipper_both = zipper_first + zipper_second         // both are ...
};

struct forward_zipper {
   static constexpr int state(int cmp) { return 1 << 1+cmp; }
};

struct set_union_zipper : forward_zipper {
   static constexpr int stable(int) { return 1; }
   static constexpr bool end1 = false, end2 = false;
   static constexpr bool contains(bool c1, bool c2) { return c1 || c2; }
};

struct set_difference_zipper : forward_zipper {
   static constexpr int stable(int state) { return state & zipper_lt; }
   static constexpr bool end1 = true, end2 = false;
   static constexpr bool contains(bool c1, bool c2) { return c1 && !c2; }
};

struct set_intersection_zipper : forward_zipper {
   static constexpr int stable(int state) { return state & zipper_eq; }
   static constexpr bool end1 = true, end2 = true;
   static constexpr bool contains(bool c1, bool c2) { return c1 && c2; }
};

struct set_symdifference_zipper : forward_zipper {
   static constexpr int stable(int state) { return state & zipper_lt+zipper_gt; }
   static constexpr bool end1 = false, end2 = false;
   static constexpr bool contains(bool c1, bool c2) { return c1 ^ c2; }
};

template <typename Zipper>
struct reverse_zipper : public Zipper {
   static constexpr int state(int cmp) { return 1 << 1-cmp; }
};

template <typename Iterator1, typename Iterator2, typename Comparator, typename Controller,
          bool use_index1 = false, bool use_index2 = false>
class iterator_zipper : public Iterator1 {
public:
   using first_type = Iterator1;
   using second_type = Iterator2;
   using iterator_category = typename least_derived_class<bidirectional_iterator_tag,
                                                          typename iterator_traits<Iterator1>::iterator_category,
                                                          typename iterator_traits<Iterator2>::iterator_category>::type;

   using iterator = iterator_zipper<typename iterator_traits<Iterator1>::iterator, typename iterator_traits<Iterator2>::iterator,
                                    Comparator, Controller, use_index1, use_index2>;
   using const_iterator = iterator_zipper<typename iterator_traits<Iterator1>::const_iterator, typename iterator_traits<Iterator2>::const_iterator,
                                          Comparator, Controller, use_index1, use_index2>;

   Iterator2 second;
protected:
   int state;
   Comparator cmp;
   Controller ctl;

   cmp_value compare(std::false_type, std::false_type) const { return cmp(**this, *second); }
   cmp_value compare(std::false_type, std::true_type) const { return cmp(**this, second.index()); }
   cmp_value compare(std::true_type, std::false_type) const { return cmp(first_type::index(), *second); }
   cmp_value compare(std::true_type, std::true_type) const { return cmp(first_type::index(), second.index()); }

   void compare()
   {
      state &= ~zipper_cmp;
      state += ctl.state(compare(bool_constant<use_index1>(), bool_constant<use_index2>()));
   }

   void incr()
   {
      const int cur_state = state;
      if (cur_state & int(zipper_lt) + int(zipper_eq)) {
         first_type::operator++();
         if (first_type::at_end()) {
            if (ctl.end1) {
               state = 0; return;
            } else {
               state >>= 3;
            }
         }
      }
      if (cur_state & int(zipper_gt) + int(zipper_eq)) {
         ++second;
         if (second.at_end()) {
            if (ctl.end2) {
               state = 0;
            } else {
               state >>= 6;
            }
         }
      }
   }

   void decr()
   {
      const int cur_state = state;
      state = zipper_both;
      if ((cur_state & int(zipper_lt)) == 0)
         first_type::operator--();
      if ((cur_state & int(zipper_gt)) == 0)
         --second;
   }

   void init()
   {
      state = zipper_both;
      if (first_type::at_end()) {
         if (ctl.end1) {
            state = 0; return;
         } else {
            state >>= 3;
         }
      }
      if (second.at_end()) {
         if (ctl.end2) {
            state = 0;
         } else {
            state >>= 6;
         }
         return;
      }
      while (state >= zipper_both) {
         compare();
         if (ctl.stable(state)) break;
         incr();
      }
   }

   template <typename, typename, typename, typename, bool, bool> friend class iterator_zipper;
   template <typename, typename, bool, bool> friend class iterator_product;
public:
   iterator_zipper() : state(0) {}
   iterator_zipper(const iterator& it)
      : first_type(static_cast<const typename iterator::first_type&>(it))
      , second(it.second)
      , state(it.state)
      , ctl(it.ctl) {}

   template <typename SourceIterator1, typename SourceIterator2,
             typename enable=typename std::enable_if<is_const_compatible_with<SourceIterator1, Iterator1>::value &&
                                                     is_const_compatible_with<SourceIterator2, Iterator2>::value>::type>
   iterator_zipper(const SourceIterator1& first_arg, const SourceIterator2& second_arg)
      : first_type(first_arg)
      , second(second_arg)
   {
      init();
   }

   iterator_zipper& operator++ ()
   {
      do {
         incr();
         if (state<zipper_both) break;
         compare();
      } while (!ctl.stable(state));
      return *this;
   }
   const iterator_zipper operator++ (int) { iterator_zipper copy=*this; operator++(); return copy; }

   iterator_zipper& operator-- ()
   {
      static_assert(iterator_pair_traits<Iterator1, Iterator2>::is_bidirectional, "iterator is not bidirectional");
      do {
         decr(); compare();
      } while (!ctl.stable(state));
      return *this;
   }
   const iterator_zipper operator-- (int) { iterator_zipper copy=*this; operator--(); return copy; }

   bool at_end() const { return state==0; }

   template <typename Other>
   std::enable_if_t<is_derived_from_any<Other, iterator, const_iterator>::value, bool>
   operator== (const Other& it) const
   {
      using other_iterator = typename is_derived_from_any<Other, iterator, const_iterator>::match;

      return at_end() ? it.at_end() :
             static_cast<const first_type&>(*this) == static_cast<const typename other_iterator::first_type&>(it)
             && second == static_cast<const other_iterator&>(it).second;
   }

   template <typename Other>
   std::enable_if_t<is_derived_from_any<Other, iterator, const_iterator>::value, bool>
   operator!= (const Other& it) const
   {
      return !operator==(it);
   }

   void rewind()
   {
      static_assert(check_iterator_feature<first_type, rewindable>::value && check_iterator_feature<second_type, rewindable>::value,
                    "iterator is not rewindable");
      first_type::rewind(); second.rewind();
      init();
   }
};

template <typename Iterator1, typename Iterator2, typename Comparator, typename Controller,
          bool use_index1, bool use_index2, typename Feature>
struct check_iterator_feature<iterator_zipper<Iterator1, Iterator2, Comparator, Controller, use_index1, use_index2>, Feature>
   : mlist_and< check_iterator_feature<Iterator1, Feature>,
                check_iterator_feature<Iterator2, Feature> > {};

template <typename Iterator1, typename Iterator2, typename Comparator, typename Controller,
          bool use_index1, bool use_index2>
struct has_partial_state< iterator_zipper<Iterator1, Iterator2, Comparator, Controller, use_index1, use_index2> > : std::true_type {};

template <typename Comparator, typename Controller, bool use_index1 = false, bool use_index2 = false>
struct zipping_coupler {
   template <typename Iterator1, typename Iterator2, typename... ExpectedFeatures>
   struct defs {
      using expected_features = typename mlist_wrap<ExpectedFeatures...>::type;

      using iterator = iterator_zipper<Iterator1, Iterator2, Comparator, Controller, use_index1, use_index2>;

      using needed_features1 = typename mix_features<expected_features,
                                                     typename mlist_prepend_if<use_index1, indexed, end_sensitive>::type >::type;
      using needed_features2 = typename mix_features<expected_features,
                                                     typename mlist_prepend_if<use_index2, indexed, end_sensitive>::type >::type;
   };
};

template <typename Comparator, typename Controller, bool use_index1, bool use_index2>
struct reverse_coupler< zipping_coupler<Comparator, Controller, use_index1, use_index2> > {
   using type = zipping_coupler< Comparator, reverse_zipper<Controller>, use_index1, use_index2>;
};

namespace operations {

template <typename OpRef1, typename OpRef2,
          bool are_equal=same_pure_type<OpRef1,OpRef2>::value,
          bool are_numeric=(std::numeric_limits<typename deref<OpRef1>::type>::is_specialized &&
                            std::numeric_limits<typename deref<OpRef2>::type>::is_specialized)>
struct zipper_helper
   : union_reference<OpRef1, OpRef2> {};

template <typename OpRef1, typename OpRef2>
struct zipper_helper<OpRef1, OpRef2, false, true>
   : add_result<typename deref<OpRef1>::type, typename deref<OpRef2>::type> {};

template <typename Iterator1Ref, typename Iterator2Ref>
struct zipper {
   typedef Iterator1Ref first_argument_type;
   typedef Iterator2Ref second_argument_type;
   typedef typename zipper_helper<typename iterator_traits<typename deref<Iterator1Ref>::type>::reference,
                                  typename iterator_traits<typename deref<Iterator2Ref>::type>::reference>::type
      result_type;

   result_type operator() (first_argument_type l, second_argument_type) const { return *l; }
   result_type operator() (partial_left, first_argument_type l, second_argument_type) const { return *l; }
   result_type operator() (partial_right, first_argument_type, second_argument_type r) const { return *r; }
};

template <typename Iterator1Ref, typename Iterator2Ref>
struct zipper_index {
   typedef Iterator1Ref first_argument_type;
   typedef Iterator2Ref second_argument_type;
   typedef Int result_type;

   result_type operator() (first_argument_type l, second_argument_type) const { return l.index(); }
   result_type operator() (partial_left, first_argument_type l, second_argument_type) const { return l.index(); }
   result_type operator() (partial_right, first_argument_type, second_argument_type r) const { return r.index(); }
};
} // end namespace operations

template <typename IteratorPair, typename Operation>
class binary_transform_eval<IteratorPair, Operation, true>
   : public transform_iterator_base<IteratorPair, Operation>::type {
   using base_t = typename transform_iterator_base<IteratorPair, Operation>::type;
public:
   typedef binary_helper<IteratorPair, Operation> helper;
   typedef typename helper::operation operation;
protected:
   operation op;

   typedef Operation op_arg_type;

   binary_transform_eval() {}

   template <typename Operation2>
   binary_transform_eval(const binary_transform_eval<typename iterator_traits<IteratorPair>::iterator, Operation2, true>& it)
      : base_t(static_cast<const typename std::remove_reference_t<decltype(it)>::base_t&>(it))
      , op(helper::create(it.op)) {}

   template <typename SourceIteratorPair>
   binary_transform_eval(const SourceIteratorPair& cur_arg, const op_arg_type& op_arg)
      : base_t(cur_arg)
      , op(helper::create(op_arg)) {}

   template <typename SourceIterator1, typename SourceIterator2>
   binary_transform_eval(const SourceIterator1& first_arg, const SourceIterator2& second_arg, const op_arg_type& op_arg)
      : base_t(first_arg, second_arg)
      , op(helper::create(op_arg)) {}

   template <typename, typename, bool> friend class binary_transform_eval;
public:
   typedef typename operation::result_type reference;

   reference operator* () const
   {
      if (this->state & zipper_lt)
         return op(operations::partial_left(), *helper::get1(*this), this->second);
      if (this->state & zipper_gt)
         return op(operations::partial_right(),
                   static_cast<const typename IteratorPair::first_type&>(*this), *helper::get2(this->second));
      // (this->state & zipper_eq)
      return op(*helper::get1(*this), *helper::get2(this->second));
   }
};

template <typename IteratorPair, typename Operation, typename IndexOperation>
class binary_transform_eval<IteratorPair, pair<Operation, IndexOperation>, true>
   : public binary_transform_eval<IteratorPair, Operation, true> {
   using base_t = binary_transform_eval<IteratorPair, Operation, true>;
protected:
   typedef binary_helper<IteratorPair,IndexOperation> ihelper;
   typename ihelper::operation iop;
   typedef pair<Operation, IndexOperation> op_arg_type;

   binary_transform_eval() {}

   template <typename Operation2, typename IndexOperation2>
   binary_transform_eval(const binary_transform_eval<typename iterator_traits<IteratorPair>::iterator, pair<Operation2, IndexOperation2>, true>& it)
      : base_t(it)
      , iop(ihelper::create(it.iop)) {}

   template <typename SourceIteratorPair>
   binary_transform_eval(const SourceIteratorPair& cur_arg, const op_arg_type& op_arg)
      : base_t(cur_arg, op_arg.first)
      , iop(ihelper::create(op_arg.second)) {}

   template <typename SourceIterator1, typename SourceIterator2>
   binary_transform_eval(const SourceIterator1& first_arg, const SourceIterator2& second_arg, const op_arg_type& op_arg)
      : base_t(first_arg, second_arg, op_arg.first)
      , iop(ihelper::create(op_arg.second)) {}

   template <typename, typename, bool> friend class binary_transform_eval;

protected:
   Int index_impl(std::false_type) const
   {
      return iop(*ihelper::get1(*this), *ihelper::get2(this->second));
   }

   Int index_impl(std::true_type) const
   {
      if (this->state & zipper_lt)
         return iop(operations::partial_left(), *ihelper::get1(*this), this->second);
      if (this->state & zipper_gt)
         return iop(operations::partial_right(),
                    static_cast<const typename IteratorPair::first_type&>(*this), *ihelper::get2(this->second));
      // (this->state & zipper_eq)
      return index_impl(std::false_type());
   }
public:
   Int index() const
   {
      return index_impl(bool_constant<operations::is_partially_defined<typename ihelper::operation>::value>());
   }
};

} // end namespace pm


// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End: