jptree.ipp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef _PTREE_IPP
  14. #define _PTREE_IPP
  15. #include "jarray.hpp"
  16. #include "jexcept.hpp"
  17. #include "jhash.hpp"
  18. #include "jmutex.hpp"
  19. #include "jsuperhash.hpp"
  20. #include "jptree.hpp"
  21. #include "jbuff.hpp"
  22. #include "jlog.hpp"
  23. #define ANE_APPEND -1
  24. #define ANE_SET -2
  25. ///////////////////
  26. class MappingStringToOwned : public MappingStringTo<IInterfacePtr,IInterfacePtr>
  27. {
  28. public:
  29. MappingStringToOwned(const char * k, IInterfacePtr a) :
  30. MappingStringTo<IInterfacePtr,IInterfacePtr>(k,a) { }
  31. ~MappingStringToOwned() { ::Release(val); }
  32. };
  33. typedef MapStringTo<IInterfacePtr, IInterfacePtr, MappingStringToOwned> MapStringToOwned;
  34. // case sensitive childmap
  35. class jlib_decl ChildMap : protected SuperHashTableOf<IPropertyTree, constcharptr>
  36. {
  37. protected:
  38. // SuperHashTable definitions
  39. virtual void onAdd(void *) override {}
  40. virtual void onRemove(void *e) override
  41. {
  42. IPropertyTree &elem = *(IPropertyTree *)e;
  43. elem.Release();
  44. }
  45. virtual const void *getFindParam(const void *e) const override
  46. {
  47. const IPropertyTree &elem = *(const IPropertyTree *)e;
  48. return elem.queryName();
  49. }
  50. virtual unsigned getHashFromElement(const void *e) const override;
  51. virtual unsigned getHashFromFindParam(const void *fp) const override
  52. {
  53. return hashc((const unsigned char *)fp, (size32_t)strlen((const char *)fp), 0);
  54. }
  55. virtual bool matchesFindParam(const void *e, const void *fp, unsigned fphash) const override
  56. {
  57. return streq(((IPropertyTree *)e)->queryName(), (const char *)fp);
  58. }
  59. public:
  60. IMPLEMENT_IINTERFACE;
  61. IMPLEMENT_SUPERHASHTABLEOF_REF_FIND(IPropertyTree, constcharptr);
  62. inline unsigned count() const { return SuperHashTableOf<IPropertyTree, constcharptr>::count(); }
  63. ChildMap() : SuperHashTableOf<IPropertyTree, constcharptr>(4)
  64. {
  65. }
  66. ~ChildMap()
  67. {
  68. _releaseAll();
  69. }
  70. virtual unsigned numChildren();
  71. virtual IPropertyTreeIterator *getIterator(bool sort);
  72. virtual bool set(const char *key, IPropertyTree *tree)
  73. {
  74. return SuperHashTableOf<IPropertyTree, constcharptr>::replace(* tree);
  75. }
  76. virtual bool replace(const char *key, IPropertyTree *tree) // provides different semantics, used if element being replaced is not to be treated as deleted.
  77. {
  78. return SuperHashTableOf<IPropertyTree, constcharptr>::replace(* tree);
  79. }
  80. virtual IPropertyTree *query(const char *key)
  81. {
  82. return find(*key);
  83. }
  84. virtual bool remove(const char *key)
  85. {
  86. return SuperHashTableOf<IPropertyTree, constcharptr>::remove(key);
  87. }
  88. virtual bool removeExact(IPropertyTree *child)
  89. {
  90. return SuperHashTableOf<IPropertyTree, constcharptr>::removeExact(child);
  91. }
  92. };
  93. // case insensitive childmap
  94. class jlib_decl ChildMapNC : public ChildMap
  95. {
  96. public:
  97. // SuperHashTable definitions
  98. virtual unsigned getHashFromFindParam(const void *fp) const override
  99. {
  100. return hashnc((const unsigned char *)fp, (size32_t)strlen((const char *)fp), 0);
  101. }
  102. virtual bool matchesFindParam(const void *e, const void *fp, unsigned fphash) const override
  103. {
  104. return strieq(((IPropertyTree *)e)->queryName(), (const char *)fp);
  105. }
  106. };
  107. inline static int validJSONUtf8ChrLen(unsigned char c)
  108. {
  109. if (c <= 31)
  110. return 0;
  111. if ('\"' == c)
  112. return 0;
  113. if ('\\' == c)
  114. return 2;
  115. return utf8CharLen(c);
  116. }
  117. inline static bool isAttribute(const char *xpath) { return (xpath && *xpath == '@'); }
  118. jlib_decl const char *splitXPathUQ(const char *xpath, StringBuffer &path);
  119. jlib_decl const char *queryHead(const char *xpath, StringBuffer &head);
  120. jlib_decl const char *queryNextUnquoted(const char *str, char c);
  121. interface IPTArrayValue
  122. {
  123. virtual ~IPTArrayValue() { }
  124. virtual bool isArray() const = 0;
  125. virtual bool isCompressed() const = 0;
  126. virtual const void *queryValue() const = 0;
  127. virtual MemoryBuffer &getValue(MemoryBuffer &tgt, bool binary) const = 0;
  128. virtual StringBuffer &getValue(StringBuffer &tgt, bool binary) const = 0;
  129. virtual size32_t queryValueSize() const = 0;
  130. virtual IPropertyTree *queryElement(unsigned idx) const = 0;
  131. virtual void addElement(IPropertyTree *e) = 0;
  132. virtual void setElement(unsigned idx, IPropertyTree *e) = 0;
  133. virtual void removeElement(unsigned idx) = 0;
  134. virtual unsigned elements() const = 0;
  135. virtual const void *queryValueRaw() const = 0;
  136. virtual size32_t queryValueRawSize() const = 0;
  137. virtual void serialize(MemoryBuffer &tgt) = 0;
  138. virtual void deserialize(MemoryBuffer &src) = 0;
  139. };
  140. class CPTArray : implements IPTArrayValue, private IArray
  141. {
  142. public:
  143. virtual bool isArray() const override { return true; }
  144. virtual bool isCompressed() const override { return false; }
  145. virtual const void *queryValue() const override { UNIMPLEMENTED; }
  146. virtual MemoryBuffer &getValue(MemoryBuffer &tgt, bool binary) const override { UNIMPLEMENTED; }
  147. virtual StringBuffer &getValue(StringBuffer &tgt, bool binary) const override { UNIMPLEMENTED; }
  148. virtual size32_t queryValueSize() const override { UNIMPLEMENTED; }
  149. virtual IPropertyTree *queryElement(unsigned idx) const override { return (idx<ordinality()) ? &((IPropertyTree &)item(idx)) : NULL; }
  150. virtual void addElement(IPropertyTree *tree) override { append(*tree); }
  151. virtual void setElement(unsigned idx, IPropertyTree *tree) override { add(*tree, idx); }
  152. virtual void removeElement(unsigned idx) override { remove(idx); }
  153. virtual unsigned elements() const override { return ordinality(); }
  154. virtual const void *queryValueRaw() const override { UNIMPLEMENTED; return NULL; }
  155. virtual size32_t queryValueRawSize() const override { UNIMPLEMENTED; return 0; }
  156. // serializable
  157. virtual void serialize(MemoryBuffer &tgt) override { UNIMPLEMENTED; }
  158. virtual void deserialize(MemoryBuffer &src) override { UNIMPLEMENTED; }
  159. };
  160. class jlib_decl CPTValue : implements IPTArrayValue, private MemoryAttr
  161. {
  162. public:
  163. CPTValue(MemoryBuffer &src)
  164. {
  165. deserialize(src);
  166. }
  167. CPTValue(size32_t size, const void *data, bool binary=false, bool raw=false, bool compressed=false);
  168. virtual bool isArray() const override { return false; }
  169. virtual bool isCompressed() const override { return compressed; }
  170. virtual const void *queryValue() const override;
  171. virtual MemoryBuffer &getValue(MemoryBuffer &tgt, bool binary) const override;
  172. virtual StringBuffer &getValue(StringBuffer &tgt, bool binary) const override;
  173. virtual size32_t queryValueSize() const override;
  174. virtual IPropertyTree *queryElement(unsigned idx) const override { UNIMPLEMENTED; return NULL; }
  175. virtual void addElement(IPropertyTree *tree) override { UNIMPLEMENTED; }
  176. virtual void setElement(unsigned idx, IPropertyTree *tree) override { UNIMPLEMENTED; }
  177. virtual void removeElement(unsigned idx) override { UNIMPLEMENTED; }
  178. virtual unsigned elements() const override { UNIMPLEMENTED; return (unsigned)-1; }
  179. virtual const void *queryValueRaw() const override { return get(); }
  180. virtual size32_t queryValueRawSize() const override { return (size32_t)length(); }
  181. // serializable
  182. virtual void serialize(MemoryBuffer &tgt) override;
  183. virtual void deserialize(MemoryBuffer &src) override;
  184. private:
  185. mutable bool compressed;
  186. };
  187. #define IptFlagTst(fs, f) (0!=(fs&(f)))
  188. #define IptFlagSet(fs, f) (fs |= (f))
  189. #define IptFlagClr(fs, f) (fs &= (~f))
  190. // NOTE - hairy code alert!
  191. // In order to keep code common between atom and local versions of ptree, we store the atom-specific information BEFORE the this pointer of AttrStr
  192. // (see class AttrStrAtom below).
  193. // This requires some care - in particular must use the right method to destroy the objects, and must not add any virtual methods to either class
  194. //#define TRACE_STRING_SIZE
  195. //#define TRACE_ATOM_SIZE
  196. //#define TRACE_ALL_STRING
  197. //#define TRACE_ALL_ATOM
  198. struct AttrStr
  199. {
  200. const char *get() const
  201. {
  202. return str_DO_NOT_USE_DIRECTLY;
  203. }
  204. char str_DO_NOT_USE_DIRECTLY[1]; // Actually [n] - null terminated
  205. static AttrStr *create(const char *k)
  206. {
  207. size32_t kl = k ? strlen(k) : 0;
  208. #ifdef TRACE_ALL_STRING
  209. DBGLOG("TRACE_ALL_STRING: %s", k);
  210. #endif
  211. #ifdef TRACE_STRING_SIZE
  212. totsize += kl+1;
  213. if (totsize > maxsize)
  214. {
  215. maxsize.store(totsize);
  216. DBGLOG("TRACE_STRING_SIZE: total size now %" I64F "d", maxsize.load());
  217. }
  218. #endif
  219. AttrStr *ret = (AttrStr *) malloc(kl+1);
  220. memcpy(ret->str_DO_NOT_USE_DIRECTLY, k, kl);
  221. ret->str_DO_NOT_USE_DIRECTLY[kl] = 0;
  222. return ret;
  223. }
  224. static inline AttrStr *createNC(const char *k)
  225. {
  226. // If we started to use a static hash table for common values, we would probably want to use a different one here for case-insensitive matches
  227. return create(k);
  228. }
  229. static void destroy(AttrStr *a)
  230. {
  231. #ifdef TRACE_STRING_SIZE
  232. totsize -= strlen(a->str_DO_NOT_USE_DIRECTLY)+1;
  233. #endif
  234. free(a);
  235. }
  236. #ifdef TRACE_STRING_SIZE
  237. static std::atomic<__int64> totsize;
  238. static std::atomic<__int64> maxsize;
  239. #endif
  240. };
  241. // In order to keep code common between atom and local versions of ptree, we store the atom-specific information BEFORE the this pointer of AttrStr
  242. // This requires some care - in particular must use the right method to destroy the objects, and must not add any virtual methods to either class
  243. // Note that memory usage is significant as we create literally millions of these objects
  244. typedef unsigned hashfunc( const unsigned char *k, unsigned length, unsigned initval);
  245. struct AttrStrAtom
  246. {
  247. unsigned hash;
  248. unsigned short linkcount;
  249. char str_DO_NOT_USE_DIRECTLY[1]; // Actually N
  250. static AttrStrAtom *create(const char *k, size32_t kl, hashfunc _hash)
  251. {
  252. #ifdef TRACE_ALL_ATOM
  253. DBGLOG("TRACE_ALL_ATOM: %s", k);
  254. #endif
  255. #ifdef TRACE_ATOM_SIZE
  256. totsize += sizeof(AttrStrAtom)+kl+1;
  257. if (totsize > maxsize)
  258. {
  259. maxsize.store(totsize);
  260. DBGLOG("TRACE_ATOM_SIZE: total size now %" I64F "d", maxsize.load());
  261. }
  262. #endif
  263. AttrStrAtom *ret = (AttrStrAtom *) malloc(offsetof(AttrStrAtom, str_DO_NOT_USE_DIRECTLY)+kl+1);
  264. memcpy(ret->str_DO_NOT_USE_DIRECTLY, k, kl);
  265. ret->str_DO_NOT_USE_DIRECTLY[kl] = 0;
  266. ret->hash = _hash((const unsigned char *) k, kl, 17);
  267. ret->linkcount = 0;
  268. return ret;
  269. }
  270. static void destroy(AttrStrAtom *a)
  271. {
  272. #ifdef TRACE_ATOM_SIZE
  273. totsize -= sizeof(AttrStrAtom)+strlen(a->str_DO_NOT_USE_DIRECTLY)+1;
  274. #endif
  275. free(a);
  276. }
  277. AttrStr *toAttrStr()
  278. {
  279. return (AttrStr *) &str_DO_NOT_USE_DIRECTLY;
  280. }
  281. static AttrStrAtom *toAtom(AttrStr *a)
  282. {
  283. return (AttrStrAtom *)(&a->str_DO_NOT_USE_DIRECTLY - offsetof(AttrStrAtom, str_DO_NOT_USE_DIRECTLY));
  284. }
  285. #ifdef TRACE_ATOM_SIZE
  286. static std::atomic<__int64> totsize;
  287. static std::atomic<__int64> maxsize;
  288. #endif
  289. };
  290. struct AttrStrC : public AttrStrAtom
  291. {
  292. static inline unsigned getHash(const char *k)
  293. {
  294. return hashc((const byte *)k, strlen(k), 17);
  295. }
  296. inline bool eq(const char *k)
  297. {
  298. return streq(k,str_DO_NOT_USE_DIRECTLY);
  299. }
  300. static AttrStrC *create(const char *k)
  301. {
  302. size32_t kl = k ? strlen(k) : 0;
  303. return (AttrStrC *) AttrStrAtom::create(k, kl, hashc);
  304. }
  305. };
  306. struct AttrStrNC : public AttrStrAtom
  307. {
  308. static inline unsigned getHash(const char *k)
  309. {
  310. return hashnc((const byte *)k, strlen(k), 17);
  311. }
  312. inline bool eq(const char *k)
  313. {
  314. return strieq(k,str_DO_NOT_USE_DIRECTLY);
  315. }
  316. static AttrStrNC *create(const char *k)
  317. {
  318. size32_t kl = k ? strlen(k) : 0;
  319. return (AttrStrNC *) AttrStrAtom::create(k, kl, hashnc);
  320. }
  321. };
  322. typedef CMinHashTable<AttrStrC> RONameTable;
  323. // NOTE - hairy code alert!
  324. // To save on storage (and contention) we store short string values in same slot as the pointer to longer
  325. // ones would occupy. This relies on the assumption that the pointers you want to store are always AT LEAST
  326. // 2-byte aligned. This should be the case on anything coming from malloc on any modern architecture.
  327. #define USE_STRUNION
  328. template<class PTR>
  329. struct PtrStrUnion
  330. {
  331. #ifdef USE_STRUNION
  332. union
  333. {
  334. PTR *ptr;
  335. #if __BYTE_ORDER == __LITTLE_ENDIAN
  336. struct
  337. {
  338. char flag;
  339. char chars[sizeof(PTR *)-1];
  340. };
  341. struct
  342. {
  343. char flagx;
  344. int8_t idx1;
  345. int16_t idx2;
  346. };
  347. #else
  348. struct
  349. {
  350. char chars[sizeof(PTR *)-1];
  351. char flag;
  352. };
  353. struct
  354. {
  355. int16_t idx2;
  356. int8_t idx1;
  357. char flagx;
  358. };
  359. #endif
  360. };
  361. inline PtrStrUnion<PTR>() : ptr(nullptr) {}
  362. inline bool isPtr() const
  363. {
  364. return (flag&1) == 0;
  365. }
  366. inline const char *get() const
  367. {
  368. if (!isPtr())
  369. {
  370. assert(flag==1);
  371. return chars;
  372. }
  373. else if (ptr)
  374. return ptr->get();
  375. else
  376. return nullptr;
  377. }
  378. inline void destroy()
  379. {
  380. if (isPtr() && ptr)
  381. PTR::destroy(ptr);
  382. }
  383. bool set(const char *key)
  384. {
  385. if (key)
  386. {
  387. size32_t l = strnlen(key, sizeof(PTR *)); // technically sizeof(PTR)-1 would do, but I suspect 8 bytes is actually more optimal to search than 7
  388. if (l <= sizeof(PTR *)-2)
  389. {
  390. flag=1;
  391. memmove(chars, key, l); // Technically, they could overlap
  392. chars[l]=0;
  393. return true;
  394. }
  395. }
  396. return false;
  397. }
  398. inline void setPtr(PTR *a)
  399. {
  400. ptr = a;
  401. assert(isPtr());
  402. }
  403. #else
  404. PTR *ptr = nullptr;
  405. inline bool isPtr()
  406. {
  407. return true;
  408. }
  409. inline const char *get()
  410. {
  411. if (ptr)
  412. return ptr->get();
  413. else
  414. return nullptr;
  415. }
  416. inline void destroy()
  417. {
  418. if (ptr)
  419. PTR::destroy(ptr);
  420. }
  421. bool set(const char *key)
  422. {
  423. return false;
  424. }
  425. inline void setPtr(PTR *a)
  426. {
  427. ptr = a;
  428. }
  429. #endif
  430. inline PTR *getPtr() const
  431. {
  432. return isPtr() ? ptr : nullptr;
  433. }
  434. };
  435. #ifdef USE_STRUNION
  436. #define USE_READONLY_ATOMTABLE
  437. #endif
  438. typedef PtrStrUnion<AttrStr> AttrStrUnion;
  439. static_assert(sizeof(AttrStrUnion) == sizeof(AttrStr *), "AttrStrUnion size mismatch"); // Sanity check!
  440. #ifdef USE_READONLY_ATOMTABLE
  441. struct AttrStrUnionWithTable : public AttrStrUnion
  442. {
  443. inline const char *get() const
  444. {
  445. if (!isPtr() && flag==3)
  446. return roNameTable->getIndex(idx2)->str_DO_NOT_USE_DIRECTLY; // Should probably rename this back now!
  447. return AttrStrUnion::get();
  448. }
  449. bool set(const char *key)
  450. {
  451. if (AttrStrUnion::set(key))
  452. return true;
  453. if (key && key[0]=='@')
  454. {
  455. unsigned idx = roNameTable->findIndex(key, AttrStrC::getHash(key));
  456. if (idx != (unsigned) -1)
  457. {
  458. assert(idx <= 0xffff);
  459. flag = 3;
  460. idx2 = idx;
  461. return true;
  462. }
  463. }
  464. return false;
  465. }
  466. static RONameTable *roNameTable;
  467. };
  468. struct AttrStrUnionWithValueTable : public AttrStrUnion
  469. {
  470. inline const char *get() const
  471. {
  472. if (flag==3) // no point in also checking !isPtr() afaics
  473. return roValueTable->getIndex(idx2)->str_DO_NOT_USE_DIRECTLY; // Should probably rename this back now!
  474. return AttrStrUnion::get();
  475. }
  476. bool set(const char *key)
  477. {
  478. if (key)
  479. {
  480. unsigned idx = roValueTable->findIndex(key, AttrStrC::getHash(key));
  481. if (idx != (unsigned) -1)
  482. {
  483. assert(idx <= 0xffff);
  484. flag = 3;
  485. idx2 = idx;
  486. return true;
  487. }
  488. #ifdef _TRACE_VALUE_MISSES
  489. PROGLOG("notfound key = %s", key);
  490. #endif
  491. }
  492. return false;
  493. }
  494. static RONameTable *roValueTable;
  495. };
  496. #else
  497. typedef AttrStrUnion AttrStrUnionWithTable;
  498. typedef AttrStrUnion AttrStrUnionWithValueTable;
  499. #endif
  500. struct AttrValue
  501. {
  502. AttrStrUnionWithTable key;
  503. AttrStrUnionWithValueTable value;
  504. };
  505. class jlib_decl PTree : public CInterfaceOf<IPropertyTree>
  506. {
  507. friend class SingleIdIterator;
  508. friend class PTLocalIteratorBase;
  509. friend class PTIdMatchIterator;
  510. friend class ChildMap;
  511. public:
  512. PTree(byte _flags=ipt_none, IPTArrayValue *_value=nullptr, ChildMap *_children=nullptr);
  513. ~PTree();
  514. virtual void beforeDispose() override { }
  515. virtual unsigned queryHash() const = 0;
  516. IPropertyTree *queryParent() { return parent; }
  517. IPropertyTree *queryChild(unsigned index);
  518. ChildMap *queryChildren() { return children; }
  519. aindex_t findChild(IPropertyTree *child, bool remove=false);
  520. inline bool isnocase() const { return IptFlagTst(flags, ipt_caseInsensitive); }
  521. ipt_flags queryFlags() const { return (ipt_flags) flags; }
  522. void serializeSelf(MemoryBuffer &tgt);
  523. void serializeCutOff(MemoryBuffer &tgt, int cutoff=-1, int depth=0);
  524. void deserializeSelf(MemoryBuffer &src);
  525. void serializeAttributes(MemoryBuffer &tgt);
  526. IPropertyTree *clone(IPropertyTree &srcTree, bool self=false, bool sub=true);
  527. void clone(IPropertyTree &srcTree, IPropertyTree &dstTree, bool sub=true);
  528. inline void setParent(IPropertyTree *_parent) { parent = _parent; }
  529. IPropertyTree *queryCreateBranch(IPropertyTree *branch, const char *prop, bool *existing=NULL);
  530. IPropertyTree *splitBranchProp(const char *xpath, const char *&_prop, bool error=false);
  531. IPTArrayValue *queryValue() { return value; }
  532. IPTArrayValue *detachValue() { IPTArrayValue *v = value; value = NULL; return v; }
  533. void setValue(IPTArrayValue *_value, bool binary) { if (value) delete value; value = _value; if (binary) IptFlagSet(flags, ipt_binary); }
  534. bool checkPattern(const char *&xxpath) const;
  535. IPropertyTree *detach()
  536. {
  537. IPropertyTree *tree = create(queryName(), value, children, true);
  538. PTree *_tree = QUERYINTERFACE(tree, PTree); assertex(_tree); _tree->setParent(this);
  539. std::swap(numAttrs, _tree->numAttrs);
  540. std::swap(attrs, _tree->attrs);
  541. ::Release(children);
  542. children = nullptr;
  543. return tree;
  544. }
  545. virtual void createChildMap() { children = isnocase()?new ChildMapNC():new ChildMap(); }
  546. virtual void setName(const char *name) = 0;
  547. // IPropertyTree impl.
  548. virtual bool hasProp(const char * xpath) const override;
  549. virtual bool isBinary(const char *xpath=NULL) const override;
  550. virtual bool isCompressed(const char *xpath=NULL) const override;
  551. virtual bool renameProp(const char *xpath, const char *newName) override;
  552. virtual bool renameTree(IPropertyTree *tree, const char *newName) override;
  553. virtual const char *queryProp(const char *xpath) const override;
  554. virtual bool getProp(const char *xpath, StringBuffer &ret) const override;
  555. virtual void setProp(const char *xpath, const char *val) override;
  556. virtual void addProp(const char *xpath, const char *val) override;
  557. virtual void appendProp(const char *xpath, const char *val) override;
  558. virtual bool getPropBool(const char *xpath, bool dft=false) const override;
  559. virtual void setPropBool(const char *xpath, bool val) override { setPropInt(xpath, val); }
  560. virtual void addPropBool(const char *xpath, bool val) override { addPropInt(xpath, val); }
  561. virtual __int64 getPropInt64(const char *xpath, __int64 dft=0) const override;
  562. virtual void setPropInt64(const char * xpath, __int64 val) override;
  563. virtual void addPropInt64(const char *xpath, __int64 val) override;
  564. virtual int getPropInt(const char *xpath, int dft=0) const override;
  565. virtual void setPropInt(const char *xpath, int val) override;
  566. virtual void addPropInt(const char *xpath, int val) override;
  567. virtual bool getPropBin(const char * xpath, MemoryBuffer &ret) const override;
  568. virtual void setPropBin(const char * xpath, size32_t size, const void *data) override;
  569. virtual void appendPropBin(const char *xpath, size32_t size, const void *data) override;
  570. virtual void addPropBin(const char *xpath, size32_t size, const void *data) override;
  571. virtual IPropertyTree *getPropTree(const char *xpath) const override;
  572. virtual IPropertyTree *queryPropTree(const char *xpath) const override;
  573. virtual IPropertyTree *getBranch(const char *xpath) const override { return LINK(queryBranch(xpath)); }
  574. virtual IPropertyTree *queryBranch(const char *xpath) const override { return queryPropTree(xpath); }
  575. virtual IPropertyTree *setPropTree(const char *xpath, IPropertyTree *val) override;
  576. virtual IPropertyTree *addPropTree(const char *xpath, IPropertyTree *val) override;
  577. virtual IPropertyTree *setPropTree(const char *xpath) override { return setPropTree(xpath, create()); }
  578. virtual IPropertyTree *addPropTree(const char *xpath) override { return addPropTree(xpath, create()); }
  579. virtual bool removeTree(IPropertyTree *child) override;
  580. virtual bool removeProp(const char *xpath) override;
  581. virtual aindex_t queryChildIndex(IPropertyTree *child) override;
  582. virtual StringBuffer &getName(StringBuffer &ret) const override;
  583. virtual IAttributeIterator *getAttributes(bool sorted=false) const override;
  584. virtual IPropertyTreeIterator *getElements(const char *xpath, IPTIteratorCodes flags = iptiter_null) const override;
  585. virtual void localizeElements(const char *xpath, bool allTail=false) override;
  586. virtual bool hasChildren() const override { return children && children->count()?true:false; }
  587. virtual unsigned numUniq() override { return checkChildren()?children->count():0; }
  588. virtual unsigned numChildren() override;
  589. virtual bool isCaseInsensitive() override { return isnocase(); }
  590. virtual unsigned getCount(const char *xpath) override;
  591. // serializable impl.
  592. virtual void serialize(MemoryBuffer &tgt) override;
  593. virtual void deserialize(MemoryBuffer &src) override;
  594. protected:
  595. aindex_t getChildMatchPos(const char *xpath);
  596. virtual ChildMap *checkChildren() const;
  597. virtual bool isEquivalent(IPropertyTree *tree) const { return (nullptr != QUERYINTERFACE(tree, PTree)); }
  598. virtual void setLocal(size32_t l, const void *data, bool binary=false);
  599. virtual void appendLocal(size32_t l, const void *data, bool binary=false);
  600. virtual void addingNewElement(IPropertyTree &child, int pos) { }
  601. virtual void removingElement(IPropertyTree *tree, unsigned pos) { }
  602. virtual IPropertyTree *create(const char *name=nullptr, IPTArrayValue *value=nullptr, ChildMap *children=nullptr, bool existing=false) = 0;
  603. virtual IPropertyTree *create(MemoryBuffer &mb) = 0;
  604. virtual IPropertyTree *ownPTree(IPropertyTree *tree);
  605. virtual void setAttribute(const char *attr, const char *val) = 0;
  606. virtual bool removeAttribute(const char *k) = 0;
  607. AttrValue *findAttribute(const char *k) const;
  608. const char *getAttributeValue(const char *k) const;
  609. unsigned getAttributeCount() const;
  610. AttrValue *getNextAttribute(AttrValue *cur) const;
  611. private:
  612. void addLocal(size32_t l, const void *data, bool binary=false, int pos=-1);
  613. void resolveParentChild(const char *xpath, IPropertyTree *&parent, IPropertyTree *&child, StringAttr &path, StringAttr &qualifier);
  614. void replaceSelf(IPropertyTree *val);
  615. protected: // data
  616. /* NB: the order of the members here is important to reduce the size of the objects, because very large numbers of these are created.
  617. * The base CInterfaceOf contains it's VMT + a unsigned link count.
  618. * Therefore the short+byte follows the 4 byte link count.
  619. */
  620. unsigned short numAttrs = 0;
  621. byte flags; // set by constructor
  622. IPropertyTree *parent = nullptr; // ! currently only used if tree embedded into array, used to locate position.
  623. ChildMap *children; // set by constructor
  624. IPTArrayValue *value; // set by constructor
  625. AttrValue *attrs = nullptr;
  626. };
  627. class CAttrValHashTable
  628. {
  629. CMinHashTable<AttrStrC> htc;
  630. CMinHashTable<AttrStrNC> htnc;
  631. CMinHashTable<AttrStrC> htv;
  632. public:
  633. inline AttrStr *addkey(const char *v,bool nc)
  634. {
  635. AttrStrAtom * ret;
  636. if (nc)
  637. ret = htnc.find(v,true);
  638. else
  639. ret = htc.find(v,true);
  640. if (ret->linkcount!=(unsigned short)-1)
  641. ret->linkcount++;
  642. return ret->toAttrStr();
  643. }
  644. inline AttrStr *addval(const char *v)
  645. {
  646. AttrStrAtom * ret = htv.find(v,true);
  647. if (ret->linkcount!=(unsigned short)-1)
  648. ret->linkcount++;
  649. return ret->toAttrStr();
  650. }
  651. inline void removekey(AttrStr *_a,bool nc)
  652. {
  653. AttrStrAtom *a = AttrStrAtom::toAtom(_a);
  654. if (a->linkcount!=(unsigned short)-1)
  655. {
  656. if (--(a->linkcount)==0)
  657. {
  658. if (nc)
  659. htnc.remove((AttrStrNC *)a);
  660. else
  661. htc.remove((AttrStrC *)a);
  662. }
  663. }
  664. }
  665. inline void removeval(AttrStr *_a)
  666. {
  667. AttrStrAtom *a = AttrStrAtom::toAtom(_a);
  668. if (a->linkcount!=(unsigned short)-1)
  669. if (--(a->linkcount)==0)
  670. htv.remove((AttrStrC *)a);
  671. }
  672. };
  673. class jlib_decl CAtomPTree : public PTree
  674. {
  675. AttrValue *newAttrArray(unsigned n);
  676. void freeAttrArray(AttrValue *a, unsigned n);
  677. PtrStrUnion<HashKeyElement> name;
  678. protected:
  679. virtual void setAttribute(const char *attr, const char *val) override;
  680. virtual bool removeAttribute(const char *k) override;
  681. public:
  682. CAtomPTree(const char *name=nullptr, byte flags=ipt_none, IPTArrayValue *value=nullptr, ChildMap *children=nullptr);
  683. ~CAtomPTree();
  684. const char *queryName() const override;
  685. virtual unsigned queryHash() const override;
  686. virtual void setName(const char *_name) override;
  687. virtual bool isEquivalent(IPropertyTree *tree) const override { return (nullptr != QUERYINTERFACE(tree, CAtomPTree)); }
  688. virtual IPropertyTree *create(const char *name=nullptr, IPTArrayValue *value=nullptr, ChildMap *children=nullptr, bool existing=false) override
  689. {
  690. return new CAtomPTree(name, flags, value, children);
  691. }
  692. virtual IPropertyTree *create(MemoryBuffer &mb) override
  693. {
  694. IPropertyTree *tree = new CAtomPTree();
  695. tree->deserialize(mb);
  696. return tree;
  697. }
  698. };
  699. jlib_decl IPropertyTree *createPropBranch(IPropertyTree *tree, const char *xpath, bool createIntermediates=false, IPropertyTree **created=NULL, IPropertyTree **createdParent=NULL);
  700. class jlib_decl LocalPTree : public PTree
  701. {
  702. protected:
  703. virtual void setAttribute(const char *attr, const char *val) override;
  704. virtual bool removeAttribute(const char *k) override;
  705. AttrStrUnion name;
  706. public:
  707. LocalPTree(const char *name=nullptr, byte flags=ipt_none, IPTArrayValue *value=nullptr, ChildMap *children=nullptr);
  708. ~LocalPTree();
  709. const char *queryName() const override;
  710. virtual unsigned queryHash() const override
  711. {
  712. const char *myname = queryName();
  713. assert(myname);
  714. size32_t nl = strlen(myname);
  715. return isnocase() ? hashnc((const byte *)myname, nl, 0): hashc((const byte *)myname, nl, 0);
  716. }
  717. virtual void setName(const char *_name) override;
  718. virtual bool isEquivalent(IPropertyTree *tree) const override { return (nullptr != QUERYINTERFACE(tree, LocalPTree)); }
  719. virtual IPropertyTree *create(const char *name=nullptr, IPTArrayValue *value=nullptr, ChildMap *children=nullptr, bool existing=false) override
  720. {
  721. return new LocalPTree(name, flags, value, children);
  722. }
  723. virtual IPropertyTree *create(MemoryBuffer &mb) override
  724. {
  725. IPropertyTree *tree = new LocalPTree();
  726. tree->deserialize(mb);
  727. return tree;
  728. }
  729. };
  730. class SingleIdIterator : public CInterfaceOf<IPropertyTreeIterator>
  731. {
  732. public:
  733. SingleIdIterator(const PTree &_tree, unsigned pos=1, unsigned _many=(unsigned)-1);
  734. ~SingleIdIterator();
  735. void setCurrent(unsigned pos);
  736. // IPropertyTreeIterator
  737. virtual bool first() override;
  738. virtual bool next() override;
  739. virtual bool isValid() override;
  740. virtual IPropertyTree & query() override { return * current; }
  741. private:
  742. unsigned many, count, whichNext, start;
  743. IPropertyTree *current;
  744. const PTree &tree;
  745. };
  746. class PTLocalIteratorBase : public CInterfaceOf<IPropertyTreeIterator>
  747. {
  748. public:
  749. PTLocalIteratorBase(const PTree *tree, const char *_id, bool _nocase, bool sort);
  750. ~PTLocalIteratorBase();
  751. virtual bool match() = 0;
  752. // IPropertyTreeIterator
  753. virtual bool first() override;
  754. virtual bool next() override;
  755. virtual bool isValid() override;
  756. virtual IPropertyTree & query() override { return iter->query(); }
  757. protected:
  758. bool nocase, sort; // pack with the link count
  759. IPropertyTreeIterator *baseIter;
  760. StringAttr id;
  761. private:
  762. const PTree *tree;
  763. IPropertyTreeIterator *iter;
  764. IPropertyTree *current;
  765. bool _next();
  766. };
  767. class PTIdMatchIterator : public PTLocalIteratorBase
  768. {
  769. public:
  770. PTIdMatchIterator(const PTree *tree, const char *id, bool nocase, bool sort) : PTLocalIteratorBase(tree, id, nocase, sort) { }
  771. virtual bool match() override;
  772. };
  773. class StackElement;
  774. class PTStackIterator : public CInterfaceOf<IPropertyTreeIterator>
  775. {
  776. public:
  777. PTStackIterator(IPropertyTreeIterator *_iter, const char *_xpath);
  778. ~PTStackIterator();
  779. // IPropertyTreeIterator
  780. virtual bool first() override;
  781. virtual bool isValid() override;
  782. virtual bool next() override;
  783. virtual IPropertyTree & query() override;
  784. private:
  785. void setIterator(IPropertyTreeIterator *iter);
  786. void pushToStack(IPropertyTreeIterator *iter, const char *xpath);
  787. IPropertyTreeIterator *popFromStack(StringAttr &path);
  788. private: // data
  789. IPropertyTreeIterator *rootIter, *iter;
  790. const char *xxpath;
  791. IPropertyTree *current;
  792. StringAttr xpath, stackPath;
  793. unsigned stacklen;
  794. unsigned stackmax;
  795. StackElement *stack;
  796. };
  797. class CPTreeMaker : public CInterfaceOf<IPTreeMaker>
  798. {
  799. bool rootProvided, noRoot; // pack into the space following the link count
  800. IPropertyTree *root;
  801. ICopyArrayOf<IPropertyTree> ptreeStack;
  802. IPTreeNodeCreator *nodeCreator;
  803. class CDefaultNodeCreator : implements IPTreeNodeCreator, public CInterface
  804. {
  805. byte flags;
  806. public:
  807. IMPLEMENT_IINTERFACE_O;
  808. CDefaultNodeCreator(byte _flags) : flags(_flags) { }
  809. virtual IPropertyTree *create(const char *tag) override { return createPTree(tag, flags); }
  810. };
  811. protected:
  812. IPropertyTree *currentNode;
  813. public:
  814. CPTreeMaker(byte flags=ipt_none, IPTreeNodeCreator *_nodeCreator=NULL, IPropertyTree *_root=NULL, bool _noRoot=false) : noRoot(_noRoot)
  815. {
  816. if (_nodeCreator)
  817. nodeCreator = LINK(_nodeCreator);
  818. else
  819. nodeCreator = new CDefaultNodeCreator(flags);
  820. if (_root)
  821. {
  822. root = LINK(_root);
  823. rootProvided = true;
  824. }
  825. else
  826. {
  827. root = NULL;
  828. rootProvided = false;
  829. }
  830. reset();
  831. }
  832. ~CPTreeMaker()
  833. {
  834. ::Release(nodeCreator);
  835. ::Release(root);
  836. }
  837. // IPTreeMaker
  838. virtual void beginNode(const char *tag, offset_t startOffset) override
  839. {
  840. if (rootProvided)
  841. {
  842. currentNode = root;
  843. rootProvided = false;
  844. }
  845. else
  846. {
  847. IPropertyTree *parent = currentNode;
  848. if (!root)
  849. {
  850. currentNode = nodeCreator->create(tag);
  851. root = currentNode;
  852. }
  853. else
  854. currentNode = nodeCreator->create(NULL);
  855. if (parent)
  856. parent->addPropTree(tag, currentNode);
  857. else if (noRoot)
  858. root->addPropTree(tag, currentNode);
  859. }
  860. ptreeStack.append(*currentNode);
  861. }
  862. virtual void newAttribute(const char *name, const char *value) override
  863. {
  864. currentNode->setProp(name, value);
  865. }
  866. virtual void beginNodeContent(const char *name) override { }
  867. virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset) override
  868. {
  869. if (binary)
  870. currentNode->setPropBin(NULL, length, value);
  871. else
  872. currentNode->setProp(NULL, (const char *)value);
  873. unsigned c = ptreeStack.ordinality();
  874. if (c==1 && !noRoot && currentNode != root)
  875. ::Release(currentNode);
  876. ptreeStack.pop();
  877. currentNode = (c>1) ? &ptreeStack.tos() : NULL;
  878. }
  879. virtual IPropertyTree *queryRoot() override { return root; }
  880. virtual IPropertyTree *queryCurrentNode() override { return currentNode; }
  881. virtual void reset() override
  882. {
  883. if (!rootProvided)
  884. {
  885. ::Release(root);
  886. if (noRoot)
  887. root = nodeCreator->create("__NoRoot__");
  888. else
  889. root = NULL;
  890. }
  891. currentNode = NULL;
  892. }
  893. virtual IPropertyTree *create(const char *tag) override
  894. {
  895. return nodeCreator->create(tag);
  896. }
  897. };
  898. #endif