Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qiterable.h
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QITERABLE_H
5#define QITERABLE_H
6
7#include <QtCore/qglobal.h>
8#include <QtCore/qtypeinfo.h>
9#include <QtCore/qtaggedpointer.h>
10
11QT_BEGIN_NAMESPACE
12
13namespace QtPrivate {
14 template<typename Type, typename Storage = Type>
16 {
17 enum Tag : bool { Const, Mutable };
18 QTaggedPointer<Storage, Tag> m_pointer;
19
20 public:
22
24 : m_pointer(reinterpret_cast<Storage *>(const_cast<void *>(pointer)), Const)
25 {
28 }
29
36
37 template<typename InputType>
39 : m_pointer(reinterpret_cast<Storage *>(const_cast<InputType *>(pointer)), Const)
40 {
41 static_assert(alignof(InputType) >= alignof(Storage));
42 }
43
44 template<typename InputType>
46 : m_pointer(reinterpret_cast<Storage *>(pointer), Mutable)
47 {
48 static_assert(alignof(InputType) >= alignof(Storage));
49 }
50
52
53 const Type *constPointer() const
54 {
55 return reinterpret_cast<const Type *>(m_pointer.data());
56 }
57
58 Type *mutablePointer() const
59 {
60 return m_pointer.tag() == Mutable ? reinterpret_cast<Type *>(m_pointer.data()) : nullptr;
61 }
62 };
63
69
71}
72
73template<class Iterator, typename IteratorCategory>
74class QTaggedIterator : public Iterator
75{
76public:
77 using iterator_category = IteratorCategory;
78 QTaggedIterator(Iterator &&it) : Iterator(std::move(it))
79 {
80 [[maybe_unused]] const auto metaContainer = this->metaContainer();
81 if constexpr (std::is_base_of_v<std::random_access_iterator_tag, IteratorCategory>) {
82 if (!metaContainer.hasRandomAccessIterator()) {
83 qFatal("You cannot use this iterator as a random access iterator");
84 this->clearIterator();
85 }
86 }
87
88 if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag, IteratorCategory>) {
89 if (!metaContainer.hasBidirectionalIterator()) {
90 qFatal("You cannot use this iterator as a bidirectional iterator");
91 this->clearIterator();
92 }
93 }
94
95 if constexpr (std::is_base_of_v<std::forward_iterator_tag, IteratorCategory>) {
96 if (!metaContainer.hasForwardIterator()) {
97 qFatal("You cannot use this iterator as a forward iterator");
98 this->clearIterator();
99 }
100 }
101
102 if constexpr (std::is_base_of_v<std::input_iterator_tag, IteratorCategory>) {
103 if (!metaContainer.hasInputIterator()) {
104 qFatal("You cannot use this iterator as an input iterator");
105 this->clearIterator();
106 }
107 }
108 }
109
110 bool operator==(const QTaggedIterator &o) const { return Iterator::operator==(o); }
111 bool operator!=(const QTaggedIterator &o) const { return Iterator::operator!=(o); }
112 QTaggedIterator &operator++() { Iterator::operator++(); return *this; }
113 QTaggedIterator operator++(int x) { return QTaggedIterator(Iterator::operator++(x)); }
114 QTaggedIterator &operator--() { Iterator::operator--(); return *this; }
115 QTaggedIterator operator--(int x) { return QTaggedIterator(Iterator::operator--(x)); }
116 QTaggedIterator &operator+=(qsizetype j) { Iterator::operator+=(j); return *this; }
117 QTaggedIterator &operator-=(qsizetype j) { Iterator::operator-=(j); return *this; }
118 QTaggedIterator operator+(qsizetype j) const { return QTaggedIterator(Iterator::operator+(j)); }
119 QTaggedIterator operator-(qsizetype j) const { return QTaggedIterator(Iterator::operator-(j)); }
120 qsizetype operator-(const QTaggedIterator &j) const { return Iterator::operator-(j); }
121
122 bool operator<(const QTaggedIterator &j) { return operator-(j) < 0; }
123 bool operator>=(const QTaggedIterator &j) { return !operator<(j); }
124 bool operator>(const QTaggedIterator &j) { return operator-(j) > 0; }
125 bool operator<=(const QTaggedIterator &j) { return !operator>(j); }
126
127 friend inline QTaggedIterator operator+(qsizetype j, const QTaggedIterator &k) { return k + j; }
128};
129
130template<class Container>
131class QIterable;
132
133template<class Container>
135{
136private:
137 QtPrivate::QConstPreservingPointer<QIterable<Container>> m_iterable;
138 void *m_iterator = nullptr;
139
140protected:
141 QBaseIterator() = default;
142 QBaseIterator(const QIterable<Container> *iterable, void *iterator)
143 : m_iterable(iterable), m_iterator(iterator)
144 {}
145
146 QBaseIterator(QIterable<Container> *iterable, void *iterator)
147 : m_iterable(iterable), m_iterator(iterator)
148 {}
149
152 {
153 other.m_iterator = nullptr;
154 }
155
158 {
159 initIterator(other.m_iterator);
160 }
161
163
165 {
166 if (this != &other) {
168 m_iterable = std::move(other.m_iterable);
169 m_iterator = std::move(other.m_iterator);
170 other.m_iterator = nullptr;
171 }
172 return *this;
173 }
174
176 {
177 if (this != &other) {
179 m_iterable = other.m_iterable;
180 initIterator(other.m_iterator);
181 }
182 return *this;
183 }
184
185 QIterable<Container> *mutableIterable() const
186 {
187 return m_iterable.mutablePointer();
188 }
189
190 const QIterable<Container> *constIterable() const
191 {
192 return m_iterable.constPointer();
193 }
194
195 void initIterator(const void *copy)
196 {
197 if (!copy)
198 return;
199 if (auto *mutableIt = mutableIterable()) {
200 m_iterator = metaContainer().begin(mutableIt->mutableIterable());
201 metaContainer().copyIterator(m_iterator, copy);
202 } else if (auto *constIt = constIterable()) {
203 m_iterator = metaContainer().constBegin(constIt->constIterable());
204 metaContainer().copyConstIterator(m_iterator, copy);
205 }
206 }
207
209 {
210 if (!m_iterator)
211 return;
213 metaContainer().destroyIterator(m_iterator);
214 else
215 metaContainer().destroyConstIterator(m_iterator);
216 }
217
218public:
219 void *mutableIterator() { return m_iterator; }
220 const void *constIterator() const { return m_iterator; }
221 Container metaContainer() const { return constIterable()->m_metaContainer; }
222};
223
224template<class Container>
225struct QIterator : public QBaseIterator<Container>
226{
227public:
229
230 explicit QIterator(QIterable<Container> *iterable, void *iterator)
231 : QBaseIterator<Container>(iterable, iterator)
232 {
233 Q_ASSERT(iterable != nullptr);
234 }
235
236 bool operator==(const QIterator &o) const
237 {
238 return this->metaContainer().compareIterator(this->constIterator(), o.constIterator());
239 }
240
241 bool operator!=(const QIterator &o) const
242 {
243 return !this->metaContainer().compareIterator(this->constIterator(), o.constIterator());
244 }
245
247 {
248 this->metaContainer().advanceIterator(this->mutableIterator(), 1);
249 return *this;
250 }
251
253 {
254 QIterable<Container> *iterable = this->mutableIterable();
255 const Container metaContainer = this->metaContainer();
256 QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
257 metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
258 metaContainer.advanceIterator(this->mutableIterator(), 1);
259 return result;
260 }
261
263 {
264 this->metaContainer().advanceIterator(this->mutableIterator(), -1);
265 return *this;
266 }
267
269 {
270 QIterable<Container> *iterable = this->mutableIterable();
271 const Container metaContainer = this->metaContainer();
272 QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
273 metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
274 metaContainer.advanceIterator(this->mutableIterator(), -1);
275 return result;
276 }
277
278 QIterator &operator+=(qsizetype j)
279 {
280 this->metaContainer().advanceIterator(this->mutableIterator(), j);
281 return *this;
282 }
283
284 QIterator &operator-=(qsizetype j)
285 {
286 this->metaContainer().advanceIterator(this->mutableIterator(), -j);
287 return *this;
288 }
289
290 QIterator operator+(qsizetype j) const
291 {
292 QIterable<Container> *iterable = this->mutableIterable();
293 const Container metaContainer = this->metaContainer();
294 QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
295 metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
296 metaContainer.advanceIterator(result.mutableIterator(), j);
297 return result;
298 }
299
300 QIterator operator-(qsizetype j) const
301 {
302 QIterable<Container> *iterable = this->mutableIterable();
303 const Container metaContainer = this->metaContainer();
304 QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
305 metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
306 metaContainer.advanceIterator(result.mutableIterator(), -j);
307 return result;
308 }
309
310 qsizetype operator-(const QIterator &j) const
311 {
312 return this->metaContainer().diffIterator(this->constIterator(), j.constIterator());
313 }
314
315 friend inline QIterator operator+(qsizetype j, const QIterator &k) { return k + j; }
316};
317
318template<class Container>
319struct QConstIterator : public QBaseIterator<Container>
320{
321public:
323
324 explicit QConstIterator(const QIterable<Container> *iterable, void *iterator)
325 : QBaseIterator<Container>(iterable, iterator)
326 {
327 }
328
329 bool operator==(const QConstIterator &o) const
330 {
331 return this->metaContainer().compareConstIterator(
332 this->constIterator(), o.constIterator());
333 }
334
335 bool operator!=(const QConstIterator &o) const
336 {
337 return !this->metaContainer().compareConstIterator(
338 this->constIterator(), o.constIterator());
339 }
340
342 {
343 this->metaContainer().advanceConstIterator(this->mutableIterator(), 1);
344 return *this;
345 }
346
348 {
349 const Container metaContainer = this->metaContainer();
350 QConstIterator result(this->constIterable(), metaContainer.constBegin(
351 this->constIterable()->constIterable()));
352 metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
353 metaContainer.advanceConstIterator(this->mutableIterator(), 1);
354 return result;
355 }
356
358 {
359 this->metaContainer().advanceConstIterator(this->mutableIterator(), -1);
360 return *this;
361 }
362
364 {
365 const Container metaContainer = this->metaContainer();
366 QConstIterator result(this->constIterable(), metaContainer.constBegin(
367 this->constIterable()->constIterable()));
368 metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
369 metaContainer.advanceConstIterator(this->mutableIterator(), -1);
370 return result;
371 }
372
373 QConstIterator &operator+=(qsizetype j)
374 {
375 this->metaContainer().advanceConstIterator(this->mutableIterator(), j);
376 return *this;
377 }
378
379 QConstIterator &operator-=(qsizetype j)
380 {
381 this->metaContainer().advanceConstIterator(this->mutableIterator(), -j);
382 return *this;
383 }
384
385 QConstIterator operator+(qsizetype j) const
386 {
387 const Container metaContainer = this->metaContainer();
388 QConstIterator result(
389 this->constIterable(),
390 metaContainer.constBegin(this->constIterable()->constIterable()));
391 metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
392 metaContainer.advanceConstIterator(result.mutableIterator(), j);
393 return result;
394 }
395
396 QConstIterator operator-(qsizetype j) const
397 {
398 const Container metaContainer = this->metaContainer();
399 QConstIterator result(this->constIterable(), metaContainer.constBegin(
400 this->constIterable()->constIterable()));
401 metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
402 metaContainer.advanceConstIterator(result.mutableIterator(), -j);
403 return result;
404 }
405
407 {
408 return this->metaContainer().diffIterator(this->constIterator(), j.constIterator());
409 }
410
411 friend inline QConstIterator operator+(qsizetype j, const QConstIterator &k)
412 {
413 return k + j;
414 }
415};
416
417template<class Container>
419{
420 friend class QBaseIterator<Container>;
421
422protected:
426
427public:
428 template<class T>
429 QIterable(const Container &metaContainer, const T *p)
430 : m_iterable(p), m_metaContainer(metaContainer)
431 {
432 }
433
434 template<class T>
435 QIterable(const Container &metaContainer, T *p)
436 : m_iterable(p), m_metaContainer(metaContainer)
437 {
438 }
439
440 template<typename Pointer>
441 QIterable(const Container &metaContainer, Pointer iterable)
442 : m_iterable(iterable), m_metaContainer(metaContainer)
443 {
444 }
445
446 QIterable(const Container &metaContainer, qsizetype alignment, const void *p)
447 : m_iterable(p, alignment), m_metaContainer(metaContainer)
448 {
449 }
450
451 QIterable(const Container &metaContainer, qsizetype alignment, void *p)
452 : m_iterable(p, alignment), m_metaContainer(metaContainer)
453 {
454 }
455
456 bool canInputIterate() const
457 {
458 return m_metaContainer.hasInputIterator();
459 }
460
461 bool canForwardIterate() const
462 {
463 return m_metaContainer.hasForwardIterator();
464 }
465
466 bool canReverseIterate() const
467 {
468 return m_metaContainer.hasBidirectionalIterator();
469 }
470
472 {
473 return m_metaContainer.hasRandomAccessIterator();
474 }
475
476 const void *constIterable() const { return m_iterable.constPointer(); }
477 void *mutableIterable() { return m_iterable.mutablePointer(); }
478
479 QConstIterator<Container> constBegin() const
480 {
481 return QConstIterator(this, m_metaContainer.constBegin(constIterable()));
482 }
483
484 QConstIterator<Container> constEnd() const
485 {
486 return QConstIterator(this, m_metaContainer.constEnd(constIterable()));
487 }
488
490 {
491 return QIterator(this, m_metaContainer.begin(mutableIterable()));
492 }
493
495 {
497 }
498
500 {
501 const void *container = constIterable();
502 if (m_metaContainer.hasSize())
503 return m_metaContainer.size(container);
504
505#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
506 // We shouldn't second-guess the underlying container, so we're not synthesizing a size.
507 return -1;
508#else
511
512 if (!m_metaContainer.hasConstIterator())
513 return -1;
514
515 const void *begin = m_metaContainer.constBegin(container);
516 const void *end = m_metaContainer.constEnd(container);
517 const qsizetype size = m_metaContainer.diffConstIterator(end, begin);
518 m_metaContainer.destroyConstIterator(begin);
519 m_metaContainer.destroyConstIterator(end);
520 return size;
521#endif
522 }
523
524 void clear()
525 {
527 }
528
529 Container metaContainer() const
530 {
531 return m_metaContainer;
532 }
533};
534
535QT_END_NAMESPACE
536
537#endif // QITERABLE_H
\inmodule QtCore QBaseIterator<Container> forms the common base class for all iterators operating on ...
Definition qiterable.h:135
QBaseIterator(QBaseIterator &&other)
Definition qiterable.h:150
QBaseIterator & operator=(QBaseIterator &&other)
Definition qiterable.h:164
QBaseIterator(QIterable< Container > *iterable, void *iterator)
Definition qiterable.h:146
const QIterable< Container > * constIterable() const
Definition qiterable.h:190
const void * constIterator() const
Returns a const pointer to the internal native iterator.
Definition qiterable.h:220
void clearIterator()
Definition qiterable.h:208
Container metaContainer() const
Definition qiterable.h:221
QBaseIterator & operator=(const QBaseIterator &other)
Definition qiterable.h:175
void * mutableIterator()
Returns a non-const pointer to the internal native iterator.
Definition qiterable.h:219
QBaseIterator()=default
QIterable< Container > * mutableIterable() const
Definition qiterable.h:185
QBaseIterator(const QIterable< Container > *iterable, void *iterator)
Definition qiterable.h:142
QBaseIterator(const QBaseIterator &other)
Definition qiterable.h:156
void initIterator(const void *copy)
Definition qiterable.h:195
\inmodule QtCore
Definition qiterable.h:419
bool canForwardIterate() const
Returns whether it is possible to iterate over the container in forward direction.
Definition qiterable.h:461
uint m_revision
Definition qiterable.h:423
QIterable(const Container &metaContainer, Pointer iterable)
Definition qiterable.h:441
QConstIterator< Container > constEnd() const
Returns a Qterable::QConstIterator for the end of the container.
Definition qiterable.h:484
const void * constIterable() const
Definition qiterable.h:476
QIterator< Container > mutableEnd()
Returns a QMetaSequence::Iterable::iterator for the end of the container.
Definition qiterable.h:494
QIterable(const Container &metaContainer, qsizetype alignment, const void *p)
Definition qiterable.h:446
Container m_metaContainer
Definition qiterable.h:425
bool canReverseIterate() const
Returns whether it is possible to iterate over the container in reverse.
Definition qiterable.h:466
QIterable(const Container &metaContainer, const T *p)
Definition qiterable.h:429
QConstIterator< Container > constBegin() const
Returns a QConstIterator for the beginning of the container.
Definition qiterable.h:479
bool canInputIterate() const
Returns whether the container has an input iterator.
Definition qiterable.h:456
bool canRandomAccessIterate() const
Returns whether it is possible to efficiently skip over multiple values using and iterator.
Definition qiterable.h:471
void clear()
Clears the container.
Definition qiterable.h:524
void * mutableIterable()
Definition qiterable.h:477
Container metaContainer() const
Definition qiterable.h:529
QtPrivate::QConstPreservingPointer< void, quint16 > m_iterable
Definition qiterable.h:424
QIterable(const Container &metaContainer, T *p)
Definition qiterable.h:435
QIterable(const Container &metaContainer, qsizetype alignment, void *p)
Definition qiterable.h:451
qsizetype size() const
Returns the number of values in the container.
Definition qiterable.h:499
QIterator< Container > mutableBegin()
Returns a QIterator for the beginning of the container.
Definition qiterable.h:489
QTaggedIterator is a template class that wraps an iterator and exposes standard iterator traits.
Definition qiterable.h:75
QTaggedIterator & operator-=(qsizetype j)
Makes the iterator go back by j items.
Definition qiterable.h:117
friend QTaggedIterator operator+(qsizetype j, const QTaggedIterator &k)
Returns an iterator to the item at j positions forward from iterator k.
Definition qiterable.h:127
bool operator<(const QTaggedIterator &j)
Definition qiterable.h:122
QTaggedIterator operator+(qsizetype j) const
Returns an iterator to the item at j positions forward from this iterator.
Definition qiterable.h:118
QTaggedIterator operator--(int x)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:115
bool operator!=(const QTaggedIterator &o) const
Returns true if other points to a different item than this iterator; otherwise returns false.
Definition qiterable.h:111
QTaggedIterator operator++(int x)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:113
bool operator<=(const QTaggedIterator &j)
Definition qiterable.h:125
bool operator==(const QTaggedIterator &o) const
Returns true if other points to the same item as this iterator; otherwise returns false.
Definition qiterable.h:110
QTaggedIterator & operator--()
The prefix {–} operator ({–it}) makes the preceding item current and returns an iterator to the new c...
Definition qiterable.h:114
QTaggedIterator & operator+=(qsizetype j)
Advances the iterator by j items.
Definition qiterable.h:116
QTaggedIterator & operator++()
The prefix {++} operator ({++it}) advances the iterator to the next item in the container and returns...
Definition qiterable.h:112
bool operator>(const QTaggedIterator &j)
Definition qiterable.h:124
QTaggedIterator operator-(qsizetype j) const
Returns an iterator to the item at j positions backward from this iterator.
Definition qiterable.h:119
QTaggedIterator(Iterator &&it)
Constructs a QTaggedIterator from an iterator or QConstIterator it.
Definition qiterable.h:78
IteratorCategory iterator_category
Definition qiterable.h:77
bool operator>=(const QTaggedIterator &j)
Definition qiterable.h:123
qsizetype operator-(const QTaggedIterator &j) const
Returns the distance between this iterator and j.
Definition qiterable.h:120
const Type * constPointer() const
Definition qiterable.h:53
Q_CORE_EXPORT void warnSynthesizedIterableAccess(SynthesizedAccessFunction function)
SynthesizedAccessFunction
Definition qiterable.h:65
The QConstIterator allows iteration over a container in a QVariant.
Definition qiterable.h:320
bool operator==(const QConstIterator &o) const
Returns true if other points to the same item as this iterator; otherwise returns false.
Definition qiterable.h:329
QConstIterator & operator+=(qsizetype j)
Advances the iterator by j items.
Definition qiterable.h:373
QConstIterator(const QIterable< Container > *iterable, void *iterator)
Creates a QConstIterator to wrap iterator, operating on iterable.
Definition qiterable.h:324
QConstIterator operator++(int)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:347
friend QConstIterator operator+(qsizetype j, const QConstIterator &k)
Definition qiterable.h:411
QConstIterator operator+(qsizetype j) const
Returns an iterator to the item at j positions forward from this iterator.
Definition qiterable.h:385
QConstIterator operator--(int)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:363
bool operator!=(const QConstIterator &o) const
Returns true if other points to a different item than this iterator; otherwise returns false.
Definition qiterable.h:335
qsizetype operator-(const QConstIterator &j) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:406
QConstIterator & operator-=(qsizetype j)
Makes the iterator go back by j items.
Definition qiterable.h:379
QConstIterator & operator--()
The prefix {–} operator ({–it}) makes the preceding item current and returns an iterator to the new c...
Definition qiterable.h:357
QConstIterator & operator++()
The prefix {++} operator ({++it}) advances the iterator to the next item in the container and returns...
Definition qiterable.h:341
QConstIterator operator-(qsizetype j) const
Returns an iterator to the item at j positions backward from this iterator.
Definition qiterable.h:396
The QIterator is a template class that allows iteration over a container in a QVariant.
Definition qiterable.h:226
bool operator==(const QIterator &o) const
Returns true if other points to the same item as this iterator; otherwise returns false.
Definition qiterable.h:236
friend QIterator operator+(qsizetype j, const QIterator &k)
Returns an iterator to the item at j positions forward from iterator k.
Definition qiterable.h:315
QIterator & operator+=(qsizetype j)
Advances the iterator by j items.
Definition qiterable.h:278
bool operator!=(const QIterator &o) const
Returns true if other points to a different item than this iterator; otherwise returns false.
Definition qiterable.h:241
QIterator operator-(qsizetype j) const
Returns an iterator to the item at j positions backward from this iterator.
Definition qiterable.h:300
QIterator & operator--()
The prefix {–} operator ({–it}) makes the preceding item current and returns an iterator to the new c...
Definition qiterable.h:262
qsizetype operator-(const QIterator &j) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:310
QIterator & operator-=(qsizetype j)
Makes the iterator go back by j items.
Definition qiterable.h:284
QIterator(QIterable< Container > *iterable, void *iterator)
Creates an iterator from an iterable and a pointer to a native iterator.
Definition qiterable.h:230
QIterator operator++(int)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:252
QIterator operator+(qsizetype j) const
Returns an iterator to the item at j positions forward from this iterator.
Definition qiterable.h:290
QIterator & operator++()
The prefix {++} operator ({++it}) advances the iterator to the next item in the container and returns...
Definition qiterable.h:246
QIterator operator--(int)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qiterable.h:268