Explorar o código

HPCC-17192 Refactor PTree to have atom and non-atom versions

Previously all property trees used atom tables for attribute
names, value and node names.

Now there are two implementations, one which uses atoms as before
and the other does not.

The atom version continues to be used by Dali for memory
conversatin reasons.  All other uses now by default use the
non-atom version.

The non-atom version is significantly quicker, in particular in
multi-threaded use cases, because it does not have to enter/leave
the mutext involved in the global atom tables.

Signed-off-by: Jake Smith <jake.smith@lexisnexisrisk.com>
Jake Smith %!s(int64=8) %!d(string=hai) anos
pai
achega
faa9b06bc3
Modificáronse 7 ficheiros con 681 adicións e 693 borrados
  1. 12 12
      dali/base/dacsds.cpp
  2. 45 44
      dali/base/dacsds.ipp
  3. 3 3
      dali/base/dasds.cpp
  4. 8 15
      dali/base/dasds.ipp
  5. 321 435
      system/jlib/jptree.cpp
  6. 280 179
      system/jlib/jptree.ipp
  7. 12 5
      system/jlib/jsuperhash.hpp

+ 12 - 12
dali/base/dacsds.cpp

@@ -756,7 +756,7 @@ IPropertyTree *CClientRemoteTree::ownPTree(IPropertyTree *tree)
         return tree;
     }
     else
-        return PTree::ownPTree(tree);
+        return PARENT::ownPTree(tree);
 }
 
 IPropertyTree *CClientRemoteTree::create(const char *name, IPTArrayValue *value, ChildMap *children, bool existing)
@@ -797,7 +797,7 @@ void CClientRemoteTree::setLocal(size32_t size, const void *data, bool _binary)
 {
     clearState(CPS_PropAppend);
     mergeState(CPS_Changed);
-    PTree::setLocal(size, data, _binary);
+    PARENT::setLocal(size, data, _binary);
 }
 
 void CClientRemoteTree::appendLocal(size32_t size, const void *data, bool binary)
@@ -807,7 +807,7 @@ void CClientRemoteTree::appendLocal(size32_t size, const void *data, bool binary
     {
         if (0 != (CPS_PropAppend & state))
         {
-            PTree::appendLocal(size, data, binary);
+            PARENT::appendLocal(size, data, binary);
             return;
         }
         else if (0 == (CPS_Changed & state))
@@ -820,7 +820,7 @@ void CClientRemoteTree::appendLocal(size32_t size, const void *data, bool binary
                 {
                     mergeState(CPS_PropAppend);
                     registerPropAppend(sz);
-                    PTree::appendLocal(size, data, binary);
+                    PARENT::appendLocal(size, data, binary);
                     return;
                 }
             }
@@ -830,14 +830,14 @@ void CClientRemoteTree::appendLocal(size32_t size, const void *data, bool binary
                 {
                     mergeState(CPS_PropAppend);
                     registerPropAppend(0); // whole value on commit to be sent for external append.
-                    PTree::appendLocal(size, data, binary);
+                    PARENT::appendLocal(size, data, binary);
                     return;
                 }
             }
         }
     }
     mergeState(CPS_Changed);
-    PTree::appendLocal(size, data, binary);
+    PARENT::appendLocal(size, data, binary);
 }
 
 void CClientRemoteTree::addingNewElement(IPropertyTree &child, int pos)
@@ -847,26 +847,26 @@ void CClientRemoteTree::addingNewElement(IPropertyTree &child, int pos)
     if (pos >= 0)
         ((CRemoteTreeBase &)child).mergeState(CPS_InsPos);
 #endif
-    PTree::addingNewElement(child, pos);
+    PARENT::addingNewElement(child, pos);
 }
 
 void CClientRemoteTree::removingElement(IPropertyTree *tree, unsigned pos)
 {
     CRemoteTreeBase *child = QUERYINTERFACE(tree, CRemoteTreeBase); assertex(child);
     registerDeleted(child->queryName(), pos, child->queryServerId());
-    PTree::removingElement(tree, pos);
+    PARENT::removingElement(tree, pos);
 }
 
-void CClientRemoteTree::setAttr(const char *attr, const char *val)
+void CClientRemoteTree::setAttribute(const char *attr, const char *val)
 {
-    PTree::setAttr(attr, val);
+    PARENT::setAttribute(attr, val);
     mergeState(CPS_AttrChanges);
     registerAttrChange(attr);
 }
 
-bool CClientRemoteTree::removeAttr(const char *attr)
+bool CClientRemoteTree::removeAttribute(const char *attr)
 {
-    if (PTree::removeAttr(attr))
+    if (PARENT::removeAttribute(attr))
     {
         registerDeletedAttr(attr);
         return true;

+ 45 - 44
dali/base/dacsds.ipp

@@ -287,6 +287,8 @@ public:
 ////////////////////
 class CClientRemoteTree : implements ITrackChanges, public CRemoteTreeBase
 {
+    typedef CRemoteTreeBase PARENT;
+
     DECL_NAMEDCOUNT;
     IPropertyTree *_queryBranch(const char *xpath);
     ChildMap *_checkChildren();
@@ -307,12 +309,8 @@ public:
     virtual void Link() const;
     virtual bool Release() const;
 
-    virtual bool renameTree(IPropertyTree *tree, const char *newName);
-
-    virtual bool isEquivalent(IPropertyTree *tree) { return (NULL != QUERYINTERFACE(tree, CClientRemoteTree)); }
-    
-    virtual void deserializeSelfRT(MemoryBuffer &mb);
-    virtual void deserializeChildrenRT(MemoryBuffer &src);
+    virtual void deserializeSelfRT(MemoryBuffer &mb) override;
+    virtual void deserializeChildrenRT(MemoryBuffer &src) override;
 
     inline void addServerTreeInfo(byte STIInfo) { serverTreeInfo += STIInfo; }
     inline bool queryLazyFetch() const { return connection.queryLazyFetch(); }
@@ -324,48 +322,51 @@ public:
     void checkExt() const;
 
     virtual bool setLazyFetch(bool fetch) { return connection.setLazyFetch(fetch); }
-    virtual ChildMap *checkChildren() const;
-    virtual IPropertyTree *create(const char *name, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false);
-    virtual IPropertyTree *create(MemoryBuffer &mb);
-    virtual void createChildMap();
-    virtual IPropertyTree *ownPTree(IPropertyTree *tree);
-    virtual void setLocal(size32_t size, const void *data, bool _binary);
-    virtual void appendLocal(size32_t size, const void *data, bool binary);
-    virtual void addingNewElement(IPropertyTree &child, int pos);
-    virtual void removingElement(IPropertyTree *tree, unsigned pos);
-    virtual void setAttr(const char *attr, const char *val);
-    virtual bool removeAttr(const char *attr);
+
+// PTree overrides
+    virtual bool isEquivalent(IPropertyTree *tree) const override { return (NULL != QUERYINTERFACE(tree, CClientRemoteTree)); }
+    virtual ChildMap *checkChildren() const override;
+    virtual IPropertyTree *create(const char *name, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false) override;
+    virtual IPropertyTree *create(MemoryBuffer &mb) override;
+    virtual void createChildMap() override;
+    virtual IPropertyTree *ownPTree(IPropertyTree *tree) override;
+    virtual void setLocal(size32_t size, const void *data, bool _binary) override;
+    virtual void appendLocal(size32_t size, const void *data, bool binary) override;
+    virtual void addingNewElement(IPropertyTree &child, int pos) override;
+    virtual void removingElement(IPropertyTree *tree, unsigned pos) override;
+    virtual void setAttribute(const char *attr, const char *val) override;
+    virtual bool removeAttribute(const char *attr) override;
 
 // IPropertyTree
-    virtual void addProp(const char *xpath, const char *val);
-    virtual void setProp(const char *xpath, const char *val);
-    virtual void addPropInt64(const char *xpath, __int64 val);
-    virtual void setPropInt64(const char *xpath, __int64 val);
-    virtual void setPropBin(const char *xpath, size32_t size, const void *data);
-    virtual IPropertyTree *setPropTree(const char *xpath, IPropertyTree *val);
-    virtual IPropertyTree *addPropTree(const char *xpath, IPropertyTree *val);
-    virtual bool removeProp(const char *xpath);
-    virtual bool removeTree(IPropertyTree *child);
-    virtual IPropertyTreeIterator *getElements(const char *xpath, IPTIteratorCodes flags = iptiter_null) const;
-    virtual bool isCompressed(const char *xpath=NULL) const;
-    virtual bool getProp(const char *xpath, StringBuffer &ret) const;
-    virtual const char *queryProp(const char * xpath) const;
-    virtual bool getPropBool(const char *xpath, bool dft=false) const;
-    virtual __int64 getPropInt64(const char *xpath, __int64 dft=0) const;
-    virtual bool getPropBin(const char *xpath, MemoryBuffer &ret) const;
-    virtual void localizeElements(const char *xpath, bool allTail=false);
-    virtual IPropertyTree *queryBranch(const char *xpath) const;
-    virtual bool hasChildren() const { return (children && children->count()) || (!children && 0 != (serverTreeInfo & STI_HaveChildren)); }
+    virtual bool renameTree(IPropertyTree *tree, const char *newName) override;
+    virtual void addProp(const char *xpath, const char *val) override;
+    virtual void setProp(const char *xpath, const char *val) override;
+    virtual void addPropInt64(const char *xpath, __int64 val) override;
+    virtual void setPropInt64(const char *xpath, __int64 val) override;
+    virtual void setPropBin(const char *xpath, size32_t size, const void *data) override;
+    virtual IPropertyTree *setPropTree(const char *xpath, IPropertyTree *val) override;
+    virtual IPropertyTree *addPropTree(const char *xpath, IPropertyTree *val) override;
+    virtual bool removeProp(const char *xpath) override;
+    virtual bool removeTree(IPropertyTree *child) override;
+    virtual IPropertyTreeIterator *getElements(const char *xpath, IPTIteratorCodes flags = iptiter_null) const override;
+    virtual bool isCompressed(const char *xpath=NULL) const override;
+    virtual bool getProp(const char *xpath, StringBuffer &ret) const override;
+    virtual const char *queryProp(const char * xpath) const override;
+    virtual bool getPropBool(const char *xpath, bool dft=false) const override;
+    virtual __int64 getPropInt64(const char *xpath, __int64 dft=0) const override;
+    virtual bool getPropBin(const char *xpath, MemoryBuffer &ret) const override;
+    virtual void localizeElements(const char *xpath, bool allTail=false) override;
+    virtual IPropertyTree *queryBranch(const char *xpath) const override;
+    virtual bool hasChildren() const override { return (children && children->count()) || (!children && 0 != (serverTreeInfo & STI_HaveChildren)); }
 
 // ITrackChanges
-    virtual ChangeInfo *queryChanges();
-    virtual void registerRenamed(const char *newName, const char *oldName, unsigned pos, __int64 id);
-    virtual void registerDeleted(const char *name, unsigned position, __int64 id);
-    virtual void registerDeletedAttr(const char *attr);
-    virtual void clearChanges();
-
-    virtual void registerAttrChange(const char *attr);
-    virtual void registerPropAppend(size32_t l);
+    virtual ChangeInfo *queryChanges() override;
+    virtual void registerRenamed(const char *newName, const char *oldName, unsigned pos, __int64 id) override;
+    virtual void registerDeleted(const char *name, unsigned position, __int64 id) override;
+    virtual void registerDeletedAttr(const char *attr) override;
+    virtual void clearChanges() override;
+    virtual void registerAttrChange(const char *attr) override;
+    virtual void registerPropAppend(size32_t l) override;
 
 private: // data
     unsigned state;

+ 3 - 3
dali/base/dasds.cpp

@@ -1624,7 +1624,7 @@ public:
     virtual void resetAsExternal(IPropertyTree &_tree)
     {
         PTree &tree = *QUERYINTERFACE(&_tree, PTree);
-        tree.clear();
+        ::Release(tree.detach());
     }
     virtual void readValue(const char *name, MemoryBuffer &mb)
     {
@@ -2265,7 +2265,7 @@ void CServerConnection::aborted(SessionId id)
 enum IncCmd { None, PropDelete, AttrDelete, PropChange, PropNew, PropExisting, ChildEndMarker, PropRename, AttrChange };
 
 CRemoteTreeBase::CRemoteTreeBase(const char *name, IPTArrayValue *value, ChildMap *children)
-    : PTree(name, ipt_none, value, children)
+    : SDS_PTREE(name, ipt_none, value, children)
 {
     serverId = 0;
 }
@@ -3010,7 +3010,7 @@ PDState CServerRemoteTree::checkChange(IPropertyTree &changeTree, CBranchChange
                         Owned<IAttributeIterator> iter = e.getAttributes();
                         ForEach(*iter)
                         {
-                            if (removeAttr(iter->queryName()))
+                            if (removeAttribute(iter->queryName()))
                                 mergePDState(res, PDS_Data);
                         }
                         break;

+ 8 - 15
dali/base/dasds.ipp

@@ -225,7 +225,9 @@ class CBranchChange;
 ///////////////////
 class CSubscriberContainerList;
 
-class CRemoteTreeBase : public PTree
+#define SDS_PTREE CAtomPTree
+
+class CRemoteTreeBase : public SDS_PTREE
 {
 public:
     CRemoteTreeBase(MemoryBuffer &mb);
@@ -238,24 +240,15 @@ public:
 
     void clearChildren();
     CRemoteTreeBase *createChild(int pos, const char *childName);
-    
+
     inline __int64 queryServerId() { return serverId; }
     virtual void setServerId(__int64 _serverId);
     virtual CSubscriberContainerList *getSubscribers(const char *xpath, CPTStack &stack) { UNIMPLEMENTED; return NULL; } // JCSMORE
 
-// PTree
-    virtual bool isEquivalent(IPropertyTree *tree) { return (NULL != QUERYINTERFACE(tree, CRemoteTreeBase)); }
-    virtual IPropertyTree *create(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false) = 0;
-    virtual IPropertyTree *create(MemoryBuffer &mb) = 0;
-
-// ITrackChanges
-    virtual ChangeInfo *queryChanges() { assertex(false); return NULL; }
-    virtual void registerRenamed(const char *newName, const char *oldName, unsigned pos, __int64 id) { }
-    virtual void registerDeleted(const char *name, unsigned pos, __int64 id) { }
-    virtual void registerDeletedAttr(const char *attr) { }
-    virtual void clearChanges() { assertex(false); }
-    virtual void registerAttrChange(const char *attr) { }
-    virtual void registerPropAppend(size32_t l) { }
+// PTree overrides
+    virtual bool isEquivalent(IPropertyTree *tree) const override { return (NULL != QUERYINTERFACE(tree, CRemoteTreeBase)); }
+    virtual IPropertyTree *create(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false) override = 0;
+    virtual IPropertyTree *create(MemoryBuffer &mb) override = 0;
 
 protected: // data
     __int64 serverId;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 321 - 435
system/jlib/jptree.cpp


+ 280 - 179
system/jlib/jptree.ipp

@@ -47,26 +47,25 @@ class jlib_decl ChildMap : protected SuperHashTableOf<IPropertyTree, constcharpt
 {
 protected:
 // SuperHashTable definitions
-    virtual void onAdd(void *) {}
-
-    virtual void onRemove(void *e)
+    virtual void onAdd(void *) override {}
+    virtual void onRemove(void *e) override
     {
-        IPropertyTree &elem= *(IPropertyTree *)e;
+        IPropertyTree &elem = *(IPropertyTree *)e;
         elem.Release();
     }
-    virtual unsigned getHashFromElement(const void *e) const;
-    virtual unsigned getHashFromFindParam(const void *fp) const
+    virtual const void *getFindParam(const void *e) const override
     {
-        return hashc((const unsigned char *)fp, (size32_t)strlen((const char *)fp), 0);
+        const IPropertyTree &elem = *(const IPropertyTree *)e;
+        return elem.queryName();
     }
-    virtual const void *getFindParam(const void *e) const
+    virtual unsigned getHashFromElement(const void *e) const;
+    virtual unsigned getHashFromFindParam(const void *fp) const override
     {
-        const IPropertyTree &elem=*(const IPropertyTree *)e;
-        return (void *)elem.queryName();
+        return hashc((const unsigned char *)fp, (size32_t)strlen((const char *)fp), 0);
     }
-    virtual bool matchesFindParam(const void *e, const void *fp, unsigned fphash) const
+    virtual bool matchesFindParam(const void *e, const void *fp, unsigned fphash) const override
     {
-        return (0 == strcmp(((IPropertyTree *)e)->queryName(), (const char *)fp));
+        return streq(((IPropertyTree *)e)->queryName(), (const char *)fp);
     }
 public: 
     IMPLEMENT_IINTERFACE;
@@ -110,13 +109,13 @@ class jlib_decl ChildMapNC : public ChildMap
 {
 public:
 // SuperHashTable definitions
-    virtual unsigned getHashFromFindParam(const void *fp) const
+    virtual unsigned getHashFromFindParam(const void *fp) const override
     {
         return hashnc((const unsigned char *)fp, (size32_t)strlen((const char *)fp), 0);
     }
-    virtual bool matchesFindParam(const void *e, const void *fp, unsigned fphash) const
+    virtual bool matchesFindParam(const void *e, const void *fp, unsigned fphash) const override
     {
-        return (0 == stricmp(((IPropertyTree *)e)->queryName(), (const char *)fp));
+        return strieq(((IPropertyTree *)e)->queryName(), (const char *)fp);
     }
 };
 
@@ -232,68 +231,6 @@ struct AttrValue
     AttrStr *value;
 };
 
-#define AM_NOCASE_FLAG (0x8000)
-#define AM_NOCASE_MASK (0x7fff)
-
-#ifdef __64BIT__
-#pragma pack(push,1)
-// Byte-Pack AttrMap and PTree because very large numbers are created.  However, this may cause problems on systems that
-// require aligned pointer access.  Without overriding the packing the structure currently wastes 8 bytes.
-// Ideally the classes would be restructured to avoid this, but it would probably require AttrMap to move into PTree
-#endif
-
-class jlib_decl AttrMap
-{
-    AttrValue *attrs;
-    unsigned short numattrs;    // use top bit for nocase flag
-    static AttrValue **freelist; // entry 0 not used
-    static unsigned freelistmax; 
-    static CLargeMemoryAllocator freeallocator;
-
-    AttrValue *newArray(unsigned n);
-    void freeArray(AttrValue *a,unsigned n);
-
-public:
-    AttrMap()
-    { 
-        attrs = NULL;
-        numattrs = 0;
-    }
-    ~AttrMap() 
-    { 
-        kill();
-    }
-    inline unsigned count() const
-    { 
-        return numattrs&AM_NOCASE_MASK; 
-    }
-    inline AttrValue *item(unsigned i) const
-    { 
-        return attrs+i; 
-    }
-    void setNoCase(bool nc) 
-    { 
-        if (nc) 
-            numattrs |= AM_NOCASE_FLAG; 
-        else 
-            numattrs &= AM_NOCASE_MASK; 
-    }
-    inline bool isNoCase() const 
-    { 
-        return (numattrs&AM_NOCASE_FLAG)!=0; 
-    }
-    void kill();
-    void set(const char *key, const char *val);
-    const char *find(const char *key) const;
-    bool remove(const char *key);
-    void swap(AttrMap &other);
-    static inline void killfreelist()
-    {
-        free(freelist);
-        freelist = NULL;
-    }
-};
-
 
 class jlib_decl PTree : public CInterfaceOf<IPropertyTree>
 {
@@ -303,26 +240,25 @@ friend class PTIdMatchIterator;
 friend class ChildMap;
 
 public:
-    PTree(MemoryBuffer &mb);
-    PTree(const char *_name=NULL, byte _flags=0, IPTArrayValue *_value=NULL, ChildMap *_children=NULL);
+    PTree(byte _flags=ipt_none, IPTArrayValue *_value=nullptr, ChildMap *_children=nullptr);
     ~PTree();
+    virtual void beforeDispose() override { }
 
+    const char *queryName() const
+    {
+        return name?name->get():nullptr;
+    }
+    HashKeyElement *queryKey() const { return name; }
     IPropertyTree *queryParent() { return parent; }
     IPropertyTree *queryChild(unsigned index);
     ChildMap *queryChildren() { return children; }
     aindex_t findChild(IPropertyTree *child, bool remove=false);
     inline bool isnocase() const { return IptFlagTst(flags, ipt_caseInsensitive); }
     ipt_flags queryFlags() const { return (ipt_flags) flags; }
-public:
+    void serializeSelf(MemoryBuffer &tgt);
     void serializeCutOff(MemoryBuffer &tgt, int cutoff=-1, int depth=0);
+    void deserializeSelf(MemoryBuffer &src);
     void serializeAttributes(MemoryBuffer &tgt);
-    virtual void serializeSelf(MemoryBuffer &tgt);
-    virtual void deserializeSelf(MemoryBuffer &src);
-    virtual void createChildMap() { children = isnocase()?new ChildMapNC():new ChildMap(); }
-
-
-    HashKeyElement *queryKey() { return name; }
-    void setName(const char *_name);
     IPropertyTree *clone(IPropertyTree &srcTree, bool self=false, bool sub=true);
     void clone(IPropertyTree &srcTree, IPropertyTree &dstTree, bool sub=true);
     inline void setParent(IPropertyTree *_parent) { parent = _parent; }
@@ -332,107 +268,273 @@ public:
     IPTArrayValue *detachValue() { IPTArrayValue *v = value; value = NULL; return v; }
     void setValue(IPTArrayValue *_value, bool binary) { if (value) delete value; value = _value; if (binary) IptFlagSet(flags, ipt_binary); }
     bool checkPattern(const char *&xxpath) const;
-    void clear();
+    IPropertyTree *detach()
+    {
+        IPropertyTree *tree = create(queryName(), value, children, true);
+        PTree *_tree = QUERYINTERFACE(tree, PTree); assertex(_tree); _tree->setParent(this);
+
+        std::swap(numAttrs, _tree->numAttrs);
+        std::swap(attrs, _tree->attrs);
+
+        ::Release(children);
+        children = nullptr;
+        return tree;
+    }
+    virtual void createChildMap() { children = isnocase()?new ChildMapNC():new ChildMap(); }
+    virtual void setName(const char *name) = 0;
 
 // IPropertyTree impl.
-    virtual bool hasProp(const char * xpath) const;
-    virtual bool isBinary(const char *xpath=NULL) const;
-    virtual bool isCompressed(const char *xpath=NULL) const;
-    virtual bool renameProp(const char *xpath, const char *newName);
-    virtual bool renameTree(IPropertyTree *tree, const char *newName);
-    virtual const char *queryProp(const char *xpath) const;
-    virtual bool getProp(const char *xpath, StringBuffer &ret) const;
-    virtual void setProp(const char *xpath, const char *val);
-    virtual void addProp(const char *xpath, const char *val);
-    virtual void appendProp(const char *xpath, const char *val);
-    virtual bool getPropBool(const char *xpath, bool dft=false) const;
-    virtual void setPropBool(const char *xpath, bool val) { setPropInt(xpath, val); }
-    virtual void addPropBool(const char *xpath, bool val) { addPropInt(xpath, val); }
-    virtual __int64 getPropInt64(const char *xpath, __int64 dft=0) const;
-    virtual void setPropInt64(const char * xpath, __int64 val);
-    virtual void addPropInt64(const char *xpath, __int64 val);
-    virtual int getPropInt(const char *xpath, int dft=0) const;
-    virtual void setPropInt(const char *xpath, int val);
-    virtual void addPropInt(const char *xpath, int val);
-    virtual bool getPropBin(const char * xpath, MemoryBuffer &ret) const;
-    virtual void setPropBin(const char * xpath, size32_t size, const void *data);
-    virtual void appendPropBin(const char *xpath, size32_t size, const void *data);
-    virtual void addPropBin(const char *xpath, size32_t size, const void *data);
-    virtual IPropertyTree *getPropTree(const char *xpath) const;
-    virtual IPropertyTree *queryPropTree(const char *xpath) const;
-    virtual IPropertyTree *getBranch(const char *xpath) const { return LINK(queryBranch(xpath)); }
-    virtual IPropertyTree *queryBranch(const char *xpath) const { return queryPropTree(xpath); }
-    virtual IPropertyTree *setPropTree(const char *xpath, IPropertyTree *val);
-    virtual IPropertyTree *addPropTree(const char *xpath, IPropertyTree *val);
-    virtual bool removeTree(IPropertyTree *child);
-    virtual bool removeProp(const char *xpath);
-    virtual aindex_t queryChildIndex(IPropertyTree *child);
-    virtual const char *queryName() const;
-    virtual StringBuffer &getName(StringBuffer &ret) const;
-    virtual IAttributeIterator *getAttributes(bool sorted=false) const;
-    virtual IPropertyTreeIterator *getElements(const char *xpath, IPTIteratorCodes flags = iptiter_null) const;
-    virtual void localizeElements(const char *xpath, bool allTail=false);
-    virtual bool hasChildren() const { return children && children->count()?true:false; }
-    virtual unsigned numUniq() { return checkChildren()?children->count():0; }  
-    virtual unsigned numChildren();
-    virtual bool isCaseInsensitive() { return isnocase(); }
-    virtual unsigned getCount(const char *xpath);
+    virtual bool hasProp(const char * xpath) const override;
+    virtual bool isBinary(const char *xpath=NULL) const override;
+    virtual bool isCompressed(const char *xpath=NULL) const override;
+    virtual bool renameProp(const char *xpath, const char *newName) override;
+    virtual bool renameTree(IPropertyTree *tree, const char *newName) override;
+    virtual const char *queryProp(const char *xpath) const override;
+    virtual bool getProp(const char *xpath, StringBuffer &ret) const override;
+    virtual void setProp(const char *xpath, const char *val) override;
+    virtual void addProp(const char *xpath, const char *val) override;
+    virtual void appendProp(const char *xpath, const char *val) override;
+    virtual bool getPropBool(const char *xpath, bool dft=false) const override;
+    virtual void setPropBool(const char *xpath, bool val) override { setPropInt(xpath, val); }
+    virtual void addPropBool(const char *xpath, bool val) override { addPropInt(xpath, val); }
+    virtual __int64 getPropInt64(const char *xpath, __int64 dft=0) const override;
+    virtual void setPropInt64(const char * xpath, __int64 val) override;
+    virtual void addPropInt64(const char *xpath, __int64 val) override;
+    virtual int getPropInt(const char *xpath, int dft=0) const override;
+    virtual void setPropInt(const char *xpath, int val) override;
+    virtual void addPropInt(const char *xpath, int val) override;
+    virtual bool getPropBin(const char * xpath, MemoryBuffer &ret) const override;
+    virtual void setPropBin(const char * xpath, size32_t size, const void *data) override;
+    virtual void appendPropBin(const char *xpath, size32_t size, const void *data) override;
+    virtual void addPropBin(const char *xpath, size32_t size, const void *data) override;
+    virtual IPropertyTree *getPropTree(const char *xpath) const override;
+    virtual IPropertyTree *queryPropTree(const char *xpath) const override;
+    virtual IPropertyTree *getBranch(const char *xpath) const override { return LINK(queryBranch(xpath)); }
+    virtual IPropertyTree *queryBranch(const char *xpath) const override { return queryPropTree(xpath); }
+    virtual IPropertyTree *setPropTree(const char *xpath, IPropertyTree *val) override;
+    virtual IPropertyTree *addPropTree(const char *xpath, IPropertyTree *val) override;
+    virtual bool removeTree(IPropertyTree *child) override;
+    virtual bool removeProp(const char *xpath) override;
+    virtual aindex_t queryChildIndex(IPropertyTree *child) override;
+    virtual StringBuffer &getName(StringBuffer &ret) const override;
+    virtual IAttributeIterator *getAttributes(bool sorted=false) const override;
+    virtual IPropertyTreeIterator *getElements(const char *xpath, IPTIteratorCodes flags = iptiter_null) const override;
+    virtual void localizeElements(const char *xpath, bool allTail=false) override;
+    virtual bool hasChildren() const override { return children && children->count()?true:false; }
+    virtual unsigned numUniq() override { return checkChildren()?children->count():0; }
+    virtual unsigned numChildren() override;
+    virtual bool isCaseInsensitive() override { return isnocase(); }
+    virtual unsigned getCount(const char *xpath) override;
 // serializable impl.
-    virtual void serialize(MemoryBuffer &tgt);
-    virtual void deserialize(MemoryBuffer &src);
-    const AttrMap &queryAttributes() const { return attributes; }
-    
+    virtual void serialize(MemoryBuffer &tgt) override;
+    virtual void deserialize(MemoryBuffer &src) override;
+
 protected:
+    aindex_t getChildMatchPos(const char *xpath);
+
     virtual ChildMap *checkChildren() const;
-    virtual bool isEquivalent(IPropertyTree *tree) { return (NULL != QUERYINTERFACE(tree, PTree)); }
+    virtual bool isEquivalent(IPropertyTree *tree) const { return (nullptr != QUERYINTERFACE(tree, PTree)); }
     virtual void setLocal(size32_t l, const void *data, bool binary=false);
     virtual void appendLocal(size32_t l, const void *data, bool binary=false);
-    virtual void setAttr(const char *attr, const char *val);
-    virtual bool removeAttr(const char *attr);
     virtual void addingNewElement(IPropertyTree &child, int pos) { }
     virtual void removingElement(IPropertyTree *tree, unsigned pos) { }
-    virtual IPropertyTree *create(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false) = 0;
+    virtual IPropertyTree *create(const char *name=nullptr, IPTArrayValue *value=nullptr, ChildMap *children=nullptr, bool existing=false) = 0;
     virtual IPropertyTree *create(MemoryBuffer &mb) = 0;
     virtual IPropertyTree *ownPTree(IPropertyTree *tree);
-    aindex_t getChildMatchPos(const char *xpath);
+
+    virtual void setAttribute(const char *attr, const char *val) = 0;
+    virtual bool removeAttribute(const char *k) = 0;
+
+    AttrValue *findAttribute(const char *k) const;
+    const char *getAttributeValue(const char *k) const;
+    unsigned getAttributeCount() const;
+    AttrValue *getNextAttribute(AttrValue *cur) const;
 
 private:
-    void init();
     void addLocal(size32_t l, const void *data, bool binary=false, int pos=-1);
     void resolveParentChild(const char *xpath, IPropertyTree *&parent, IPropertyTree *&child, StringAttr &path, StringAttr &qualifier);
     void replaceSelf(IPropertyTree *val);
 
 protected: // data
-    IPropertyTree *parent; // ! currently only used if tree embedded into array, used to locate position.
-    HashKeyElement *name;
-    ChildMap *children;
-    IPTArrayValue *value;
-    //The packing (#pragma pack) is overridden because very large numbers of these objects are created, and the
-    //following two members currently cause 8 bytes to be wasted.  Refactoring the contents of AttrMap into this
-    //class would allow the fields to pack cleanly.
-    AttrMap attributes;     // this has 2 "extra" bytes - which could pack into the space following the count
-    byte flags;             // this could also pack into the space following the count.
+    /* NB: the order of the members here is important to reduce the size of the objects, because very large numbers of these are created.
+     * The base CInterfaceOf contains it's VMT + a unsigned link count.
+     * Therefore the short+byte follows the 4 byte link count.
+     */
+
+    unsigned short numAttrs = 0;
+    byte flags;           // set by constructor
+    IPropertyTree *parent = nullptr; // ! currently only used if tree embedded into array, used to locate position.
+    ChildMap *children;   // set by constructor
+    IPTArrayValue *value; // set by constructor
+    HashKeyElement *name = nullptr;
+    AttrValue *attrs = nullptr;
 };
 
-#ifdef __64BIT__
-#pragma pack(pop)
-#endif
+
+struct AttrStrC : public AttrStr
+{
+    static inline unsigned getHash(const char *k)
+    {
+        return hashc((const byte *)k, strlen(k), 17);
+    }
+    inline bool eq(const char *k)
+    {
+        return streq(k,str);
+    }
+    static AttrStrC *create(const char *k)
+    {
+        size32_t kl = (k?strlen(k):0);
+        AttrStrC *ret = (AttrStrC *)malloc(sizeof(AttrStrC)+kl);
+        memcpy(ret->str, k, kl);
+        ret->str[kl] = 0;
+        ret->hash = hashc((const byte *)k, kl, 17);
+        ret->linkcount = 0;
+        return ret;
+    }
+    static void destroy(AttrStrC *a)
+    {
+        free(a);
+    }
+};
+
+struct AttrStrNC : public AttrStr
+{
+    static inline unsigned getHash(const char *k)
+    {
+        return hashnc((const byte *)k, strlen(k), 17);
+    }
+    inline bool eq(const char *k)
+    {
+        return strieq(k,str);
+    }
+    static AttrStrNC *create(const char *k)
+    {
+        size32_t kl = (k?strlen(k):0);
+        AttrStrNC *ret = (AttrStrNC *)malloc(sizeof(AttrStrNC)+kl);
+        memcpy(ret->str,k,kl);
+        ret->str[kl] = 0;
+        ret->hash = hashnc((const byte *)k, kl, 17);
+        ret->linkcount = 0;
+        return ret;
+    }
+    static void destroy(AttrStrNC *a)
+    {
+        free(a);
+    }
+};
+
+class CAttrValHashTable
+{
+    CMinHashTable<AttrStrC>  htc;
+    CMinHashTable<AttrStrNC> htnc;
+    CMinHashTable<AttrStrC>  htv;
+public:
+    inline AttrStr *addkey(const char *v,bool nc)
+    {
+        AttrStr * ret;
+        if (nc)
+            ret = htnc.find(v,true);
+        else
+            ret = htc.find(v,true);
+        if (ret->linkcount!=(unsigned short)-1)
+            ret->linkcount++;
+        return ret;
+    }
+    inline AttrStr *addval(const char *v)
+    {
+        AttrStr * ret = htv.find(v,true);
+        if (ret->linkcount!=(unsigned short)-1)
+            ret->linkcount++;
+        return ret;
+    }
+    inline void removekey(AttrStr *a,bool nc)
+    {
+        if (a->linkcount!=(unsigned short)-1)
+        {
+            if (--(a->linkcount)==0)
+            {
+                if (nc)
+                    htnc.remove((AttrStrNC *)a);
+                else
+                    htc.remove((AttrStrC *)a);
+            }
+        }
+    }
+    inline void removeval(AttrStr *a)
+    {
+        if (a->linkcount!=(unsigned short)-1)
+            if (--(a->linkcount)==0)
+                htv.remove((AttrStrC *)a);
+    }
+};
+
+
+class jlib_decl CAtomPTree : public PTree
+{
+    static AtomRefTable *keyTable, *keyTableNC;
+    static CriticalSection hashcrit;
+    static CAttrValHashTable *attrHT;
+    static AttrValue **freelist; // entry 0 not used
+    static unsigned freelistmax;
+    static CLargeMemoryAllocator freeallocator;
+
+    AttrValue *newAttrArray(unsigned n);
+    void freeAttrArray(AttrValue *a, unsigned n);
+
+protected:
+    virtual void setAttribute(const char *attr, const char *val) override;
+    virtual bool removeAttribute(const char *k) override;
+public:
+    static inline void init()
+    {
+        keyTable = new AtomRefTable;
+        keyTableNC = new AtomRefTable(true);
+        attrHT = new CAttrValHashTable;
+    }
+    static inline void kill()
+    {
+        delete attrHT;
+        keyTable->Release();
+        keyTableNC->Release();
+        free(freelist);
+        freelist = NULL;
+    }
+
+    CAtomPTree(const char *name=nullptr, byte flags=ipt_none, IPTArrayValue *value=nullptr, ChildMap *children=nullptr);
+    ~CAtomPTree();
+    virtual void setName(const char *_name) override;
+    virtual bool isEquivalent(IPropertyTree *tree) const override { return (nullptr != QUERYINTERFACE(tree, CAtomPTree)); }
+    virtual IPropertyTree *create(const char *name=nullptr, IPTArrayValue *value=nullptr, ChildMap *children=nullptr, bool existing=false)
+    {
+        return new CAtomPTree(name, flags, value, children);
+    }
+    virtual IPropertyTree *create(MemoryBuffer &mb) override
+    {
+        IPropertyTree *tree = new CAtomPTree();
+        tree->deserialize(mb);
+        return tree;
+    }
+};
 
 
 jlib_decl IPropertyTree *createPropBranch(IPropertyTree *tree, const char *xpath, bool createIntermediates=false, IPropertyTree **created=NULL, IPropertyTree **createdParent=NULL);
 
-class LocalPTree : public PTree
+class jlib_decl LocalPTree : public PTree
 {
+protected:
+    virtual void setAttribute(const char *attr, const char *val) override;
+    virtual bool removeAttribute(const char *k) override;
 public:
-    LocalPTree(const char *name=NULL, byte flags=ipt_none, IPTArrayValue *value=NULL, ChildMap *children=NULL)
-        : PTree(name, flags, value, children) { }
+    LocalPTree(const char *name=nullptr, byte flags=ipt_none, IPTArrayValue *value=nullptr, ChildMap *children=nullptr);
+    ~LocalPTree();
 
-    virtual bool isEquivalent(IPropertyTree *tree) { return (NULL != QUERYINTERFACE(tree, LocalPTree)); }
-    virtual IPropertyTree *create(const char *name=NULL, IPTArrayValue *value=NULL, ChildMap *children=NULL, bool existing=false)
+    virtual void setName(const char *_name) override;
+    virtual bool isEquivalent(IPropertyTree *tree) const override { return (nullptr != QUERYINTERFACE(tree, LocalPTree)); }
+    virtual IPropertyTree *create(const char *name=nullptr, IPTArrayValue *value=nullptr, ChildMap *children=nullptr, bool existing=false) override
     {
         return new LocalPTree(name, flags, value, children);
     }
-    virtual IPropertyTree *create(MemoryBuffer &mb)
+    virtual IPropertyTree *create(MemoryBuffer &mb) override
     {
         IPropertyTree *tree = new LocalPTree();
         tree->deserialize(mb);
@@ -440,7 +542,6 @@ public:
     }
 };
 
-class PTree;
 class SingleIdIterator : public CInterfaceOf<IPropertyTreeIterator>
 {
 public:
@@ -449,10 +550,10 @@ public:
     void setCurrent(unsigned pos);
 
 // IPropertyTreeIterator
-    virtual bool first();
-    virtual bool next();
-    virtual bool isValid();
-    virtual IPropertyTree & query() { return * current; }
+    virtual bool first() override;
+    virtual bool next() override;
+    virtual bool isValid() override;
+    virtual IPropertyTree & query() override { return * current; }
 
 private:
     unsigned many, count, whichNext, start;
@@ -470,10 +571,10 @@ public:
     virtual bool match() = 0;
 
 // IPropertyTreeIterator
-    virtual bool first();
-    virtual bool next();
-    virtual bool isValid();
-    virtual IPropertyTree & query() { return iter->query(); }
+    virtual bool first() override;
+    virtual bool next() override;
+    virtual bool isValid() override;
+    virtual IPropertyTree & query() override { return iter->query(); }
 
 protected:
     bool nocase, sort;  // pack with the link count
@@ -503,10 +604,10 @@ public:
     ~PTStackIterator();
 
 // IPropertyTreeIterator
-    virtual bool first();
-    virtual bool isValid();
-    virtual bool next();
-    virtual IPropertyTree & query();
+    virtual bool first() override;
+    virtual bool isValid() override;
+    virtual bool next() override;
+    virtual IPropertyTree & query() override;
 
 private:
     void setIterator(IPropertyTreeIterator *iter);
@@ -537,7 +638,7 @@ class CPTreeMaker : public CInterfaceOf<IPTreeMaker>
 
         CDefaultNodeCreator(byte _flags) : flags(_flags) { }
 
-        virtual IPropertyTree *create(const char *tag) { return createPTree(tag, flags); }
+        virtual IPropertyTree *create(const char *tag) override { return createPTree(tag, flags); }
     };
 protected:
     IPropertyTree *currentNode;
@@ -567,7 +668,7 @@ public:
     }
 
 // IPTreeMaker
-    virtual void beginNode(const char *tag, offset_t startOffset)
+    virtual void beginNode(const char *tag, offset_t startOffset) override
     {
         if (rootProvided)
         {
@@ -591,12 +692,12 @@ public:
         }
         ptreeStack.append(*currentNode);
     }
-    virtual void newAttribute(const char *name, const char *value)
+    virtual void newAttribute(const char *name, const char *value) override
     {
         currentNode->setProp(name, value);
     }
-    virtual void beginNodeContent(const char *name) { }
-    virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset)
+    virtual void beginNodeContent(const char *name) override { }
+    virtual void endNode(const char *tag, unsigned length, const void *value, bool binary, offset_t endOffset) override
     {
         if (binary)
             currentNode->setPropBin(NULL, length, value);
@@ -608,9 +709,9 @@ public:
         ptreeStack.pop();
         currentNode = (c>1) ? &ptreeStack.tos() : NULL;
     }
-    virtual IPropertyTree *queryRoot() { return root; }
-    virtual IPropertyTree *queryCurrentNode() { return currentNode; }
-    virtual void reset()
+    virtual IPropertyTree *queryRoot() override { return root; }
+    virtual IPropertyTree *queryCurrentNode() override { return currentNode; }
+    virtual void reset() override
     {
         if (!rootProvided)
         {

+ 12 - 5
system/jlib/jsuperhash.hpp

@@ -478,11 +478,8 @@ friend class AtomRefTable;
 typedef const char constcharptr;
 class jlib_decl AtomRefTable : public SuperHashTableOf<HashKeyElement, constcharptr>
 {
-protected:
-    CriticalSection crit;
-    bool nocase;
-
-    inline HashKeyElement *createKeyElement(const char *key)
+public:
+    static HashKeyElement *createKeyElement(const char *key, bool nocase)
     {
         size32_t l = (size32_t)strlen(key);
         HashKeyElement *hke = (HashKeyElement *) checked_malloc(sizeof(HashKeyElement)+l+1,-605);
@@ -492,6 +489,16 @@ protected:
         else
             hke->hashValue = hashc((const unsigned char *)key, l, 0);
         hke->linkCount = 0;
+        return hke;
+    }
+
+protected:
+    CriticalSection crit;
+    bool nocase;
+
+    inline HashKeyElement *createKeyElement(const char *key)
+    {
+        HashKeyElement *hke = createKeyElement(key, nocase);
         verifyex(add(*hke));
         return hke;
     }