ua_namespace.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #include "ua_namespace.h"
  2. struct UA_Namespace {
  3. const UA_Node **entries;
  4. UA_UInt32 size;
  5. UA_UInt32 count;
  6. UA_UInt32 sizePrimeIndex;
  7. };
  8. typedef UA_UInt32 hash_t;
  9. /* The size of the hash-map is always a prime number. They are chosen to be
  10. close to the next power of 2. So the size ca. doubles with each prime. */
  11. static hash_t const primes[] = {
  12. 7, 13, 31, 61, 127, 251,
  13. 509, 1021, 2039, 4093, 8191, 16381,
  14. 32749, 65521, 131071, 262139, 524287, 1048573,
  15. 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
  16. 134217689, 268435399, 536870909, 1073741789, 2147483647, 4294967291
  17. };
  18. static INLINE hash_t mod(hash_t h, hash_t size) {
  19. return h % size;
  20. }
  21. static INLINE hash_t mod2(hash_t h, hash_t size) {
  22. return 1 + (h % (size - 2));
  23. }
  24. static INLINE UA_Int16 higher_prime_index(hash_t n) {
  25. UA_UInt16 low = 0;
  26. UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
  27. while(low != high) {
  28. UA_UInt16 mid = low + (high - low) / 2;
  29. if(n > primes[mid])
  30. low = mid + 1;
  31. else
  32. high = mid;
  33. }
  34. return low;
  35. }
  36. /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
  37. static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len) {
  38. const int32_t nblocks = len / 4;
  39. const uint32_t *blocks;
  40. static const uint32_t c1 = 0xcc9e2d51;
  41. static const uint32_t c2 = 0x1b873593;
  42. static const uint32_t r1 = 15;
  43. static const uint32_t r2 = 13;
  44. static const uint32_t m = 5;
  45. static const uint32_t n = 0xe6546b64;
  46. hash_t hash = len;
  47. if(data == UA_NULL)
  48. return 0;
  49. blocks = (const uint32_t *)data;
  50. for(int32_t i = 0;i < nblocks;i++) {
  51. uint32_t k = blocks[i];
  52. k *= c1;
  53. k = (k << r1) | (k >> (32 - r1));
  54. k *= c2;
  55. hash ^= k;
  56. hash = ((hash << r2) | (hash >> (32 - r2))) * m + n;
  57. }
  58. const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
  59. uint32_t k1 = 0;
  60. switch(len & 3) {
  61. case 3:
  62. k1 ^= tail[2] << 16;
  63. case 2:
  64. k1 ^= tail[1] << 8;
  65. case 1:
  66. k1 ^= tail[0];
  67. k1 *= c1;
  68. k1 = (k1 << r1) | (k1 >> (32 - r1));
  69. k1 *= c2;
  70. hash ^= k1;
  71. }
  72. hash ^= len;
  73. hash ^= (hash >> 16);
  74. hash *= 0x85ebca6b;
  75. hash ^= (hash >> 13);
  76. hash *= 0xc2b2ae35;
  77. hash ^= (hash >> 16);
  78. return hash;
  79. }
  80. static INLINE hash_t hash(const UA_NodeId *n) {
  81. switch(n->identifierType) {
  82. case UA_NODEIDTYPE_NUMERIC:
  83. /* Knuth's multiplicative hashing */
  84. return n->identifier.numeric * 2654435761; // mod(2^32) is implicit
  85. case UA_NODEIDTYPE_STRING:
  86. return hash_array(n->identifier.string.data, n->identifier.string.length);
  87. case UA_NODEIDTYPE_GUID:
  88. return hash_array((UA_Byte *)&(n->identifier.guid), sizeof(UA_Guid));
  89. case UA_NODEIDTYPE_BYTESTRING:
  90. return hash_array((UA_Byte *)n->identifier.byteString.data, n->identifier.byteString.length);
  91. default:
  92. return 0;
  93. }
  94. }
  95. static INLINE void clear_entry(UA_Namespace *ns, const UA_Node **entry) {
  96. const UA_Node *node;
  97. if(entry == UA_NULL || *entry == UA_NULL)
  98. return;
  99. node = *entry;
  100. switch(node->nodeClass) {
  101. case UA_NODECLASS_OBJECT:
  102. UA_ObjectNode_delete((UA_ObjectNode *)node);
  103. break;
  104. case UA_NODECLASS_VARIABLE:
  105. UA_VariableNode_delete((UA_VariableNode *)node);
  106. break;
  107. case UA_NODECLASS_METHOD:
  108. UA_MethodNode_delete((UA_MethodNode *)node);
  109. break;
  110. case UA_NODECLASS_OBJECTTYPE:
  111. UA_ObjectTypeNode_delete((UA_ObjectTypeNode *)node);
  112. break;
  113. case UA_NODECLASS_VARIABLETYPE:
  114. UA_VariableTypeNode_delete((UA_VariableTypeNode *)node);
  115. break;
  116. case UA_NODECLASS_REFERENCETYPE:
  117. UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *)node);
  118. break;
  119. case UA_NODECLASS_DATATYPE:
  120. UA_DataTypeNode_delete((UA_DataTypeNode *)node);
  121. break;
  122. case UA_NODECLASS_VIEW:
  123. UA_ViewNode_delete((UA_ViewNode *)node);
  124. break;
  125. default:
  126. break;
  127. }
  128. entry = UA_NULL;
  129. ns->count--;
  130. }
  131. /* Returns UA_SUCCESS if an entry was found. Otherwise, UA_ERROR is returned and the "entry"
  132. argument points to the first free entry under the NodeId. */
  133. static INLINE UA_Int32 find_entry(const UA_Namespace *ns, const UA_NodeId *nodeid, const UA_Node ***entry) {
  134. hash_t h = hash(nodeid);
  135. UA_UInt32 size = ns->size;
  136. hash_t index = mod(h, size);
  137. const UA_Node **e = &ns->entries[index];
  138. if(*e == UA_NULL) {
  139. *entry = e;
  140. return UA_ERROR;
  141. }
  142. if(UA_NodeId_equal(&(*e)->nodeId, nodeid) == UA_EQUAL) {
  143. *entry = e;
  144. return UA_SUCCESS;
  145. }
  146. hash_t hash2 = mod2(h, size);
  147. for(;;) {
  148. index += hash2;
  149. if(index >= size)
  150. index -= size;
  151. e = &ns->entries[index];
  152. if(*e == UA_NULL) {
  153. *entry = e;
  154. return UA_ERROR;
  155. }
  156. if(UA_NodeId_equal(&(*e)->nodeId, nodeid) == UA_EQUAL) {
  157. *entry = e;
  158. return UA_SUCCESS;
  159. }
  160. }
  161. /* NOTREACHED */
  162. return UA_SUCCESS;
  163. }
  164. /* The following function changes size of memory allocated for the entries and
  165. repeatedly inserts the table elements. The occupancy of the table after the
  166. call will be about 50%. If memory allocation failures occur, this function
  167. will return UA_ERROR. */
  168. static UA_Int32 expand(UA_Namespace *ns) {
  169. const UA_Node **nentries;
  170. int32_t nsize;
  171. UA_UInt32 nindex;
  172. const UA_Node **oentries = ns->entries;
  173. int32_t osize = ns->size;
  174. const UA_Node **olimit = &oentries[osize];
  175. int32_t count = ns->count;
  176. /* Resize only when table after removal of unused elements is either too full or too empty. */
  177. if(count * 2 < osize && (count * 8 > osize || osize <= 32))
  178. return UA_SUCCESS;
  179. nindex = higher_prime_index(count * 2);
  180. nsize = primes[nindex];
  181. if(UA_alloc((void **)&nentries, sizeof(UA_Node *) * nsize) != UA_SUCCESS)
  182. return UA_ERR_NO_MEMORY;
  183. memset(nentries, 0, nsize * sizeof(UA_Node *));
  184. ns->entries = nentries;
  185. ns->size = nsize;
  186. ns->sizePrimeIndex = nindex;
  187. const UA_Node **p = oentries;
  188. do {
  189. if(*p != UA_NULL) {
  190. const UA_Node **e;
  191. find_entry(ns, &(*p)->nodeId, &e); /* We know this returns an empty entry here */
  192. *e = *p;
  193. }
  194. p++;
  195. } while(p < olimit);
  196. UA_free(oentries);
  197. return UA_SUCCESS;
  198. }
  199. /**********************/
  200. /* Exported functions */
  201. /**********************/
  202. UA_Int32 UA_Namespace_new(UA_Namespace **result) {
  203. UA_Namespace *ns;
  204. UA_UInt32 sizePrimeIndex, size;
  205. if(UA_alloc((void **)&ns, sizeof(UA_Namespace)) != UA_SUCCESS)
  206. return UA_ERR_NO_MEMORY;
  207. sizePrimeIndex = higher_prime_index(32);
  208. size = primes[sizePrimeIndex];
  209. if(UA_alloc((void **)&ns->entries, sizeof(UA_Node *) * size) != UA_SUCCESS) {
  210. UA_free(ns);
  211. return UA_ERR_NO_MEMORY;
  212. }
  213. /* set entries to zero */
  214. memset(ns->entries, 0, size * sizeof(UA_Node *));
  215. *ns = (UA_Namespace) {ns->entries, size, 0, sizePrimeIndex };
  216. *result = ns;
  217. return UA_SUCCESS;
  218. }
  219. UA_Int32 UA_Namespace_delete(UA_Namespace *ns) {
  220. UA_UInt32 size = ns->size;
  221. const UA_Node **entries = ns->entries;
  222. for(UA_UInt32 i = 0;i < size;i++)
  223. clear_entry(ns, &entries[i]);
  224. UA_free(ns->entries);
  225. UA_free(ns);
  226. return UA_SUCCESS;
  227. }
  228. UA_Int32 UA_Namespace_insert(UA_Namespace *ns, UA_Node **node, UA_Byte flags) {
  229. if(ns == UA_NULL || node == UA_NULL || *node == UA_NULL)
  230. return UA_ERROR;
  231. if(ns->size * 3 <= ns->count * 4) {
  232. if(expand(ns) != UA_SUCCESS)
  233. return UA_ERROR;
  234. }
  235. const UA_Node **entry;
  236. UA_Int32 found = find_entry(ns, &(*node)->nodeId, &entry);
  237. if(flags & UA_NAMESPACE_INSERT_UNIQUE) {
  238. if(found == UA_SUCCESS)
  239. return UA_ERROR; /* There is already an entry for that nodeid */
  240. else
  241. *entry = *node;
  242. } else {
  243. if(found == UA_SUCCESS)
  244. clear_entry(ns, entry);
  245. *entry = *node;
  246. }
  247. if(!(flags & UA_NAMESPACE_INSERT_GETMANAGED))
  248. *node = UA_NULL;
  249. ns->count++;
  250. return UA_SUCCESS;
  251. }
  252. UA_Int32 UA_Namespace_get(const UA_Namespace *ns, const UA_NodeId *nodeid, const UA_Node **managedNode) {
  253. const UA_Node **entry;
  254. if(ns == UA_NULL || nodeid == UA_NULL || managedNode == UA_NULL)
  255. return UA_ERROR;
  256. if(find_entry(ns, nodeid, &entry) != UA_SUCCESS)
  257. return UA_ERROR;
  258. *managedNode = *entry;
  259. return UA_SUCCESS;
  260. }
  261. UA_Int32 UA_Namespace_remove(UA_Namespace *ns, const UA_NodeId *nodeid) {
  262. const UA_Node **entry;
  263. if(find_entry(ns, nodeid, &entry) != UA_SUCCESS)
  264. return UA_ERROR;
  265. // Check before if deleting the node makes the UA_Namespace inconsistent.
  266. clear_entry(ns, entry);
  267. /* Downsize the hashmap if it is very empty */
  268. if(ns->count * 8 < ns->size && ns->size > 32)
  269. expand(ns);
  270. return UA_SUCCESS;
  271. }
  272. UA_Int32 UA_Namespace_iterate(const UA_Namespace *ns, UA_Namespace_nodeVisitor visitor) {
  273. if(ns == UA_NULL || visitor == UA_NULL)
  274. return UA_ERROR;
  275. for(UA_UInt32 i = 0;i < ns->size;i++) {
  276. const UA_Node *node = ns->entries[i];
  277. if(node != UA_NULL)
  278. visitor(node);
  279. }
  280. return UA_SUCCESS;
  281. }
  282. void UA_Namespace_releaseManagedNode(const UA_Node *managed) {
  283. ;
  284. }