hb-iter.hh 8.8 KB
Newer Older
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
/*
 * Copyright © 2018  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Behdad Esfahbod
 */

#ifndef HB_ITER_HH
#define HB_ITER_HH

#include "hb.hh"
B
Behdad Esfahbod 已提交
31
#include "hb-dsalgs.hh" // for hb_addressof
32
#include "hb-meta.hh"
33
#include "hb-null.hh"
34 35 36 37 38 39


/* Unified iterator object.
 *
 * The goal of this template is to make the same iterator interface
 * available to all types, and make it very easy and compact to use.
40
 * hb_iter_tator objects are small, light-weight, objects that can be
41
 * copied by value.  If the collection / object being iterated on
42
 * is writable, then the iterator returns lvalues, otherwise it
43 44 45
 * returns rvalues.
 */

B
Behdad Esfahbod 已提交
46 47 48 49 50

/*
 * Base classes for iterators.
 */

51
/* Base class for all iterators. */
52
template <typename Iter, typename Item = typename Iter::__item_t__>
53
struct hb_iter_t
54
{
B
Behdad Esfahbod 已提交
55 56
  typedef Iter iter_t;
  typedef Item item_t;
B
Behdad Esfahbod 已提交
57
  enum { item_size = hb_static_size (Item) };
58 59
  enum { is_iterator = true };
  enum { is_random_access_iterator = false };
B
Behdad Esfahbod 已提交
60
  enum { is_sorted_iterator = false };
61

62 63
  private:
  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
B
Behdad Esfahbod 已提交
64 65
  const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
        iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
66
  public:
67

B
Behdad Esfahbod 已提交
68 69 70 71
  /* TODO:
   * Port operators below to use hb_enable_if to sniff which method implements
   * an operator and use it, and remove hb_iter_mixin_t completely. */

72
  /* Operators. */
73 74 75
  iter_t iter () const { return *thiz(); }
  explicit_operator bool () const { return thiz()->__more__ (); }
  unsigned len () const { return thiz()->__len__ (); }
B
Behdad Esfahbod 已提交
76
  hb_remove_reference (item_t)* operator -> () const { return hb_addressof (**thiz()); }
77 78
  item_t operator * () const { return thiz()->__item__ (); }
  item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
79 80 81 82
  iter_t& operator += (unsigned count) { thiz()->__forward__ (count); return *thiz(); }
  iter_t& operator ++ () { thiz()->__next__ (); return *thiz(); }
  iter_t& operator -= (unsigned count) { thiz()->__rewind__ (count); return *thiz(); }
  iter_t& operator -- () { thiz()->__prev__ (); return *thiz(); }
B
Behdad Esfahbod 已提交
83 84
  iter_t operator + (unsigned count) const { iter_t c (*thiz()); c += count; return c; }
  friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
B
Behdad Esfahbod 已提交
85
  iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
B
Behdad Esfahbod 已提交
86
  iter_t operator - (unsigned count) const { iter_t c (*thiz()); c -= count; return c; }
B
Behdad Esfahbod 已提交
87
  iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
88

89 90
  protected:
  hb_iter_t () {}
B
Behdad Esfahbod 已提交
91 92
  hb_iter_t (const hb_iter_t &o HB_UNUSED) {}
  void operator = (const hb_iter_t &o HB_UNUSED) {}
93 94
};

95
#define HB_ITER_USING(Name) \
96 97
  using iter_t = typename Name::iter_t; \
  using item_t = typename Name::item_t; \
98
  using Name::item_size; \
99
  using Name::is_iterator; \
100 101 102 103 104 105 106 107 108 109
  using Name::iter; \
  using Name::operator bool; \
  using Name::len; \
  using Name::operator ->; \
  using Name::operator *; \
  using Name::operator []; \
  using Name::operator +=; \
  using Name::operator ++; \
  using Name::operator -=; \
  using Name::operator --; \
B
Behdad Esfahbod 已提交
110
  using Name::operator +; \
111 112 113
  using Name::operator -; \
  static_assert (true, "")

114
/* Mixin to fill in what the subclass doesn't provide. */
115
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
116 117 118 119 120 121 122
struct hb_iter_mixin_t
{
  private:
  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
  const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
        iter_t* thiz ()       { return static_cast<      iter_t *> (this); }
  public:
123

B
Behdad Esfahbod 已提交
124
  /* Access: Implement __item__(), or __item_at__() if random-access. */
125 126
  item_t __item__ () const { return (*thiz())[0]; }
  item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
127

128
  /* Termination: Implement __more__(), or __len__() if random-access. */
129
  bool __more__ () const { return thiz()->len (); }
130 131
  unsigned __len__ () const
  { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; }
132 133

