diff --git a/.gitignore b/.gitignore index 0244d92..eb5a7e9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ *.so **/*.o tests/test -examples/ex_* +examples/ex_? .cache hints.txt tmp/ @@ -13,6 +13,8 @@ git.diff .codelite/ .cmaketools.json *.tags +tags +TAGS *.dll build/ cmake-build* diff --git a/examples/ex_1.c b/examples/ex_1.c index 6b777ed..ebc8f69 100644 --- a/examples/ex_1.c +++ b/examples/ex_1.c @@ -1,20 +1,22 @@ #include -#include #include -#include #include "../include/sparsemap.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wvariadic-macros" -#define __diag(...) \ - do { fprintf(stderr, "%s:%d:%s(): ",__FILE__, __LINE__, __func__);\ - fprintf(stderr, __VA_ARGS__); } while (0) +#define __diag(...) \ + do { \ + fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) #pragma GCC diagnostic pop // NOTE: currently, this code serves as a sample and unittest. -int main() { +int +main() +{ size_t size = 4; setbuf(stderr, 0); // disable buffering __diag("Please wait a moment..."); @@ -85,11 +87,11 @@ int main() { } // open and compare - sparsemap_t *sm2 = sparsemap_open(buffer, sizeof(buffer)); + sparsemap_t _sm3, *sm3 = &_sm3; + sparsemap_open(sm3, buffer, sizeof(buffer)); for (int i = 0; i < 10000; i++) { - assert(sparsemap_is_set(sm2, i) == sparsemap_is_set(map, i)); + assert(sparsemap_is_set(sm3, i) == sparsemap_is_set(map, i)); } - free(sm2); // unset [10000..0] for (int i = 10000; i >= 0; i--) { @@ -152,8 +154,7 @@ int main() { } // split and move, aligned to MiniMap capacity - sparsemap_t _sm2; - sm2 = &_sm2; + sparsemap_t _sm2, *sm2 = &_sm2; sparsemap_init(sm2, buffer2, sizeof(buffer2), 0); sparsemap_clear(sm2); for (int i = 0; i < 2048 * 2; i++) { @@ -187,4 +188,4 @@ int main() { } fprintf(stderr, " ok\n"); - } +} diff --git a/examples/ex_2.c b/examples/ex_2.c new file mode 100644 index 0000000..a255261 --- /dev/null +++ b/examples/ex_2.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + +#include "../include/sparsemap.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#define __diag(...) \ + do { \ + fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +#pragma GCC diagnostic pop + +#define SEED + +int +main(void) +{ + int i = 0; + + // disable buffering + setbuf(stderr, 0); + + // start with a 1KiB buffer, 1024 bits + uint8_t *buf = calloc(1024, sizeof(uint8_t)); + + // create the sparse bitmap + sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 1024, 0); + + // Set every other bit (pathologically worst case) to see what happens + // when the map is full. + for (i = 0; i < 7744; i++) { + if (i % 2) + continue; + sparsemap_set(map, i, true); + assert(sparsemap_is_set(map, i) == true); + } + // On 1024 KiB of buffer with every other bit set the map holds 7744 bits + // and then runs out of space. This next _set() call will fail/abort. + sparsemap_set(map, ++i, true); + assert(sparsemap_is_set(map, i) == true); + return 0; +} diff --git a/examples/ex_3.c b/examples/ex_3.c new file mode 100644 index 0000000..dc73b53 --- /dev/null +++ b/examples/ex_3.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include + +#include "../include/sparsemap.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#define __diag(...) \ + do { \ + fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +#pragma GCC diagnostic pop + +#define SEED + +/* https://burtleburtle.net/bob/rand/smallprng.html */ +typedef struct rnd_ctx { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; +} rnd_ctx_t; +#define __rot(x, k) (((x) << (k)) | ((x) >> (32 - (k)))) +uint32_t +__random(rnd_ctx_t *x) +{ + uint32_t e = x->a - __rot(x->b, 27); + x->a = x->b ^ __rot(x->c, 17); + x->b = x->c + x->d; + x->c = x->d + e; + x->d = e + x->a; + return x->d; +} + +void +__random_seed(rnd_ctx_t *x, uint32_t seed) +{ + uint32_t i; + x->a = 0xf1ea5eed, x->b = x->c = x->d = seed; + for (i = 0; i < 20; ++i) { + (void)__random(x); + } +} + +void +shuffle(rnd_ctx_t *prng, int *array, size_t n) +{ + size_t i, j; + + if (n > 1) { + for (i = n - 1; i > 0; i--) { + j = (unsigned int)(__random(prng) % (i + 1)); + // XOR swap algorithm + if (i != j) { // avoid self-swap leading to zero-ing the element + array[i] = array[i] ^ array[j]; + array[j] = array[i] ^ array[j]; + array[i] = array[i] ^ array[j]; + } + } + } +} + +int +main(void) +{ + int i = 0; + rnd_ctx_t prng; + int array[1024] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, + 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, + 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, + 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, + 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, + 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, + 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, + 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, + 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, + 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, + 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, + 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, + 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, + 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, + 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, + 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, + 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, + 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, + 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, + 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, + 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, + 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, + 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, + 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, + 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, + 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, + 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, + 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, + 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, + 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, + 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, + 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, + 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, + 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, + 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, + 1020, 1021, 1022, 1023, 1024 }; + + // disable buffering + setbuf(stderr, 0); + + // seed the PRNG +#ifdef SEED + __random_seed(&prng, 8675309); +#else + __random_seed(&prng, (unsigned int)time(NULL) ^ getpid()); +#endif + + // randomize setting the bits on + shuffle(&prng, array, 1024); + + // start with a 1KiB buffer, 1024 bits + uint8_t *buf = calloc(1024, sizeof(uint8_t)); + + // create the sparse bitmap + sparsemap_t *map = sparsemap(buf, sizeof(uint8_t) * 1024, 0); + + // set all the bits on in a random order + for (i = 0; i < 1024; i++) { + __diag("set %d\n", array[i]); + sparsemap_set(map, array[i], true); + assert(sparsemap_is_set(map, array[i]) == true); + } + + sparsemap_set(map, 1025, true); + assert(sparsemap_is_set(map, 1025) == true); + + return 0; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c8aedb6 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1712192574, + "narHash": "sha256-LbbVOliJKTF4Zl2b9salumvdMXuQBr2kuKP5+ZwbYq4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f480f9d09e4b4cf87ee6151eba068197125714de", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 2d8d35f..cdd6e23 100644 --- a/flake.nix +++ b/flake.nix @@ -1,8 +1,10 @@ { description = "A Concurrent Skip List library for key/value pairs."; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; outputs = { self @@ -12,40 +14,45 @@ }: flake-utils.lib.eachDefaultSystem (system: let -# pkgs = nixpkgs.legacyPackages.${system}; pkgs = import nixpkgs { inherit system; config = { allowUnfree = true; }; }; - in - { - devShells.default = pkgs.mkShell { - packages = with pkgs; [ - autoconf - bashInteractive - clang-tools - ed - gdb - graphviz-nox - meson - python311Packages.rbtools - ]; + supportedSystems = [ "x86_64-linux" ]; + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + nixpkgsFor = forAllSystems (system: import nixpkgs { + inherit system; + overlays = [ self.overlay ]; + }); + in { + pkgs = import nixpkgs { + inherit system; + devShell = nixpkgs.legacyPackages.${system} { + pkgs.mkShell = { + nativeBuildInputs = with pkgs.buildPackages; [ + act + autoconf + clang + ed + gcc + gdb + gettext + graphviz-nox + libtool + m4 + perl + pkg-config + python3 + ripgrep + ]; + buildInputs = with pkgs; [ + libbacktrace + glibc.out + glibc.static + ]; + }; + DOCKER_BUILDKIT = 1; + }; }; - buildInputs = with pkgs; [ - glibc - ]; - nativeBuildInputs = with pkgs.buildPackages; [ - act - binutils - coreutils - gcc - gettext - libtool - m4 - make - perl - pkg-config - ripgrep - ]; }); } diff --git a/include/sparsemap.h b/include/sparsemap.h index f51d680..23d32b9 100644 --- a/include/sparsemap.h +++ b/include/sparsemap.h @@ -84,7 +84,7 @@ void sparsemap_init(sparsemap_t *map, uint8_t *data, size_t size, size_t used); void sparsemap_clear(sparsemap_t *map); /* Opens an existing sparsemap at the specified buffer. */ -sparsemap_t *sparsemap_open(uint8_t *data, size_t data_size); +void sparsemap_open(sparsemap_t *, uint8_t *data, size_t data_size); /* Resizes the data range. */ void sparsemap_set_data_size(sparsemap_t *map, size_t data_size); diff --git a/src/sparsemap.c b/src/sparsemap.c index a9abe20..8ec8eea 100644 --- a/src/sparsemap.c +++ b/src/sparsemap.c @@ -15,22 +15,20 @@ * PERFORMANCE OF THIS SOFTWARE. */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" #include -#include +#include #include -#include #include #include -#pragma GCC diagnostic pop #include #include #ifdef SPARSEMAP_DIAGNOSTIC #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" #pragma GCC diagnostic ignored "-Wvariadic-macros" +#include #define __sm_diag(format, ...) \ __sm_diag_(__FILE__, __LINE__, __func__, format, ##__VA_ARGS__) #pragma GCC diagnostic pop @@ -647,7 +645,7 @@ __sm_get_chunk_map_offset(sparsemap_t *map, size_t idx) uint8_t *p = start; for (size_t i = 0; i < count - 1; i++) { - sm_idx_t start = *(sm_idx_t *)p; //TODO wtf... + sm_idx_t start = *(sm_idx_t *)p; __sm_assert(start == __sm_get_aligned_offset(start)); __sm_chunk_t chunk; __sm_chunk_map_init(&chunk, p + sizeof(sm_idx_t)); @@ -692,7 +690,7 @@ __sm_append_data(sparsemap_t *map, uint8_t *buffer, size_t buffer_size) /** * Inserts data somewhere in the middle of m_data. */ -static void +static int __sm_insert_data(sparsemap_t *map, size_t offset, uint8_t *buffer, size_t buffer_size) { @@ -757,16 +755,12 @@ sparsemap_init(sparsemap_t *map, uint8_t *data, size_t size, size_t used) /** * Opens an existing sparsemap at the specified buffer. */ -sparsemap_t * -sparsemap_open(uint8_t *data, size_t data_size) +void +sparsemap_open(sparsemap_t *map, uint8_t *data, size_t data_size) { - sparsemap_t *map = (sparsemap_t *)calloc(1, sizeof(sparsemap_t)); - if (map) { - map->m_data = data; - map->m_data_used = 0; - map->m_data_size = data_size; - } - return map; + map->m_data = data; + map->m_data_used = 0; + map->m_data_size = data_size; } /**