• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2018  Google, Inc.
3  * Copyright © 2019  Facebook, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Google Author(s): Behdad Esfahbod
26  * Facebook Author(s): Behdad Esfahbod
27  */
28 
29 #ifndef HB_ITER_HH
30 #define HB_ITER_HH
31 
32 #include "hb.hh"
33 #include "hb-algs.hh"
34 #include "hb-meta.hh"
35 
36 
37 /* Unified iterator object.
38  *
39  * The goal of this template is to make the same iterator interface
40  * available to all types, and make it very easy and compact to use.
41  * hb_iter_tator objects are small, light-weight, objects that can be
42  * copied by value.  If the collection / object being iterated on
43  * is writable, then the iterator returns lvalues, otherwise it
44  * returns rvalues.
45  *
46  * TODO Document more.
47  *
48  * If iterator implementation implements operator!=, then can be
49  * used in range-based for loop.  That comes free if the iterator
50  * is random-access.  Otherwise, the range-based for loop incurs
51  * one traversal to find end(), which can be avoided if written
52  * as a while-style for loop, or if iterator implements a faster
53  * __end__() method.
54  * TODO When opting in for C++17, address this by changing return
55  * type of .end()?
56  */
57 
58 /*
59  * Base classes for iterators.
60  */
61 
62 /* Base class for all iterators. */
63 template <typename iter_t, typename Item = typename iter_t::__item_t__>
64 struct hb_iter_t
65 {
66   typedef Item item_t;
67   static constexpr unsigned item_size = hb_static_size (Item);
68   static constexpr bool is_iterator = true;
69   static constexpr bool is_random_access_iterator = false;
70   static constexpr bool is_sorted_iterator = false;
71 
72   private:
73   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
thizhb_iter_t74   const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
thizhb_iter_t75         iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
76   public:
77 
78   /* TODO:
79    * Port operators below to use hb_enable_if to sniff which method implements
80    * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
81 
82   /* Operators. */
iterhb_iter_t83   iter_t iter () const { return *thiz(); }
operator +hb_iter_t84   iter_t operator + () const { return *thiz(); }
beginhb_iter_t85   iter_t begin () const { return *thiz(); }
endhb_iter_t86   iter_t end () const { return thiz()->__end__ (); }
operator boolhb_iter_t87   explicit operator bool () const { return thiz()->__more__ (); }
lenhb_iter_t88   unsigned len () const { return thiz()->__len__ (); }
89   /* The following can only be enabled if item_t is reference type.  Otherwise
90    * it will be returning pointer to temporary rvalue.
91    * TODO Use a wrapper return type to fix for non-reference type. */
92   template <typename T = item_t,
93 	    hb_enable_if (hb_is_reference (T))>
operator ->hb_iter_t94   hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
operator *hb_iter_t95   item_t operator * () const { return thiz()->__item__ (); }
operator *hb_iter_t96   item_t operator * () { return thiz()->__item__ (); }
operator []hb_iter_t97   item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
operator []hb_iter_t98   item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
operator +=hb_iter_t99   iter_t& operator += (unsigned count) &  { thiz()->__forward__ (count); return *thiz(); }
operator +=hb_iter_t100   iter_t  operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
operator ++hb_iter_t101   iter_t& operator ++ () &  { thiz()->__next__ (); return *thiz(); }
operator ++hb_iter_t102   iter_t  operator ++ () && { thiz()->__next__ (); return *thiz(); }
operator -=hb_iter_t103   iter_t& operator -= (unsigned count) &  { thiz()->__rewind__ (count); return *thiz(); }
operator -=hb_iter_t104   iter_t  operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
operator --hb_iter_t105   iter_t& operator -- () &  { thiz()->__prev__ (); return *thiz(); }
operator --hb_iter_t106   iter_t  operator -- () && { thiz()->__prev__ (); return *thiz(); }
operator +hb_iter_t107   iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
operator +(unsigned count,const iter_t & it)108   friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
operator ++hb_iter_t109   iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
operator -hb_iter_t110   iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
operator --hb_iter_t111   iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
112   template <typename T>
operator >>hb_iter_t113   iter_t& operator >> (T &v) &  { v = **thiz(); ++*thiz(); return *thiz(); }
114   template <typename T>
operator >>hb_iter_t115   iter_t  operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
116   template <typename T>
operator <<hb_iter_t117   iter_t& operator << (const T v) &  { **thiz() = v; ++*thiz(); return *thiz(); }
118   template <typename T>
operator <<hb_iter_t119   iter_t  operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
120 
121   protected:
122   hb_iter_t () = default;
123   hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
124   hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
125   hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
126   hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
127 };
128 
129 #define HB_ITER_USING(Name) \
130   using item_t = typename Name::item_t; \
131   using Name::begin; \
132   using Name::end; \
133   using Name::item_size; \
134   using Name::is_iterator; \
135   using Name::iter; \
136   using Name::operator bool; \
137   using Name::len; \
138   using Name::operator ->; \
139   using Name::operator *; \
140   using Name::operator []; \
141   using Name::operator +=; \
142   using Name::operator ++; \
143   using Name::operator -=; \
144   using Name::operator --; \
145   using Name::operator +; \
146   using Name::operator -; \
147   using Name::operator >>; \
148   using Name::operator <<; \
149   static_assert (true, "")
150 
151 /* Returns iterator / item type of a type. */
152 template <typename Iterable>
153 using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
154 template <typename Iterable>
155 using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
156 
157 
158 template <typename> struct hb_array_t;
159 
160 struct
161 {
162   template <typename T> hb_iter_type<T>
operator ()__anon7feb0be90108163   operator () (T&& c) const
164   { return hb_deref (hb_forward<T> (c)).iter (); }
165 
166   /* Specialization for C arrays. */
167 
168   template <typename Type> inline hb_array_t<Type>
operator ()__anon7feb0be90108169   operator () (Type *array, unsigned int length) const
170   { return hb_array_t<Type> (array, length); }
171 
172   template <typename Type, unsigned int length> hb_array_t<Type>
operator ()__anon7feb0be90108173   operator () (Type (&array)[length]) const
174   { return hb_array_t<Type> (array, length); }
175 
176 }
177 HB_FUNCOBJ (hb_iter);
178 
179 /* Mixin to fill in what the subclass doesn't provide. */
180 template <typename iter_t, typename item_t = typename iter_t::__item_t__>
181 struct hb_iter_fallback_mixin_t
182 {
183   private:
184   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
thizhb_iter_fallback_mixin_t185   const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
thizhb_iter_fallback_mixin_t186         iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
187   public:
188 
189   /* Access: Implement __item__(), or __item_at__() if random-access. */
__item__hb_iter_fallback_mixin_t190   item_t __item__ () const { return (*thiz())[0]; }
__item_at__hb_iter_fallback_mixin_t191   item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
192 
193   /* Termination: Implement __more__(), or __len__() if random-access. */
__more__hb_iter_fallback_mixin_t194   bool __more__ () const { return bool (thiz()->len ()); }
__len__hb_iter_fallback_mixin_t195   unsigned __len__ () const
196   { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
197 
198   /* Advancing: Implement __next__(), or __forward__() if random-access. */
__next__hb_iter_fallback_mixin_t199   void __next__ () { *thiz() += 1; }
__forward__hb_iter_fallback_mixin_t200   void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
201 
202   /* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
__prev__hb_iter_fallback_mixin_t203   void __prev__ () { *thiz() -= 1; }
__rewind__hb_iter_fallback_mixin_t204   void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
205 
206   /* Range-based for: Implement __end__() if can be done faster,
207    * and operator!=. */
__end__hb_iter_fallback_mixin_t208   iter_t __end__ () const
209   {
210     if (thiz()->is_random_access_iterator)
211       return *thiz() + thiz()->len ();
212     /* Above expression loops twice. Following loops once. */
213     auto it = *thiz();
214     while (it) ++it;
215     return it;
216   }
217 
218   protected:
219   hb_iter_fallback_mixin_t () = default;
220   hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
221   hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
222   hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
223   hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
224 };
225 
226 template <typename iter_t, typename item_t = typename iter_t::__item_t__>
227 struct hb_iter_with_fallback_t :
228   hb_iter_t<iter_t, item_t>,
229   hb_iter_fallback_mixin_t<iter_t, item_t>
230 {
231   protected:
232   hb_iter_with_fallback_t () = default;
233   hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
234   hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
235   hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
236   hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
237 };
238 
239 /*
240  * Meta-programming predicates.
241  */
242 
243 /* hb_is_iterator() / hb_is_iterator_of() */
244 
245 template<typename Iter, typename Item>
246 struct hb_is_iterator_of
247 {
248   template <typename Item2 = Item>
249   static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
250   static hb_false_type impl (hb_priority<0>, const void *);
251 
252   public:
253   static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
254 };
255 #define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
256 #define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
257 
258 /* hb_is_iterable() */
259 
260 template <typename T>
261 struct hb_is_iterable
262 {
263   private:
264 
265   template <typename U>
266   static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
267 
268   template <typename>
269   static hb_false_type impl (hb_priority<0>);
270 
271   public:
272   static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
273 };
274 #define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
275 
276 /* hb_is_source_of() / hb_is_sink_of() */
277 
278 template<typename Iter, typename Item>
279 struct hb_is_source_of
280 {
281   private:
282   template <typename Iter2 = Iter,
283 	    hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
284   static hb_true_type impl (hb_priority<2>);
285   template <typename Iter2 = Iter>
286   static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
287   static hb_false_type impl (hb_priority<0>);
288 
289   public:
290   static constexpr bool value = decltype (impl (hb_prioritize))::value;
291 };
292 #define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
293 
294 template<typename Iter, typename Item>
295 struct hb_is_sink_of
296 {
297   private:
298   template <typename Iter2 = Iter,
299 	    hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
300   static hb_true_type impl (hb_priority<2>);
301   template <typename Iter2 = Iter>
302   static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
303   static hb_false_type impl (hb_priority<0>);
304 
305   public:
306   static constexpr bool value = decltype (impl (hb_prioritize))::value;
307 };
308 #define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
309 
310 /* This is commonly used, so define: */
311 #define hb_is_sorted_source_of(Iter, Item) \
312 	(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
313 
314 
315 /* Range-based 'for' for iterables. */
316 
317 template <typename Iterable,
318 	  hb_requires (hb_is_iterable (Iterable))>
319 static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
320 
321 template <typename Iterable,
322 	  hb_requires (hb_is_iterable (Iterable))>
323 static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
324 
325 /* begin()/end() are NOT looked up non-ADL.  So each namespace must declare them.
326  * Do it for namespace OT. */
327 namespace OT {
328 
329 template <typename Iterable,
330 	  hb_requires (hb_is_iterable (Iterable))>
331 static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
332 
333 template <typename Iterable,
334 	  hb_requires (hb_is_iterable (Iterable))>
335 static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
336 
337 }
338 
339 
340 /*
341  * Adaptors, combiners, etc.
342  */
343 
344 template <typename Lhs, typename Rhs,
345 	  hb_requires (hb_is_iterator (Lhs))>
346 static inline auto
347 operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
348 
349 /* hb_map(), hb_filter(), hb_reduce() */
350 
351 enum  class hb_function_sortedness_t {
352   NOT_SORTED,
353   RETAINS_SORTING,
354   SORTED,
355 };
356 
357 template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
358 	 hb_requires (hb_is_iterator (Iter))>
359 struct hb_map_iter_t :
360   hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
361 	    decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
362 {
hb_map_iter_thb_map_iter_t363   hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
364 
365   typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
366   static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
367   static constexpr bool is_sorted_iterator =
368     Sorted == hb_function_sortedness_t::SORTED ? true :
369     Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
370     false;
__item__hb_map_iter_t371   __item_t__ __item__ () const { return hb_get (f.get (), *it); }
__item_at__hb_map_iter_t372   __item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
__more__hb_map_iter_t373   bool __more__ () const { return bool (it); }
__len__hb_map_iter_t374   unsigned __len__ () const { return it.len (); }
__next__hb_map_iter_t375   void __next__ () { ++it; }
__forward__hb_map_iter_t376   void __forward__ (unsigned n) { it += n; }
__prev__hb_map_iter_t377   void __prev__ () { --it; }
__rewind__hb_map_iter_t378   void __rewind__ (unsigned n) { it -= n; }
__end__hb_map_iter_t379   hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
operator !=hb_map_iter_t380   bool operator != (const hb_map_iter_t& o) const
381   { return it != o.it; }
382 
383   private:
384   Iter it;
385   hb_reference_wrapper<Proj> f;
386 };
387 
388 template <typename Proj, hb_function_sortedness_t Sorted>
389 struct hb_map_iter_factory_t
390 {
hb_map_iter_factory_thb_map_iter_factory_t391   hb_map_iter_factory_t (Proj f) : f (f) {}
392 
393   template <typename Iter,
394 	    hb_requires (hb_is_iterator (Iter))>
395   hb_map_iter_t<Iter, Proj, Sorted>
operator ()hb_map_iter_factory_t396   operator () (Iter it)
397   { return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
398 
399   private:
400   Proj f;
401 };
402 struct
403 {
404   template <typename Proj>
405   hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
operator ()__anon7feb0be90208406   operator () (Proj&& f) const
407   { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
408 }
409 HB_FUNCOBJ (hb_map);
410 struct
411 {
412   template <typename Proj>
413   hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
operator ()__anon7feb0be90308414   operator () (Proj&& f) const
415   { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
416 }
417 HB_FUNCOBJ (hb_map_retains_sorting);
418 struct
419 {
420   template <typename Proj>
421   hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
operator ()__anon7feb0be90408422   operator () (Proj&& f) const
423   { return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
424 }
425 HB_FUNCOBJ (hb_map_sorted);
426 
427 template <typename Iter, typename Pred, typename Proj,
428 	 hb_requires (hb_is_iterator (Iter))>
429 struct hb_filter_iter_t :
430   hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
431 			  typename Iter::item_t>
432 {
hb_filter_iter_thb_filter_iter_t433   hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
434   { while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
435 
436   typedef typename Iter::item_t __item_t__;
437   static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
__item__hb_filter_iter_t438   __item_t__ __item__ () const { return *it; }
__more__hb_filter_iter_t439   bool __more__ () const { return bool (it); }
__next__hb_filter_iter_t440   void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
__prev__hb_filter_iter_t441   void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
__end__hb_filter_iter_t442   hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
operator !=hb_filter_iter_t443   bool operator != (const hb_filter_iter_t& o) const
444   { return it != o.it; }
445 
446   private:
447   Iter it;
448   hb_reference_wrapper<Pred> p;
449   hb_reference_wrapper<Proj> f;
450 };
451 template <typename Pred, typename Proj>
452 struct hb_filter_iter_factory_t
453 {
hb_filter_iter_factory_thb_filter_iter_factory_t454   hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
455 
456   template <typename Iter,
457 	    hb_requires (hb_is_iterator (Iter))>
458   hb_filter_iter_t<Iter, Pred, Proj>
operator ()hb_filter_iter_factory_t459   operator () (Iter it)
460   { return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
461 
462   private:
463   Pred p;
464   Proj f;
465 };
466 struct
467 {
468   template <typename Pred = decltype ((hb_identity)),
469 	    typename Proj = decltype ((hb_identity))>
470   hb_filter_iter_factory_t<Pred, Proj>
operator ()__anon7feb0be90508471   operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
472   { return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
473 }
474 HB_FUNCOBJ (hb_filter);
475 
476 template <typename Redu, typename InitT>
477 struct hb_reduce_t
478 {
hb_reduce_thb_reduce_t479   hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
480 
481   template <typename Iter,
482 	    hb_requires (hb_is_iterator (Iter)),
483 	    typename AccuT = decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>
484   AccuT
operator ()hb_reduce_t485   operator () (Iter it)
486   {
487     AccuT value = init_value;
488     for (; it; ++it)
489       value = r (value, *it);
490     return value;
491   }
492 
493   private:
494   Redu r;
495   InitT init_value;
496 };
497 struct
498 {
499   template <typename Redu, typename InitT>
500   hb_reduce_t<Redu, InitT>
operator ()__anon7feb0be90608501   operator () (Redu&& r, InitT init_value) const
502   { return hb_reduce_t<Redu, InitT> (r, init_value); }
503 }
504 HB_FUNCOBJ (hb_reduce);
505 
506 
507 /* hb_zip() */
508 
509 template <typename A, typename B>
510 struct hb_zip_iter_t :
511   hb_iter_t<hb_zip_iter_t<A, B>,
512 	    hb_pair_t<typename A::item_t, typename B::item_t>>
513 {
hb_zip_iter_thb_zip_iter_t514   hb_zip_iter_t () {}
hb_zip_iter_thb_zip_iter_t515   hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
516 
517   typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
518   static constexpr bool is_random_access_iterator =
519     A::is_random_access_iterator &&
520     B::is_random_access_iterator;
521   /* Note.  The following categorization is only valid if A is strictly sorted,
522    * ie. does NOT have duplicates.  Previously I tried to categorize sortedness
523    * more granularly, see commits:
524    *
525    *   513762849a683914fc266a17ddf38f133cccf072
526    *   4d3cf2adb669c345cc43832d11689271995e160a
527    *
528    * However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
529    * SortedArrayOf, etc all needed to be updated to add more variants.  At that
530    * point I saw it not worth the effort, and instead we now deem all sorted
531    * collections as essentially strictly-sorted for the purposes of zip.
532    *
533    * The above assumption is not as bad as it sounds.  Our "sorted" comes with
534    * no guarantees.  It's just a contract, put in place to help you remember,
535    * and think about, whether an iterator you receive is expected to be
536    * sorted or not.  As such, it's not perfect by definition, and should not
537    * be treated so.  The inaccuracy here just errs in the direction of being
538    * more permissive, so your code compiles instead of erring on the side of
539    * marking your zipped iterator unsorted in which case your code won't
540    * compile.
541    *
542    * This semantical limitation does NOT affect logic in any other place I
543    * know of as of this writing.
544    */
545   static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
546 
__item__hb_zip_iter_t547   __item_t__ __item__ () const { return __item_t__ (*a, *b); }
__item_at__hb_zip_iter_t548   __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
__more__hb_zip_iter_t549   bool __more__ () const { return bool (a) && bool (b); }
__len__hb_zip_iter_t550   unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
__next__hb_zip_iter_t551   void __next__ () { ++a; ++b; }
__forward__hb_zip_iter_t552   void __forward__ (unsigned n) { a += n; b += n; }
__prev__hb_zip_iter_t553   void __prev__ () { --a; --b; }
__rewind__hb_zip_iter_t554   void __rewind__ (unsigned n) { a -= n; b -= n; }
__end__hb_zip_iter_t555   hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
556   /* Note, we should stop if ANY of the iters reaches end.  As such two compare
557    * unequal if both items are unequal, NOT if either is unequal. */
operator !=hb_zip_iter_t558   bool operator != (const hb_zip_iter_t& o) const
559   { return a != o.a && b != o.b; }
560 
561   private:
562   A a;
563   B b;
564 };
565 struct
566 {
567   template <typename A, typename B,
568 	    hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
569   hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
operator ()__anon7feb0be90708570   operator () (A&& a, B&& b) const
571   { return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
572 }
573 HB_FUNCOBJ (hb_zip);
574 
575 /* hb_apply() */
576 
577 template <typename Appl>
578 struct hb_apply_t
579 {
hb_apply_thb_apply_t580   hb_apply_t (Appl a) : a (a) {}
581 
582   template <typename Iter,
583 	    hb_requires (hb_is_iterator (Iter))>
operator ()hb_apply_t584   void operator () (Iter it)
585   {
586     for (; it; ++it)
587       (void) hb_invoke (a, *it);
588   }
589 
590   private:
591   Appl a;
592 };
593 struct
594 {
595   template <typename Appl> hb_apply_t<Appl>
operator ()__anon7feb0be90808596   operator () (Appl&& a) const
597   { return hb_apply_t<Appl> (a); }
598 
599   template <typename Appl> hb_apply_t<Appl&>
operator ()__anon7feb0be90808600   operator () (Appl *a) const
601   { return hb_apply_t<Appl&> (*a); }
602 }
603 HB_FUNCOBJ (hb_apply);
604 
605 /* hb_iota()/hb_range() */
606 
607 template <typename T, typename S>
608 struct hb_counter_iter_t :
609   hb_iter_t<hb_counter_iter_t<T, S>, T>
610 {
hb_counter_iter_thb_counter_iter_t611   hb_counter_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
612 
613   typedef T __item_t__;
614   static constexpr bool is_random_access_iterator = true;
615   static constexpr bool is_sorted_iterator = true;
__item__hb_counter_iter_t616   __item_t__ __item__ () const { return +v; }
__item_at__hb_counter_iter_t617   __item_t__ __item_at__ (unsigned j) const { return v + j * step; }
__more__hb_counter_iter_t618   bool __more__ () const { return v != end_; }
__len__hb_counter_iter_t619   unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
__next__hb_counter_iter_t620   void __next__ () { v += step; }
__forward__hb_counter_iter_t621   void __forward__ (unsigned n) { v += n * step; }
__prev__hb_counter_iter_t622   void __prev__ () { v -= step; }
__rewind__hb_counter_iter_t623   void __rewind__ (unsigned n) { v -= n * step; }
__end__hb_counter_iter_t624   hb_counter_iter_t __end__ () const { return hb_counter_iter_t (end_, end_, step); }
operator !=hb_counter_iter_t625   bool operator != (const hb_counter_iter_t& o) const
626   { return v != o.v; }
627 
628   private:
end_forhb_counter_iter_t629   static inline T end_for (T start, T end_, S step)
630   {
631     if (!step)
632       return end_;
633     auto res = (end_ - start) % step;
634     if (!res)
635       return end_;
636     end_ += step - res;
637     return end_;
638   }
639 
640   private:
641   T v;
642   T end_;
643   S step;
644 };
645 struct
646 {
647   template <typename T = unsigned, typename S = unsigned> hb_counter_iter_t<T, S>
operator ()__anon7feb0be90908648   operator () (T start = 0u, S&& step = 1u) const
649   { return hb_counter_iter_t<T, S> (start, step >= 0 ? hb_int_max (T) : hb_int_min (T), step); }
650 }
651 HB_FUNCOBJ (hb_iota);
652 struct
653 {
654   template <typename T = unsigned> hb_counter_iter_t<T, unsigned>
operator ()__anon7feb0be90a08655   operator () (T end = (unsigned) -1) const
656   { return hb_counter_iter_t<T, unsigned> (0, end, 1u); }
657 
658   template <typename T, typename S = unsigned> hb_counter_iter_t<T, S>
operator ()__anon7feb0be90a08659   operator () (T start, T end, S&& step = 1u) const
660   { return hb_counter_iter_t<T, S> (start, end, step); }
661 }
662 HB_FUNCOBJ (hb_range);
663 
664 /* hb_enumerate */
665 
666 struct
667 {
668   template <typename Iterable,
669 	    typename Index = unsigned,
670 	    hb_requires (hb_is_iterable (Iterable))>
671   auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
672   ( hb_zip (hb_iota (start), it) )
673 }
674 HB_FUNCOBJ (hb_enumerate);
675 
676 
677 /* hb_sink() */
678 
679 template <typename Sink>
680 struct hb_sink_t
681 {
hb_sink_thb_sink_t682   hb_sink_t (Sink s) : s (s) {}
683 
684   template <typename Iter,
685 	    hb_requires (hb_is_iterator (Iter))>
operator ()hb_sink_t686   void operator () (Iter it)
687   {
688     for (; it; ++it)
689       s << *it;
690   }
691 
692   private:
693   Sink s;
694 };
695 struct
696 {
697   template <typename Sink> hb_sink_t<Sink>
operator ()__anon7feb0be90c08698   operator () (Sink&& s) const
699   { return hb_sink_t<Sink> (s); }
700 
701   template <typename Sink> hb_sink_t<Sink&>
operator ()__anon7feb0be90c08702   operator () (Sink *s) const
703   { return hb_sink_t<Sink&> (*s); }
704 }
705 HB_FUNCOBJ (hb_sink);
706 
707 /* hb-drain: hb_sink to void / blackhole / /dev/null. */
708 
709 struct
710 {
711   template <typename Iter,
712 	    hb_requires (hb_is_iterator (Iter))>
operator ()__anon7feb0be90d08713   void operator () (Iter it) const
714   {
715     for (; it; ++it)
716       (void) *it;
717   }
718 }
719 HB_FUNCOBJ (hb_drain);
720 
721 /* hb_unzip(): unzip and sink to two sinks. */
722 
723 template <typename Sink1, typename Sink2>
724 struct hb_unzip_t
725 {
hb_unzip_thb_unzip_t726   hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
727 
728   template <typename Iter,
729 	    hb_requires (hb_is_iterator (Iter))>
operator ()hb_unzip_t730   void operator () (Iter it)
731   {
732     for (; it; ++it)
733     {
734       const auto &v = *it;
735       s1 << v.first;
736       s2 << v.second;
737     }
738   }
739 
740   private:
741   Sink1 s1;
742   Sink2 s2;
743 };
744 struct
745 {
746   template <typename Sink1, typename Sink2> hb_unzip_t<Sink1, Sink2>
operator ()__anon7feb0be90e08747   operator () (Sink1&& s1, Sink2&& s2) const
748   { return hb_unzip_t<Sink1, Sink2> (s1, s2); }
749 
750   template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
operator ()__anon7feb0be90e08751   operator () (Sink1 *s1, Sink2 *s2) const
752   { return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
753 }
754 HB_FUNCOBJ (hb_unzip);
755 
756 
757 /* hb-all, hb-any, hb-none. */
758 
759 struct
760 {
761   template <typename Iterable,
762 	    typename Pred = decltype ((hb_identity)),
763 	    typename Proj = decltype ((hb_identity)),
764 	    hb_requires (hb_is_iterable (Iterable))>
operator ()__anon7feb0be90f08765   bool operator () (Iterable&& c,
766 		    Pred&& p = hb_identity,
767 		    Proj&& f = hb_identity) const
768   {
769     for (auto it = hb_iter (c); it; ++it)
770       if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
771 	return false;
772     return true;
773   }
774 }
775 HB_FUNCOBJ (hb_all);
776 struct
777 {
778   template <typename Iterable,
779 	    typename Pred = decltype ((hb_identity)),
780 	    typename Proj = decltype ((hb_identity)),
781 	    hb_requires (hb_is_iterable (Iterable))>
operator ()__anon7feb0be91008782   bool operator () (Iterable&& c,
783 		    Pred&& p = hb_identity,
784 		    Proj&& f = hb_identity) const
785   {
786     for (auto it = hb_iter (c); it; ++it)
787       if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
788 	return true;
789     return false;
790   }
791 }
792 HB_FUNCOBJ (hb_any);
793 struct
794 {
795   template <typename Iterable,
796 	    typename Pred = decltype ((hb_identity)),
797 	    typename Proj = decltype ((hb_identity)),
798 	    hb_requires (hb_is_iterable (Iterable))>
operator ()__anon7feb0be91108799   bool operator () (Iterable&& c,
800 		    Pred&& p = hb_identity,
801 		    Proj&& f = hb_identity) const
802   {
803     for (auto it = hb_iter (c); it; ++it)
804       if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
805 	return false;
806     return true;
807   }
808 }
809 HB_FUNCOBJ (hb_none);
810 
811 /*
812  * Algorithms operating on iterators.
813  */
814 
815 template <typename C, typename V,
816 	  hb_requires (hb_is_iterable (C))>
817 inline void
hb_fill(C & c,const V & v)818 hb_fill (C& c, const V &v)
819 {
820   for (auto i = hb_iter (c); i; i++)
821     *i = v;
822 }
823 
824 template <typename S, typename D>
825 inline void
hb_copy(S && is,D && id)826 hb_copy (S&& is, D&& id)
827 {
828   hb_iter (is) | hb_sink (id);
829 }
830 
831 
832 #endif /* HB_ITER_HH */
833