  /* Advancing: Implement __next__(), or __forward__() if random-access. */
134 135
  void __next__ () { *thiz() += 1; }
  void __forward__ (unsigned n) { while (n--) ++*thiz(); }
136

B
Behdad Esfahbod 已提交
137
  /* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
138 139
  void __prev__ () { *thiz() -= 1; }
  void __rewind__ (unsigned n) { while (n--) --*thiz(); }
B
Behdad Esfahbod 已提交
140

B
Behdad Esfahbod 已提交
141 142 143 144
  protected:
  hb_iter_mixin_t () {}
  hb_iter_mixin_t (const hb_iter_mixin_t &o HB_UNUSED) {}
  void operator = (const hb_iter_mixin_t &o HB_UNUSED) {}
145 146
};

B
Behdad Esfahbod 已提交
147 148 149 150
/*
 * Meta-programming predicates.
 */

151 152 153
/* hb_is_iterable() */

template<typename T, typename B>
B
Behdad Esfahbod 已提交
154 155
struct _hb_is_iterable
{ enum { value = false }; };
156
template<typename T>
157
struct _hb_is_iterable<T, hb_bool_tt<true || sizeof (Null(T).iter ())> >
B
Behdad Esfahbod 已提交
158
{ enum { value = true }; };
B
Behdad Esfahbod 已提交
159

160
template<typename T>
B
Behdad Esfahbod 已提交
161 162
struct hb_is_iterable { enum { value = _hb_is_iterable<T, hb_true_t>::value }; };
#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
163

B
Behdad Esfahbod 已提交
164 165 166
/* TODO Add hb_is_iterable_of().
 * TODO Add random_access / sorted variants. */

B
Behdad Esfahbod 已提交
167

168
/* hb_is_iterator() / hb_is_random_access_iterator() / hb_is_sorted_iterator() */
169

170
template <typename Iter>
171
struct _hb_is_iterator_of
172
{
B
Behdad Esfahbod 已提交
173
  char operator () (...) { return 0; }
B
Behdad Esfahbod 已提交
174 175 176 177
  template<typename Item> int operator () (hb_iter_t<Iter, Item> *) { return 0; }
  template<typename Item> int operator () (hb_iter_t<Iter, const Item> *) { return 0; }
  template<typename Item> int operator () (hb_iter_t<Iter, Item&> *) { return 0; }
  template<typename Item> int operator () (hb_iter_t<Iter, const Item&> *) { return 0; }
178 179
  static_assert (sizeof (char) != sizeof (int), "");
};
180
template<typename Iter, typename Item>
181 182 183 184
struct hb_is_iterator_of { enum {
  value = sizeof (int) == sizeof (hb_declval (_hb_is_iterator_of<Iter>) (hb_declval (Iter*))) }; };
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
185

186 187 188 189 190
#define hb_is_random_access_iterator_of(Iter, Item) \
  hb_is_iterator_of (Iter, Item) && Iter::is_random_access_iterator
#define hb_is_random_access_iterator(Iter) \
  hb_is_random_access_iterator_of (Iter, typename Iter::item_t)

191
#define hb_is_sorted_iterator_of(Iter, Item) \
192
  hb_is_iterator_of (Iter, Item) && Iter::is_sorted_iterator
193 194
#define hb_is_sorted_iterator(Iter) \
  hb_is_sorted_iterator_of (Iter, typename Iter::item_t)
195

B
Behdad Esfahbod 已提交
196 197 198
/*
 * Algorithms operating on iterators or iteratables.
 */
199

200 201 202
template <typename C, typename V> inline
  hb_enable_if_t (hb_is_iterable (C),
void)
B
Behdad Esfahbod 已提交
203
hb_fill (C& c, const V &v)
204 205 206 207 208
{
  for (typename C::iter_t i (c); i; i++)
    hb_assign (*i, v);
}

209 210 211 212
template <typename S, typename D> inline
  hb_enable_if_t (hb_is_iterator (S) && hb_is_iterator (D),
bool)
hb_copy (D id, S is)
213 214 215 216 217 218 219
{
  for (; id && is; ++id, ++is)
    *id = *is;
  return !is;
}


B
Behdad Esfahbod 已提交
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
template <typename A, typename B>
struct hb_zip_t :
  hb_iter_t<hb_zip_t<A, B>, hb_pair_t<typename A::item_t, typename B::item_t> >
{
  hb_zip_t () {}
  hb_zip_t (A a, B b) : a (a), b (b) {}

  typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
  enum { is_random_access_iterator =
	   A::is_random_access_iterator &&
	   B::is_random_access_iterator };
  enum { is_sorted_iterator =
	   A::is_sorted_iterator &&
	   B::is_sorted_iterator };
  __item_t__ __item__ () const { return __item_t__ (*a, *b); }
  __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
  bool __more__ () const { return a && b; }
  unsigned __len__ () const { return MIN (a.len (), b.len ()); }
  void __next__ () { ++a; ++b; }
  void __forward__ (unsigned n) { a += n; b += n; }
  void __prev__ () { --a; --b; }
  void __rewind__ (unsigned n) { a -= n; b -= n; }

  private:
  A a;
  B b;
};

template <typename A, typename B> inline
typename hb_enable_if<hb_is_iterable (A) && hb_is_iterable (B),
hb_zip_t<typename A::iter_t, typename B::iter_t> >::type
hb_zip (A& a, B &b)
{ return hb_zip_t<typename A::iter_t, typename B::iter_t> (a.iter (), b.iter ()); }

254
#endif /* HB_ITER_HH */