import as C++
This commit is contained in:
commit
b6ccffe809
13 changed files with 4062 additions and 0 deletions
197
.clang-format
Normal file
197
.clang-format
Normal file
|
@ -0,0 +1,197 @@
|
|||
# Basic .clang-format
|
||||
---
|
||||
BasedOnStyle: WebKit
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: WebKit
|
||||
BreakBeforeTernaryOperators: false
|
||||
# TODO: BreakStringLiterals can cause very strange formatting so turn it off?
|
||||
BreakStringLiterals: false
|
||||
# Prefer:
|
||||
# some_var = function(arg1,
|
||||
# arg2)
|
||||
# over:
|
||||
# some_var =
|
||||
# function(arg1, arg2)
|
||||
PenaltyBreakAssignment: 100
|
||||
# Prefer:
|
||||
# some_long_function(arg1, arg2
|
||||
# arg3)
|
||||
# over:
|
||||
# some_long_function(
|
||||
# arg1, arg2, arg3)
|
||||
PenaltyBreakBeforeFirstCallParameter: 100
|
||||
CompactNamespaces: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ForEachMacros:
|
||||
- ARB_ARRFOREACH
|
||||
- ARB_ARRFOREACH_REVWCOND
|
||||
- ARB_ARRFOREACH_REVERSE
|
||||
- ARB_FOREACH
|
||||
- ARB_FOREACH_FROM
|
||||
- ARB_FOREACH_SAFE
|
||||
- ARB_FOREACH_REVERSE
|
||||
- ARB_FOREACH_REVERSE_FROM
|
||||
- ARB_FOREACH_REVERSE_SAFE
|
||||
- BIT_FOREACH_ISCLR
|
||||
- BIT_FOREACH_ISSET
|
||||
- CPU_FOREACH
|
||||
- CPU_FOREACH_ISCLR
|
||||
- CPU_FOREACH_ISSET
|
||||
- FOREACH_THREAD_IN_PROC
|
||||
- FOREACH_PROC_IN_SYSTEM
|
||||
- FOREACH_PRISON_CHILD
|
||||
- FOREACH_PRISON_DESCENDANT
|
||||
- FOREACH_PRISON_DESCENDANT_LOCKED
|
||||
- FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL
|
||||
- MNT_VNODE_FOREACH_ALL
|
||||
- MNT_VNODE_FOREACH_ACTIVE
|
||||
- RB_FOREACH
|
||||
- RB_FOREACH_FROM
|
||||
- RB_FOREACH_SAFE
|
||||
- RB_FOREACH_REVERSE
|
||||
- RB_FOREACH_REVERSE_FROM
|
||||
- RB_FOREACH_REVERSE_SAFE
|
||||
- SLIST_FOREACH
|
||||
- SLIST_FOREACH_FROM
|
||||
- SLIST_FOREACH_FROM_SAFE
|
||||
- SLIST_FOREACH_SAFE
|
||||
- SLIST_FOREACH_PREVPTR
|
||||
- SPLAY_FOREACH
|
||||
- LIST_FOREACH
|
||||
- LIST_FOREACH_FROM
|
||||
- LIST_FOREACH_FROM_SAFE
|
||||
- LIST_FOREACH_SAFE
|
||||
- STAILQ_FOREACH
|
||||
- STAILQ_FOREACH_FROM
|
||||
- STAILQ_FOREACH_FROM_SAFE
|
||||
- STAILQ_FOREACH_SAFE
|
||||
- TAILQ_FOREACH
|
||||
- TAILQ_FOREACH_FROM
|
||||
- TAILQ_FOREACH_FROM_SAFE
|
||||
- TAILQ_FOREACH_REVERSE
|
||||
- TAILQ_FOREACH_REVERSE_FROM
|
||||
- TAILQ_FOREACH_REVERSE_FROM_SAFE
|
||||
- TAILQ_FOREACH_REVERSE_SAFE
|
||||
- TAILQ_FOREACH_SAFE
|
||||
- VM_MAP_ENTRY_FOREACH
|
||||
- VM_PAGE_DUMP_FOREACH
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
Language: Cpp
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Right
|
||||
ContinuationIndentWidth: 4
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
ColumnLimit: 160
|
||||
UseTab: Never
|
||||
SpaceAfterCStyleCast: false
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^\"opt_.*\.h\"'
|
||||
Priority: 1
|
||||
SortPriority: 10
|
||||
- Regex: '^<sys/cdefs\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 20
|
||||
- Regex: '^<sys/types\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 21
|
||||
- Regex: '^<sys/param\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 22
|
||||
- Regex: '^<sys/systm\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 23
|
||||
- Regex: '^<sys.*/'
|
||||
Priority: 2
|
||||
SortPriority: 24
|
||||
- Regex: '^<vm/vm\.h>'
|
||||
Priority: 3
|
||||
SortPriority: 30
|
||||
- Regex: '^<vm/'
|
||||
Priority: 3
|
||||
SortPriority: 31
|
||||
- Regex: '^<machine/'
|
||||
Priority: 4
|
||||
SortPriority: 40
|
||||
- Regex: '^<(x86|amd64|i386|xen)/'
|
||||
Priority: 5
|
||||
SortPriority: 50
|
||||
- Regex: '^<dev/'
|
||||
Priority: 6
|
||||
SortPriority: 60
|
||||
- Regex: '^<net.*/'
|
||||
Priority: 7
|
||||
SortPriority: 70
|
||||
- Regex: '^<protocols/'
|
||||
Priority: 7
|
||||
SortPriority: 71
|
||||
- Regex: '^<(fs|nfs(|client|server)|ufs)/'
|
||||
Priority: 8
|
||||
SortPriority: 80
|
||||
- Regex: '^<[^/].*\.h'
|
||||
Priority: 9
|
||||
SortPriority: 90
|
||||
- Regex: '^\".*\.h\"'
|
||||
Priority: 10
|
||||
SortPriority: 100
|
||||
# LLVM's header include ordering style is almost the exact opposite of ours.
|
||||
# Unfortunately, they have hard-coded their preferences into clang-format.
|
||||
# Clobbering this regular expression to avoid matching prevents non-system
|
||||
# headers from being forcibly moved to the top of the include list.
|
||||
# http://llvm.org/docs/CodingStandards.html#include-style
|
||||
IncludeIsMainRegex: 'BLAH_DONT_MATCH_ANYTHING'
|
||||
SortIncludes: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
TypenameMacros:
|
||||
- ARB_ELMTYPE
|
||||
- ARB_HEAD
|
||||
- ARB8_HEAD
|
||||
- ARB16_HEAD
|
||||
- ARB32_HEAD
|
||||
- ARB_ENTRY
|
||||
- ARB8_ENTRY
|
||||
- ARB16_ENTRY
|
||||
- ARB32_ENTRY
|
||||
- LIST_CLASS_ENTRY
|
||||
- LIST_CLASS_HEAD
|
||||
- LIST_ENTRY
|
||||
- LIST_HEAD
|
||||
- QUEUE_TYPEOF
|
||||
- RB_ENTRY
|
||||
- RB_HEAD
|
||||
- SLIST_CLASS_HEAD
|
||||
- SLIST_CLASS_ENTRY
|
||||
- SLIST_HEAD
|
||||
- SLIST_ENTRY
|
||||
- SMR_POINTER
|
||||
- SPLAY_ENTRY
|
||||
- SPLAY_HEAD
|
||||
- STAILQ_CLASS_ENTRY
|
||||
- STAILQ_CLASS_HEAD
|
||||
- STAILQ_ENTRY
|
||||
- STAILQ_HEAD
|
||||
- TAILQ_CLASS_ENTRY
|
||||
- TAILQ_CLASS_HEAD
|
||||
- TAILQ_ENTRY
|
||||
- TAILQ_HEAD
|
25
.clang-tidy
Normal file
25
.clang-tidy
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
Checks: >
|
||||
bugprone-*,
|
||||
clang-analyzer-*,
|
||||
google-*,
|
||||
misc-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-macro-parentheses,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-not-null-terminated-result,
|
||||
-bugprone-reserved-identifier,
|
||||
-bugprone-sizeof-expression,
|
||||
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
|
||||
-clang-analyzer-security.insecureAPI.strcpy,
|
||||
-google-readability-todo,
|
||||
-misc-unused-parameters,
|
||||
-misc-no-recursion,
|
||||
-performance-no-int-to-ptr,
|
||||
-bugprone-assignment-in-if-condition,
|
||||
|
||||
...
|
5
.envrc
Normal file
5
.envrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
|
||||
fi
|
||||
watch_file devShell.nix shell.nix flake.nix
|
||||
use flake || use nix
|
120
.gitignore
vendored
Normal file
120
.gitignore
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
libsparesemap.a
|
||||
libsparesemap.so
|
||||
**/*.o
|
||||
tests/test
|
||||
examples/main
|
||||
.cache
|
||||
hints.txt
|
||||
tmp/
|
||||
git.diff
|
||||
.direnv
|
||||
.vscode/.ropeproject
|
||||
.vscode/ipch
|
||||
.codelite/
|
||||
.cmaketools.json
|
||||
*.tags
|
||||
*.dll
|
||||
build/
|
||||
cmake-build*
|
||||
.cmake_dirty
|
||||
Makefile
|
||||
Testing/
|
||||
compile_commands.json
|
||||
.tern*
|
||||
*.iml
|
||||
*.dat
|
||||
*.fsm
|
||||
*.db
|
||||
|
||||
# Created by https://www.gitignore.io/api/jetbrains
|
||||
# Edit at https://www.gitignore.io/?templates=jetbrains
|
||||
|
||||
### JetBrains ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### JetBrains Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# End of https://www.gitignore.io/api/jetbrains
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Christoph Rupp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
90
README.md
Normal file
90
README.md
Normal file
|
@ -0,0 +1,90 @@
|
|||
|
||||
`sparsemap` is a sparse, compressed bitmap. In best case, it can store 2048
|
||||
bits in just 8 bytes. In worst case, it stores the 2048 bits uncompressed and
|
||||
requires additional 8 bytes of overhead.
|
||||
|
||||
The "best" case happens when large consecutive sequences of the bits are
|
||||
either set ("1") or not set ("0"). If your numbers are consecutive 64bit
|
||||
integers then sparsemap can compress up to 16kb in just 8 bytes.
|
||||
|
||||
## How does it work?
|
||||
|
||||
On the lowest level, bits are stored in BitVectors (a uint32_t or uint64_t).
|
||||
|
||||
Each BitVector has an additional descriptor (2 bits). All descriptors are
|
||||
stored in a single Word which is prepended to the BitVectors. (The descriptor
|
||||
Word and the BitVectors have the same size.) The descriptor of a BitVector
|
||||
specifies whether the BitVector consists only of set bits ("1"), unset
|
||||
bits ("0") or has a mixed payload. In the first and second case the
|
||||
BitVector is not stored.
|
||||
|
||||
An example shows a sequence of 4 x 16 bits (here, each BitVector and the
|
||||
Descriptor word has 16 bits):
|
||||
|
||||
Descriptor:
|
||||
00 00 00 00 11 00 11 10
|
||||
^^ ^^ ^^ ^^-- BitVector #0 - #3 are "0000000000000000"
|
||||
^^-- BitVector #4 is "1111111111111111"
|
||||
^^-- BitVector #5 is "0000000000000000"
|
||||
^^-- BitVector #7 is "1111111111111111"
|
||||
^^-- BitVector #7 is "0110010101111001"
|
||||
|
||||
Since the first 7 BitVectors are either all "1" or "0" they are not stored.
|
||||
The actual memory sequence looks like this:
|
||||
|
||||
0000000011001110 0110010101111001
|
||||
|
||||
Instead of storing 8 Words (16 bytes), we only store 2 Words (2 bytes): one
|
||||
for the Descriptor, one for last BitVector #7.
|
||||
|
||||
Since such a construct (it's called a MiniMap) has a limited capacity, another
|
||||
structure is created on top of it, a `Sparsemap`. The Sparsemap stores a list
|
||||
of MiniMaps, and for each MiniMap it stores the absolute address. I.e. if
|
||||
the user sets bit 0 and bit 10000, and the MiniMap capacity is 2048, the
|
||||
Sparsemap creates two MiniMaps. The first starts at offset 0, the second starts
|
||||
at offset 8192.
|
||||
|
||||
# Usage instructions
|
||||
|
||||
The file `main.cc` has example code. Here is a small excerpt:
|
||||
|
||||
// we need a buffer to store the SparseMap
|
||||
unsigned char buffer[1024];
|
||||
|
||||
sparsemap::SparseMap<uint32_t, uint64_t> sm;
|
||||
sm.create(buffer, sizeof(buffer));
|
||||
|
||||
// after initialization, the used size is just 4 bytes (sizeof(uint32_t))
|
||||
assert(sm.get_size() == sizeof(uint32_t));
|
||||
|
||||
// set the first bit
|
||||
sm.set(0, true);
|
||||
|
||||
// check that the first bit was set
|
||||
assert(sm.is_set(0) == true);
|
||||
|
||||
// unset the first bit
|
||||
assert(sm.is_set(1) == false);
|
||||
|
||||
// check that the first bit is now no longer set
|
||||
sm.set(0, false);
|
||||
|
||||
## Final words
|
||||
|
||||
This bitmap implementation has very efficient compression when using on long
|
||||
sequences of set (or unset) bits. I.e. with a word size of 64bit, and a
|
||||
payload of consecutive numbers without gaps, the payload of 2048 x
|
||||
sizeof(uint64_t) = 16kb can be stored in just 8 bytes!
|
||||
|
||||
However, if the sequence is not consecutive and has gaps, it's possible that
|
||||
the compression is completely inefficient, and the size basically is identical
|
||||
to an uncompressed bitvector (even higher because a few bytes are required for
|
||||
metadata). In such cases, other compression schemes are more efficient (i.e.
|
||||
http://lemire.me/blog/archives/2008/08/20/the-mythical-bitmap-index/).
|
||||
|
||||
This library was originally created for hamsterdb [http://hamsterdb.com] in
|
||||
order to compress the key indices. For several technical reasons this turned
|
||||
out to be impossible, though. (If you're curious then feel free to drop
|
||||
me a mail.) I'm releasing it as open source, hoping that others can make good
|
||||
use of it.
|
||||
|
205
examples/main.c
Normal file
205
examples/main.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
#include <sparsemap.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace sparsemap;
|
||||
|
||||
//
|
||||
// this code serves as a sample but also as a unittest.
|
||||
//
|
||||
int main() {
|
||||
int size = 4;
|
||||
setbuf(stdout, 0); // disable printf() buffering
|
||||
printf("Please wait a moment.");
|
||||
#if 1
|
||||
uint8_t buffer[1024];
|
||||
uint8_t buffer2[1024];
|
||||
|
||||
SparseMap<uint32_t, uint64_t> sm;
|
||||
sm.create(buffer, sizeof(buffer));
|
||||
assert(sm.get_size() == size);
|
||||
sm.set(0, true);
|
||||
assert(sm.get_size() == size + 4 + 8 + 8);
|
||||
assert(sm.is_set(0) == true);
|
||||
assert(sm.get_size() == size + 4 + 8 + 8);
|
||||
assert(sm.is_set(1) == false);
|
||||
sm.set(0, false);
|
||||
assert(sm.get_size() == size);
|
||||
|
||||
sm.clear();
|
||||
sm.set(64, true);
|
||||
assert(sm.is_set(64) == true);
|
||||
assert(sm.get_size() == size + 4 + 8 + 8);
|
||||
|
||||
sm.clear();
|
||||
printf(".");
|
||||
|
||||
// set [0..100000]
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
assert(sm.is_set(i) == false);
|
||||
sm.set(i, true);
|
||||
if (i > 5) {
|
||||
for (int j = i - 5; j <= i; j++)
|
||||
assert(sm.is_set(j) == true);
|
||||
}
|
||||
|
||||
assert(sm.is_set(i) == true);
|
||||
}
|
||||
|
||||
printf(".");
|
||||
|
||||
for (int i = 0; i < 100000; i++)
|
||||
assert(sm.is_set(i) == true);
|
||||
|
||||
// unset [0..10000]
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
assert(sm.is_set(i) == true);
|
||||
sm.set(i, false);
|
||||
assert(sm.is_set(i) == false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10000; i++)
|
||||
assert(sm.is_set(i) == false);
|
||||
|
||||
sm.clear();
|
||||
printf(".");
|
||||
|
||||
// set [10000..0]
|
||||
for (int i = 10000; i >= 0; i--) {
|
||||
assert(sm.is_set(i) == false);
|
||||
sm.set(i, true);
|
||||
assert(sm.is_set(i) == true);
|
||||
}
|
||||
|
||||
for (int i = 10000; i >= 0; i--)
|
||||
assert(sm.is_set(i) == true);
|
||||
printf(".");
|
||||
|
||||
// open and compare
|
||||
SparseMap<uint32_t, uint64_t> sm2;
|
||||
sm2.open(buffer, sizeof(buffer));
|
||||
for (int i = 0; i < 10000; i++)
|
||||
assert(sm2.is_set(i) == sm.is_set(i));
|
||||
|
||||
// unset [10000..0]
|
||||
for (int i = 10000; i >= 0; i--) {
|
||||
assert(sm.is_set(i) == true);
|
||||
sm.set(i, false);
|
||||
assert(sm.is_set(i) == false);
|
||||
}
|
||||
|
||||
for (int i = 10000; i >= 0; i--)
|
||||
assert(sm.is_set(i) == false);
|
||||
|
||||
printf(".");
|
||||
sm.clear();
|
||||
|
||||
sm.set(0, true);
|
||||
sm.set(2048 * 2 + 1, true);
|
||||
assert(sm.is_set(0) == true);
|
||||
assert(sm.is_set(2048 * 2 + 0) == false);
|
||||
assert(sm.is_set(2048 * 2 + 1) == true);
|
||||
assert(sm.is_set(2048 * 2 + 2) == false);
|
||||
sm.set(2048, true);
|
||||
assert(sm.is_set(0) == true);
|
||||
assert(sm.is_set(2047) == false);
|
||||
assert(sm.is_set(2048) == true);
|
||||
assert(sm.is_set(2049) == false);
|
||||
assert(sm.is_set(2048 * 2 + 2) == false);
|
||||
assert(sm.is_set(2048 * 2 + 0) == false);
|
||||
assert(sm.is_set(2048 * 2 + 1) == true);
|
||||
assert(sm.is_set(2048 * 2 + 2) == false);
|
||||
|
||||
sm.clear();
|
||||
printf(".");
|
||||
|
||||
for (int i = 0; i < 100000; i++)
|
||||
sm.set(i, true);
|
||||
for (int i = 0; i < 100000; i++)
|
||||
assert(sm.select(i) == (unsigned)i);
|
||||
|
||||
sm.clear();
|
||||
printf(".");
|
||||
|
||||
for (int i = 1; i < 513; i++)
|
||||
sm.set(i, true);
|
||||
for (int i = 1; i < 513; i++)
|
||||
assert(sm.select(i - 1) == (unsigned)i);
|
||||
|
||||
sm.clear();
|
||||
printf(".");
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
sm.set(i * 10, true);
|
||||
for (int i = 0; i < 8; i++)
|
||||
assert(sm.select(i) == (unsigned)i * 10);
|
||||
|
||||
// split and move, aligned to MiniMap capacity
|
||||
sm2.create(buffer2, sizeof(buffer2));
|
||||
sm.clear();
|
||||
for (int i = 0; i < 2048 * 2; i++)
|
||||
sm.set(i, true);
|
||||
sm.split(2048, &sm2);
|
||||
for (int i = 0; i < 2048; i++) {
|
||||
assert(sm.is_set(i) == true);
|
||||
assert(sm2.is_set(i) == false);
|
||||
}
|
||||
for (int i = 2048; i < 2048 * 2; i++) {
|
||||
assert(sm.is_set(i) == false);
|
||||
assert(sm2.is_set(i) == true);
|
||||
}
|
||||
printf(".");
|
||||
|
||||
// split and move, aligned to BitVector capacity
|
||||
sm2.create(buffer2, sizeof(buffer2));
|
||||
sm.clear();
|
||||
for (int i = 0; i < 2048 * 3; i++)
|
||||
sm.set(i, true);
|
||||
sm.split(64, &sm2);
|
||||
for (int i = 0; i < 64; i++) {
|
||||
assert(sm.is_set(i) == true);
|
||||
assert(sm2.is_set(i) == false);
|
||||
}
|
||||
for (int i = 64; i < 2048 * 3; i++) {
|
||||
assert(sm.is_set(i) == false);
|
||||
assert(sm2.is_set(i) == true);
|
||||
}
|
||||
|
||||
printf("ok\n");
|
||||
#else
|
||||
//
|
||||
// This code was used to create the lookup table for
|
||||
// sparsemap::MiniMap<>::calc_vector_size()
|
||||
//
|
||||
printf(" ");
|
||||
for (unsigned int ch = 0; ch <= 0xff; ch++) {
|
||||
if (ch > 0 && ch % 16 == 0)
|
||||
printf("\n ");
|
||||
|
||||
/*
|
||||
// check if value is invalid (contains 2#01)
|
||||
if ((ch & (0x3 << 0)) >> 0 == 1
|
||||
|| (ch & (0x3 << 2)) >> 2 == 1
|
||||
|| (ch & (0x3 << 4)) >> 4 == 1
|
||||
|| (ch & (0x3 << 6)) >> 6 == 1) {
|
||||
//printf("%d: -1\n", (int)ch);
|
||||
printf(" -1,");
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
// count all occurrences of 2#10
|
||||
int size = 0;
|
||||
if ((ch & (0x3 << 0)) >> 0 == 2)
|
||||
size++;
|
||||
if ((ch & (0x3 << 2)) >> 2 == 2)
|
||||
size++;
|
||||
if ((ch & (0x3 << 4)) >> 4 == 2)
|
||||
size++;
|
||||
if ((ch & (0x3 << 6)) >> 6 == 2)
|
||||
size++;
|
||||
//printf("%u: %d\n", (unsigned int)ch, size);
|
||||
printf(" %d,", size);
|
||||
}
|
||||
#endif
|
||||
}
|
51
flake.nix
Normal file
51
flake.nix
Normal file
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
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";
|
||||
|
||||
outputs =
|
||||
{ self
|
||||
, nixpkgs
|
||||
, flake-utils
|
||||
, ...
|
||||
}:
|
||||
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
|
||||
];
|
||||
};
|
||||
buildInputs = with pkgs; [
|
||||
glibc
|
||||
];
|
||||
nativeBuildInputs = with pkgs.buildPackages; [
|
||||
act
|
||||
binutils
|
||||
coreutils
|
||||
gcc
|
||||
gettext
|
||||
libtool
|
||||
m4
|
||||
make
|
||||
perl
|
||||
pkg-config
|
||||
ripgrep
|
||||
];
|
||||
});
|
||||
}
|
72
include/popcount.h
Normal file
72
include/popcount.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
*
|
||||
* from https://github.com/efficient/rankselect/popcount.h
|
||||
*
|
||||
* licensed under Apache 2
|
||||
*/
|
||||
|
||||
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
#ifndef _FASTRANK_POPCOUNT_H_
|
||||
#define _FASTRANK_POPCOUNT_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define L8 0x0101010101010101ULL // Every lowest 8th bit set: 00000001...
|
||||
#define G2 0xAAAAAAAAAAAAAAAAULL // Every highest 2nd bit: 101010...
|
||||
#define G4 0x3333333333333333ULL // 00110011 ... used to group the sum of 4 bits.
|
||||
#define G8 0x0F0F0F0F0F0F0F0FULL
|
||||
#define H8 0x8080808080808080ULL
|
||||
#define L9 0x0040201008040201ULL
|
||||
#define H9 (L9 << 8)
|
||||
#define L16 0x0001000100010001ULL
|
||||
#define H16 0x8000800080008000ULL
|
||||
|
||||
#define ONES_STEP_4 ( 0x1111111111111111ULL )
|
||||
#define ONES_STEP_8 ( 0x0101010101010101ULL )
|
||||
#define ONES_STEP_9 ( 1ULL << 0 | 1ULL << 9 | 1ULL << 18 | 1ULL << 27 | 1ULL << 36 | 1ULL << 45 | 1ULL << 54 )
|
||||
#define ONES_STEP_16 ( 1ULL << 0 | 1ULL << 16 | 1ULL << 32 | 1ULL << 48 )
|
||||
#define MSBS_STEP_4 ( 0x8ULL * ONES_STEP_4 )
|
||||
#define MSBS_STEP_8 ( 0x80ULL * ONES_STEP_8 )
|
||||
#define MSBS_STEP_9 ( 0x100ULL * ONES_STEP_9 )
|
||||
#define MSBS_STEP_16 ( 0x8000ULL * ONES_STEP_16 )
|
||||
#define INCR_STEP_8 ( 0x80ULL << 56 | 0x40ULL << 48 | 0x20ULL << 40 | 0x10ULL << 32 | 0x8ULL << 24 | 0x4ULL << 16 | 0x2ULL << 8 | 0x1 )
|
||||
|
||||
#define ONES_STEP_32 ( 0x0000000100000001ULL )
|
||||
#define MSBS_STEP_32 ( 0x8000000080000000ULL )
|
||||
|
||||
#define COMPARE_STEP_8(x,y) ( ( ( ( ( (x) | MSBS_STEP_8 ) - ( (y) & ~MSBS_STEP_8 ) ) ^ (x) ^ ~(y) ) & MSBS_STEP_8 ) >> 7 )
|
||||
#define LEQ_STEP_8(x,y) ( ( ( ( ( (y) | MSBS_STEP_8 ) - ( (x) & ~MSBS_STEP_8 ) ) ^ (x) ^ (y) ) & MSBS_STEP_8 ) >> 7 )
|
||||
|
||||
#define UCOMPARE_STEP_9(x,y) ( ( ( ( ( ( (x) | MSBS_STEP_9 ) - ( (y) & ~MSBS_STEP_9 ) ) | ( x ^ y ) ) ^ ( x | ~y ) ) & MSBS_STEP_9 ) >> 8 )
|
||||
#define UCOMPARE_STEP_16(x,y) ( ( ( ( ( ( (x) | MSBS_STEP_16 ) - ( (y) & ~MSBS_STEP_16 ) ) | ( x ^ y ) ) ^ ( x | ~y ) ) & MSBS_STEP_16 ) >> 15 )
|
||||
#define ULEQ_STEP_9(x,y) ( ( ( ( ( ( (y) | MSBS_STEP_9 ) - ( (x) & ~MSBS_STEP_9 ) ) | ( x ^ y ) ) ^ ( x & ~y ) ) & MSBS_STEP_9 ) >> 8 )
|
||||
#define ULEQ_STEP_16(x,y) ( ( ( ( ( ( (y) | MSBS_STEP_16 ) - ( (x) & ~MSBS_STEP_16 ) ) | ( x ^ y ) ) ^ ( x & ~y ) ) & MSBS_STEP_16 ) >> 15 )
|
||||
#define ZCOMPARE_STEP_8(x) ( ( ( x | ( ( x | MSBS_STEP_8 ) - ONES_STEP_8 ) ) & MSBS_STEP_8 ) >> 7 )
|
||||
|
||||
// Population count of a 64 bit integer in SWAR (SIMD within a register) style
|
||||
// From Sebastiano Vigna, "Broadword Implementation of Rank/Select Queries"
|
||||
// http://sux.dsi.unimi.it/paper.pdf p4
|
||||
// This variant uses multiplication for the last summation instead of
|
||||
// continuing the shift/mask/addition chain.
|
||||
inline int suxpopcount(uint64_t x) {
|
||||
// Step 1: 00 - 00 = 0; 01 - 00 = 01; 10 - 01 = 01; 11 - 01 = 10;
|
||||
x = x - ((x & G2) >> 1);
|
||||
// step 2: add 2 groups of 2.
|
||||
x = (x & G4) + ((x >> 2) & G4);
|
||||
// 2 groups of 4.
|
||||
x = (x + (x >> 4)) & G8;
|
||||
// Using a multiply to collect the 8 groups of 8 together.
|
||||
x = x * L8 >> 56;
|
||||
return x;
|
||||
}
|
||||
|
||||
// Default to using the GCC builtin popcount. On architectures
|
||||
// with -march popcnt, this compiles to a single popcnt instruction.
|
||||
#ifndef popcount
|
||||
# define popcount __builtin_popcountll
|
||||
#else
|
||||
# define popcount suxpopcount
|
||||
#endif
|
||||
|
||||
#endif /* _FASTRANK_POPCOUNT_H_ */
|
0
include/sparsemap.h
Normal file
0
include/sparsemap.h
Normal file
BIN
main
Executable file
BIN
main
Executable file
Binary file not shown.
1021
src/sparsemap.c
Normal file
1021
src/sparsemap.c
Normal file
File diff suppressed because it is too large
Load diff
2255
tests/munit.c
Normal file
2255
tests/munit.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue