-
Notifications
You must be signed in to change notification settings - Fork 51
/
span.hpp
520 lines (417 loc) · 20.3 KB
/
span.hpp
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
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
#ifndef _C4_SPAN_HPP_
#define _C4_SPAN_HPP_
/** @file span.hpp Provides span classes. */
#include "c4/config.hpp"
#include "c4/error.hpp"
#include "c4/szconv.hpp"
#include <algorithm>
namespace c4 {
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a crtp base for implementing span classes
*
* A span is a non-owning range of elements contiguously stored in memory.
* Unlike STL's array_view, the span allows write-access to its members.
*
* To obtain subspans from a span, the following const member functions
* are available:
* - subspan(first, num)
* - range(first, last)
* - first(num)
* - last(num)
*
* A span can also be resized via the following non-const member functions:
* - resize(sz)
* - ltrim(num)
* - rtrim(num)
*
* @see span
* @see cspan
* @see spanrs
* @see cspanrs
* @see spanrsl
* @see cspanrsl
*/
template<class T, class I, class SpanImpl>
class span_crtp
{
// some utility defines, undefined at the end of this class
#define _c4this ((SpanImpl *)this)
#define _c4cthis ((SpanImpl const*)this)
#define _c4ptr ((SpanImpl *)this)->m_ptr
#define _c4cptr ((SpanImpl const*)this)->m_ptr
#define _c4sz ((SpanImpl *)this)->m_size
#define _c4csz ((SpanImpl const*)this)->m_size
public:
_c4_DEFINE_ARRAY_TYPES(T, I);
public:
C4_ALWAYS_INLINE constexpr I value_size() const noexcept { return sizeof(T); }
C4_ALWAYS_INLINE constexpr I elm_size () const noexcept { return sizeof(T); }
C4_ALWAYS_INLINE constexpr I type_size () const noexcept { return sizeof(T); }
C4_ALWAYS_INLINE I byte_size () const noexcept { return _c4csz*sizeof(T); }
C4_ALWAYS_INLINE bool empty() const noexcept { return _c4csz == 0; }
C4_ALWAYS_INLINE I size() const noexcept { return _c4csz; }
//C4_ALWAYS_INLINE I capacity() const noexcept { return _c4sz; } // this must be defined by impl classes
C4_ALWAYS_INLINE void clear() noexcept { _c4sz = 0; }
C4_ALWAYS_INLINE T * data() noexcept { return _c4ptr; }
C4_ALWAYS_INLINE T const* data() const noexcept { return _c4cptr; }
C4_ALWAYS_INLINE iterator begin() noexcept { return _c4ptr; }
C4_ALWAYS_INLINE const_iterator begin() const noexcept { return _c4cptr; }
C4_ALWAYS_INLINE const_iterator cbegin() const noexcept { return _c4cptr; }
C4_ALWAYS_INLINE iterator end() noexcept { return _c4ptr + _c4sz; }
C4_ALWAYS_INLINE const_iterator end() const noexcept { return _c4cptr + _c4csz; }
C4_ALWAYS_INLINE const_iterator cend() const noexcept { return _c4cptr + _c4csz; }
C4_ALWAYS_INLINE reverse_iterator rbegin() noexcept { return reverse_iterator(_c4ptr + _c4sz); }
C4_ALWAYS_INLINE const_reverse_iterator rbegin() const noexcept { return reverse_iterator(_c4cptr + _c4csz); }
C4_ALWAYS_INLINE const_reverse_iterator crbegin() const noexcept { return reverse_iterator(_c4cptr + _c4csz); }
C4_ALWAYS_INLINE reverse_iterator rend() noexcept { return const_reverse_iterator(_c4ptr); }
C4_ALWAYS_INLINE const_reverse_iterator rend() const noexcept { return const_reverse_iterator(_c4cptr); }
C4_ALWAYS_INLINE const_reverse_iterator crend() const noexcept { return const_reverse_iterator(_c4cptr); }
C4_ALWAYS_INLINE T & front() C4_NOEXCEPT_X { C4_XASSERT(!empty()); return _c4ptr [0]; }
C4_ALWAYS_INLINE T const& front() const C4_NOEXCEPT_X { C4_XASSERT(!empty()); return _c4cptr[0]; }
C4_ALWAYS_INLINE T & back() C4_NOEXCEPT_X { C4_XASSERT(!empty()); return _c4ptr [_c4sz - 1]; }
C4_ALWAYS_INLINE T const& back() const C4_NOEXCEPT_X { C4_XASSERT(!empty()); return _c4cptr[_c4csz - 1]; }
C4_ALWAYS_INLINE T & operator[] (I i) C4_NOEXCEPT_X { C4_XASSERT(i >= 0 && i < _c4sz ); return _c4ptr [i]; }
C4_ALWAYS_INLINE T const& operator[] (I i) const C4_NOEXCEPT_X { C4_XASSERT(i >= 0 && i < _c4csz); return _c4cptr[i]; }
C4_ALWAYS_INLINE SpanImpl subspan(I first, I num) const C4_NOEXCEPT_X
{
C4_XASSERT((first >= 0 && first < _c4csz) || (first == _c4csz && num == 0));
C4_XASSERT((first + num >= 0) && (first + num <= _c4csz));
return _c4cthis->_select(_c4cptr + first, num);
}
C4_ALWAYS_INLINE SpanImpl subspan(I first) const C4_NOEXCEPT_X ///< goes up until the end of the span
{
C4_XASSERT(first >= 0 && first <= _c4csz);
return _c4cthis->_select(_c4cptr + first, _c4csz - first);
}
C4_ALWAYS_INLINE SpanImpl range(I first, I last) const C4_NOEXCEPT_X ///< last element is NOT included
{
C4_XASSERT(((first >= 0) && (first < _c4csz)) || (first == _c4csz && first == last));
C4_XASSERT((last >= 0) && (last <= _c4csz));
C4_XASSERT(last >= first);
return _c4cthis->_select(_c4cptr + first, last - first);
}
C4_ALWAYS_INLINE SpanImpl range(I first) const C4_NOEXCEPT_X ///< goes up until the end of the span
{
C4_XASSERT(((first >= 0) && (first <= _c4csz)));
return _c4cthis->_select(_c4cptr + first, _c4csz - first);
}
C4_ALWAYS_INLINE SpanImpl first(I num) const C4_NOEXCEPT_X ///< get the first num elements, starting at 0
{
C4_XASSERT((num >= 0) && (num <= _c4csz));
return _c4cthis->_select(_c4cptr, num);
}
C4_ALWAYS_INLINE SpanImpl last(I num) const C4_NOEXCEPT_X ///< get the last num elements, starting at size()-num
{
C4_XASSERT((num >= 0) && (num <= _c4csz));
return _c4cthis->_select(_c4cptr + _c4csz - num, num);
}
bool is_subspan(span_crtp const& ss) const noexcept
{
if(_c4cptr == nullptr) return false;
auto *b = begin(), *e = end();
auto *ssb = ss.begin(), *sse = ss.end();
if(ssb >= b && sse <= e)
{
return true;
}
else
{
return false;
}
}
/** COMPLement Left: return the complement to the left of the beginning of the given subspan.
* If ss does not begin inside this, returns an empty substring. */
SpanImpl compll(span_crtp const& ss) const C4_NOEXCEPT_X
{
auto ssb = ss.begin();
auto b = begin();
auto e = end();
if(ssb >= b && ssb <= e)
{
return subspan(0, static_cast<size_t>(ssb - b));
}
else
{
return subspan(0, 0);
}
}
/** COMPLement Right: return the complement to the right of the end of the given subspan.
* If ss does not end inside this, returns an empty substring. */
SpanImpl complr(span_crtp const& ss) const C4_NOEXCEPT_X
{
auto sse = ss.end();
auto b = begin();
auto e = end();
if(sse >= b && sse <= e)
{
return subspan(static_cast<size_t>(sse - b), static_cast<size_t>(e - sse));
}
else
{
return subspan(0, 0);
}
}
C4_ALWAYS_INLINE bool same_span(span_crtp const& that) const noexcept
{
return size() == that.size() && data() == that.data();
}
template<class I2, class Impl2>
C4_ALWAYS_INLINE bool same_span(span_crtp<T, I2, Impl2> const& that) const C4_NOEXCEPT_X
{
I tsz = szconv<I>(that.size()); // x-asserts that the size does not overflow
return size() == tsz && data() == that.data();
}
#undef _c4this
#undef _c4cthis
#undef _c4ptr
#undef _c4cptr
#undef _c4sz
#undef _c4csz
};
//-----------------------------------------------------------------------------
template<class T, class Il, class Ir, class _Impll, class _Implr>
inline constexpr bool operator==
(
span_crtp<T, Il, _Impll> const& l,
span_crtp<T, Ir, _Implr> const& r
)
{
#if C4_CPP >= 14
return std::equal(l.begin(), l.end(), r.begin(), r.end());
#else
return l.same_span(r) || std::equal(l.begin(), l.end(), r.begin());
#endif
}
template<class T, class Il, class Ir, class _Impll, class _Implr>
inline constexpr bool operator!=
(
span_crtp<T, Il, _Impll> const& l,
span_crtp<T, Ir, _Implr> const& r
)
{
return ! (l == r);
}
//-----------------------------------------------------------------------------
template<class T, class Il, class Ir, class _Impll, class _Implr>
inline constexpr bool operator<
(
span_crtp<T, Il, _Impll> const& l,
span_crtp<T, Ir, _Implr> const& r
)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
template<class T, class Il, class Ir, class _Impll, class _Implr>
inline constexpr bool operator<=
(
span_crtp<T, Il, _Impll> const& l,
span_crtp<T, Ir, _Implr> const& r
)
{
return ! (l > r);
}
//-----------------------------------------------------------------------------
template<class T, class Il, class Ir, class _Impll, class _Implr>
inline constexpr bool operator>
(
span_crtp<T, Il, _Impll> const& l,
span_crtp<T, Ir, _Implr> const& r
)
{
return r < l;
}
//-----------------------------------------------------------------------------
template<class T, class Il, class Ir, class _Impll, class _Implr>
inline constexpr bool operator>=
(
span_crtp<T, Il, _Impll> const& l,
span_crtp<T, Ir, _Implr> const& r
)
{
return ! (l < r);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A non-owning span of elements contiguously stored in memory. */
template<class T, class I=C4_SIZE_TYPE>
class span : public span_crtp<T, I, span<T, I>>
{
friend class span_crtp<T, I, span<T, I>>;
T * C4_RESTRICT m_ptr;
I m_size;
C4_ALWAYS_INLINE span _select(T *p, I sz) const { return span(p, sz); }
public:
_c4_DEFINE_ARRAY_TYPES(T, I);
using NCT = typename std::remove_const<T>::type; //!< NCT=non const type
using CT = typename std::add_const<T>::type; //!< CT=const type
using const_type = span<CT, I>;
/// convert automatically to span of const T
operator span<CT, I> () const { span<CT, I> s(m_ptr, m_size); return s; }
public:
C4_ALWAYS_INLINE C4_CONSTEXPR14 span() noexcept : m_ptr{nullptr}, m_size{0} {}
span(span const&) = default;
span(span &&) = default;
span& operator= (span const&) = default;
span& operator= (span &&) = default;
public:
/** @name Construction and assignment from same type */
/** @{ */
template<size_t N> C4_ALWAYS_INLINE C4_CONSTEXPR14 span (T (&arr)[N]) noexcept : m_ptr{arr}, m_size{N} {}
template<size_t N> C4_ALWAYS_INLINE C4_CONSTEXPR14 void assign(T (&arr)[N]) noexcept { m_ptr = arr; m_size = N; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 span(T *p, I sz) noexcept : m_ptr{p}, m_size{sz} {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 void assign(T *p, I sz) noexcept { m_ptr = p; m_size = sz; }
C4_ALWAYS_INLINE C4_CONSTEXPR14 span (c4::aggregate_t, std::initializer_list<T> il) noexcept : m_ptr{&*il.begin()}, m_size{il.size()} {}
C4_ALWAYS_INLINE C4_CONSTEXPR14 void assign(c4::aggregate_t, std::initializer_list<T> il) noexcept { m_ptr = &*il.begin(); m_size = il.size(); }
/** @} */
public:
C4_ALWAYS_INLINE I capacity() const noexcept { return m_size; }
C4_ALWAYS_INLINE void resize(I sz) C4_NOEXCEPT_A { C4_ASSERT(sz <= m_size); m_size = sz; }
C4_ALWAYS_INLINE void rtrim (I n ) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && n < m_size); m_size -= n; }
C4_ALWAYS_INLINE void ltrim (I n ) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && n < m_size); m_size -= n; m_ptr += n; }
};
template<class T, class I=C4_SIZE_TYPE> using cspan = span<const T, I>;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A non-owning span resizeable up to a capacity. Subselection or resizing
* will keep the original provided it starts at begin(). If subselection or
* resizing change the pointer, then the original capacity information will
* be lost.
*
* Thus, resizing via resize() and ltrim() and subselecting via first()
* or any of subspan() or range() when starting from the beginning will keep
* the original capacity. OTOH, using last(), or any of subspan() or range()
* with an offset from the start will remove from capacity (shifting the
* pointer) by the corresponding offset. If this is undesired, then consider
* using spanrsl.
*
* @see spanrs for a span resizeable on the right
* @see spanrsl for a span resizeable on the right and left
*/
template<class T, class I=C4_SIZE_TYPE>
class spanrs : public span_crtp<T, I, spanrs<T, I>>
{
friend class span_crtp<T, I, spanrs<T, I>>;
T * C4_RESTRICT m_ptr;
I m_size;
I m_capacity;
C4_ALWAYS_INLINE spanrs _select(T *p, I sz) const noexcept
{
C4_ASSERT(p >= m_ptr);
size_t delta = static_cast<size_t>(p - m_ptr);
C4_ASSERT(m_capacity >= delta);
return spanrs(p, sz, static_cast<size_t>(m_capacity - delta));
}
public:
_c4_DEFINE_ARRAY_TYPES(T, I);
using NCT = typename std::remove_const<T>::type; //!< NCT=non const type
using CT = typename std::add_const<T>::type; //!< CT=const type
using const_type = spanrs<CT, I>;
/// convert automatically to span of T
C4_ALWAYS_INLINE operator span<T, I > () const noexcept { return span<T, I>(m_ptr, m_size); }
/// convert automatically to span of const T
//C4_ALWAYS_INLINE operator span<CT, I> () const noexcept { span<CT, I> s(m_ptr, m_size); return s; }
/// convert automatically to spanrs of const T
C4_ALWAYS_INLINE operator spanrs<CT, I> () const noexcept { spanrs<CT, I> s(m_ptr, m_size, m_capacity); return s; }
public:
C4_ALWAYS_INLINE spanrs() noexcept : m_ptr{nullptr}, m_size{0}, m_capacity{0} {}
spanrs(spanrs const&) = default;
spanrs(spanrs &&) = default;
spanrs& operator= (spanrs const&) = default;
spanrs& operator= (spanrs &&) = default;
public:
/** @name Construction and assignment from same type */
/** @{ */
C4_ALWAYS_INLINE spanrs(T *p, I sz) noexcept : m_ptr{p}, m_size{sz}, m_capacity{sz} {}
/** @warning will reset the capacity to sz */
C4_ALWAYS_INLINE void assign(T *p, I sz) noexcept { m_ptr = p; m_size = sz; m_capacity = sz; }
C4_ALWAYS_INLINE spanrs(T *p, I sz, I cap) noexcept : m_ptr{p}, m_size{sz}, m_capacity{cap} {}
C4_ALWAYS_INLINE void assign(T *p, I sz, I cap) noexcept { m_ptr = p; m_size = sz; m_capacity = cap; }
template<size_t N> C4_ALWAYS_INLINE spanrs(T (&arr)[N]) noexcept : m_ptr{arr}, m_size{N}, m_capacity{N} {}
template<size_t N> C4_ALWAYS_INLINE void assign(T (&arr)[N]) noexcept { m_ptr = arr; m_size = N; m_capacity = N; }
C4_ALWAYS_INLINE spanrs(c4::aggregate_t, std::initializer_list<T> il) noexcept : m_ptr{il.begin()}, m_size{il.size()}, m_capacity{il.size()} {}
C4_ALWAYS_INLINE void assign(c4::aggregate_t, std::initializer_list<T> il) noexcept { m_ptr = il.begin(); m_size = il.size(); m_capacity = il.size(); }
/** @} */
public:
C4_ALWAYS_INLINE I capacity() const noexcept { return m_capacity; }
C4_ALWAYS_INLINE void resize(I sz) C4_NOEXCEPT_A { C4_ASSERT(sz <= m_capacity); m_size = sz; }
C4_ALWAYS_INLINE void rtrim (I n ) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && n < m_size); m_size -= n; }
C4_ALWAYS_INLINE void ltrim (I n ) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && n < m_size); m_size -= n; m_ptr += n; m_capacity -= n; }
};
template<class T, class I=C4_SIZE_TYPE> using cspanrs = spanrs<const T, I>;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A non-owning span which always retains the capacity of the original
* range it was taken from (though it may loose its original size).
* The resizing methods resize(), ltrim(), rtrim() as well
* as the subselection methods subspan(), range(), first() and last() can be
* used at will without loosing the original capacity; the full capacity span
* can always be recovered by calling original().
*/
template<class T, class I=C4_SIZE_TYPE>
class spanrsl : public span_crtp<T, I, spanrsl<T, I>>
{
friend class span_crtp<T, I, spanrsl<T, I>>;
T *C4_RESTRICT m_ptr; ///< the current ptr. the original ptr is (m_ptr - m_offset).
I m_size; ///< the current size. the original size is unrecoverable.
I m_capacity; ///< the current capacity. the original capacity is (m_capacity + m_offset).
I m_offset; ///< the offset of the current m_ptr to the start of the original memory block.
C4_ALWAYS_INLINE spanrsl _select(T *p, I sz) const noexcept
{
C4_ASSERT(p >= m_ptr);
I delta = static_cast<I>(p - m_ptr);
C4_ASSERT(m_capacity >= delta);
return spanrsl(p, sz, static_cast<I>(m_capacity - delta), m_offset + delta);
}
public:
_c4_DEFINE_ARRAY_TYPES(T, I);
using NCT = typename std::remove_const<T>::type; //!< NCT=non const type
using CT = typename std::add_const<T>::type; //!< CT=const type
using const_type = spanrsl<CT, I>;
C4_ALWAYS_INLINE operator span<T, I> () const noexcept { return span<T, I>(m_ptr, m_size); }
C4_ALWAYS_INLINE operator spanrs<T, I> () const noexcept { return spanrs<T, I>(m_ptr, m_size, m_capacity); }
C4_ALWAYS_INLINE operator spanrsl<CT, I> () const noexcept { return spanrsl<CT, I>(m_ptr, m_size, m_capacity, m_offset); }
public:
C4_ALWAYS_INLINE spanrsl() noexcept : m_ptr{nullptr}, m_size{0}, m_capacity{0}, m_offset{0} {}
spanrsl(spanrsl const&) = default;
spanrsl(spanrsl &&) = default;
spanrsl& operator= (spanrsl const&) = default;
spanrsl& operator= (spanrsl &&) = default;
public:
C4_ALWAYS_INLINE spanrsl(T *p, I sz) noexcept : m_ptr{p}, m_size{sz}, m_capacity{sz}, m_offset{0} {}
C4_ALWAYS_INLINE void assign(T *p, I sz) noexcept { m_ptr = p; m_size = sz; m_capacity = sz; m_offset = 0; }
C4_ALWAYS_INLINE spanrsl(T *p, I sz, I cap) noexcept : m_ptr{p}, m_size{sz}, m_capacity{cap}, m_offset{0} {}
C4_ALWAYS_INLINE void assign(T *p, I sz, I cap) noexcept { m_ptr = p; m_size = sz; m_capacity = cap; m_offset = 0; }
C4_ALWAYS_INLINE spanrsl(T *p, I sz, I cap, I offs) noexcept : m_ptr{p}, m_size{sz}, m_capacity{cap}, m_offset{offs} {}
C4_ALWAYS_INLINE void assign(T *p, I sz, I cap, I offs) noexcept { m_ptr = p; m_size = sz; m_capacity = cap; m_offset = offs; }
template<size_t N> C4_ALWAYS_INLINE spanrsl(T (&arr)[N]) noexcept : m_ptr{arr}, m_size{N}, m_capacity{N}, m_offset{0} {}
template<size_t N> C4_ALWAYS_INLINE void assign(T (&arr)[N]) noexcept { m_ptr = arr; m_size = N; m_capacity = N; m_offset = 0; }
C4_ALWAYS_INLINE spanrsl(c4::aggregate_t, std::initializer_list<T> il) noexcept : m_ptr{il.begin()}, m_size{il.size()}, m_capacity{il.size()}, m_offset{0} {}
C4_ALWAYS_INLINE void assign (c4::aggregate_t, std::initializer_list<T> il) noexcept { m_ptr = il.begin(); m_size = il.size(); m_capacity = il.size(); m_offset = 0; }
public:
C4_ALWAYS_INLINE I offset() const noexcept { return m_offset; }
C4_ALWAYS_INLINE I capacity() const noexcept { return m_capacity; }
C4_ALWAYS_INLINE void resize(I sz) C4_NOEXCEPT_A { C4_ASSERT(sz <= m_capacity); m_size = sz; }
C4_ALWAYS_INLINE void rtrim (I n ) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && n < m_size); m_size -= n; }
C4_ALWAYS_INLINE void ltrim (I n ) C4_NOEXCEPT_A { C4_ASSERT(n >= 0 && n < m_size); m_size -= n; m_ptr += n; m_offset += n; m_capacity -= n; }
/** recover the original span as an spanrsl */
C4_ALWAYS_INLINE spanrsl original() const
{
return spanrsl(m_ptr - m_offset, m_capacity + m_offset, m_capacity + m_offset, 0);
}
/** recover the original span as a different span type. Example: spanrs<...> orig = s.original<spanrs>(); */
template<template<class, class> class OtherSpanType>
C4_ALWAYS_INLINE OtherSpanType<T, I> original()
{
return OtherSpanType<T, I>(m_ptr - m_offset, m_capacity + m_offset);
}
};
template<class T, class I=C4_SIZE_TYPE> using cspanrsl = spanrsl<const T, I>;
C4_SUPPRESS_WARNING_GCC_CLANG_POP
} // namespace c4
#endif /* _C4_SPAN_HPP_ */