PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/bitpath_stubs.c

http://github.com/paurkedal/ocaml-bitpath
C | 475 lines | 419 code | 38 blank | 18 comment | 67 complexity | b9b01e0a3567d354d63faddf92e063ac MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. /* Copyright (C) 2012--2017 Petter A. Urkedal <paurkedal@gmail.com>
  2. *
  3. * This library is free software; you can redistribute it and/or modify it
  4. * under the terms of the GNU Lesser General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or (at your
  6. * option) any later version, with the OCaml static compilation exception.
  7. *
  8. * This library is distributed in the hope that it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  11. * License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public License
  14. * along with this library. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "bitpath.h"
  17. #include <caml/callback.h>
  18. #include <caml/custom.h>
  19. #include <caml/fail.h>
  20. #include <caml/memory.h>
  21. #include <caml/mlvalues.h>
  22. #include <string.h>
  23. #include <assert.h>
  24. #ifndef MIN
  25. # define MIN(x, y) ((x) <= (y)? (x) : (y))
  26. #endif
  27. #define WORD_ROT(i, k) ((i << k) | (i >> (8*sizeof(bitpath_word_t) - i)))
  28. #define WORD_WIDTH BITPATH_WORD_WIDTH
  29. #define WORD_SIZE (BITPATH_WORD_WIDTH / 8)
  30. #define WORD_SZ16 (BITPATH_WORD_WIDTH / 16)
  31. #define WORD_CNT(n) (((n) + WORD_WIDTH - 1) / WORD_WIDTH)
  32. #define WORD_MOD(i) (WORD_WIDTH - 1 - (i) % WORD_WIDTH)
  33. #define WORD_MOD8(i) ((WORD_SIZE - 1 - (i) % WORD_SIZE) * 8)
  34. #define WORD_MOD16(i) ((WORD_SZ16 - 1 - (i) % WORD_SZ16) * 16)
  35. #define BITPATH_GET(i, s) ((s->arr[(i) / WORD_WIDTH] >> WORD_MOD(i)) & 1)
  36. #define BITPATH_GET8(i, s) ((s->arr[(i) / WORD_SIZE] >> WORD_MOD8(i)) & 0xff)
  37. #define BITPATH_GET16(i, s) \
  38. ((s->arr[(i) / WORD_SZ16] >> WORD_MOD16(i)) & 0xffff)
  39. #ifndef BITPATH_INLINED
  40. static void
  41. _bitpath_finalize(value s_v)
  42. {
  43. free(BITPATH(s_v)->arr);
  44. }
  45. #endif
  46. static int
  47. _bitpath_compare(value sA_v, value sB_v)
  48. {
  49. size_t i;
  50. size_t mA = WORD_CNT(BITPATH(sA_v)->len);
  51. size_t mB = WORD_CNT(BITPATH(sB_v)->len);
  52. for (i = 0; i < MIN(mA, mB); ++i) {
  53. bitpath_word_t wA = BITPATH(sA_v)->arr[i];
  54. bitpath_word_t wB = BITPATH(sB_v)->arr[i];
  55. if (wA < wB) return -1;
  56. if (wA > wB) return 1;
  57. }
  58. if (mA < mB) return -1;
  59. if (mA > mB) return 1;
  60. return 0;
  61. }
  62. value
  63. camlbitpath_compare(value sA_v, value sB_v)
  64. {
  65. return Val_int(_bitpath_compare(sA_v, sB_v));
  66. }
  67. /* Based on Bob Jenkins' hash functions. */
  68. #if BITPATH_WORD_WIDTH >= 64
  69. # define MIX(a, b, c) \
  70. do { \
  71. a -= b + c; a ^= (c >> 43); \
  72. b -= c + a; b ^= (a << 9); \
  73. c -= a + b; c ^= (b >> 8); \
  74. a -= b + c; a ^= (c >> 38); \
  75. b -= c + a; b ^= (a << 23); \
  76. c -= a + b; c ^= (b >> 5); \
  77. a -= b + c; a ^= (c >> 35); \
  78. b -= c + a; b ^= (a << 49); \
  79. c -= a + b; c ^= (b >> 11); \
  80. a -= b + c; a ^= (c >> 12); \
  81. b -= c + a; b ^= (a << 18); \
  82. c -= a + b; c ^= (b >> 22); \
  83. } while (0)
  84. #else
  85. # define MIX(a, b, c) \
  86. do { \
  87. a -= c; a ^= WORD_ROT(c, 4); c += b; \
  88. b -= a; b ^= WORD_ROT(a, 6); a += c; \
  89. c -= b; c ^= WORD_ROT(b, 8); b += a; \
  90. a -= c; a ^= WORD_ROT(c, 16); c += b; \
  91. b -= a; b ^= WORD_ROT(a, 19); a += c; \
  92. c -= b; c ^= WORD_ROT(b, 4); b += a; \
  93. } while (0)
  94. #endif
  95. static long
  96. _bitpath_hash(value s_v)
  97. {
  98. size_t i, m = WORD_CNT(BITPATH(s_v)->len);
  99. long a, b, c;
  100. a = 0xba5ebee7;
  101. b = 0xcafebabe;
  102. c = BITPATH(s_v)->len;
  103. for (i = 0; i + 2 < m; i += 3) {
  104. a += BITPATH(s_v)->arr[i];
  105. b += BITPATH(s_v)->arr[i + 1];
  106. c += BITPATH(s_v)->arr[i + 2];
  107. MIX(a, b, c);
  108. }
  109. if (i < m) {
  110. a += BITPATH(s_v)->arr[i];
  111. if (i + 1 < m) b += BITPATH(s_v)->arr[i + 1];
  112. MIX(a, b, c);
  113. }
  114. return c;
  115. }
  116. static struct custom_operations _bitpath_ops = {
  117. "org.eideticdew.p.bitpath",
  118. #ifndef BITPATH_INLINED
  119. _bitpath_finalize,
  120. #else
  121. custom_finalize_default,
  122. #endif
  123. _bitpath_compare,
  124. _bitpath_hash,
  125. custom_serialize_default,
  126. custom_deserialize_default,
  127. custom_compare_ext_default,
  128. };
  129. static value
  130. _bitpath_alloc(size_t m)
  131. {
  132. #ifdef BITPATH_INLINED
  133. return caml_alloc_custom(&_bitpath_ops,
  134. sizeof(struct bitpath) + (m - 1)*sizeof(bitpath_word_t),
  135. 0, 1);
  136. #else
  137. value s = caml_alloc_custom(&_bitpath_ops,
  138. sizeof(struct bitpath), 0, 1);
  139. BITPATH(s)->arr = malloc(m * WORD_SIZE);
  140. return s;
  141. #endif
  142. }
  143. static value _bitpath_empty = Val_unit;
  144. value
  145. camlbitpath_make_empty(value _)
  146. {
  147. assert(_bitpath_empty == Val_unit);
  148. caml_register_global_root(&_bitpath_empty);
  149. _bitpath_empty = _bitpath_alloc(0);
  150. BITPATH(_bitpath_empty)->len = 0;
  151. return _bitpath_empty;
  152. }
  153. value
  154. camlbitpath_init(value n_v, value f_v)
  155. {
  156. CAMLparam2 (n_v, f_v);
  157. CAMLlocal1 (s_v);
  158. size_t i, j, n = Long_val(n_v);
  159. size_t m0 = n / WORD_WIDTH;
  160. size_t m = WORD_CNT(n);
  161. s_v = _bitpath_alloc(m);
  162. BITPATH(s_v)->len = n;
  163. if (!BITPATH(s_v)->arr)
  164. caml_raise_out_of_memory();
  165. for (i = 0; i < m0; ++i) {
  166. bitpath_word_t w = 0;
  167. for (j = 0; j < WORD_WIDTH; ++j) {
  168. int x = Bool_val(caml_callback(f_v, Val_long(i * WORD_WIDTH + j)));
  169. w <<= 1;
  170. w |= x;
  171. }
  172. BITPATH(s_v)->arr[i] = w;
  173. }
  174. if (m0 < m) {
  175. bitpath_word_t w = 0;
  176. for (j = 0; j < n % WORD_WIDTH; ++j) {
  177. int x = Bool_val(caml_callback(f_v, Val_long(m0 * WORD_WIDTH + j)));
  178. w <<= 1;
  179. w |= x;
  180. }
  181. BITPATH(s_v)->arr[m0] = w << (WORD_WIDTH - n % WORD_WIDTH);
  182. }
  183. CAMLreturn (s_v);
  184. }
  185. value
  186. camlbitpath_init8(value n_v, value f_v)
  187. {
  188. CAMLparam2 (n_v, f_v);
  189. CAMLlocal1 (s_v);
  190. size_t i, j, n = Long_val(n_v);
  191. size_t m0 = n / WORD_WIDTH;
  192. size_t m = WORD_CNT(n);
  193. s_v = _bitpath_alloc(m);
  194. BITPATH(s_v)->len = n;
  195. if (!BITPATH(s_v)->arr)
  196. caml_raise_out_of_memory();
  197. for (i = 0; i < m0; ++i) {
  198. bitpath_word_t w = 0;
  199. for (j = 0; j < WORD_SIZE; ++j) {
  200. int x = Int_val(caml_callback(f_v, Val_long(i * WORD_SIZE + j)));
  201. w <<= 8;
  202. w |= x;
  203. }
  204. BITPATH(s_v)->arr[i] = w;
  205. }
  206. if (m0 < m) {
  207. bitpath_word_t w = 0;
  208. int n_oct = (n % WORD_WIDTH + 7) / 8;
  209. for (j = 0; j < n_oct; ++j) {
  210. int x = Int_val(caml_callback(f_v, Val_long(m0 * WORD_SIZE + j)));
  211. w <<= 8;
  212. w |= x;
  213. }
  214. w >>= n_oct * 8 - n % WORD_WIDTH;
  215. BITPATH(s_v)->arr[m0] = w << (WORD_WIDTH - 1 - (n - 1) % WORD_WIDTH);
  216. }
  217. CAMLreturn (s_v);
  218. }
  219. value
  220. camlbitpath_init16(value n_v, value f_v)
  221. {
  222. CAMLparam2 (n_v, f_v);
  223. CAMLlocal1 (s_v);
  224. size_t i, j, n = Long_val(n_v);
  225. size_t m0 = n / WORD_WIDTH;
  226. size_t m = WORD_CNT(n);
  227. s_v = _bitpath_alloc(m);
  228. BITPATH(s_v)->len = n;
  229. if (!BITPATH(s_v)->arr)
  230. caml_raise_out_of_memory();
  231. for (i = 0; i < m0; ++i) {
  232. bitpath_word_t w = 0;
  233. for (j = 0; j < WORD_SZ16; ++j) {
  234. int x = Int_val(caml_callback(f_v, Val_long(i*WORD_SZ16 + j)));
  235. w <<= 16;
  236. w |= x;
  237. }
  238. BITPATH(s_v)->arr[i] = w;
  239. }
  240. if (m0 < m) {
  241. bitpath_word_t w = 0;
  242. int n_hxd = (n % WORD_WIDTH + 15) / 16;
  243. for (j = 0; j < n_hxd; ++j) {
  244. int x = Int_val(caml_callback(f_v, Val_long(m0 * WORD_SZ16 + j)));
  245. w <<= 16;
  246. w |= x;
  247. }
  248. w >>= n_hxd * 16 - n % WORD_WIDTH;
  249. BITPATH(s_v)->arr[m0] = w << (WORD_WIDTH - 1 - (n - 1) % WORD_WIDTH);
  250. }
  251. CAMLreturn (s_v);
  252. }
  253. #include <stdio.h>
  254. value
  255. camlbitpath_const(value n_v, value x_v)
  256. {
  257. CAMLparam2 (n_v, x_v);
  258. CAMLlocal1 (s_v);
  259. size_t i, n, m;
  260. bitpath_word_t x;
  261. n = Long_val(n_v);
  262. if (n == 0) {
  263. assert(_bitpath_empty != Val_unit);
  264. CAMLreturn (_bitpath_empty);
  265. }
  266. m = WORD_CNT(n);
  267. x = Bool_val(x_v)? ~BITPATH_WORD_C(0) : 0;
  268. s_v = _bitpath_alloc(m);
  269. BITPATH(s_v)->len = n;
  270. if (!BITPATH(s_v)->arr)
  271. caml_raise_out_of_memory();
  272. for (i = 0; i < m - 1; ++i)
  273. BITPATH(s_v)->arr[i] = x;
  274. BITPATH(s_v)->arr[m - 1] = x << (WORD_WIDTH - 1 - (n - 1) % WORD_WIDTH);
  275. CAMLreturn (s_v);
  276. }
  277. value
  278. camlbitpath_not(value sA_v)
  279. {
  280. CAMLparam1 (sA_v);
  281. CAMLlocal1 (sN_v);
  282. size_t i, n, m;
  283. n = BITPATH(sA_v)->len;
  284. if (n == 0) {
  285. assert(_bitpath_empty != Val_unit);
  286. CAMLreturn (_bitpath_empty);
  287. }
  288. m = WORD_CNT(n);
  289. sN_v = _bitpath_alloc(m);
  290. BITPATH(sN_v)->len = n;
  291. for (i = 0; i < m - 1; ++i)
  292. BITPATH(sN_v)->arr[i] = ~BITPATH(sA_v)->arr[i];
  293. BITPATH(sN_v)->arr[m - 1] = ~BITPATH(sA_v)->arr[m - 1]
  294. & (~BITPATH_WORD_C(0) << (WORD_WIDTH - 1 - (n - 1) % WORD_WIDTH));
  295. CAMLreturn (sN_v);
  296. }
  297. value
  298. camlbitpath_length(value s_v)
  299. {
  300. return Val_long(BITPATH(s_v)->len);
  301. }
  302. value
  303. camlbitpath_get(value s_v, value i_v)
  304. {
  305. size_t i = Long_val(i_v);
  306. return Val_bool(BITPATH_GET(i, BITPATH(s_v)));
  307. }
  308. value
  309. camlbitpath_get8(value s_v, value i_v)
  310. {
  311. size_t i = Long_val(i_v);
  312. return Val_int(BITPATH_GET8(i, BITPATH(s_v)));
  313. }
  314. value
  315. camlbitpath_get16(value s_v, value i_v)
  316. {
  317. size_t i = Long_val(i_v);
  318. return Val_int(BITPATH_GET16(i, BITPATH(s_v)));
  319. }
  320. value
  321. camlbitpath_coprefix_length(value sA_v, value sB_v)
  322. {
  323. size_t i, n = MIN(BITPATH(sA_v)->len, BITPATH(sB_v)->len);
  324. size_t j, m = n / WORD_WIDTH;
  325. for (j = 0; j < m; ++j)
  326. if (BITPATH(sA_v)->arr[j] != BITPATH(sB_v)->arr[j])
  327. break;
  328. for (i = j * WORD_WIDTH; i < n; ++i)
  329. if (BITPATH_GET(i, BITPATH(sA_v)) !=
  330. BITPATH_GET(i, BITPATH(sB_v)))
  331. break;
  332. return Val_long(i);
  333. }
  334. value
  335. camlbitpath_coslice_length(value iA_v, value sA_v, value iB_v, value sB_v)
  336. {
  337. size_t iA = Long_val(iA_v);
  338. size_t iB = Long_val(iB_v);
  339. size_t i, n = MIN(BITPATH(sA_v)->len - iA, BITPATH(sB_v)->len - iB);
  340. /* TODO: This can be optimized to operate on words, but it'll take some
  341. * coding for unaligned cases. */
  342. for (i = 0; i < n; ++i)
  343. if (BITPATH_GET(iA + i, BITPATH(sA_v)) !=
  344. BITPATH_GET(iB + i, BITPATH(sB_v)))
  345. break;
  346. return Val_long(i);
  347. }
  348. value
  349. camlbitpath_slice(value iL_v, value iU_v, value sA_v)
  350. {
  351. static char errbuf[160 + 3*sizeof(size_t)]; /* NB! Max 2 lines & 2 %zd's */
  352. CAMLparam3 (sA_v, iL_v, iU_v);
  353. CAMLlocal1 (s_v);
  354. size_t iL = Long_val(iL_v);
  355. size_t iU = Long_val(iU_v);
  356. size_t nA, n, m;
  357. if (iL < 0) {
  358. sprintf(errbuf, "Bitpath.slice: The lower bound %zd is negative.", iL);
  359. caml_invalid_argument(errbuf);
  360. }
  361. if (iL > iU) {
  362. sprintf(errbuf, "Bitpath.slice: "
  363. "The lower bound %zd larger than the upper bound %zd.", iL, iU);
  364. caml_invalid_argument(errbuf);
  365. }
  366. if (iL == iU) {
  367. assert(_bitpath_empty != Val_unit);
  368. CAMLreturn (_bitpath_empty);
  369. }
  370. nA = BITPATH(sA_v)->len;
  371. if (iU > nA) {
  372. sprintf(errbuf, "Bitpath.slice: "
  373. "Upper bound %zd is larger than the length %zd.", iU, nA);
  374. caml_invalid_argument(errbuf);
  375. }
  376. if (iL == 0 && iU == nA) CAMLreturn (sA_v);
  377. n = iU - iL;
  378. m = WORD_CNT(n);
  379. assert(m > 0);
  380. s_v = _bitpath_alloc(m);
  381. BITPATH(s_v)->len = n;
  382. if (!BITPATH(s_v)->arr)
  383. caml_raise_out_of_memory();
  384. if (iL % WORD_WIDTH == 0)
  385. memcpy(BITPATH(s_v)->arr, BITPATH(sA_v)->arr + iL / WORD_WIDTH,
  386. m * WORD_SIZE);
  387. else {
  388. bitpath_word_t w0, w1;
  389. int jL = iL % WORD_WIDTH;
  390. size_t k, kL = iL / WORD_WIDTH;
  391. w0 = BITPATH(sA_v)->arr[kL];
  392. for (k = 0; k < m; ++k) {
  393. w1 = BITPATH(sA_v)->arr[kL + k + 1];
  394. BITPATH(s_v)->arr[k] = (w0 << jL) | (w1 >> (WORD_WIDTH - jL));
  395. w0 = w1;
  396. }
  397. }
  398. BITPATH(s_v)->arr[m - 1] &= ~BITPATH_WORD_C(0)
  399. << (WORD_WIDTH - 1 - (n - 1) % WORD_WIDTH);
  400. CAMLreturn (s_v);
  401. }
  402. value
  403. camlbitpath_cat(value sA_v, value sB_v)
  404. {
  405. CAMLparam2 (sA_v, sB_v);
  406. CAMLlocal1 (s_v);
  407. size_t i, n, m;
  408. size_t nA = BITPATH(sA_v)->len;
  409. size_t nB = BITPATH(sB_v)->len;
  410. if (nA == 0) CAMLreturn (sB_v);
  411. if (nB == 0) CAMLreturn (sA_v);
  412. n = nA + nB;
  413. m = WORD_CNT(n);
  414. s_v = _bitpath_alloc(m);
  415. BITPATH(s_v)->len = n;
  416. if (!BITPATH(s_v)->arr)
  417. caml_raise_out_of_memory();
  418. memcpy(BITPATH(s_v)->arr, BITPATH(sA_v)->arr,
  419. nA / WORD_WIDTH * WORD_SIZE);
  420. if (nA % WORD_WIDTH == 0)
  421. memcpy(BITPATH(s_v)->arr + nA / WORD_WIDTH, BITPATH(sB_v)->arr,
  422. WORD_CNT(nB) * WORD_SIZE);
  423. else {
  424. bitpath_word_t w0, w1;
  425. int j = nA % WORD_WIDTH;
  426. size_t m0 = nA / WORD_WIDTH + WORD_CNT(nB);
  427. w0 = BITPATH(sA_v)->arr[nA / WORD_WIDTH] >> (WORD_WIDTH - j);
  428. for (i = nA / WORD_WIDTH; i < m0; ++i) {
  429. w1 = BITPATH(sB_v)->arr[i - nA / WORD_WIDTH];
  430. BITPATH(s_v)->arr[i] = (w0 << (WORD_WIDTH - j)) | (w1 >> j);
  431. w0 = w1;
  432. }
  433. if (m0 < m)
  434. BITPATH(s_v)->arr[m0] = w0 << (WORD_WIDTH - j);
  435. }
  436. CAMLreturn (s_v);
  437. }