rtlds_imp.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #ifndef rtlds_imp_hpp
  15. #define rtlds_imp_hpp
  16. #include "eclhelper.hpp"
  17. #include "eclrtl_imp.hpp"
  18. //These interfaces aren't always used (because of speed), although may be sensible to switch to them if they prove useful
  19. //either for hiding the implementations, or because I can then write general library functions.
  20. interface IRtlDatasetSimpleCursor
  21. {
  22. virtual const byte * first() = 0;
  23. virtual const byte * next() = 0;
  24. };
  25. interface IRtlDatasetCursor : public IRtlDatasetSimpleCursor
  26. {
  27. virtual const byte * get() = 0;
  28. virtual bool isValid() = 0;
  29. virtual const byte * select(unsigned idx) = 0;
  30. };
  31. //---------------------------------------------------------------------------
  32. interface IResourceContext;
  33. typedef size32_t (*DefaultRowCreator)(ARowBuilder & self, IResourceContext *ctx);
  34. //shouldn't really be derived from ARowBuilder - not a isA, but more efficient
  35. class ECLRTL_API RtlDatasetBuilder : protected ARowBuilder, public RtlCInterface
  36. {
  37. public:
  38. RtlDatasetBuilder();
  39. ~RtlDatasetBuilder();
  40. RTLIMPLEMENT_IINTERFACE
  41. void getData(size32_t & len, void * & data);
  42. size32_t getSize();
  43. byte * queryData();
  44. void queryData(size32_t & len, void * & data);
  45. byte * createRow() { return rowBuilder().getSelf(); }
  46. void finalizeRow(size32_t rowSize) { totalSize += rowSize; self = NULL; }
  47. inline ARowBuilder & rowBuilder() { return *this; }
  48. //IRowBuilder
  49. virtual byte * ensureCapacity(size32_t required, const char * fieldName);
  50. virtual void reportMissingRow() const;
  51. virtual byte * createSelf() = 0;
  52. protected:
  53. void ensure(size32_t required);
  54. protected:
  55. virtual void flushDataset();
  56. protected:
  57. size32_t maxSize;
  58. size32_t totalSize;
  59. byte * buffer;
  60. };
  61. class ECLRTL_API RtlFixedDatasetBuilder : public RtlDatasetBuilder
  62. {
  63. public:
  64. RtlFixedDatasetBuilder(unsigned _recordSize, unsigned _initRows);
  65. byte * createSelf();
  66. protected:
  67. unsigned recordSize;
  68. };
  69. class ECLRTL_API RtlLimitedFixedDatasetBuilder : public RtlFixedDatasetBuilder
  70. {
  71. public:
  72. RtlLimitedFixedDatasetBuilder(unsigned _recordSize, unsigned _maxRows, DefaultRowCreator _rowCreator, IResourceContext *_ctx);
  73. byte * createRow();
  74. protected:
  75. virtual void flushDataset();
  76. protected:
  77. unsigned maxRows;
  78. DefaultRowCreator rowCreator;
  79. IResourceContext *ctx;
  80. };
  81. class ECLRTL_API RtlVariableDatasetBuilder : public RtlDatasetBuilder
  82. {
  83. public:
  84. RtlVariableDatasetBuilder(IRecordSize & _recordSize);
  85. void deserializeRow(IOutputRowDeserializer & deserializer, IRowDeserializerSource & in);
  86. virtual byte * createSelf();
  87. protected:
  88. IRecordSize * recordSize;
  89. unsigned maxRowSize;
  90. };
  91. class ECLRTL_API RtlLimitedVariableDatasetBuilder : public RtlVariableDatasetBuilder
  92. {
  93. public:
  94. RtlLimitedVariableDatasetBuilder(IRecordSize & _recordSize, unsigned _maxRows, DefaultRowCreator _rowCreator, IResourceContext * _ctx);
  95. byte * createRow();
  96. protected:
  97. virtual void flushDataset();
  98. protected:
  99. unsigned numRows;
  100. unsigned maxRows;
  101. DefaultRowCreator rowCreator;
  102. IResourceContext *ctx;
  103. };
  104. //---------------------------------------------------------------------------
  105. class ECLRTL_API rtlRowAttr
  106. {
  107. public:
  108. inline rtlRowAttr() { row=NULL; };
  109. inline ~rtlRowAttr() { dispose(); }
  110. inline void clear() { dispose(); row = NULL; }
  111. inline byte * getClear() { byte * ret = row; row = NULL; return ret; }
  112. inline byte * getbytes() const { return row; }
  113. inline byte * link() const { return (byte *)rtlLinkRow(row); }
  114. inline void set(byte * _row) { rtlLinkRow(_row); dispose(); row = _row; }
  115. inline void setown(byte * _row) { dispose(); row = _row; }
  116. inline void set(const void * _row) { rtlLinkRow(_row); setown(_row); }
  117. inline void setown(const void * _row) { dispose(); row = static_cast<byte *>(const_cast<void *>(_row)); } // ugly - need to clean up const tracking in code generator
  118. protected:
  119. inline void dispose() { rtlReleaseRow(row); }
  120. private:
  121. //Force errors....
  122. inline rtlRowAttr(const rtlRowAttr &) {}
  123. inline rtlRowAttr & operator = (const rtlRowAttr & other) { row = NULL; return *this; }
  124. protected:
  125. byte * row;
  126. };
  127. class ECLRTL_API rtlRowsAttr
  128. {
  129. public:
  130. inline rtlRowsAttr() { count = 0; rows=NULL; };
  131. inline ~rtlRowsAttr() { dispose(); }
  132. inline void clear() { dispose(); rows = NULL; }
  133. inline byte * * * addrrows() { clear(); return &rows; }
  134. inline byte * * queryrows() const { return rows; }
  135. inline unsigned querycount() const { return count; }
  136. byte * * linkrows() const;
  137. inline byte * * & refrows() { clear(); return rows; }
  138. void set(size32_t _count, byte * * _rows);
  139. void setRow(IEngineRowAllocator * rowAllocator, const byte * row);
  140. void setown(size32_t _count, byte * * _rows);
  141. protected:
  142. void dispose();
  143. private:
  144. //Force errors....
  145. inline rtlRowsAttr(const rtlRowsAttr &) {}
  146. inline rtlRowsAttr & operator = (const rtlRowsAttr & other) { count = 0; rows = NULL; return *this; }
  147. public:
  148. unsigned count;
  149. protected:
  150. byte * * rows;
  151. };
  152. //---------------------------------------------------------------------------
  153. void ECLRTL_API rtlReportFieldOverflow(unsigned size, unsigned max, const RtlFieldInfo * field);
  154. class ECLRTL_API RtlRowBuilderBase : implements ARowBuilder, public RtlCInterface
  155. {
  156. public:
  157. RTLIMPLEMENT_IINTERFACE
  158. virtual void reportMissingRow() const;
  159. };
  160. class ECLRTL_API RtlDynamicRowBuilder : implements RtlRowBuilderBase
  161. {
  162. public:
  163. inline RtlDynamicRowBuilder(IEngineRowAllocator * _rowAllocator) : rowAllocator(_rowAllocator)
  164. {
  165. if (rowAllocator)
  166. create();
  167. else
  168. {
  169. self = NULL;
  170. maxLength = 0;
  171. }
  172. }
  173. inline RtlDynamicRowBuilder(IEngineRowAllocator * _rowAllocator, bool createInitial) : rowAllocator(_rowAllocator)
  174. {
  175. if (rowAllocator && createInitial)
  176. create();
  177. else
  178. {
  179. self = NULL;
  180. maxLength = 0;
  181. }
  182. }
  183. //This is here to allow group aggregates to perform resizing.
  184. inline RtlDynamicRowBuilder(IEngineRowAllocator * _rowAllocator, size32_t _maxLength, void * _self) : rowAllocator(_rowAllocator)
  185. {
  186. self = static_cast<byte *>(_self);
  187. maxLength = _maxLength;
  188. }
  189. inline ~RtlDynamicRowBuilder() { clear(); }
  190. virtual byte * ensureCapacity(size32_t required, const char * fieldName);
  191. inline RtlDynamicRowBuilder & ensureRow() { if (!self) create(); return *this; }
  192. inline bool exists() { return (self != NULL); }
  193. inline const void * finalizeRowClear(size32_t len)
  194. {
  195. const unsigned finalMaxLength = maxLength;
  196. maxLength = 0;
  197. return rowAllocator->finalizeRow(len, getUnfinalizedClear(), finalMaxLength);
  198. }
  199. inline size32_t getMaxLength() const { return maxLength; }
  200. inline void * getUnfinalizedClear() { void * ret = self; self = NULL; return ret; }
  201. inline void clear() { if (self) { rowAllocator->releaseRow(self); self = NULL; } }
  202. inline RtlDynamicRowBuilder & setAllocator(IEngineRowAllocator * _rowAllocator) { rowAllocator = _rowAllocator; return *this; }
  203. inline void setown(size32_t _maxLength, void * _self) { self = static_cast<byte *>(_self); maxLength = _maxLength; }
  204. void swapWith(RtlDynamicRowBuilder & other);
  205. protected:
  206. inline byte * create() { self = static_cast<byte *>(rowAllocator->createRow(maxLength)); return self; }
  207. virtual byte * createSelf() { return create(); }
  208. protected:
  209. IEngineRowAllocator * rowAllocator; // does this need to be linked???
  210. size32_t maxLength;
  211. };
  212. class ECLRTL_API RtlStaticRowBuilder : extends RtlRowBuilderBase
  213. {
  214. public:
  215. inline RtlStaticRowBuilder(void * _self, size32_t _maxLength)
  216. {
  217. self = static_cast<byte *>(_self);
  218. maxLength = _maxLength;
  219. }
  220. virtual byte * ensureCapacity(size32_t required, const char * fieldName);
  221. inline void clear() { self = NULL; maxLength = 0; }
  222. inline void set(size32_t _maxLength, void * _self) { self = static_cast<byte *>(_self); maxLength = _maxLength; }
  223. protected:
  224. virtual byte * createSelf();
  225. protected:
  226. size32_t maxLength;
  227. };
  228. class ECLRTL_API RtlNestedRowBuilder : extends RtlRowBuilderBase
  229. {
  230. public:
  231. inline RtlNestedRowBuilder(ARowBuilder & _container, size32_t _offset, size32_t _suffix)
  232. : container(_container), offset(_offset), suffix(_suffix)
  233. {
  234. self = container.row()+offset;
  235. }
  236. virtual byte * ensureCapacity(size32_t required, const char * fieldName)
  237. {
  238. self = container.ensureCapacity(offset+required+suffix, fieldName) + offset;
  239. return self;
  240. }
  241. protected:
  242. virtual byte * createSelf()
  243. {
  244. self = container.getSelf()+offset;
  245. return self;
  246. }
  247. protected:
  248. ARowBuilder & container;
  249. size32_t offset;
  250. size32_t suffix;
  251. };
  252. //---------------------------------------------------------------------------
  253. class ECLRTL_API CSimpleSourceRowPrefetcher : public ISourceRowPrefetcher, public RtlCInterface
  254. {
  255. public:
  256. CSimpleSourceRowPrefetcher(IOutputMetaData & _meta, ICodeContext * _ctx, unsigned _activityId)
  257. {
  258. deserializer.setown(_meta.querySerializedMeta()->createRowDeserializer(_ctx, _activityId));
  259. rowAllocator.setown(_ctx->getRowAllocator(&_meta, _activityId));
  260. }
  261. RTLIMPLEMENT_IINTERFACE
  262. virtual void readAhead(IRowDeserializerSource & in)
  263. {
  264. RtlDynamicRowBuilder rowBuilder(rowAllocator);
  265. size32_t len = deserializer->deserialize(rowBuilder, in);
  266. rtlReleaseRow(rowBuilder.finalizeRowClear(len));
  267. }
  268. protected:
  269. Owned<IOutputRowDeserializer> deserializer;
  270. Owned<IEngineRowAllocator> rowAllocator;
  271. };
  272. //---------------------------------------------------------------------------
  273. class ECLRTL_API RtlLinkedDatasetBuilder
  274. {
  275. public:
  276. RtlLinkedDatasetBuilder(IEngineRowAllocator * _rowAllocator, int _choosenLimit=-1);
  277. ~RtlLinkedDatasetBuilder();
  278. void append(const void * source);
  279. void appendRows(size32_t num, byte * * rows);
  280. inline void appendEOG() { appendOwn(NULL); }
  281. byte * createRow();
  282. void cloneRow(size32_t len, const void * ptr);
  283. void deserialize(IOutputRowDeserializer & deserializer, IRowDeserializerSource & in, bool isGrouped);
  284. void deserializeRow(IOutputRowDeserializer & deserializer, IRowDeserializerSource & in);
  285. void expand(size32_t required);
  286. void resize(size32_t required);
  287. void finalizeRows();
  288. void finalizeRow(size32_t len);
  289. inline RtlDynamicRowBuilder & rowBuilder() { return builder; }
  290. inline void ensure(size32_t required) { if (required > max) expand(required); }
  291. inline size32_t getcount() { finalizeRows(); return count; }
  292. byte * * linkrows();
  293. inline byte * * queryrows() { finalizeRows(); return rowset; }
  294. void appendOwn(const void * row);
  295. inline byte * row() const { return builder.row(); }
  296. protected:
  297. IEngineRowAllocator * rowAllocator;
  298. RtlDynamicRowBuilder builder;
  299. byte * * rowset;
  300. size32_t count;
  301. size32_t max;
  302. size32_t choosenLimit;
  303. };
  304. class ECLRTL_API RtlLinkedDictionaryBuilder
  305. {
  306. public:
  307. RtlLinkedDictionaryBuilder(IEngineRowAllocator * _rowAllocator, IHThorHashLookupInfo *_hashInfo, unsigned _initialTableSize);
  308. RtlLinkedDictionaryBuilder(IEngineRowAllocator * _rowAllocator, IHThorHashLookupInfo *_hashInfo);
  309. ~RtlLinkedDictionaryBuilder();
  310. void append(const void * source);
  311. void appendOwn(const void * source);
  312. void appendRows(size32_t num, byte * * rows);
  313. inline size32_t getcount() { return tableSize; }
  314. inline byte * * linkrows() { return rtlLinkRowset(table); }
  315. byte * createRow() { return builder.getSelf(); }
  316. void finalizeRow(size32_t len);
  317. inline RtlDynamicRowBuilder & rowBuilder() { return builder; }
  318. /*
  319. Not clear which if any of these we will want...
  320. void cloneRow(size32_t len, const void * ptr);
  321. void deserialize(IOutputRowDeserializer & deserializer, IRowDeserializerSource & in, bool isGrouped);
  322. void deserializeRow(IOutputRowDeserializer & deserializer, IRowDeserializerSource & in);
  323. void expand(size32_t required);
  324. void resize(size32_t required);
  325. void finalizeRows();
  326. inline void ensure(size32_t required) { if (required > max) expand(required); }
  327. inline byte * * queryrows() { finalizeRows(); return rowset; }
  328. inline byte * row() const { return builder.row(); }
  329. */
  330. protected:
  331. void checkSpace();
  332. void init(IEngineRowAllocator * _rowAllocator, IHThorHashLookupInfo *_hashInfo, unsigned _initialTableSize);
  333. protected:
  334. IEngineRowAllocator *rowAllocator;
  335. IHash *hash;
  336. ICompare *compare;
  337. RtlDynamicRowBuilder builder;
  338. byte * * table;
  339. size32_t usedCount;
  340. size32_t usedLimit;
  341. size32_t initialSize;
  342. size32_t tableSize;
  343. };
  344. extern ECLRTL_API byte *rtlDictionaryLookup(IHThorHashLookupInfo &hashInfo, size32_t tableSize, byte **table, const byte *source, byte *defaultRow);
  345. extern ECLRTL_API void appendRowsToRowset(size32_t & targetCount, byte * * & targetRowset, IEngineRowAllocator * rowAllocator, size32_t count, byte * * rows);
  346. extern ECLRTL_API void rtlDeserializeRowset(size32_t & count, byte * * & rowset, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, IRowDeserializerSource & in);
  347. extern ECLRTL_API void rtlDeserializeRowset(size32_t & count, byte * * & rowset, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, size32_t lenSrc, const void * src);
  348. extern ECLRTL_API void rtlSerializeRowset(IRowSerializerTarget & out, IOutputRowSerializer * serializer, size32_t count, byte * * rows);
  349. extern ECLRTL_API void rtlSerializeRowset(unsigned & tlen, void * & tgt, IOutputRowSerializer * serializer, size32_t count, byte * * rows);
  350. extern ECLRTL_API void rtlDataset2RowsetX(size32_t & count, byte * * & rowset, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, size32_t lenSrc, const void * src, bool isGrouped);
  351. extern ECLRTL_API void rtlRowset2DatasetX(unsigned & tlen, void * & tgt, IOutputRowSerializer * serializer, size32_t count, byte * * rows, bool isGrouped);
  352. extern ECLRTL_API void rtlDataset2RowsetX(size32_t & count, byte * * & rowset, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, size32_t lenSrc, const void * src);
  353. extern ECLRTL_API void rtlGroupedDataset2RowsetX(size32_t & count, byte * * & rowset, IEngineRowAllocator * _rowAllocator, IOutputRowDeserializer * deserializer, size32_t lenSrc, const void * src);
  354. extern ECLRTL_API void rtlRowset2DatasetX(unsigned & tlen, void * & tgt, IOutputRowSerializer * serializer, size32_t count, byte * * rows);
  355. extern ECLRTL_API void rtlGroupedRowset2DatasetX(unsigned & tlen, void * & tgt, IOutputRowSerializer * serializer, size32_t count, byte * * rows);
  356. extern ECLRTL_API size32_t rtlDeserializeRow(size32_t lenOut, void * out, IOutputRowDeserializer * deserializer, const void * src);
  357. extern ECLRTL_API size32_t rtlSerializeRow(size32_t lenOut, void * out, IOutputRowSerializer * serializer, const void * src);
  358. extern ECLRTL_API size32_t rtlDeserializeToBuilder(ARowBuilder & builder, IOutputRowDeserializer * deserializer, const void * src);
  359. extern ECLRTL_API size32_t rtlSerializeToBuilder(ARowBuilder & builder, IOutputRowSerializer * serializer, const void * src);
  360. //---------------------------------------------------------------------------
  361. class ECLRTL_API ARtlDatasetCursor
  362. {
  363. //if we ever made the functions virtual, then they would go in here
  364. };
  365. class ECLRTL_API RtlDatasetCursor : public ARtlDatasetCursor
  366. {
  367. public:
  368. RtlDatasetCursor(size32_t _len, const void * _data);
  369. bool exists();
  370. const byte * first();
  371. const byte * get();
  372. void setDataset(size32_t len, const void * data);
  373. bool isValid();
  374. //const byte * next();
  375. protected:
  376. const byte * buffer;
  377. const byte * end;
  378. const byte * cur;
  379. };
  380. class ECLRTL_API RtlFixedDatasetCursor : public RtlDatasetCursor
  381. {
  382. public:
  383. RtlFixedDatasetCursor(size32_t _len, const void * _data, unsigned _recordSize);
  384. RtlFixedDatasetCursor();
  385. void init(size32_t _len, const void * _data, unsigned _recordSize);
  386. size32_t count();
  387. size32_t getSize();
  388. const byte * next();
  389. const byte * select(unsigned idx);
  390. protected:
  391. unsigned recordSize;
  392. };
  393. class ECLRTL_API RtlVariableDatasetCursor : public RtlDatasetCursor
  394. {
  395. public:
  396. RtlVariableDatasetCursor(size32_t _len, const void * _data, IRecordSize & _recordSize);
  397. RtlVariableDatasetCursor();
  398. void init(size32_t _len, const void * _data, IRecordSize & _recordSize);
  399. size32_t count();
  400. size32_t getSize();
  401. const byte * next();
  402. const byte * select(unsigned idx);
  403. protected:
  404. IRecordSize * recordSize;
  405. };
  406. class ECLRTL_API RtlLinkedDatasetCursor : public ARtlDatasetCursor
  407. {
  408. public:
  409. RtlLinkedDatasetCursor(unsigned _numRows, byte * * _rows);
  410. RtlLinkedDatasetCursor();
  411. void setDataset(unsigned _numRows, byte * * _rows) { init(_numRows, _rows); }
  412. void init(unsigned _numRows, byte * * _rows);
  413. inline size32_t count() { return numRows; }
  414. inline bool exists() { return numRows != 0; }
  415. // size32_t getSize() // no sensible implementation
  416. const byte * next();
  417. const byte * select(unsigned idx);
  418. const byte * first();
  419. const byte * get();
  420. bool isValid();
  421. protected:
  422. byte * * rows;
  423. unsigned numRows;
  424. unsigned cur;
  425. };
  426. //Some sample helper functions/classes:
  427. interface ICompare;
  428. extern bool ECLRTL_API rtlCheckInList(const void * lhs, IRtlDatasetCursor * cursor, ICompare * compare);
  429. class ECLRTL_API RtlHashInlistChecker
  430. {
  431. public:
  432. RtlHashInlistChecker(IHash * hashLeft, IHash * hashList, IRtlDatasetCursor * cursor);
  433. bool inList(const void * lhs);
  434. };
  435. class ECLRTL_API RtlCompoundIterator
  436. {
  437. public:
  438. RtlCompoundIterator();
  439. ~RtlCompoundIterator();
  440. void init(unsigned numLevels);
  441. void addIter(unsigned idx, IRtlDatasetSimpleCursor * iter, byte * * cursor);
  442. bool first(unsigned level);
  443. bool next(unsigned level);
  444. inline bool first() { ok = first(numLevels-1); return ok; }
  445. inline bool next() { ok = next(numLevels-1); return ok; }
  446. inline bool isValid() { return ok; }
  447. protected:
  448. inline void setCursor(unsigned level, const void * value)
  449. {
  450. *cursors[level] = (byte *)value;
  451. }
  452. protected:
  453. IRtlDatasetSimpleCursor * * iters;
  454. byte * * * cursors;
  455. unsigned numLevels;
  456. bool ok;
  457. };
  458. //Probably generate inline , rather than use this class, since very simple code...
  459. class ECLRTL_API RtlSimpleIterator
  460. {
  461. public:
  462. void addIter(unsigned idx, IRtlDatasetSimpleCursor * iter, byte * * cursor);
  463. bool first();
  464. bool next();
  465. inline bool isValid() { return (*cursor != NULL); }
  466. protected:
  467. IRtlDatasetSimpleCursor * iter;
  468. byte * * cursor;
  469. };
  470. #endif