/* The occupancy of the table after the call will be about 50% */ static UA_StatusCode expand(UA_NodeStore *ns) { UA_UInt32 osize = ns->size; UA_UInt32 count = ns->count; /* Resize only when table after removal of unused elements is either too full or too empty */ if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODESTORE_MINSIZE)) return UA_STATUSCODE_GOOD; UA_NodeStoreEntry **oentries = ns->entries; UA_UInt32 nindex = higher_prime_index(count * 2); UA_UInt32 nsize = primes[nindex]; UA_NodeStoreEntry **nentries; if(!(nentries = UA_calloc(nsize, sizeof(UA_NodeStoreEntry*)))) return UA_STATUSCODE_BADOUTOFMEMORY; ns->entries = nentries; ns->size = nsize; ns->sizePrimeIndex = nindex; /* recompute the position of every entry and insert the pointer */ for(size_t i = 0, j = 0; i < osize && j < count; i++) { if(!oentries[i]) continue; UA_NodeStoreEntry **e; containsNodeId(ns, &oentries[i]->node.nodeId, &e); /* We know this returns an empty entry here */ *e = oentries[i]; j++; } UA_free(oentries); return UA_STATUSCODE_GOOD; }
UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) { UA_NodeStoreEntry *slot; if(!containsNodeId(ns, nodeid, &slot)) return UA_STATUSCODE_BADNODEIDUNKNOWN; deleteEntry(slot); ns->count--; /* Downsize the hashmap if it is very empty */ if(ns->count * 8 < ns->size && ns->size > 32) expand(ns); // this can fail. we just continue with the bigger hashmap. return UA_STATUSCODE_GOOD; }
UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *oldNode, UA_Node *node, UA_Node **inserted) { UA_NodeStoreEntry *slot; if(!containsNodeId(ns, &node->nodeId, &slot)) return UA_STATUSCODE_BADNODEIDUNKNOWN; /* that is not the node you are looking for */ if(&slot->node.node != oldNode) return UA_STATUSCODE_BADINTERNALERROR; deleteEntry(slot); fillEntry(slot, node); if(inserted) *inserted = &slot->node.node; return UA_STATUSCODE_GOOD; }
UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_Node **inserted) { if(ns->size * 3 <= ns->count * 4) { if(expand(ns) != UA_STATUSCODE_GOOD) return UA_STATUSCODE_BADINTERNALERROR; } UA_NodeStoreEntry *entry; UA_NodeId tempNodeid; tempNodeid = node->nodeId; tempNodeid.namespaceIndex = 0; if(UA_NodeId_isNull(&tempNodeid)) { /* find a free nodeid */ if(node->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1 node->nodeId.namespaceIndex = 1; UA_Int32 identifier = ns->count+1; // start value UA_Int32 size = ns->size; hash_t increase = mod2(identifier, size); while(UA_TRUE) { node->nodeId.identifier.numeric = identifier; if(!containsNodeId(ns, &node->nodeId, &entry)) break; identifier += increase; if(identifier >= size) identifier -= size; } } else { if(containsNodeId(ns, &node->nodeId, &entry)) return UA_STATUSCODE_BADNODEIDEXISTS; } fillEntry(entry, node); ns->count++; if(inserted) *inserted = &entry->node.node; return UA_STATUSCODE_GOOD; }
UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) { UA_NodeStoreEntry *slot; if(!containsNodeId(ns, nodeid, &slot)) return NULL; return &slot->node.node; }