summaryrefslogtreecommitdiff
path: root/xpcom/string/nsStringIterator.h
blob: e309a21e909024eebcf978290620da96036d086e (plain)
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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsStringIterator_h___
#define nsStringIterator_h___

#include "nsCharTraits.h"
#include "nsAlgorithm.h"
#include "nsDebug.h"

/**
 * @see nsTAString
 */

template <class CharT>
class nsReadingIterator
{
public:
  typedef nsReadingIterator<CharT>    self_type;
  typedef ptrdiff_t                   difference_type;
  typedef size_t                      size_type;
  typedef CharT                       value_type;
  typedef const CharT*                pointer;
  typedef const CharT&                reference;

private:
  friend class nsAString;
  friend class nsACString;

  // unfortunately, the API for nsReadingIterator requires that the
  // iterator know its start and end positions.  this was needed when
  // we supported multi-fragment strings, but now it is really just
  // extra baggage.  we should remove mStart and mEnd at some point.

  const CharT* mStart;
  const CharT* mEnd;
  const CharT* mPosition;

public:
  nsReadingIterator()
  {
  }
  // nsReadingIterator( const nsReadingIterator<CharT>& );                    // auto-generated copy-constructor OK
  // nsReadingIterator<CharT>& operator=( const nsReadingIterator<CharT>& );  // auto-generated copy-assignment operator OK

  pointer get() const
  {
    return mPosition;
  }

  CharT operator*() const
  {
    return *get();
  }

  self_type& operator++()
  {
    ++mPosition;
    return *this;
  }

  self_type operator++(int)
  {
    self_type result(*this);
    ++mPosition;
    return result;
  }

  self_type& operator--()
  {
    --mPosition;
    return *this;
  }

  self_type operator--(int)
  {
    self_type result(*this);
    --mPosition;
    return result;
  }

  self_type& advance(difference_type aN)
  {
    if (aN > 0) {
      difference_type step = XPCOM_MIN(aN, mEnd - mPosition);

      NS_ASSERTION(step > 0,
                   "can't advance a reading iterator beyond the end of a string");

      mPosition += step;
    } else if (aN < 0) {
      difference_type step = XPCOM_MAX(aN, -(mPosition - mStart));

      NS_ASSERTION(step < 0,
                   "can't advance (backward) a reading iterator beyond the end of a string");

      mPosition += step;
    }
    return *this;
  }

  // We return an unsigned type here (with corresponding assert) rather than
  // the more usual difference_type because we want to make this class go
  // away in favor of mozilla::RangedPtr.  Since RangedPtr has the same
  // requirement we are enforcing here, the transition ought to be much
  // smoother.
  size_type operator-(const self_type& aOther) const
  {
    MOZ_ASSERT(mPosition >= aOther.mPosition);
    return mPosition - aOther.mPosition;
  }
};

/**
 * @see nsTAString
 */

template <class CharT>
class nsWritingIterator
{
public:
  typedef nsWritingIterator<CharT>   self_type;
  typedef ptrdiff_t                  difference_type;
  typedef size_t                     size_type;
  typedef CharT                      value_type;
  typedef CharT*                     pointer;
  typedef CharT&                     reference;

private:
  friend class nsAString;
  friend class nsACString;

  // unfortunately, the API for nsWritingIterator requires that the
  // iterator know its start and end positions.  this was needed when
  // we supported multi-fragment strings, but now it is really just
  // extra baggage.  we should remove mStart and mEnd at some point.

  CharT* mStart;
  CharT* mEnd;
  CharT* mPosition;

public:
  nsWritingIterator()
  {
  }
  // nsWritingIterator( const nsWritingIterator<CharT>& );                    // auto-generated copy-constructor OK
  // nsWritingIterator<CharT>& operator=( const nsWritingIterator<CharT>& );  // auto-generated copy-assignment operator OK

  pointer get() const
  {
    return mPosition;
  }

  reference operator*() const
  {
    return *get();
  }

  self_type& operator++()
  {
    ++mPosition;
    return *this;
  }

  self_type operator++(int)
  {
    self_type result(*this);
    ++mPosition;
    return result;
  }

  self_type& operator--()
  {
    --mPosition;
    return *this;
  }

  self_type operator--(int)
  {
    self_type result(*this);
    --mPosition;
    return result;
  }

  self_type& advance(difference_type aN)
  {
    if (aN > 0) {
      difference_type step = XPCOM_MIN(aN, mEnd - mPosition);

      NS_ASSERTION(step > 0,
                   "can't advance a writing iterator beyond the end of a string");

      mPosition += step;
    } else if (aN < 0) {
      difference_type step = XPCOM_MAX(aN, -(mPosition - mStart));

      NS_ASSERTION(step < 0,
                   "can't advance (backward) a writing iterator beyond the end of a string");

      mPosition += step;
    }
    return *this;
  }

  // We return an unsigned type here (with corresponding assert) rather than
  // the more usual difference_type because we want to make this class go
  // away in favor of mozilla::RangedPtr.  Since RangedPtr has the same
  // requirement we are enforcing here, the transition ought to be much
  // smoother.
  size_type operator-(const self_type& aOther) const
  {
    MOZ_ASSERT(mPosition >= aOther.mPosition);
    return mPosition - aOther.mPosition;
  }
};

template <class CharT>
struct nsCharSinkTraits<nsWritingIterator<CharT>>
{
  static void
  write(nsWritingIterator<CharT>& aIter, const CharT* aStr, uint32_t aN)
  {
    nsCharTraits<CharT>::move(aIter.get(), aStr, aN);
    aIter.advance(aN);
  }
};

template <class CharT>
inline bool
operator==(const nsReadingIterator<CharT>& aLhs,
           const nsReadingIterator<CharT>& aRhs)
{
  return aLhs.get() == aRhs.get();
}

template <class CharT>
inline bool
operator!=(const nsReadingIterator<CharT>& aLhs,
           const nsReadingIterator<CharT>& aRhs)
{
  return aLhs.get() != aRhs.get();
}


//
// |nsWritingIterator|s
//

template <class CharT>
inline bool
operator==(const nsWritingIterator<CharT>& aLhs,
           const nsWritingIterator<CharT>& aRhs)
{
  return aLhs.get() == aRhs.get();
}

template <class CharT>
inline bool
operator!=(const nsWritingIterator<CharT>& aLhs,
           const nsWritingIterator<CharT>& aRhs)
{
  return aLhs.get() != aRhs.get();
}

#endif /* !defined(nsStringIterator_h___) */