FieldLookup.hx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (C)2005-2016 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package cs.internal;
  23. @:native('haxe.lang.FieldLookup')
  24. @:final @:nativeGen
  25. @:classCode("#pragma warning disable 628\n")
  26. @:keep @:static class FieldLookup
  27. {
  28. @:protected private static var fieldIds:cs.NativeArray<Int>;
  29. @:protected private static var fields:cs.NativeArray<String>;
  30. @:protected private static var length:Int;
  31. static function __init__()
  32. {
  33. length = fieldIds.Length;
  34. }
  35. private static function addFields(nids:cs.NativeArray<Int>, nfields:cs.NativeArray<String>):Void
  36. {
  37. // first see if we need to add anything
  38. var cids = fieldIds,
  39. cfields = fields;
  40. var nlen = nids.Length;
  41. var clen = length;
  42. if (nfields.Length != nlen) throw 'Different fields length: $nlen and ${nfields.Length}';
  43. //TODO optimize
  44. var needsChange = false;
  45. for (i in nids)
  46. {
  47. if (findHash(i, cids, clen) < 0)
  48. {
  49. needsChange = true;
  50. break;
  51. }
  52. }
  53. // if we do, lock and merge
  54. if (needsChange)
  55. {
  56. cs.Lib.lock(FieldLookup, {
  57. // trace(cs.Lib.array(nids), cs.Lib.array(cids));
  58. var ansIds = new cs.NativeArray(clen + nlen),
  59. ansFields = new cs.NativeArray(clen + nlen);
  60. var ci = 0, ni = 0, ansi = 0;
  61. while (ci < clen && ni < nlen)
  62. {
  63. if (cids[ci] < nids[ni])
  64. {
  65. ansIds[ansi] = cids[ci];
  66. ansFields[ansi] = cfields[ci];
  67. ++ci;
  68. } else {
  69. ansIds[ansi] = nids[ni];
  70. ansFields[ansi] = nfields[ni];
  71. ++ni;
  72. }
  73. ++ansi;
  74. }
  75. if (ci < clen)
  76. {
  77. cs.system.Array.Copy(cids, ci, ansIds, ansi, clen - ci);
  78. cs.system.Array.Copy(cfields, ci, ansFields, ansi, clen - ci);
  79. ansi += clen - ci;
  80. }
  81. if (ni < nlen)
  82. {
  83. cs.system.Array.Copy(nids, ni, ansIds, ansi, nlen - ni);
  84. cs.system.Array.Copy(nfields, ni, ansFields, ansi, nlen - ni);
  85. ansi += nlen - ni;
  86. }
  87. // trace(cs.Lib.array(ansIds));
  88. fieldIds = ansIds;
  89. fields = ansFields;
  90. length = ansi;
  91. });
  92. }
  93. }
  94. //s cannot be null here
  95. private static inline function doHash(s:String):Int
  96. {
  97. var acc = 0; //alloc_int
  98. for (i in 0...s.length)
  99. {
  100. acc = (( 223 * (acc >> 1) + cast(s[i], Int)) << 1);
  101. }
  102. return acc >>> 1; //always positive
  103. }
  104. public static function lookupHash(key:Int):String
  105. {
  106. //start of binary search algorithm
  107. var ids = fieldIds;
  108. var min = 0;
  109. var max = length;
  110. while (min < max)
  111. {
  112. var mid = min + Std.int((max - min) / 2);
  113. var imid = ids[mid];
  114. if (key < imid)
  115. {
  116. max = mid;
  117. } else if (key > imid) {
  118. min = mid + 1;
  119. } else {
  120. return fields[mid];
  121. }
  122. }
  123. //if not found, it's definitely an error
  124. throw "Field not found for hash " + key;
  125. }
  126. public static function hash(s:String):Int
  127. {
  128. if (s == null) return 0;
  129. var key = doHash(s);
  130. //start of binary search algorithm
  131. var ids = fieldIds,
  132. fld = fields;
  133. var min = 0;
  134. var max = length;
  135. var len = length;
  136. while (min < max)
  137. {
  138. var mid = Std.int(min + (max - min) / 2); //overflow safe
  139. var imid = ids[mid];
  140. if (key < imid)
  141. {
  142. max = mid;
  143. } else if (key > imid) {
  144. min = mid + 1;
  145. } else {
  146. var field = fld[mid];
  147. if (field != s)
  148. return ~key; //special case
  149. return key;
  150. }
  151. }
  152. //if not found, min holds the value where we should insert the key
  153. //ensure thread safety:
  154. cs.Lib.lock(FieldLookup, {
  155. if (len != length) //race condition which will very rarely happen - other thread modified sooner.
  156. return hash(s); //since we already own the lock, this second try will always succeed
  157. #if erase_generics
  158. fieldIds = insertInt(fieldIds, length, min, key);
  159. fields = insertString(fields, length, min, s);
  160. #else
  161. insert(fieldIds, length, min, key);
  162. insert(fields, length, min, s);
  163. // ids.insert(min, key);
  164. // fields.insert(min, s);
  165. #end
  166. ++length;
  167. });
  168. return key;
  169. }
  170. public static function findHash(hash:Int, hashs:cs.NativeArray<Int>, length:Int):Int
  171. {
  172. var min = 0;
  173. var max = length;
  174. while (min < max)
  175. {
  176. var mid = Std.int((max + min) / 2); //overflow safe
  177. var imid = hashs[mid];
  178. if (hash < imid)
  179. {
  180. max = mid;
  181. } else if (hash > imid) {
  182. min = mid + 1;
  183. } else {
  184. return mid;
  185. }
  186. }
  187. //if not found, return a negative value of where it should be inserted
  188. return ~min;
  189. }
  190. #if !erase_generics
  191. static function remove<T>(a:cs.NativeArray<T>, length:Int, pos:Int)
  192. {
  193. cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);
  194. a[length - 1] = null;
  195. }
  196. static function insert<T>(a:cs.Ref<cs.NativeArray<T>>, length:Int, pos:Int, x:T)
  197. {
  198. var capacity = a.Length;
  199. if (pos == length)
  200. {
  201. if (capacity == length)
  202. {
  203. var newarr = new NativeArray((length << 1) + 1);
  204. a.CopyTo(newarr, 0);
  205. a = newarr;
  206. }
  207. }
  208. else if (pos == 0)
  209. {
  210. if (capacity == length)
  211. {
  212. var newarr = new NativeArray((length << 1) + 1);
  213. cs.system.Array.Copy(a, 0, newarr, 1, length);
  214. a = newarr;
  215. }
  216. else
  217. {
  218. cs.system.Array.Copy(a, 0, a, 1, length);
  219. }
  220. }
  221. else
  222. {
  223. if (capacity == length)
  224. {
  225. var newarr = new NativeArray((length << 1) + 1);
  226. cs.system.Array.Copy(a, 0, newarr, 0, pos);
  227. cs.system.Array.Copy(a, pos, newarr, pos + 1, length - pos);
  228. a = newarr;
  229. }
  230. else
  231. {
  232. cs.system.Array.Copy(a, pos, a, pos + 1, length - pos);
  233. cs.system.Array.Copy(a, 0, a, 0, pos);
  234. }
  235. }
  236. a[pos] = x;
  237. }
  238. #else
  239. static function removeInt(a:cs.NativeArray<Int>, length:Int, pos:Int)
  240. {
  241. cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);
  242. a[length - 1] = 0;
  243. }
  244. static function removeFloat(a:cs.NativeArray<Float>, length:Int, pos:Int)
  245. {
  246. cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);
  247. a[length - 1] = 0;
  248. }
  249. static function removeDynamic(a:cs.NativeArray<Dynamic>, length:Int, pos:Int)
  250. {
  251. cs.system.Array.Copy(a, pos + 1, a, pos, length - pos - 1);
  252. a[length - 1] = null;
  253. }
  254. @:extern
  255. static inline function __insert<T>(a:cs.NativeArray<T>, length:Int, pos:Int, x:T):cs.NativeArray<T>
  256. {
  257. var capacity = a.Length;
  258. if (pos == length)
  259. {
  260. if (capacity == length)
  261. {
  262. var newarr = new NativeArray((length << 1) + 1);
  263. a.CopyTo(newarr, 0);
  264. a = newarr;
  265. }
  266. }
  267. else if (pos == 0)
  268. {
  269. if (capacity == length)
  270. {
  271. var newarr = new NativeArray((length << 1) + 1);
  272. cs.system.Array.Copy(a, 0, newarr, 1, length);
  273. a = newarr;
  274. }
  275. else
  276. {
  277. cs.system.Array.Copy(a, 0, a, 1, length);
  278. }
  279. }
  280. else
  281. {
  282. if (capacity == length)
  283. {
  284. var newarr = new NativeArray((length << 1) + 1);
  285. cs.system.Array.Copy(a, 0, newarr, 0, pos);
  286. cs.system.Array.Copy(a, pos, newarr, pos + 1, length - pos);
  287. a = newarr;
  288. }
  289. else
  290. {
  291. cs.system.Array.Copy(a, pos, a, pos + 1, length - pos);
  292. cs.system.Array.Copy(a, 0, a, 0, pos);
  293. }
  294. }
  295. a[pos] = x;
  296. return a;
  297. }
  298. static function insertInt(a:cs.NativeArray<Int>, length:Int, pos:Int, x:Int):cs.NativeArray<Int> return __insert(a, length, pos, x);
  299. static function insertFloat(a:cs.NativeArray<Float>, length:Int, pos:Int, x:Float):cs.NativeArray<Float> return __insert(a, length, pos, x);
  300. static function insertDynamic(a:cs.NativeArray<Dynamic>, length:Int, pos:Int, x:Dynamic):cs.NativeArray<Dynamic> return __insert(a, length, pos, x);
  301. static function insertString(a:cs.NativeArray<String>, length:Int, pos:Int, x:Dynamic):cs.NativeArray<String> return __insert(a, length, pos, x);
  302. #end
  303. }