├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile.am ├── Makefile.posix ├── README.md ├── azure-pipelines.yml ├── bootstrap.sh ├── configure.ac ├── doc ├── benchmarks.md ├── deps.md └── references.md ├── make_test.sh ├── src ├── Makefile.am ├── libsrt.h ├── saux │ ├── schar.c │ ├── schar.h │ ├── scommon.c │ ├── scommon.h │ ├── sconfig.h │ ├── scopyright.h │ ├── scrc32.h │ ├── sdata.c │ ├── sdata.h │ ├── sdbg.c │ ├── sdbg.h │ ├── senc.c │ ├── senc.h │ ├── shash.c │ ├── shash.h │ ├── ssearch.c │ ├── ssearch.h │ ├── ssort.c │ ├── ssort.h │ ├── sstringo.c │ ├── sstringo.h │ ├── stree.c │ └── stree.h ├── sbitset.c ├── sbitset.h ├── shmap.c ├── shmap.h ├── shset.c ├── shset.h ├── smap.c ├── smap.h ├── smset.c ├── smset.h ├── sstring.c ├── sstring.h ├── svector.c └── svector.h ├── test ├── Makefile.am ├── bench.cc ├── counter.c ├── counter.h ├── counterpp.cc ├── enc.c ├── histogram.c ├── histogram.h ├── histogrampp.cc ├── ifilters.h ├── imgc.c ├── imgd.c ├── imgtools.c ├── imgtools.h ├── rgbi.h ├── stest.c ├── table.c └── utf8_examples.h ├── utl ├── .clang-format ├── c2doc.py ├── check_style.sh ├── format.sh ├── m4 │ └── mode.m4 └── mk_doc.sh └── win └── vs2013 ├── stest.sln └── stest.vcxproj /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | # Precompiled Headers 7 | *.gch 8 | *.pch 9 | # Dynamic libraries 10 | *.so 11 | *.dylib 12 | *.dll 13 | # Static libraries 14 | *.lai 15 | *.la 16 | *.a 17 | *.lib 18 | # Executables 19 | *.exe 20 | bench 21 | counter 22 | enc 23 | histogram 24 | imgc 25 | imgd 26 | stest 27 | table 28 | counterpp 29 | histogrampp 30 | # Profiling 31 | *.gcda 32 | *.gcno 33 | gmon.out 34 | # Other 35 | *.suo 36 | *.swp 37 | win/vs2013/Debug/ 38 | win/vs2013/Release/ 39 | win/vs2013/stest_Debug/ 40 | win/vs2013/stest_Release/ 41 | win/vs2013/x64/ 42 | private/ 43 | doc/out/ 44 | # Auto-tools 45 | Makefile.in 46 | Makefile 47 | .deps 48 | .libs 49 | autom4te.cache 50 | config.* 51 | configure 52 | install-sh 53 | ltmain.sh 54 | missing 55 | depcomp 56 | libtool 57 | compile 58 | aclocal.m4 59 | utl/tmp 60 | .dirstamp 61 | *.log 62 | *.trs 63 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: gcc 3 | script: ./make_test.sh 4 | before_install: 5 | - sudo apt-get update -qq 6 | - sudo apt-get install -qq gcc-arm-linux-gnueabi 7 | - sudo apt-get install -qq g++-arm-linux-gnueabi 8 | - sudo apt-get install -qq clang 9 | - sudo apt-get install -qq tcc 10 | - sudo apt-get install -qq gcc-multilib 11 | - sudo apt-get install -qq g++-multilib 12 | - sudo apt-get install -qq valgrind 13 | - sudo apt-get install -qq python3 14 | - sudo apt-get install -qq realpath 15 | 16 | env: 17 | - SLIBSRT_ENV=not_used 18 | 19 | matrix: 20 | fast_finish: true 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2019, F. Aragon 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile.am 3 | # 4 | # libsrt root folder Automake template 5 | # 6 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | # 9 | 10 | MAINTAINERCLEANFILES = aclocal.m4 configure Makefile.in 11 | 12 | SUBDIRS = src test 13 | 14 | maintainer-clean-local: 15 | rm -rf $(top_srcdir)/utl/tmp 16 | -------------------------------------------------------------------------------- /Makefile.posix: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for libsrt (POSIX systems: Linux, BSDs/Unix/Unix-like, etc.) 3 | # 4 | # Examples: 5 | # Build with defaults: make 6 | # " gcc and profiling: make -f Makefile.posix CC=gcc PROFILING=1 7 | # " gcc using C89/90 standard: make -f Makefile.posix CC=gcc C99=0 8 | # " g++ default C++ settings: make -f Makefile.posix CC=g++ 9 | # " clang++ using C++11 standard: make -f Makefile.posix CC=clang++ CPP11=1 10 | # " TinyCC with debug symbols: make -f Makefile.posix CC=tcc DEBUG=1 11 | # " gcc cross compiler (PPC): make -f Makefile.posix CC=powerpc-linux-gnu-gcc 12 | # " gcc cross compiler (ARM): make -f Makefile.posix CC=arm-linux-gnueabi-gcc 13 | # Build without CRC32 hash tables, 1 bit/loop (100MB/s on i5@3GHz): 14 | # make -f Makefile.posix ADD_CFLAGS="-DS_CRC32_SLC=0" 15 | # or make -f Makefile.posix MINIMAL=1 16 | # Build with CRC32 1024 byte hash table, 1 byte/loop (400MB/s on i5@3GHz): 17 | # make -f Makefile.posix ADD_CFLAGS="-DS_CRC32_SLC=1" 18 | # Build with CRC32 4096 byte hash table, 4 bytes/loop (1000MB/s on i5@3GHz): 19 | # make -f Makefile.posix ADD_CFLAGS="-DS_CRC32_SLC=4" 20 | # Build with CRC32 8192 byte hash table, 8 bytes/loop (2000MB/s on i5@3GHz): 21 | # make -f Makefile.posix ADD_CFLAGS="-DS_CRC32_SLC=8" 22 | # Build with CRC32 12288 byte hash table, 12 bytes/loop (2500MB/s on i5@3GHz): 23 | # make -f Makefile.posix ADD_CFLAGS="-DS_CRC32_SLC=12" 24 | # or make -f Makefile.posix # this is the default 25 | # Build with CRC32 16384 byte hash table, 16 bytes/loop (2700MB/s on i5@3GHz): 26 | # make -f Makefile.posix ADD_CFLAGS="-DS_CRC32_SLC=16" 27 | # Build without VARGS support (default VARGS=1): 28 | # make -f Makefile.posix VARGS=0 29 | # 30 | # Observations: 31 | # - On FreeBSD use gmake instead of make (as in that system "make" is "pmake", 32 | # and not GNU make). If not installed, use: pkg install gmake 33 | # 34 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 35 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 36 | # 37 | 38 | # Makefile parameters and context detection handling 39 | 40 | ifndef C99 41 | C99 = 0 42 | endif 43 | ifdef C89 44 | C90 = $(C89) 45 | endif 46 | ifndef VARGS 47 | VARGS=1 48 | endif 49 | ifndef C11 50 | C11 = 0 51 | endif 52 | ifndef CPP11 53 | CPP11 = 0 54 | endif 55 | ifndef CPP0X 56 | CPP0X = 0 57 | endif 58 | ifndef PROFILING 59 | PROFILING = 0 60 | endif 61 | ifndef DEBUG 62 | DEBUG = 0 63 | endif 64 | ifndef PEDANTIC 65 | PEDANTIC = 0 66 | endif 67 | ifndef MINIMAL 68 | MINIMAL = 0 69 | endif 70 | ifdef MINIMAL_BUILD 71 | MINIMAL = $(MINIMAL_BUILD) 72 | endif 73 | ifndef FORCE32 74 | FORCE32 = 0 75 | endif 76 | ifndef HAS_PNG 77 | HAS_PNG = 0 78 | endif 79 | ifndef HAS_JPG 80 | HAS_JPG = 0 81 | endif 82 | ifdef HAS_JPEG 83 | HAS_JPG = $(HAS_JPEG) 84 | endif 85 | 86 | # Configure compiler context 87 | 88 | ifndef UNAME 89 | UNAME = $(shell uname) 90 | endif 91 | ifndef UNAME_M 92 | UNAME_M = $(shell uname -m) 93 | endif 94 | ifndef UNAME_P 95 | UNAME_P = $(shell uname -p) 96 | endif 97 | ifndef OCTEON 98 | OCTEON = 0 99 | ifeq ($(UNAME_M), mips64) 100 | ifeq ($(UNAME), Linux) 101 | OCTEON = $(shell cat /proc/cpuinfo | grep cpu.model | \ 102 | grep Octeon | head -1 | wc -l) 103 | endif 104 | endif 105 | endif 106 | 107 | CFLAGS = 108 | CXXFLAGS = 109 | LDLIBS = 110 | LDFLAGS = 111 | COMMON_FLAGS = -pipe 112 | CPP_MODE = 0 113 | GNUC = 0 114 | CLANG = 0 115 | EN_BENCH = 1 116 | USE_LRT = 1 117 | 118 | ifeq ($(CC), gcc) 119 | GNUC = 1 120 | endif 121 | 122 | GCCLOC = $(shell cc -dM -E - < /dev/null | grep __GNUC__ | head -1 | wc -l) 123 | ifeq ($(shell expr $(GCCLOC) == 1), 1) 124 | GNUC = 1 125 | endif 126 | 127 | ifeq ($(GNUC), 1) 128 | GCC_MAJOR = $(shell gcc -dM -E - < /dev/null | grep __GNUC__ | \ 129 | awk '{print $$3}') 130 | GCC_MINOR = $(shell gcc -dM -E - < /dev/null | grep __GNUC_MINOR__ | \ 131 | awk '{print $$3}') 132 | GCCV = $(shell printf "%i%02i" $(GCC_MAJOR) $(GCC_MINOR)) 133 | ifeq ($(shell expr $(GCCV) \< 208), 1) 134 | OLD_GCC = 1 135 | EN_BENCH = 0 136 | USE_LRT = 0 137 | endif 138 | else 139 | USE_LRT = 0 140 | # Add CPP targets only if not using TCC 141 | ifeq (,$(findstring tcc,$(CC))) 142 | # Add librt for all but for mingw and Darwin cases 143 | ifeq (,$(findstring mingw,$(CC))) 144 | ifeq (,$(findstring Darwin,$(UNAME))) 145 | USE_LRT = 1 146 | endif 147 | endif 148 | else 149 | EN_BENCH = 0 150 | endif 151 | 152 | endif 153 | 154 | ifeq ($(CC), g++) 155 | GNUC = 1 156 | CPP_MODE = 1 157 | endif 158 | ifeq ($(CC), clang) 159 | CLANG = 1 160 | CL_MAJOR = $(shell clang -dM -E - < /dev/null | grep __clang_major__ | \ 161 | awk '{print $$3}') 162 | CL_MINOR = $(shell clang -dM -E - < /dev/null | grep __clang_minor__ | \ 163 | awk '{print $$3}') 164 | CLV = $(shell printf "%i%02i" $(CL_MAJOR) $(CL_MINOR)) 165 | endif 166 | ifeq ($(CC), clang++) 167 | CLANG = 1 168 | CPP_MODE = 1 169 | endif 170 | 171 | ifeq ($(CC), tcc) 172 | PROFILING = 0 173 | else 174 | ifeq ($(CPP_MODE), 1) 175 | ifeq ($(CPP11), 1) 176 | CFLAGS += -std=c++11 177 | endif 178 | ifeq ($(CPP0X), 1) 179 | CFLAGS += -std=c++0x 180 | endif 181 | else 182 | ifeq ($(C11), 1) 183 | CFLAGS += -std=c1x 184 | else 185 | ifeq ($(C99), 1) 186 | CFLAGS += -std=c99 187 | else 188 | ifeq ($(C90), 1) 189 | CFLAGS += -std=c89 -DS_C90 190 | endif 191 | endif 192 | endif 193 | endif 194 | 195 | ifeq ($(CPP11), 1) 196 | CXXFLAGS += -std=c++11 197 | endif 198 | ifeq ($(CPP0X), 1) 199 | CXXFLAGS += -std=c++0x 200 | endif 201 | 202 | ifeq ($(PEDANTIC), 1) 203 | ifeq ($(GNUC), 1) 204 | CFLAGS += -Wall -Wextra # -Werror 205 | endif 206 | ifeq ($(CLANG), 1) 207 | CFLAGS += -Weverything -Wno-old-style-cast \ 208 | -Wno-format-nonliteral 209 | endif 210 | COMMON_FLAGS += -pedantic 211 | endif 212 | ifeq ($(GNUC), 1) 213 | ifneq ($(OLD_GCC), 1) 214 | COMMON_FLAGS += -Wstrict-aliasing 215 | endif 216 | endif 217 | endif 218 | 219 | ifeq ($(VARGS), 0) 220 | CFLAGS += -DS_NO_VARGS 221 | endif 222 | 223 | ifeq ($(DEBUG), 1) 224 | COMMON_FLAGS += -O0 -ggdb -DS_DEBUG 225 | ifeq ($(MINIMAL), 1) 226 | COMMON_FLAGS += -DS_MINIMAL 227 | endif 228 | 229 | ifeq ($(CLANG), 1) 230 | ifeq ($(shell expr $(CLV) \> 599), 1) 231 | # Clang 6.0 or later 232 | COMMON_FLAGS += -fsanitize=bounds 233 | endif 234 | else 235 | ifeq ($(GNUC), 1) 236 | ifeq ($(shell expr $(GCCV) \> 408), 1) 237 | # gcc >= 4.9 238 | COMMON_FLAGS += -fstack-protector-strong 239 | else 240 | ifeq ($(shell expr $(GCCV) \> 400), 1) 241 | # gcc >= 4.1 242 | COMMON_FLAGS += -fstack-protector-all 243 | endif 244 | endif 245 | endif 246 | endif 247 | else 248 | ifeq ($(MINIMAL), 1) 249 | COMMON_FLAGS += -Os -DS_MINIMAL 250 | else 251 | COMMON_FLAGS += -O3 252 | endif 253 | COMMON_FLAGS += -DNDEBUG 254 | endif 255 | 256 | ifeq ($(PROFILING), 1) 257 | COMMON_FLAGS += -ggdb 258 | # gcov flags: 259 | COMMON_FLAGS += -fprofile-arcs -ftest-coverage 260 | LDFLAGS += -lgcov -coverage 261 | # gprof flags: 262 | COMMON_FLAGS += -pg 263 | else 264 | ifeq ($(DEBUG), 1) 265 | COMMON_FLAGS += -fno-omit-frame-pointer 266 | else 267 | COMMON_FLAGS += -fomit-frame-pointer 268 | endif 269 | endif 270 | 271 | ifeq ($(FORCE32), 1) 272 | ifeq ($(UNAME_M), x86_64) 273 | COMMON_FLAGS += -m32 274 | endif 275 | ifeq ($(UNAME_M), ppc64) 276 | COMMON_FLAGS += -m32 277 | endif 278 | ifeq ($(UNAME_M), mips64) 279 | ifeq ($(OCTEON), 1) 280 | GCC_COMMON_FLAGS += -march=octeon 281 | else 282 | GCC_COMMON_FLAGS += -mips32 283 | endif 284 | endif 285 | else 286 | ifeq ($(UNAME_M), mips64) 287 | GCC_COMMON_FLAGS += -mabi=64 288 | ifeq ($(OCTEON), 1) 289 | GCC_COMMON_FLAGS += -march=octeon 290 | else 291 | GCC_COMMON_FLAGS += -mips64 292 | endif 293 | endif 294 | ifeq ($(UNAME_M), ppc64) 295 | COMMON_FLAGS += -m64 296 | endif 297 | endif 298 | 299 | # ARM v6 little endian (e.g. ARM11 on Raspberr Pi I): the flag will enable 300 | # HW unaligned access 301 | ifeq ($(UNAME_M), armv6l) 302 | COMMON_FLAGS += -march=armv6 303 | endif 304 | 305 | # ARM v7-a little endian (e.g. ARM Cortex A5/7/8/9/15/17, QC Scorpion/Krait) 306 | # (ARM v7-m and v7-r will be built as ARM v5) 307 | ifeq ($(UNAME_M), armv7l) 308 | COMMON_FLAGS += -march=armv7-a 309 | endif 310 | 311 | # ARM v8 312 | ifeq ($(UNAME_M), armv8l) 313 | COMMON_FLAGS += -march=armv8-a 314 | endif 315 | 316 | ifneq ($(HAS_PNG), 0) 317 | COMMON_FLAGS += -DHAS_PNG=$(HAS_PNG) 318 | LDLIBS += -lz 319 | ifeq ($(HAS_PNG), 16) 320 | LDLIBS += -lpng16 321 | else 322 | ifeq ($(HAS_PNG), 15) 323 | LDLIBS += -lpng15 324 | else 325 | LDLIBS += -lpng 326 | endif 327 | endif 328 | endif 329 | 330 | ifeq ($(HAS_JPG), 1) 331 | COMMON_FLAGS += -DHAS_JPG 332 | LDLIBS += -ljpeg 333 | endif 334 | 335 | ifeq ($(GNUC), 1) 336 | COMMON_FLAGS += $(GCC_COMMON_FLAGS) 337 | endif 338 | 339 | CFLAGS += $(COMMON_FLAGS) -Isrc 340 | CXXFLAGS += $(COMMON_FLAGS) -Isrc 341 | LDFLAGS += $(COMMON_FLAGS) 342 | 343 | ifdef ADD_CFLAGS 344 | CFLAGS += $(ADD_CFLAGS) 345 | endif 346 | 347 | ifdef ADD_CXXFLAGS 348 | CXXFLAGS += $(ADD_CXXFLAGS) 349 | endif 350 | 351 | ifdef ADD_FLAGS 352 | CFLAGS += $(ADD_FLAGS) 353 | CXXFLAGS += $(ADD_FLAGS) 354 | endif 355 | 356 | ifdef ADD_FLAGS2 357 | CFLAGS += $(ADD_FLAGS2) 358 | CXXFLAGS += $(ADD_FLAGS2) 359 | endif 360 | 361 | # Build rules 362 | 363 | VPATH = src:src/saux:test 364 | SOURCES = sdata.c sdbg.c senc.c sstring.c sstringo.c schar.c ssearch.c ssort.c \ 365 | svector.c stree.c smap.c smset.c shmap.c shset.c shash.c scommon.c \ 366 | sbitset.c 367 | ESOURCES= imgtools.c 368 | HEADERS = scommon.h $(SOURCES:.c=.h) test/*.h 369 | OBJECTS = $(SOURCES:.c=.o) 370 | EOBJECTS= $(ESOURCES:.c=.o) 371 | LIBSRT = libsrt.a 372 | ELIBSRT = elibsrt.a 373 | TEST = stest 374 | EXAMPLES = counter enc histogram imgc imgd table 375 | ifeq ($(UNAME_M), mips) 376 | # Disable CPP targets on MIPS with unknown processor (e.g. PS2) 377 | ifeq ($(UNAME_P), unknown) 378 | EN_BENCH = 0 379 | endif 380 | endif 381 | ifeq ($(EN_BENCH), 1) 382 | EXAMPLES += bench counterpp histogrampp 383 | endif 384 | 385 | ifeq ($(USE_LRT), 1) 386 | LDLIBS += -lrt 387 | endif 388 | 389 | EXES = $(TEST) $(EXAMPLES) 390 | 391 | # Rules for building: library, test 392 | 393 | all: $(EXES) run_tests 394 | $(OBJECTS): $(HEADERS) 395 | $(LIBSRT): $(OBJECTS) 396 | ar rcs $@ $^ 397 | $(ELIBSRT): $(EOBJECTS) 398 | ar rcs $@ $^ 399 | $(EXES): $% $(ELIBSRT) $(LIBSRT) 400 | 401 | run_tests: stest 402 | @./$(TEST) 403 | clean: 404 | @rm -f $(OBJECTS) $(LIBSRT) $(ELIBSRT) *\.o *\.dSYM *\.gcno *\.gcda \ 405 | *\.gcov *\.out callgrind* out\.txt clang_analysis.txt \ 406 | *\.errors* 407 | @for X in $(EXES) ; do rm -f $$X $$X.o ; done 408 | .PHONY: clean all run_tests 409 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - master 3 | 4 | pool: 5 | vmImage: 'Ubuntu-16.04' 6 | 7 | steps: 8 | - script: | 9 | ./bootstrap.sh && ./configure && \ 10 | make -j $(grep processor /proc/cpuinfo | wc -l) && \ 11 | make check && make clean 12 | displayName: 'make' 13 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # bootstrap.sh 4 | # 5 | # libsrt 'configure' bootstrap 6 | # 7 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 8 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 9 | # 10 | ARC="autoreconf -f -i" 11 | if ! $ARC >/dev/null 2>&1 ; then 12 | echo "Bootstrap error: $ARC failed (code: $?)" >&2 13 | fi 14 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # 2 | # configure.ac 3 | # 4 | # libsrt Autoconf template 5 | # 6 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | # 9 | 10 | AC_INIT([libsrt], [0.1-master], [https://github.com/faragon/libsrt/issues]) 11 | 12 | PACKAGE_URL="https://github.com/faragon/libsrt" 13 | AC_SUBST([PACKAGE_URL]) 14 | PACKAGE_FULLNAME="libsrt" 15 | AC_SUBST([PACKAGE_FULLNAME]) 16 | 17 | AC_CONFIG_AUX_DIR([utl/tmp/config-aux]) 18 | AC_CONFIG_MACRO_DIR([utl/tmp/config-m4]) 19 | 20 | CONFIG_ARGS="`echo $ac_configure_args | sed -e \"s% '[[A-Z]]*FLAGS=[[^']]\+'%%g\"`" 21 | AC_SUBST([CONFIG_ARGS]) 22 | 23 | AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) 24 | 25 | CFLAGS="${CFLAGS:-}" 26 | CXXFLAGS="${CXXFLAGS:-}" 27 | ori_cf="$CFLAGS" 28 | ori_cxxf="$CXXFLAGS" 29 | AC_LANG([C]) 30 | AC_PROG_INSTALL 31 | AC_PROG_CC 32 | AC_PROG_CXX 33 | AC_PROG_LD 34 | AM_PROG_CC_C_O 35 | CFLAGS="$ori_cf" 36 | CXXFLAGS="$ori_cxxf" 37 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 38 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 39 | 40 | PKG_PROG_PKG_CONFIG 41 | 42 | AUTOCONF_ENV="SHELL=/bin/sh" 43 | 44 | LT_INIT 45 | AC_ENABLE_STATIC 46 | 47 | m4_include([utl/m4/mode.m4]) 48 | 49 | AC_CONFIG_FILES([ 50 | Makefile 51 | src/Makefile 52 | test/Makefile 53 | ]) 54 | 55 | AC_OUTPUT 56 | 57 | -------------------------------------------------------------------------------- /doc/benchmarks.md: -------------------------------------------------------------------------------- 1 | Benchmarks overview 2 | === 3 | 4 | * 'bench' executable is built using 'make' 5 | * Benchmark time precision limited to clock\_gettime() resolution on Linux 6 | * Some functions are not yet optimized (e.g. vector) 7 | 8 | Notes on libsrt space and time complexity 9 | === 10 | 11 | * libsrt strings (srt\_string) 12 | * Overhead for strings below 256 bytes: 5 bytes (including space for terminator for ensuring ss\_c() -equivalent to .c\_str() in C++- will work properly always) 13 | * Overhead for strings >= 256 bytes: 1 + 5 * sizeof(size\_t) bytes, i.e. 21 bytes in 32-bit mode, and 41 bytes for 64-bit (including 1 byte reserved for optional terminator) 14 | * Time complexity for concatenation: O(n) -fast, allowing multiple concatenation with just one logical resize- 15 | * Time complexity for string search: O(n) -fast, using Rabin-Karp algorithm with dynamic hash function change- 16 | * libsrt vectors (srt\_vector) 17 | * Overhead: 5 * sizeof(size\_t) bytes 18 | * Time complexity for sort: O(n) for 8-bit (counting sort), O(n log n) for 16/32/64 bit elements (MSD binary radix sort), and same as provided C library qsort() function for generic elements 19 | * libsrt maps (srt\_map) 20 | * Overhead (global): 6 * sizeof(size\_t) bytes 21 | * Overhead (per map element): 8 bytes (31 bits x 2 for tree left/right, 1 bit for red/black, 1 bit unused) 22 | * Special overhead: for the case of string maps, strings up to 19 bytes in length are stored in the node (up to 54 shared between the key-value in the case of string-string map), without requiring extra heap allocation. Because of that, when strings with length >= 20, 2 * 20 bytes (32-bit mode) or 2 * 16 bytes (64-bit mode) is wasted per node. The overhead is small, as in every case the memory usage of libsrt strings is under C++ std::map memory usage (in the case of strings below 20 bytes, the difference is abysmal). 23 | * Time complexity for insert, search, delete: O(log n) 24 | * Time for cleanup ("free"/"delete"): O(1) for sets not having string elements, O(n) when having string elements 25 | * libsrt sets (srt\_set) 26 | * Similar to the map case, but with smaller nodes (key-only) 27 | * Time complexity for insert, search, delete: O(log n) 28 | * Time for cleanup ("free"/"delete"): O(1) for maps not having string elements, O(n) when having string elements 29 | * libsrt bitsets (srt\_bitset) 30 | * Overhead: 5 * sizeof(size\_t) bytes (implemented internally over srt\_vector) 31 | * Time complexity for set/clear: O(1) 32 | * Time complexity for population count ("popcount"): O(1) -because of tracking set/clear operations, avoiding the need of counting on every call- 33 | * libsrt hash maps (srt\_hmap) 34 | * Overhead (per element): 12 bytes (32 bits for data location, 32 bits for collision counter, 32 bits for the hash value) 35 | * Special overhead: same as in str\_map and str\_set (short string optimization) 36 | * Time complexity for insert, search, delete: O(n) -amortized O(1)-. On average it is 2x-5x faster than srt\_map, however, because of dynamic rehash important delays could happen on big hash maps. For real-time requirements, ensure you reserve enough elements beforehand. 37 | * Time for cleanup ("free"/"delete"): O(1) for sets not having string elements, O(n) when having string elements 38 | * libsrt hash sets (srt\_hset) 39 | * Similar to the hash map case, but with smaller nodes (key-only) 40 | * Time complexity for insert, search, delete: O(n) -amortized O(1)- (same as srt\_hmap) 41 | * Time for cleanup ("free"/"delete"): O(1) for maps not having string elements, O(n) when having string elements (same as srt\_hmap) 42 | 43 | Notes on STL (C++) space and time complexity 44 | === 45 | 46 | * STL strings (std::string) 47 | * Depending on implementation, it could have optimization for short strings (<= 16 bytes) or not 48 | * Non-optimized short strings or strings over 16 bytes, by default require heap allocation, even if the instance is allocated in the stack (in C++11 can be forced using stack allocation, with explicit allocator, but it is not the default behavior) 49 | * Time complexity for concatenation: O(n) -fast- 50 | * Time complexity for string search: O(n) -fast for most cases, but slow for corner cases like e.g. needle = '1111111112', haystack = '111111111111111111111111111111111111112'-) 51 | * STL vectors (std::vector) 52 | * No default stack allocation 53 | * Time complexity for sort: O(n log n) 54 | * STL maps (std::map) 55 | * Overhead per map element is notable, because the red-black tree implementation 56 | * Time complexity for insert, search, delete: O(log n) 57 | * Time for cleanup ("free"/"delete"): O(1) for maps not having string elements, O(n) when having string elements 58 | * STL sets (std::set) 59 | * Similar to STL map, but key-only 60 | * STL hash maps (std::unordered\_map) 61 | * Faster than maps for small elements (8 to 64 bit integers) 62 | * Slower than maps for big elements, e.g. strings 63 | * Time complexity for insert, search, delete: O(n) -O(1) for in the case ideal hash having 0 collisions- 64 | * Time for cleanup ("free"/"delete"): O(1) if for hash-maps not having string elements, O(n) when having string elements 65 | * STL hash-sets (std::unordered\_set) 66 | * Similar to STL hash maps, but key-only 67 | * STL bitsets 68 | * Require max size on compile time 69 | * Allows stack allocation 70 | * Time complexity for set/clear: O(1) 71 | * Time complexity for population count ("popcount"): O(n) 72 | 73 | -------------------------------------------------------------------------------- /doc/deps.md: -------------------------------------------------------------------------------- 1 | Dependencies 2 | === 3 | 4 | When using the C library 5 | --- 6 | 7 | * __ctype_b_loc 8 | * feof 9 | * ferror 10 | * fputs 11 | * fread 12 | * free 13 | * fwrite 14 | * malloc 15 | * memchr 16 | * memcmp 17 | * memcpy 18 | * memmove 19 | * memset 20 | * qsort 21 | * realloc 22 | * remove (stest.c) 23 | * snprintf 24 | * sprintf 25 | * __stack_chk_fail 26 | * stdout 27 | * strcpy (sdbg.c) 28 | * strlen 29 | * strstr 30 | * towlower 31 | * vsnprintf 32 | * wcslen 33 | 34 | -------------------------------------------------------------------------------- /doc/references.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faragon/libsrt/eee28e6dfc23f76c7b8f76f32ef68418619064be/doc/references.md -------------------------------------------------------------------------------- /make_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # make_test.sh 4 | # 5 | # Syntax: ./make_test.sh [mask] 6 | # 7 | # Where: 8 | # - No parameters: all tests 9 | # - mask = "or" operation of the following: 10 | # 1: Validate all available C/C++ builds 11 | # 2: Valgrind memcheck 12 | # 4: Clang static analyzer 13 | # 8: Generate documentation 14 | # 16: Check coding style 15 | # 32: Autoconf builds 16 | # 17 | # Examples: 18 | # ./make_test.sh # Equivalent to ./make_test.sh 31 19 | # ./make_test.sh 1 # Do the builds 20 | # ./make_test.sh 17 # Do the builds and check coding style 21 | # ./make_test.sh 24 # Generate documentation and check coding style 22 | # 23 | # libsrt build, test, and documentation generation. 24 | # 25 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 26 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 27 | # 28 | 29 | if (($# == 1)) && (($1 >= 1 && $1 < 64)) ; then TMUX=$1 ; else TMUX=63 ; fi 30 | if [ "$SKIP_FORCE32" == "1" ] ; then 31 | FORCE32T="" 32 | else 33 | FORCE32T="FORCE32=1" 34 | fi 35 | 36 | GCC=gcc 37 | GPP=g++ 38 | CLANG=clang 39 | CLANGPP=clang++ 40 | TCC=tcc 41 | 42 | CLV=$(clang --version | grep version | awk '{print $3}' | \ 43 | awk -F '-' '{print $1}') 44 | for i in 7.0.0 ; do 45 | if [ "$i" = "$CLV" ] ; then 46 | CLANG=blacklisted_$CLANG ; CLANGPP=blacklisted_$CLANGPP 47 | fi 48 | done 49 | 50 | TEST_CC[0]="$GCC" 51 | TEST_CC[1]="$GCC" 52 | TEST_CC[2]="$GCC" 53 | TEST_CC[3]="$GCC" 54 | TEST_CC[4]="$CLANG" 55 | TEST_CC[5]="$CLANG" 56 | TEST_CC[6]="$CLANG" 57 | TEST_CC[7]="$TCC" 58 | TEST_CC[8]="$GPP" 59 | TEST_CC[9]="$GPP" 60 | TEST_CC[10]="$CLANGPP" 61 | TEST_CC[11]="$CLANGPP" 62 | TEST_CC[12]="arm-linux-gnueabi-$GCC" 63 | TEST_CC[13]="arm-linux-gnueabi-$GCC" 64 | TEST_CC[14]=${TEST_CC[0]} 65 | TEST_CC[15]=${TEST_CC[0]} 66 | TEST_CC[16]=${TEST_CC[0]} 67 | TEST_CC[17]=${TEST_CC[0]} 68 | TEST_CC[18]=${TEST_CC[0]} 69 | TEST_CC[19]=${TEST_CC[0]} 70 | TEST_CC[20]=${TEST_CC[0]} 71 | TEST_CC[21]=${TEST_CC[0]} 72 | TEST_CC[22]=${TEST_CC[0]} 73 | TEST_CXX[0]="$GPP" 74 | TEST_CXX[1]="$GPP" 75 | TEST_CXX[2]="$GPP" 76 | TEST_CXX[3]="$GPP" 77 | TEST_CXX[4]="$CLANGPP" 78 | TEST_CXX[5]="$CLANGPP" 79 | TEST_CXX[6]="$CLANGPP" 80 | TEST_CXX[7]="echo" 81 | TEST_CXX[8]="$GPP" 82 | TEST_CXX[9]="$GPP" 83 | TEST_CXX[10]="$CLANGPP" 84 | TEST_CXX[11]="$CLANGPP" 85 | TEST_CXX[12]="arm-linux-gnueabi-$GPP" 86 | TEST_CXX[13]="arm-linux-gnueabi-$GPP" 87 | TEST_CXX[14]=${TEST_CXX[0]} 88 | TEST_CXX[15]=${TEST_CXX[0]} 89 | TEST_CXX[16]=${TEST_CXX[0]} 90 | TEST_CXX[17]=${TEST_CXX[0]} 91 | TEST_CXX[18]=${TEST_CXX[0]} 92 | TEST_CXX[19]=${TEST_CXX[0]} 93 | TEST_CXX[20]=${TEST_CXX[0]} 94 | TEST_CXX[21]=${TEST_CXX[0]} 95 | TEST_CXX[22]=${TEST_CXX[0]} 96 | TEST_FLAGS[0]="C99=1 PEDANTIC=1" 97 | TEST_FLAGS[1]="PROFILING=1" 98 | TEST_FLAGS[2]="C99=0" 99 | TEST_FLAGS[3]="C99=0 $FORCE32T" 100 | TEST_FLAGS[4]="C99=1 PEDANTIC=1" 101 | TEST_FLAGS[5]="C99=0 $FORCE32T" 102 | TEST_FLAGS[6]="C99=1" 103 | TEST_FLAGS[7]="" 104 | TEST_FLAGS[8]="" 105 | TEST_FLAGS[9]="CPP0X=1" 106 | TEST_FLAGS[10]="" 107 | TEST_FLAGS[11]="CPP11=1" 108 | TEST_FLAGS[12]="C99=0" 109 | TEST_FLAGS[13]="C99=1" 110 | TEST_FLAGS[14]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_DISABLE_SM_STRING_OPTIMIZATION" 111 | TEST_FLAGS[15]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_CRC32_SLC=0 \ 112 | ADD_FLAGS2=-DS_DISABLE_SEARCH_GUARANTEE" 113 | TEST_FLAGS[16]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_CRC32_SLC=1" 114 | TEST_FLAGS[17]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_CRC32_SLC=4" 115 | TEST_FLAGS[18]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_CRC32_SLC=8" 116 | TEST_FLAGS[19]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_CRC32_SLC=12" 117 | TEST_FLAGS[20]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_CRC32_SLC=16" 118 | TEST_FLAGS[21]="${TEST_FLAGS[0]} ADD_FLAGS=-DSD_DISABLE_HEURISTIC_GROWTH" 119 | TEST_FLAGS[22]="${TEST_FLAGS[0]} ADD_FLAGS=-DS_DISABLE_LE_OPTIMIZATIONS" 120 | TEST_DO_UT[0]="all" 121 | TEST_DO_UT[1]="all" 122 | TEST_DO_UT[2]="all" 123 | TEST_DO_UT[3]="all" 124 | TEST_DO_UT[4]="all" 125 | TEST_DO_UT[5]="all" 126 | TEST_DO_UT[6]="all" 127 | TEST_DO_UT[7]="all" 128 | TEST_DO_UT[8]="all" 129 | TEST_DO_UT[9]="all" 130 | TEST_DO_UT[10]="all" 131 | TEST_DO_UT[11]="all" 132 | TEST_DO_UT[12]="stest" 133 | TEST_DO_UT[13]="stest" 134 | TEST_DO_UT[14]=${TEST_DO_UT[0]} 135 | TEST_DO_UT[15]=${TEST_DO_UT[0]} 136 | TEST_DO_UT[16]=${TEST_DO_UT[0]} 137 | TEST_DO_UT[17]=${TEST_DO_UT[0]} 138 | TEST_DO_UT[18]=${TEST_DO_UT[0]} 139 | TEST_DO_UT[19]=${TEST_DO_UT[0]} 140 | TEST_DO_UT[20]=${TEST_DO_UT[0]} 141 | TEST_DO_UT[21]=${TEST_DO_UT[0]} 142 | TEST_DO_UT[22]=${TEST_DO_UT[0]} 143 | ILOOP_FLAGS[0]="" 144 | ILOOP_FLAGS[1]="DEBUG=1" 145 | ILOOP_FLAGS[2]="MINIMAL=1" 146 | ILOOP_FLAGS[3]="MINIMAL=1 DEBUG=1" 147 | VALGRIND_LOOP_FLAGS[0]="DEBUG=1" 148 | VALGRIND_LOOP_FLAGS[1]="DEBUG=1 ADD_FLAGS=-DS_DISABLE_SM_STRING_OPTIMIZATION" 149 | VALGRIND_LOOP_FLAGS[2]="MINIMAL=1 DEBUG=1" 150 | VALGRIND_LOOP_FLAGS[3]="MINIMAL=1 DEBUG=1" 151 | VALGRIND_LOOP_FLAGS[3]+=" ADD_FLAGS=-DS_DISABLE_SM_STRING_OPTIMIZATION" 152 | VALGRIND_LOOP_FLAGS[4]="DEBUG=1 ADD_FLAGS=-DS_FORCE_REALLOC_COPY" 153 | ERRORS=0 154 | NPROCS=0 155 | MJOBS=1 156 | 157 | if [ -e /proc/cpuinfo ] ; then # Linux CPU count 158 | NPROCS=$(grep processor /proc/cpuinfo | wc -l) 159 | fi 160 | if [ $(uname) = Darwin ] ; then # OSX CPU count 161 | NPROCS=$(sysctl hw.ncpu | awk '{print $2}') 162 | fi 163 | if (( NPROCS > MJOBS )) ; then MJOBS=$((2 * $NPROCS)) ; fi 164 | 165 | echo "make_test.sh running..." 166 | 167 | # Locate GNU Make 168 | if [ "$MAKE" == "" ] ; then 169 | if type gmake >/dev/null 2>&1 ; then 170 | MAKE="gmake -f Makefile.posix" 171 | else 172 | MAKE="make -f Makefile.posix" 173 | fi 174 | else 175 | MAKE="$MAKE -f Makefile.posix" 176 | fi 177 | 178 | for i in $GCC $CLANG ; do 179 | if type $i >/dev/null 2>&1 ; then $i --version ; fi ; done 180 | if type $TCC >/dev/null 2>&1 ; then $TCC -version ; fi 181 | 182 | if (($TMUX & 1)) ; then 183 | for ((i = 0; i < ${#TEST_CC[@]}; i++)) ; do 184 | if type ${TEST_CC[$i]} >/dev/null 2>&1 >/dev/null ; then 185 | for ((j = 0 ; j < ${#ILOOP_FLAGS[@]}; j++)) ; do 186 | CMD="$MAKE -j $MJOBS CC=${TEST_CC[$i]}" 187 | CMD+=" CXX=${TEST_CXX[$i]} ${TEST_FLAGS[$i]}" 188 | CMD+=" ${ILOOP_FLAGS[$j]} ${TEST_DO_UT[$i]}" 189 | $MAKE clean >/dev/null 2>&1 190 | echo -n "Test #$i.$j: [$CMD] ..." 191 | if $CMD >/dev/null 2>&1 ; then 192 | echo " OK" 193 | else echo " ERROR" 194 | ERRORS=$((ERRORS + 1)) 195 | fi 196 | done 197 | else 198 | echo "Test #$i: ${TEST_CC[$i]} not found (skipped)" 199 | fi 200 | done 201 | fi 202 | 203 | VAL_ERR_TAG="ERROR SUMMARY:" 204 | VAL_ERR_FILE=valgrind.errors 205 | 206 | if (($TMUX & 2)) && type valgrind >/dev/null 2>&1 ; then 207 | for ((j = 0 ; j < ${#VALGRIND_LOOP_FLAGS[@]}; j++)) ; do 208 | MAKEFLAGS=${VALGRIND_LOOP_FLAGS[$j]} 209 | echo -n "Valgrind test ($MAKEFLAGS)..." 210 | VAL_ERR_FILEx=$VAL_ERR_FILE".$j" 211 | if $MAKE clean >/dev/null 2>&1 && \ 212 | $MAKE -j $MJOBS $MAKEFLAGS >/dev/null 2>&1 && \ 213 | valgrind --track-origins=yes --tool=memcheck \ 214 | --leak-check=yes --show-reachable=yes \ 215 | --num-callers=20 --track-fds=yes \ 216 | ./stest >/dev/null 2>$VAL_ERR_FILEx ; then 217 | VAL_ERRS=$(grep "$VAL_ERR_TAG" "$VAL_ERR_FILEx" | \ 218 | awk -F 'ERROR SUMMARY:' '{print $2}' | \ 219 | awk '{print $1}') 220 | if (( $VAL_ERRS > 0 )) ; then 221 | ERRORS=$((ERRORS + $VAL_ERRS)) 222 | echo " ERROR" 223 | else 224 | echo " OK" 225 | fi 226 | else echo " ERROR" 227 | ERRORS=$((ERRORS + 1)) 228 | fi 229 | done 230 | fi 231 | 232 | if (($TMUX & 4)) && type scan-build >/dev/null 2>&1 ; then 233 | echo -n "Clang static analyzer..." 234 | $MAKE clean 235 | if scan-build -v $MAKE CC=$CLANG 2>&1 >clang_analysis.txt ; then 236 | echo " OK" 237 | else echo " ERROR" 238 | ERRORS=$((ERRORS + 1)) 239 | fi 240 | fi 241 | 242 | if (($TMUX & 8)) ; then 243 | $MAKE clean 244 | OUT_DOC=doc/out 245 | mkdir $OUT_DOC 2>/dev/null 246 | if type python3 >/dev/null 2>&1 ; then 247 | echo "Documentation generation test..." 248 | if ! utl/mk_doc.sh src $OUT_DOC ; then 249 | ERRORS=$((ERRORS + 1)) 250 | fi 251 | else 252 | echo "WARNING: doc not generated (python3 not found)" 253 | fi 254 | if type gcov >/dev/null 2>&1 ; then 255 | echo "Coverage report generation..." 256 | COVERAGE_OUT=$OUT_DOC/coverage.txt 257 | $MAKE -j $MJOBS CC=$GCC PROFILING=1 2>/dev/null >/dev/null 258 | for f in schar scommon sdata senc shash smap smset shmap \ 259 | shset ssearch ssort sstring sstringo stree svector \ 260 | stest ; do 261 | gcov $f.c >/dev/null 2>/dev/null 262 | done 263 | rm -f $COVERAGE_OUT 2>/dev/null 264 | ls -1 *c.gcov | awk -F '.gcov' '{print $1}' | while read f ; do 265 | echo "$f:"$(gcov $f | sed -e "/$f.gcov/"',$d' | \ 266 | awk -F ':' '{print $2}' | awk '{print $1}') >> \ 267 | $COVERAGE_OUT 268 | done 269 | echo "$COVERAGE_OUT:" 270 | cat $COVERAGE_OUT 271 | else 272 | echo "WARNING: coverage report not generated (gcov not found)" 273 | fi 274 | fi 275 | 276 | if (($TMUX & 16)) ; then 277 | echo "Checking style..." 278 | SRCS="src/*c src/saux/*c test/*c test/*h Makefile.posix Makefile.am" 279 | ls -1 $SRCS *\.sh utl/*\.sh | while read line ; do 280 | if ! utl/check_style.sh "$line" ; then 281 | echo "$line... ERROR: style" 282 | ERRORS=$((ERRORS + 1)) 283 | fi 284 | done 285 | if type egrep >/dev/null 2>&1 ; then 286 | find $SRCS src/*h src/saux/*h LICENSE README.md doc \ 287 | make_test.sh -type f | \ 288 | while read line ; do 289 | if (($(sed -n '/ \+$/p' <$line | wc -l) > 0)) ; then 290 | echo "$line... ERROR, trailing spaces:" 291 | sed -n '/ \+$/p' <$line | while read l2 ; do 292 | echo -e "\t$l2[*]" 293 | done 294 | ERRORS=$((ERRORS + 1)) 295 | fi 296 | done 297 | fi 298 | fi 299 | 300 | $MAKE clean 301 | 302 | if (($TMUX & 32)) ; then 303 | echo "Autoconf build:" 304 | for j in ./bootstrap.sh ./configure "make -j $NPROCS" \ 305 | "make check" "make clean" ; do 306 | echo -n -e "\t$j: " 307 | if $j >/dev/null 2>&1 ; then 308 | echo "OK" 309 | else 310 | echo "ERROR" 311 | ERRORS=$((ERRORS + 1)) 312 | break 313 | fi 314 | done 315 | make clean >/dev/null 2>&1 316 | fi 317 | 318 | exit $((ERRORS > 0 ? 1 : 0)) 319 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # src/Makefile.am 3 | # 4 | # libsrt library Automake template 5 | # 6 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | # 9 | 10 | MAINTAINERCLEANFILES = Makefile.in 11 | lib_LTLIBRARIES = libsrt.la 12 | libsrt_la_SOURCES = sbitset.c shmap.c shset.c smap.c smset.c sstring.c \ 13 | svector.c saux/schar.c saux/scommon.c saux/sdata.c \ 14 | saux/sdbg.c saux/senc.c saux/shash.c saux/ssearch.c \ 15 | saux/ssort.c saux/sstringo.c saux/stree.c 16 | library_include_HEADERS = libsrt.h sbitset.h shmap.h shset.h smap.h smset.h \ 17 | sstring.h svector.h saux/schar.h saux/sconfig.h \ 18 | saux/scrc32.h saux/sdbg.h saux/shash.h saux/ssort.h \ 19 | saux/stree.h saux/scommon.h saux/scopyright.h saux/sdata.h \ 20 | saux/senc.h saux/ssearch.h saux/sstringo.h 21 | library_includedir = $(includedir)/libsrt 22 | -------------------------------------------------------------------------------- /src/libsrt.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSRT_H 2 | #define LIBSRT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * libsrt.h 9 | * 10 | * Header file for the libsrt library. 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | */ 15 | 16 | #include "sbitset.h" 17 | #include "shmap.h" 18 | #include "shset.h" 19 | #include "smap.h" 20 | #include "smset.h" 21 | #include "sstring.h" 22 | #include "svector.h" 23 | 24 | #ifdef __cplusplus 25 | } /* extern "C" { */ 26 | #endif 27 | #endif /* #ifndef LIBSRT_H */ 28 | -------------------------------------------------------------------------------- /src/saux/schar.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHAR_H 2 | #define SCHAR_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * schar.h 9 | * 10 | * Unicode processing helper functions. 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | * 15 | * Designed to be used by libraries or wrapped by some abstraction (e.g. 16 | * srt_string/libsrt), not as general-purpose direct usage. 17 | * 18 | * Features: 19 | * 20 | * - Unicode <-> UTF-8 character conversion. 21 | * - Compute Unicode required size for UTF-8 representation. 22 | * - Count Unicode characters into UTF-8 stream. 23 | * - Lowercase/uppercase conversions. 24 | * - Not relies on C library nor OS Unicode support ("locale"). 25 | * - Small memory footprint (not using hash tables). 26 | * - Fast 27 | * 28 | * Observations: 29 | * - Turkish (tr_CY/tr_TR) is an especial case that breaks the possibility 30 | * of generic case conversion, because of the 'i' <-> 'I' collision with 31 | * other case conversion for other languages using the latin alphabet, as 32 | * in that locale there are two lowercase 'i', with and without dot, and 33 | * also two uppercase 'I' with, and without dot, so the 'i' <-> 'I' don't 34 | * applies. For covering that case, equivalent to having the tr_* locale 35 | * set, sc_tolower_tr()/sc_toupper_tr() are provided. 36 | */ 37 | 38 | #include "scommon.h" 39 | 40 | enum SSUTF8 { 41 | SSU8_SX = 0x80, 42 | SSU8_S1 = 0x00, 43 | SSU8_S2 = 0xc0, 44 | SSU8_S3 = 0xe0, 45 | SSU8_S4 = 0xf0, 46 | SSU8_S5 = 0xf8, 47 | SSU8_S6 = 0xfc, 48 | SSUB_MX = 0x3f, 49 | SSU8_M1 = 0x80, 50 | SSU8_M2 = 0xe0, 51 | SSU8_M3 = 0xf0, 52 | SSU8_M4 = 0xf8, 53 | SSU8_M5 = 0xfc, 54 | SSU8_M6 = 0xfe, 55 | SSU8_MAX_SIZE = 6 56 | }; 57 | 58 | enum SSUTF16 { 59 | SSU16_HS0 = 0xd800, /* high surrogate range */ 60 | SSU16_HSN = 0xdbff, 61 | SSU16_LS0 = 0xdc00, /* low surrogate range */ 62 | SSU16_LSN = 0xdfff, 63 | SSU16_SM = 0xfc00, 64 | SSU16_SMI = 0x03ff 65 | }; 66 | 67 | #define SSU8_VALID_START(c) (((c)&0xc0) != SSU8_SX) 68 | #define SSU16_SIMPLE(c) \ 69 | (((unsigned short)(c)) < SSU16_HS0 || ((unsigned short)(c)) > SSU16_LSN) 70 | #define SSU16_VALID_HS(c) (((c)&SSU16_SM) == SSU16_HS0) 71 | #define SSU16_VALID_LS(c) (((c)&SSU16_SM) == SSU16_LS0) 72 | #define SSU16_TO_U32(hs, ls) ((((hs)&SSU16_SMI) << 10) | ((ls)&SSU16_SMI)) 73 | 74 | size_t sc_utf8_char_size(const char *s, size_t off, size_t max_off, 75 | size_t *enc_errors); 76 | size_t sc_utf8_count_chars(const char *s, size_t s_size, size_t *enc_errors); 77 | size_t sc_wc_to_utf8_size(int32_t c); 78 | size_t sc_wc_to_utf8(int32_t c, char *s, size_t off, size_t max_off); 79 | size_t sc_utf8_to_wc(const char *s, size_t off, size_t max_off, 80 | int32_t *unicode_out, size_t *encoding_errors); 81 | size_t sc_unicode_count_to_utf8_size(const char *, size_t off, size_t max_off, 82 | size_t unicode_count, 83 | size_t *actual_unicode_count); 84 | ssize_t sc_utf8_calc_case_extra_size(const char *s, size_t off, size_t s_size, 85 | int32_t (*ssc_toX)(int32_t)); 86 | int32_t sc_tolower(int32_t c); 87 | int32_t sc_toupper(int32_t c); 88 | int32_t sc_tolower_tr(int32_t c); 89 | int32_t sc_toupper_tr(int32_t c); 90 | size_t sc_parallel_toX(const char *s, size_t off, size_t max, char *o, 91 | int32_t (*ssc_toX)(int32_t)); 92 | 93 | #ifdef __cplusplus 94 | } /* extern "C" { */ 95 | #endif 96 | #endif /* SCHAR_H */ 97 | -------------------------------------------------------------------------------- /src/saux/scommon.c: -------------------------------------------------------------------------------- 1 | /* 2 | * scommon.c 3 | * 4 | * Common stuff 5 | * 6 | * Copyright (c) 2015-2021 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "scommon.h" 11 | 12 | #define D8_LE_MASK S_NBITMASK(8 - D8_LE_SHIFT) 13 | #define D16_LE_MASK S_NBITMASK(16 - D16_LE_SHIFT) 14 | #define D24_LE_MASK S_NBITMASK(24 - D24_LE_SHIFT) 15 | #define D32_LE_MASK S_NBITMASK(32 - D32_LE_SHIFT) 16 | #define D40_LE_MASK S_NBITMASK64(40 - D40_LE_SHIFT) 17 | #define D48_LE_MASK S_NBITMASK64(48 - D48_LE_SHIFT) 18 | #define D56_LE_MASK S_NBITMASK64(56 - D56_LE_SHIFT) 19 | 20 | enum SPK64IDMASK { 21 | D8_LE_ID = 1, 22 | D16_LE_ID = 2, 23 | D24_LE_ID = 4, 24 | D32_LE_ID = 8, 25 | D40_LE_ID = 16, 26 | D48_LE_ID = 32, 27 | D56_LE_ID = 64, 28 | D72_LE_ID = 128 29 | }; 30 | enum SPK64SIZE { 31 | D8_LE_SZ = 1, 32 | D16_LE_SZ = 2, 33 | D24_LE_SZ = 3, 34 | D32_LE_SZ = 4, 35 | D40_LE_SZ = 5, 36 | D48_LE_SZ = 6, 37 | D56_LE_SZ = 7, 38 | D72_LE_SZ = 9 39 | }; 40 | enum SPK64SHIFT { 41 | D8_LE_SHIFT = 1, 42 | D16_LE_SHIFT, 43 | D24_LE_SHIFT, 44 | D32_LE_SHIFT, 45 | D40_LE_SHIFT, 46 | D48_LE_SHIFT, 47 | D56_LE_SHIFT 48 | }; 49 | 50 | void s_st_pk_u64(uint8_t **buf0, uint64_t v) 51 | { 52 | uint8_t *buf; 53 | if (!buf0 || !*buf0) 54 | return; 55 | buf = *buf0; 56 | /* 7-bit (8-bit container) */ 57 | if (v <= D8_LE_MASK) { 58 | buf[0] = D8_LE_ID | (uint8_t)(v << D8_LE_SHIFT); 59 | (*buf0) += D8_LE_SZ; 60 | return; 61 | } 62 | /* 14-bit (16-bit container) */ 63 | if (v <= D16_LE_MASK) { 64 | S_ST_LE_U16(buf, D16_LE_ID | (uint16_t)(v << D16_LE_SHIFT)); 65 | (*buf0) += D16_LE_SZ; 66 | return; 67 | } 68 | /* 21-bit (24-bit container) */ 69 | if (v <= D24_LE_MASK) { 70 | S_ST_LE_U32(buf, D24_LE_ID | (uint32_t)(v << D24_LE_SHIFT)); 71 | (*buf0) += D24_LE_SZ; 72 | return; 73 | } 74 | /* 28-bit (32-bit container) */ 75 | if (v <= D32_LE_MASK) { 76 | S_ST_LE_U32(buf, D32_LE_ID | ((uint32_t)v << D32_LE_SHIFT)); 77 | (*buf0) += D32_LE_SZ; 78 | return; 79 | } 80 | /* 35-bit (40-bit container) */ 81 | if (v <= D40_LE_MASK) { 82 | S_ST_LE_U64(buf, D40_LE_ID | (v << D40_LE_SHIFT)); 83 | (*buf0) += D40_LE_SZ; 84 | return; 85 | } 86 | /* 42-bit (48-bit container) */ 87 | if (v <= D48_LE_MASK) { 88 | S_ST_LE_U64(buf, D48_LE_ID | (v << D48_LE_SHIFT)); 89 | (*buf0) += D48_LE_SZ; 90 | return; 91 | } 92 | /* 49-bit (56-bit container) */ 93 | if (v <= D56_LE_MASK) { 94 | S_ST_LE_U64(buf, D56_LE_ID | (v << D56_LE_SHIFT)); 95 | (*buf0) += D56_LE_SZ; 96 | return; 97 | } 98 | /* 64-bit (72-bit container) */ 99 | buf[0] = D72_LE_ID; 100 | S_ST_LE_U64(buf + 1, v); 101 | (*buf0) += D72_LE_SZ; 102 | } 103 | 104 | uint64_t s_ld_pk_u64(const uint8_t **buf0, size_t bs) 105 | { 106 | size_t hdr_bytes; 107 | const uint8_t *buf; 108 | RETURN_IF(!buf0 || !bs, 0); 109 | buf = *buf0; 110 | RETURN_IF(!buf, 0); 111 | hdr_bytes = s_pk_u64_size(buf); 112 | (*buf0) += hdr_bytes; 113 | RETURN_IF(hdr_bytes > bs, 0); 114 | switch (hdr_bytes) { 115 | case D8_LE_SZ: 116 | return buf[0] >> D8_LE_SHIFT; 117 | case D16_LE_SZ: 118 | return S_LD_LE_U16(buf) >> D16_LE_SHIFT; 119 | case D24_LE_SZ: 120 | return D24_LE_MASK & (S_LD_LE_U32(buf) >> D24_LE_SHIFT); 121 | case D32_LE_SZ: 122 | return S_LD_LE_U32(buf) >> D32_LE_SHIFT; 123 | case D40_LE_SZ: 124 | return D40_LE_MASK & (S_LD_LE_U64(buf) >> D40_LE_SHIFT); 125 | case D48_LE_SZ: 126 | return D48_LE_MASK & (S_LD_LE_U64(buf) >> D48_LE_SHIFT); 127 | case D56_LE_SZ: 128 | return D56_LE_MASK & (S_LD_LE_U64(buf) >> D56_LE_SHIFT); 129 | case D72_LE_SZ: 130 | return S_LD_LE_U64(buf + 1); 131 | } 132 | return 0; 133 | } 134 | 135 | /* clang-format off */ 136 | size_t s_pk_u64_size(const uint8_t *buf) 137 | { 138 | int h = *buf; 139 | return h & D8_LE_ID ? D8_LE_SZ : h & D16_LE_ID ? D16_LE_SZ : 140 | h & D24_LE_ID ? D24_LE_SZ : h & D32_LE_ID ? D32_LE_SZ : 141 | h & D40_LE_ID ? D40_LE_SZ : h & D48_LE_ID ? D48_LE_SZ : 142 | h & D56_LE_ID ? D56_LE_SZ : h & D72_LE_ID ? D72_LE_SZ : 0; 143 | } 144 | /* clang-format on */ 145 | 146 | /* 147 | * Integer log2(N) approximation 148 | */ 149 | #define SLOG2STEP(mask, bits) \ 150 | test = !!(i & mask); \ 151 | o |= test * bits; \ 152 | i = test * (i >> bits) | !test * i; 153 | 154 | unsigned slog2_32(uint32_t i) 155 | { 156 | unsigned o = 0, test; 157 | SLOG2STEP(0xffff0000, 16); 158 | SLOG2STEP(0xff00, 8); 159 | SLOG2STEP(0xf0, 4); 160 | SLOG2STEP(0x0c, 2); 161 | SLOG2STEP(0x02, 1); 162 | return o; 163 | } 164 | 165 | unsigned slog2_64(uint64_t i) 166 | { 167 | unsigned o = 0, test; 168 | SLOG2STEP(0xffffffff00000000LL, 32); 169 | SLOG2STEP(0xffff0000, 16); 170 | SLOG2STEP(0xff00, 8); 171 | SLOG2STEP(0xf0, 4); 172 | SLOG2STEP(0x0c, 2); 173 | SLOG2STEP(0x02, 1); 174 | return o; 175 | } 176 | 177 | #define SLOG2_CEIL(lf, i) \ 178 | unsigned a, b; \ 179 | RETURN_IF(!i, 0); \ 180 | a = lf(i - 1); \ 181 | b = lf(i); \ 182 | return a == b ? b + 1 : b 183 | 184 | /* log2, rounding-up */ 185 | unsigned slog2_ceil_32(uint32_t i) 186 | { 187 | SLOG2_CEIL(slog2_32, i); 188 | } 189 | 190 | unsigned slog2_ceil(uint64_t i) 191 | { 192 | SLOG2_CEIL(slog2_64, i); 193 | } 194 | 195 | uint64_t snextpow2(uint64_t i) 196 | { 197 | #if 1 198 | i--; 199 | i |= i >> 1; 200 | i |= i >> 2; 201 | i |= i >> 4; 202 | i |= i >> 8; 203 | i |= i >> 16; 204 | i |= i >> 32; 205 | return i + 1; 206 | #else 207 | return i <= 2 ? i : (uint64_t)1 << slog2_ceil_64(i); 208 | #endif 209 | } 210 | 211 | -------------------------------------------------------------------------------- /src/saux/sconfig.h: -------------------------------------------------------------------------------- 1 | #ifndef SCONFIG_H 2 | #define SCONFIG_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * sconfig.h 9 | * 10 | * Third party interface configuration. 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | */ 15 | 16 | /* 17 | * Heap allocation 18 | */ 19 | 20 | #ifndef _s_malloc 21 | #define _s_malloc malloc 22 | #endif 23 | #ifndef _s_calloc 24 | #define _s_calloc calloc 25 | #endif 26 | #ifndef _s_realloc 27 | #define _s_realloc realloc 28 | #endif 29 | #ifndef _s_free 30 | #define _s_free free 31 | #endif 32 | 33 | /* 34 | * For covering the case of errors masked because of the realloc function 35 | * returning the same base address, a mechanism for detecting those errors 36 | * is provided (used in the Valgrind test phase, protecting the build) 37 | */ 38 | #if defined(S_FORCE_REALLOC_COPY) && defined(_s_realloc) \ 39 | && (defined(__GNUC__) || defined(__clang__) || defined(__TINYC__)) 40 | #include 41 | #include 42 | #undef _s_realloc 43 | inline static void *_s_realloc(void *ptr, size_t size) 44 | { 45 | void *ptr_next; 46 | size_t size_prev = malloc_usable_size(ptr), 47 | size_next = size > size_prev ? size : size_prev; 48 | ptr_next = malloc(size_next); 49 | if (!ptr_next) 50 | return NULL; 51 | memcpy(ptr_next, ptr, size_prev); 52 | memset(ptr, 0xfa, size_prev); 53 | free(ptr); 54 | return ptr_next; 55 | } 56 | #endif 57 | 58 | #ifdef __cplusplus 59 | } /* extern "C" { */ 60 | #endif 61 | #endif /* SCONFIG_H */ 62 | -------------------------------------------------------------------------------- /src/saux/scopyright.h: -------------------------------------------------------------------------------- 1 | #ifndef SCOPYRIGHT_H 2 | #define SCOPYRIGHT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * scopyright.h 9 | * 10 | * Copyright constants. 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | */ 15 | 16 | #define LIBSRT_COPYRIGHT \ 17 | "Copyright (c) 2015-2019 F. Aragon. All rights reserved." 18 | #define LIBSRT_LICENSE \ 19 | "Released under the BSD 3-Clause License (see the doc/LICENSE)" 20 | 21 | #ifdef __cplusplus 22 | } /* extern "C" { */ 23 | #endif 24 | #endif /* SCOPYRIGHT_H */ 25 | -------------------------------------------------------------------------------- /src/saux/sdata.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sdata.c 3 | * 4 | * Dynamic size data handling. Helper functions, not part of the API. 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "sdata.h" 11 | #include "scommon.h" 12 | 13 | /* 14 | * Allocation heuristic configuration 15 | * 16 | * SD_GROW_PCT (e.g. 25%): if possible, allocate at least 25% the current 17 | * allocated memory. 18 | * SD_GROW_MAX_INC: maximum amount of over-incremented elements. 19 | */ 20 | 21 | #ifdef S_MINIMAL 22 | #define SD_GROW_PCT 10 23 | #else 24 | #define SD_GROW_PCT 25 25 | #endif 26 | #define SD_GROW_MAX_INC 1000000 27 | 28 | static srt_data sd_void0 = EMPTY_SDataFull; 29 | srt_data *sd_void = &sd_void0; 30 | 31 | /* 32 | * Allocation 33 | */ 34 | 35 | srt_data *sd_alloc(size_t header_size, size_t elem_size, size_t initial_reserve, 36 | srt_bool dyn_st, size_t extra_tail_bytes) 37 | { 38 | size_t alloc_size = sd_alloc_size_raw(header_size, elem_size, 39 | initial_reserve, dyn_st); 40 | srt_data *d = (srt_data *)s_malloc(alloc_size + extra_tail_bytes); 41 | if (d) { 42 | sd_reset(d, header_size, elem_size, initial_reserve, S_FALSE, 43 | dyn_st); 44 | S_PROFILE_ALLOC_CALL; 45 | } else { 46 | S_ERROR("not enough memory"); 47 | d = sd_void; 48 | } 49 | return d; 50 | } 51 | 52 | srt_data *sd_alloc_into_ext_buf(void *buffer, size_t max_size, 53 | size_t header_size, size_t elem_size, 54 | srt_bool dyn_st) 55 | { 56 | srt_data *d; 57 | RETURN_IF(!buffer || !max_size, NULL); /* not enough memory */ 58 | d = (srt_data *)buffer; 59 | sd_reset(d, header_size, elem_size, max_size, S_TRUE, dyn_st); 60 | return d; 61 | } 62 | 63 | void sd_free(srt_data **d) 64 | { 65 | if (d && *d) { 66 | /* 67 | * Request for freeing external buffers are ignored 68 | */ 69 | S_ASSERT(!(*d)->f.ext_buffer); 70 | if (!(*d)->f.ext_buffer) 71 | s_free(*d); 72 | *d = NULL; 73 | } 74 | } 75 | 76 | void sd_free_va(srt_data **first, va_list ap) 77 | { 78 | srt_data **next = first; 79 | while (!s_varg_tail_ptr_tag(next)) { /* last element tag */ 80 | if (next) { 81 | sd_free((srt_data **)next); 82 | *next = NULL; 83 | } 84 | next = (srt_data **)va_arg(ap, srt_data **); 85 | } 86 | } 87 | 88 | void sd_reset(srt_data *d, size_t header_size, size_t elem_size, 89 | size_t max_size, srt_bool ext_buf, srt_bool dyn_st) 90 | { 91 | if (d) { 92 | d->f.ext_buffer = ext_buf; 93 | sd_reset_alloc_errors(d); 94 | d->f.flag1 = d->f.flag2 = d->f.flag3 = d->f.flag4 = 0; 95 | d->f.st_mode = !dyn_st ? SData_Full 96 | : max_size <= 255 ? SData_DynSmall 97 | : SData_DynFull; 98 | if (sdx_full_st(d)) { 99 | d->header_size = header_size; 100 | d->elem_size = elem_size; 101 | d->sub_type = 0; 102 | } else { 103 | ((struct SDataSmall *)d)->aux = 0; 104 | } 105 | sdx_set_size(d, 0); 106 | sdx_set_max_size(d, max_size); 107 | } 108 | } 109 | 110 | /* Acknowledgements: similar to git's strbuf_grow */ 111 | size_t sd_grow(srt_data **d, size_t extra_size, size_t extra_tail_bytes) 112 | { 113 | size_t size, new_size; 114 | RETURN_IF(!d, 0); 115 | size = sd_size(*d); 116 | RETURN_IF(s_size_t_overflow(size, extra_size), 0); 117 | new_size = sd_reserve(d, size + extra_size, extra_tail_bytes); 118 | return new_size >= (size + extra_size) ? (new_size - size) : 0; 119 | } 120 | 121 | S_INLINE size_t sd_reserve_aux(srt_data **d, size_t max_size, 122 | size_t full_header_size, size_t extra_tail_bytes) 123 | { 124 | #ifdef SD_ENABLE_HEURISTIC_GROWTH 125 | size_t inc; 126 | #endif 127 | int chg; 128 | srt_bool is_dyn; 129 | size_t curr_hdr_size, next_hdr_size; 130 | size_t curr_max_size, elem_size, as, size; 131 | srt_data *d_next; 132 | char *p; 133 | RETURN_IF(!d || !*d || (*d)->f.st_mode == SData_VoidData, 0); 134 | curr_max_size = sdx_max_size(*d); 135 | if (curr_max_size < max_size) { 136 | if ((*d)->f.ext_buffer) { 137 | S_ERROR("out of memory on fixed-size " 138 | "allocated space"); 139 | sd_set_alloc_errors(*d); 140 | return curr_max_size; 141 | } 142 | #ifdef SD_ENABLE_HEURISTIC_GROWTH 143 | inc = s_size_t_pct(max_size, SD_GROW_PCT); 144 | inc = S_MIN(inc, SD_GROW_MAX_INC); 145 | if (!s_size_t_overflow(max_size, inc)) 146 | max_size += inc; 147 | #endif 148 | is_dyn = sdx_dyn_st(*d); 149 | chg = sdx_chk_st_change(*d, max_size); 150 | curr_hdr_size = sdx_header_size(*d); 151 | next_hdr_size = chg > 0 ? full_header_size : curr_hdr_size; 152 | elem_size = sdx_elem_size(*d); 153 | as = sd_alloc_size_raw(full_header_size, elem_size, max_size, 154 | is_dyn); 155 | d_next = (srt_data *)s_realloc(*d, as + extra_tail_bytes); 156 | if (!d_next) { 157 | S_ERROR("sd_reserve: not enough memory"); 158 | sd_set_alloc_errors(*d); 159 | return curr_max_size; 160 | } 161 | *d = d_next; 162 | S_PROFILE_ALLOC_CALL; 163 | if (chg > 0) { /* Change from small to full container*/ 164 | size = ((struct SDataSmall *)d_next)->size; 165 | p = (char *)d_next; 166 | memmove(p + next_hdr_size, p + curr_hdr_size, size); 167 | d_next->f.st_mode = SData_DynFull; 168 | d_next->header_size = full_header_size; 169 | d_next->sub_type = 0; 170 | d_next->elem_size = 1; 171 | d_next->size = size; 172 | } 173 | sdx_set_max_size(*d, max_size); 174 | } 175 | return sdx_max_size(*d); 176 | } 177 | 178 | size_t sd_reserve(srt_data **d, size_t max_size, size_t extra_tail_bytes) 179 | { 180 | RETURN_IF(!d || !*d, 0); 181 | return sd_reserve_aux(d, max_size, (*d)->header_size, extra_tail_bytes); 182 | } 183 | 184 | size_t sdx_reserve(srt_data **d, size_t max_size, size_t full_header_size, 185 | size_t extra_tail_bytes) 186 | { 187 | RETURN_IF(!d || !*d, 0); 188 | return sd_reserve_aux(d, max_size, full_header_size, extra_tail_bytes); 189 | } 190 | 191 | srt_data *sd_shrink(srt_data **d, size_t extra_tail_bytes) 192 | { 193 | size_t max_size, new_max_size, as; 194 | srt_data *d_next; 195 | ASSERT_RETURN_IF(!d || !(*d), sd_void); /* BEHAVIOR */ 196 | RETURN_IF((*d)->f.ext_buffer, *d); /* non-shrinkable */ 197 | RETURN_IF(!sdx_full_st(*d), *d); /* BEHAVIOR: shrink only full st */ 198 | max_size = sd_max_size(*d); 199 | new_max_size = (*d)->size; 200 | if (new_max_size < max_size) { 201 | as = sd_alloc_size_raw((*d)->header_size, (*d)->elem_size, 202 | new_max_size, S_FALSE); 203 | d_next = (srt_data *)s_realloc(*d, as + extra_tail_bytes); 204 | if (d_next) { 205 | *d = d_next; 206 | (*d)->max_size = new_max_size; 207 | } else { 208 | S_ERROR("sd_shrink: warning realloc error"); 209 | } 210 | } 211 | return *d; 212 | } 213 | -------------------------------------------------------------------------------- /src/saux/sdbg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sdbg.c 3 | * 4 | * Debug helpers (data formatting, etc.). 5 | * 6 | * Copyright (c) 2015-2020 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "sdbg.h" 11 | 12 | const char *sv_type_to_label(const enum eSV_Type t) 13 | { 14 | switch (t) { 15 | #define CXSV(t) \ 16 | case t: \ 17 | return #t 18 | CXSV(SV_I8); 19 | CXSV(SV_U8); 20 | CXSV(SV_I16); 21 | CXSV(SV_U16); 22 | CXSV(SV_I32); 23 | CXSV(SV_U32); 24 | CXSV(SV_I64); 25 | CXSV(SV_U64); 26 | CXSV(SV_F); 27 | CXSV(SV_D); 28 | CXSV(SV_GEN); 29 | default: 30 | break; 31 | } 32 | return "?"; 33 | } 34 | 35 | void sv_log_obj(srt_string **log, const srt_vector *v) 36 | { 37 | size_t elems; 38 | enum eSV_Type t; 39 | size_t elem_size, i; 40 | srt_string *aux; 41 | const char *buf; 42 | if (!log) 43 | return; 44 | elems = sd_size((const srt_data *)v); 45 | t = v ? (enum eSV_Type)v->d.sub_type : SV_GEN; 46 | elem_size = v ? v->d.elem_size : 0; 47 | ss_cat_printf(log, 512, 48 | "srt_vector: t: %s, elem size: " FMT_ZU ", sz: " FMT_ZU 49 | ", { ", 50 | sv_type_to_label(t), elem_size, elems); 51 | i = 0; 52 | aux = ss_alloca(elem_size * 2); 53 | buf = (const char *)sv_get_buffer_r(v); 54 | for (; i < elems; i++) { 55 | ss_cpy_cn(&aux, buf + i * elem_size, elem_size); 56 | ss_cat_enc_hex(log, aux); 57 | if (i + 1 < elems) 58 | ss_cat_cn(log, ", ", 2); 59 | } 60 | ss_cat_c(log, " }\n"); 61 | } 62 | 63 | struct st_log_context_data { 64 | srt_string **log; 65 | ss_cat_stn tf; 66 | }; 67 | 68 | static int aux_st_log_traverse(struct STraverseParams *tp) 69 | { 70 | struct st_log_context_data *d = 71 | (struct st_log_context_data *)tp->context; 72 | if (tp->c == ST_NIL) { 73 | ss_cat_printf(d->log, 128, "\nLevel: %u\n", 74 | (unsigned)tp->level); 75 | } else { 76 | const srt_tnode *cn = get_node_r(tp->t, tp->c); 77 | d->tf(d->log, cn, tp->c); 78 | ss_cat_c(d->log, " "); 79 | } 80 | return 0; 81 | } 82 | 83 | void st_log_obj(srt_string **log, const srt_tree *t, ss_cat_stn f) 84 | { 85 | ssize_t levels; 86 | struct st_log_context_data context = {log, f}; 87 | if (!log) 88 | return; 89 | ss_cpy_c(log, ""); 90 | levels = st_traverse_levelorder(t, aux_st_log_traverse, &context); 91 | if (levels == 0) 92 | ss_cat_c(log, "empty tree"); 93 | else 94 | ss_cat_printf(log, 128, "\nlevels: %i, nodes: %u\n", 95 | (int)levels, (unsigned)st_size(t)); 96 | fprintf(stdout, "%s", ss_to_c(*log)); 97 | } 98 | 99 | static void ndx2s(char *out, size_t out_max, srt_tndx id) 100 | { 101 | if (id == ST_NIL) 102 | strcpy(out, "nil"); 103 | else 104 | snprintf(out, out_max, "%u", (unsigned)id); 105 | } 106 | 107 | static int aux_sm_log_traverse(struct STraverseParams *tp) 108 | { 109 | char id[128], l[128], r[128]; 110 | char k[4096] = "", v[4096] = ""; 111 | srt_string **log = (srt_string **)tp->context; 112 | const srt_tnode *cn; 113 | if (tp->c == ST_NIL) { 114 | ss_cat_printf(log, 128, "\nLevel: %u\n", (unsigned)tp->level); 115 | return 0; 116 | } 117 | cn = get_node_r(tp->t, tp->c); 118 | switch (tp->t->d.sub_type) { 119 | case SM_II32: 120 | sprintf(k, FMT_I32, ((const struct SMapii *)cn)->x.k); 121 | sprintf(v, FMT_I32, ((const struct SMapii *)cn)->v); 122 | break; 123 | case SM_UU32: 124 | sprintf(k, FMT_U32, ((const struct SMapuu *)cn)->x.k); 125 | sprintf(v, FMT_U32, ((const struct SMapuu *)cn)->v); 126 | break; 127 | case SM_II: 128 | case SM_IS: 129 | case SM_IP: 130 | sprintf(k, FMT_I, ((const struct SMapI *)cn)->k); 131 | break; 132 | case SM_SI: 133 | sprintf(k, "%s", 134 | ss_to_c(sso_get((const srt_stringo *)&( 135 | (const struct SMapSI *)cn) 136 | ->x.k))); 137 | break; 138 | case SM_SS: 139 | case SM_SP: 140 | sprintf(k, "%s", 141 | ss_to_c(sso_get( 142 | (const srt_stringo *)&((const struct SMapS *)cn) 143 | ->k))); 144 | break; 145 | } 146 | switch (tp->t->d.sub_type) { 147 | case SM_II: 148 | sprintf(v, FMT_I, ((const struct SMapII *)cn)->v); 149 | break; 150 | case SM_SI: 151 | sprintf(v, FMT_I, ((const struct SMapSI *)cn)->v); 152 | break; 153 | case SM_IS: 154 | sprintf(k, "%s", 155 | ss_to_c(sso_get((const srt_stringo *)&( 156 | (const struct SMapIS *)cn) 157 | ->v))); 158 | break; 159 | case SM_IP: 160 | sprintf(k, "%p", (const void *)((const struct SMapIP *)cn)->v); 161 | break; 162 | case SM_SS: 163 | sprintf(k, "%s", 164 | ss_to_c(sso_get(&((const struct SMapSS *)cn)->s))); 165 | break; 166 | case SM_SP: 167 | sprintf(k, "%p", (const void *)((const struct SMapSP *)cn)->v); 168 | break; 169 | } 170 | ndx2s(id, sizeof(id), tp->c); 171 | ndx2s(l, sizeof(l), cn->x.l); 172 | ndx2s(r, sizeof(r), cn->r); 173 | ss_cat_printf(log, 128, "[%s: (%s, %s) -> (%s, %s; r:%u)] ", id, k, v, 174 | l, r, cn->x.is_red); 175 | return 0; 176 | } 177 | 178 | void sm_log_obj(srt_string **log, const srt_map *m) 179 | { 180 | ssize_t levels; 181 | if (!log) 182 | return; 183 | ss_cpy_c(log, ""); 184 | levels = st_traverse_levelorder((const srt_tree *)m, 185 | (st_traverse)aux_sm_log_traverse, log); 186 | if (levels == 0) 187 | ss_cat_c(log, "empty map"); 188 | else 189 | ss_cat_printf(log, 128, "\nlevels: %i, nodes: %u\n", 190 | (int)levels, (unsigned)st_size(m)); 191 | fprintf(stdout, "%s", ss_to_c(*log)); 192 | } 193 | 194 | void shm_log_obj(srt_string **log, const srt_hmap *h) 195 | { 196 | size_t es, i; 197 | const struct SHMBucket *b; 198 | const struct SHMapii *e; 199 | if (!log) 200 | return; 201 | ss_cpy_c(log, ""); 202 | switch (h->d.sub_type) { 203 | case SHM0_II32: 204 | case SHM0_UU32: 205 | b = shm_get_buckets_r(h); 206 | e = (const struct SHMapii *)shm_get_buffer_r(h); 207 | ss_cat_printf(log, 128, 208 | "hbits: %u, size: " FMT_ZU ", max_size: " FMT_ZU 209 | "\n", 210 | h->hbits, shm_size(h), shm_max_size(h)); 211 | for (i = 0; i < (size_t)h->hmask + 1; i++) { 212 | ss_cat_printf(log, 128, 213 | "b[" FMT_ZU 214 | "] h: %08x " 215 | "l: %u cnt: %u\n", 216 | i, b[i].hash, b[i].loc, b[i].cnt); 217 | } 218 | es = shm_size(h); 219 | for (i = 0; i < es; i++) 220 | ss_cat_printf(log, 128, "e[" FMT_ZU "] kv: %u, %u\n", i, 221 | e[i].x.k, e[i].v); 222 | break; 223 | default: 224 | ss_cpy_c(log, "[not implemented]"); 225 | break; 226 | } 227 | } 228 | 229 | void s_hex_dump(srt_string **log, const char *label, const char *buf, 230 | size_t buf_size) 231 | { 232 | srt_string *aux; 233 | if (!log) 234 | return; 235 | aux = ss_dup_cn(buf, buf_size); 236 | if (label) 237 | ss_cat_c(log, label); 238 | ss_cat_enc_hex(log, aux); 239 | ss_free(&aux); 240 | } 241 | -------------------------------------------------------------------------------- /src/saux/sdbg.h: -------------------------------------------------------------------------------- 1 | #ifndef SDBG_H 2 | #define SDBG_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * sdbg.h 9 | * 10 | * Debug helpers (data formatting, etc.). 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | * 15 | * Observations: 16 | * - This is intended for debugging. 17 | */ 18 | 19 | #include "../shmap.h" 20 | #include "../smap.h" 21 | #include "../sstring.h" 22 | #include "../svector.h" 23 | #include "stree.h" 24 | 25 | typedef srt_string *(*ss_cat_stn)(srt_string **s, const srt_tnode *n, const srt_tndx id); 26 | 27 | const char *sv_type_to_label(enum eSV_Type t); 28 | void sv_log_obj(srt_string **log, const srt_vector *v); 29 | void st_log_obj(srt_string **log, const srt_tree *t, ss_cat_stn f); 30 | void sm_log_obj(srt_string **log, const srt_map *m); 31 | void shm_log_obj(srt_string **log, const srt_hmap *h); 32 | void s_hex_dump(srt_string **log, const char *label, const char *buf, size_t buf_size); 33 | 34 | #ifdef __cplusplus 35 | } /* extern "C" { */ 36 | #endif 37 | #endif /* SDBG_H */ 38 | -------------------------------------------------------------------------------- /src/saux/senc.h: -------------------------------------------------------------------------------- 1 | #ifndef SENC_H 2 | #define SENC_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * senc.h 9 | * 10 | * Buffer encoding/decoding 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | * 15 | * Features (base64 and hex encoding/decoding): 16 | * 17 | * - Aliasing safe (input and output buffer can be the same). 18 | * - RFC 3548/4648 base 16 (hexadecimal) and 64 encoding/decoding. 19 | * - Fast (~1 GB/s on i5-3330 @3GHz -using one core- and gcc 4.8.2 -O2) 20 | * 21 | * Features (JSON and XML escape/unescape): 22 | * 23 | * - Aliasing safe. 24 | * - JSON escape subset of RFC 4627 25 | * - XML escape subset of XML 1.0 W3C 26 Nov 2008 (4.6 Predefined Entities) 26 | * - Fast decoding (~1 GB/s on i5-3330 @3GHz -using one core-) 27 | * - "Fast" decoding (200-400 MB/s on "; there is room for optimization) 28 | * 29 | * Features (custom LZ77 implementation): 30 | * 31 | * - Encoding time complexity: O(n) 32 | * - Decoding time complexity: O(n) 33 | * 34 | * Observations: 35 | * - Tables take 288 bytes (could be reduced to 248 bytes -tweaking access 36 | * to b64d[]-, but it would require to increase the number of operations in 37 | * order to shift -and secure- access to that area, being code increase more 38 | * than those 40 bytes). 39 | */ 40 | 41 | #include "scommon.h" 42 | 43 | #define SDEBUG_LZ_STATS 0 44 | 45 | typedef size_t (*srt_enc_f)(const uint8_t *s, size_t ss, uint8_t *o); 46 | typedef size_t (*srt_enc_f2)(const uint8_t *s, size_t ss, uint8_t *o, size_t known_sso); 47 | 48 | size_t senc_b64(const uint8_t *s, size_t ss, uint8_t *o); 49 | size_t sdec_b64(const uint8_t *s, size_t ss, uint8_t *o); 50 | size_t senc_hex(const uint8_t *s, size_t ss, uint8_t *o); 51 | size_t senc_HEX(const uint8_t *s, size_t ss, uint8_t *o); 52 | size_t sdec_hex(const uint8_t *s, size_t ss, uint8_t *o); 53 | size_t senc_esc_xml(const uint8_t *s, size_t ss, uint8_t *o, size_t known_sso); 54 | size_t sdec_esc_xml(const uint8_t *s, size_t ss, uint8_t *o); 55 | size_t senc_esc_json(const uint8_t *s, size_t ss, uint8_t *o, size_t known_sso); 56 | size_t sdec_esc_json(const uint8_t *s, size_t ss, uint8_t *o); 57 | size_t senc_esc_url(const uint8_t *s, size_t ss, uint8_t *o, size_t known_sso); 58 | size_t sdec_esc_url(const uint8_t *s, size_t ss, uint8_t *o); 59 | size_t senc_esc_dquote(const uint8_t *s, size_t ss, uint8_t *o, size_t known_sso); 60 | size_t sdec_esc_dquote(const uint8_t *s, size_t ss, uint8_t *o); 61 | size_t senc_esc_squote(const uint8_t *s, size_t ss, uint8_t *o, size_t known_sso); 62 | size_t sdec_esc_squote(const uint8_t *s, size_t ss, uint8_t *o); 63 | size_t senc_lz(const uint8_t *s, size_t ss, uint8_t *o); 64 | size_t senc_lzh(const uint8_t *s, size_t ss, uint8_t *o); 65 | size_t sdec_lz(const uint8_t *s, size_t ss, uint8_t *o); 66 | 67 | #define senc_b16 senc_HEX 68 | #define sdec_b16 sdec_hex 69 | 70 | #ifdef __cplusplus 71 | } /* extern "C" { */ 72 | #endif 73 | #endif /* SENC_H */ 74 | -------------------------------------------------------------------------------- /src/saux/shash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * shash.c 3 | * 4 | * Buffer hashing 5 | * 6 | * Copyright (c) 2015-2021 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "shash.h" 11 | 12 | /* 13 | * Constants 14 | */ 15 | 16 | #define S_CRC32_POLY 0xedb88320 17 | #define S_FNV_PRIME ((uint32_t)0x01000193) 18 | #define MH3_32_C1 0xcc9e2d51 19 | #define MH3_32_C2 0x1b873593 20 | 21 | /* 22 | * CRC-32 implementations 23 | */ 24 | 25 | #ifndef S_BUILD_CRC32_TABLES 26 | 27 | #if defined __ARM_FEATURE_CRC32 && __ARM_FEATURE_CRC32 28 | 29 | #define ARMv8_CRC32X(crc, u64) \ 30 | __asm__("crc32x %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(u64)) 31 | #define ARMv8_CRC32W(crc, u32) \ 32 | __asm__("crc32w %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(u32)) 33 | #define ARMv8_CRC32B(crc, u8) \ 34 | __asm__("crc32b %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(u8)) 35 | 36 | uint32_t sh_crc32(uint32_t crc, const void *buf, size_t buf_size) 37 | { 38 | size_t i, bs4, bs8; 39 | const uint8_t *p = (const uint8_t *)buf; 40 | RETURN_IF(!buf, S_CRC32_INIT); 41 | crc = ~crc; 42 | bs8 = (buf_size / 8) * 8; 43 | for (i = 0; i < bs8; i += 8) 44 | ARMv8_CRC32X(crc, *((uint64_t *)(p + i))); 45 | bs4 = (buf_size / 4) * 4; 46 | for (; i < bs4; i += 4) 47 | ARMv8_CRC32W(crc, *((uint32_t *)(p + i))); 48 | for (; i < buf_size; i++) 49 | ARMv8_CRC32B(crc, p[i]); 50 | return ~crc; 51 | } 52 | 53 | #elif defined(S_MINIMAL) || (defined(S_CRC32_SLC) && S_CRC32_SLC == 0) 54 | 55 | /* 56 | * Compact implementation, without hash tables (one bit per loop) 57 | */ 58 | uint32_t sh_crc32(uint32_t crc, const void *buf, size_t buf_size) 59 | { 60 | size_t i, j; 61 | const uint8_t *p = (const uint8_t *)buf; 62 | RETURN_IF(!buf, S_CRC32_INIT); 63 | crc = ~crc; 64 | for (i = 0; i < buf_size; i++) { 65 | crc ^= p[i]; 66 | for (j = 0; j < 8; j++) { 67 | int b0 = crc & 1; 68 | crc >>= 1; 69 | if (b0) 70 | crc ^= S_CRC32_POLY; 71 | } 72 | } 73 | return ~crc; 74 | } 75 | 76 | #else 77 | 78 | #include "scrc32.h" 79 | 80 | #define S_U32_BYTE0(a) ((a)&0xff) 81 | #define S_U32_BYTE1(a) (((a) >> 8) & 0xff) 82 | #define S_U32_BYTE2(a) (((a) >> 16) & 0xff) 83 | #define S_U32_BYTE3(a) (((a) >> 24) & 0xff) 84 | #if S_CRC32_SLC == 4 85 | #define SC32A a 86 | #elif S_CRC32_SLC == 8 87 | #define SC32A b 88 | #define SC32B a 89 | #elif S_CRC32_SLC == 12 90 | #define SC32A c 91 | #define SC32B b 92 | #define SC32C a 93 | #else 94 | #define SC32A d 95 | #define SC32B c 96 | #define SC32C b 97 | #define SC32D a 98 | #endif 99 | 100 | /* 101 | * 1, 4, 8, 12, and 16 bytes per loop using 1024 to 16384 bytes table 102 | */ 103 | uint32_t sh_crc32(uint32_t crc, const void *buf, size_t buf_size) 104 | { 105 | #if S_CRC32_SLC >= 4 106 | size_t bsX; 107 | #endif 108 | size_t i; 109 | const uint8_t *p; 110 | RETURN_IF(!buf, S_CRC32_INIT); 111 | i = 0; 112 | p = (const uint8_t *)buf; 113 | crc = ~crc; 114 | #if (S_CRC32_SLC == 4 || S_CRC32_SLC == 8 || S_CRC32_SLC == 12 \ 115 | || S_CRC32_SLC == 16) 116 | bsX = (buf_size / S_CRC32_SLC) * S_CRC32_SLC; 117 | for (; i < bsX; i += S_CRC32_SLC) { 118 | uint32_t a = S_LD_LE_U32(p + i) ^ crc 119 | #if S_CRC32_SLC >= 8 120 | , 121 | b = S_LD_LE_U32(p + i + 4) 122 | #endif 123 | #if S_CRC32_SLC >= 12 124 | , 125 | c = S_LD_LE_U32(p + i + 8) 126 | #endif 127 | #if S_CRC32_SLC == 16 128 | , 129 | d = S_LD_LE_U32(p + i + 12) 130 | #endif 131 | ; 132 | crc = crc32_tab[0][S_U32_BYTE3(SC32A)] 133 | ^ crc32_tab[1][S_U32_BYTE2(SC32A)] 134 | ^ crc32_tab[2][S_U32_BYTE1(SC32A)] 135 | ^ crc32_tab[3][S_U32_BYTE0(SC32A)] 136 | #if S_CRC32_SLC >= 8 137 | ^ crc32_tab[4][S_U32_BYTE3(SC32B)] 138 | ^ crc32_tab[5][S_U32_BYTE2(SC32B)] 139 | ^ crc32_tab[6][S_U32_BYTE1(SC32B)] 140 | ^ crc32_tab[7][S_U32_BYTE0(SC32B)] 141 | #endif 142 | #if S_CRC32_SLC >= 12 143 | ^ crc32_tab[8][S_U32_BYTE3(SC32C)] 144 | ^ crc32_tab[9][S_U32_BYTE2(SC32C)] 145 | ^ crc32_tab[10][S_U32_BYTE1(SC32C)] 146 | ^ crc32_tab[11][S_U32_BYTE0(SC32C)] 147 | #endif 148 | #if S_CRC32_SLC == 16 149 | ^ crc32_tab[12][S_U32_BYTE3(SC32D)] 150 | ^ crc32_tab[13][S_U32_BYTE2(SC32D)] 151 | ^ crc32_tab[14][S_U32_BYTE1(SC32D)] 152 | ^ crc32_tab[15][S_U32_BYTE0(SC32D)] 153 | #endif 154 | ; 155 | } 156 | #endif 157 | for (; i < buf_size; i++) 158 | crc = crc32_tab[0][(crc ^ p[i]) & 0xff] ^ (crc >> 8); 159 | return ~crc; 160 | } 161 | 162 | #endif /* #ifdef S_MINIMAL */ 163 | 164 | #define ADLER32_BASE 65521 /* Largest prime below 2^16 */ 165 | #define ADLER32_NMAX 5552 166 | 167 | uint32_t sh_adler32(uint32_t adler, const void *buf0, size_t buf_size) 168 | { 169 | uint32_t s1, s2; 170 | size_t remaining, k; 171 | const unsigned char *buf; 172 | RETURN_IF(!buf0, S_ADLER32_INIT); 173 | remaining = buf_size; 174 | buf = (const unsigned char *)buf0; 175 | s1 = (adler & 0xffff); 176 | s2 = (adler >> 16) & 0xffff; 177 | for (; remaining > 0; s1 %= ADLER32_BASE, s2 %= ADLER32_BASE) { 178 | k = remaining < ADLER32_NMAX ? remaining : ADLER32_NMAX; 179 | remaining -= k; 180 | for (; k >= 16; buf += 16, k -= 16) { 181 | s1 += buf[0]; 182 | s2 += s1; 183 | s1 += buf[1]; 184 | s2 += s1; 185 | s1 += buf[2]; 186 | s2 += s1; 187 | s1 += buf[3]; 188 | s2 += s1; 189 | s1 += buf[4]; 190 | s2 += s1; 191 | s1 += buf[5]; 192 | s2 += s1; 193 | s1 += buf[6]; 194 | s2 += s1; 195 | s1 += buf[7]; 196 | s2 += s1; 197 | s1 += buf[8]; 198 | s2 += s1; 199 | s1 += buf[9]; 200 | s2 += s1; 201 | s1 += buf[10]; 202 | s2 += s1; 203 | s1 += buf[11]; 204 | s2 += s1; 205 | s1 += buf[12]; 206 | s2 += s1; 207 | s1 += buf[13]; 208 | s2 += s1; 209 | s1 += buf[14]; 210 | s2 += s1; 211 | s1 += buf[15]; 212 | s2 += s1; 213 | } 214 | for (; k > 0; k--, s1 += *buf++, s2 += s1) 215 | ; 216 | } 217 | return (s2 << 16) | s1; 218 | } 219 | 220 | uint32_t sh_fnv1(uint32_t fnv, const void *buf0, size_t buf_size) 221 | { 222 | size_t i; 223 | const uint8_t *buf = (const uint8_t *)buf0; 224 | for (i = 0; i < buf_size; i++) { 225 | fnv *= S_FNV_PRIME; 226 | fnv ^= buf[i]; 227 | } 228 | return fnv; 229 | } 230 | 231 | uint32_t sh_fnv1a(uint32_t fnv, const void *buf0, size_t buf_size) 232 | { 233 | size_t i; 234 | const uint8_t *buf = (const uint8_t *)buf0; 235 | for (i = 0; i < buf_size; i++) { 236 | fnv ^= buf[i]; 237 | fnv *= S_FNV_PRIME; 238 | } 239 | return fnv; 240 | } 241 | 242 | S_INLINE uint32_t rotl32(uint32_t x, int r) 243 | { 244 | return (x << r) | (x >> (32 - r)); 245 | } 246 | 247 | uint32_t sh_mh3_32(uint32_t acc, const void *buf, size_t buf_size) 248 | { 249 | uint32_t h = acc, k; 250 | size_t i, l4 = (buf_size / 4) * 4; 251 | const uint8_t *data = (const uint8_t *)buf; 252 | /* body: 4 bytes per loop */ 253 | for (i = 0; i < l4; i += 4) { 254 | k = S_LD_LE_U32(data + i) * MH3_32_C1; 255 | k = rotl32(k, 15) * MH3_32_C2; 256 | h = (rotl32(h ^ k, 13) * 5) + 0xe6546b64; 257 | } 258 | /* tail */ 259 | k = 0; 260 | switch (buf_size & 3) { 261 | case 3: 262 | k ^= (uint32_t)(data[i + 2] << 16); 263 | /* fallthrough */ 264 | case 2: 265 | k ^= (uint32_t)(data[i + 1] << 8); 266 | /* fallthrough */ 267 | case 1: 268 | k ^= data[i]; 269 | k *= MH3_32_C1; 270 | k = rotl32(k, 15) * MH3_32_C2; 271 | h ^= k; 272 | break; 273 | } 274 | /* avalanche */ 275 | h ^= buf_size; 276 | h ^= h >> 16; 277 | h *= 0x85ebca6b; 278 | h ^= h >> 13; 279 | h *= 0xc2b2ae35; 280 | h ^= h >> 16; 281 | return h; 282 | } 283 | 284 | #else 285 | 286 | /* 287 | * gcc shash.c -DS_BUILD_CRC32_TABLES -o a ; ./a >scrc32.h 288 | */ 289 | int main(int argc, const char **argv) 290 | { 291 | /* 292 | * Generation of scrc32.h content 293 | * 294 | * Learned from: 295 | * https://web.archive.org/web/20121011093914/http://www.intel.com 296 | * /technology/comms/perfnet/download/CRC_generators.pdf 297 | * http://create.stephan-brumme.com/crc32/ 298 | */ 299 | size_t i, j; 300 | uint32_t c32t[16][256]; 301 | for (i = 0; i < 256; i++) { 302 | uint32_t crc = i; 303 | for (j = 0; j < 8; j++) { 304 | int b0 = crc & 1; 305 | crc >>= 1; 306 | if (b0) 307 | crc ^= S_CRC32_POLY; 308 | } 309 | c32t[0][i] = crc; 310 | } 311 | for (j = 1; j < 16; j++) { 312 | for (i = 0; i < 256; i++) { 313 | #define C32L(s) \ 314 | c32t[s][i] = (c32t[s - 1][i] >> 8) ^ c32t[0][c32t[s - 1][i] & 0xff]; 315 | C32L(1); 316 | C32L(2); 317 | C32L(3); 318 | C32L(4); 319 | C32L(5); 320 | C32L(6); 321 | C32L(7); 322 | C32L(8); 323 | C32L(9); 324 | C32L(10); 325 | C32L(11); 326 | C32L(12); 327 | C32L(13); 328 | C32L(14); 329 | C32L(15); 330 | } 331 | } 332 | /* 333 | * Flush table to the output 334 | */ 335 | printf("/*\n" 336 | " * scrc32.h\n" 337 | " *\n" 338 | " * Precomputed CRC-32 for polynomial 0x%08x\n" 339 | " * (gcc shash.c -DS_BUILD_CRC32_TABLES -o a; ./a >scrc32.h)\n" 340 | " *\n" 341 | " * " LIBSRT_COPYRIGHT 342 | "\n" 343 | " * " LIBSRT_LICENSE 344 | "\n" 345 | " */\n\n" 346 | "#ifndef SCRC32_H\n" 347 | "#define SCRC32_H\n\n" 348 | "#ifndef S_CRC32_SLC\n" 349 | "#define S_CRC32_SLC 12\n" 350 | "#else\n" 351 | "#if S_CRC32_SLC != 0 && S_CRC32_SLC != 1 && " 352 | "S_CRC32_SLC != 4 && \\\n" 353 | " S_CRC32_SLC != 8 && S_CRC32_SLC != 12 && " 354 | "S_CRC32_SLC != 16\n" 355 | "#undef S_CRC32_SLC /* if invalid slice size, default to 1 */\n" 356 | "#define S_CRC32_SLC 1\n" 357 | "#endif\n" 358 | "#endif\n\n" 359 | "#if S_CRC32_SLC > 0\n\n" 360 | "static const uint32_t crc32_tab[S_CRC32_SLC][256] = {\n", 361 | S_CRC32_POLY); 362 | int rows = 6; 363 | for (i = 0; i < 16; i++) { 364 | printf("\t{\n\t"); 365 | for (j = 0; j < 256; j++) { 366 | printf("0x%08x", (unsigned)c32t[i][j]); 367 | if (j < 255) { 368 | if ((j % rows) == (rows - 1)) 369 | printf(",\n\t"); 370 | else 371 | printf(", "); 372 | } 373 | } 374 | printf("\n\t}"); 375 | switch (i) { 376 | case 0: 377 | printf("\n#if S_CRC32_SLC >= 4\n\t,"); 378 | break; 379 | case 3: 380 | printf("\n#endif /*#if S_CRC32_SLC >= 4*/"); 381 | printf("\n#if S_CRC32_SLC >= 8\n\t,"); 382 | break; 383 | case 7: 384 | printf("\n#endif /*#if S_CRC32_SLC >= 8*/"); 385 | printf("\n#if S_CRC32_SLC >= 12\n\t,"); 386 | break; 387 | case 11: 388 | printf("\n#endif /*#if S_CRC32_SLC >= 12*/"); 389 | printf("\n#if S_CRC32_SLC >= 16\n\t,"); 390 | break; 391 | case 15: 392 | printf("\n#endif /*#if S_CRC32_SLC >= 16*/\n"); 393 | break; 394 | default: 395 | printf(","); 396 | } 397 | printf("\n"); 398 | } 399 | printf("};\n\n" 400 | "#endif /*#if S_CRC32_SLC > 0*/\n\n" 401 | "#endif /* #ifdef SCRC32_H */\n\n"); 402 | } 403 | 404 | #endif /* #ifndef S_BUILD_CRC32_TABLES */ 405 | -------------------------------------------------------------------------------- /src/saux/shash.h: -------------------------------------------------------------------------------- 1 | #ifndef SHASH_H 2 | #define SHASH_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * shash.h 9 | * 10 | * Buffer hashing 11 | * 12 | * Copyright (c) 2015-2020 F. Aragon. All rights reserved. 13 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 14 | * 15 | * Features: 16 | * 17 | * - Six CRC-32 modes (make ADD_CFLAGS="-DS_CRC32_SLC=0/1/4/8/16"): 18 | * + Minimal, without hash tables: 1 bit/loop (100MB/s on i5@3GHz) 19 | * + 1024 byte hash table: 1 byte/loop (400MB/s on i5@3GHz) 20 | * + 4096 byte hash table: 4 bytes/loop (1000MB/s on i5@3GHz) 21 | * + 8192 byte hash table: 8 bytes/loop (2000MB/s on i5@3GHz) 22 | * + 12288 byte hash table: 12 bytes/loop (2500MB/s on i5@3GHz) 23 | * + 16384 byte hash table: 16 bytes/loop (2700MB/s on i5@3GHz) 24 | */ 25 | 26 | #include "scommon.h" 27 | 28 | /* Linux hashing algorithm for 32 and 64-bit values */ 29 | #define S_GR32 0x61C88647 30 | #define S_GR64 ((uint64_t)0x61C8864680B583EBULL) 31 | 32 | #define S_CRC32_INIT 0 33 | #define S_ADLER32_INIT 1 34 | #define S_FNV1_INIT ((uint32_t)0x811c9dc5) 35 | #define S_MH3_32_INIT 42 36 | 37 | /* #notAPI: |CRC-32 (0xedb88320 polynomial)|CRC accumulator (for offset 0 must be 0);buffer;buffer size (in bytes)|32-bit hash|O(n)|1;2| */ 38 | uint32_t sh_crc32(uint32_t crc, const void *buf, size_t buf_size); 39 | /* #notAPI: |Adler32 checksum|Adler32 accumulator (for offset 0 must be 1);buffer;buffer size (in bytes)|32-bit hash|O(n)|1;2| */ 40 | uint32_t sh_adler32(uint32_t adler, const void *buf, size_t buf_size); 41 | /* #notAPI: |FNV-1 hash|FNV accumulator (for offset 0 must be S_FNV_INIT);buffer;buffer size (in bytes)|32-bit hash|O(n)|1;2| */ 42 | uint32_t sh_fnv1(uint32_t fnv, const void *buf, size_t buf_size); 43 | /* #notAPI: |FNV-1A hash|FNV-1A accumulator (for offset 0 must be S_FNV1A_INIT);buffer;buffer size (in bytes)|32-bit hash|O(n)|1;2| */ 44 | uint32_t sh_fnv1a(uint32_t fnv, const void *buf, size_t buf_size); 45 | /* #notAPI: |MurmurHash3-32 hash|MH3 accumulator (for offset 0 must be S_MM3_32_INIT);buffer;buffer size (in bytes)|32-bit hash|O(n)|1;2| */ 46 | uint32_t sh_mh3_32(uint32_t acc, const void *buf, size_t buf_size); 47 | 48 | S_INLINE uint32_t sh_hash32(uint32_t v) 49 | { 50 | return (v * S_GR32); 51 | } 52 | 53 | S_INLINE uint32_t sh_hash64(uint64_t v) 54 | { 55 | return (uint32_t)(v * S_GR64); 56 | } 57 | 58 | // Floating point hashing: if matches the size of integers, use the 59 | // integer hash. Otherwise, use FNV-1A hashing. 60 | 61 | S_INLINE uint32_t sh_hash_f(float v) 62 | { 63 | uint32_t v32; 64 | if (sizeof(v) == sizeof(v32)) { 65 | memcpy(&v32, &v, sizeof(v)); 66 | return sh_hash32(v32); 67 | } 68 | return sh_fnv1a(S_FNV1_INIT, &v, sizeof(v)); 69 | } 70 | 71 | S_INLINE uint32_t sh_hash_d(double v) 72 | { 73 | return sh_fnv1a(S_FNV1_INIT, &v, sizeof(v)); 74 | } 75 | 76 | #ifdef __cplusplus 77 | } /* extern "C" { */ 78 | #endif 79 | #endif /* SHASH_H */ 80 | -------------------------------------------------------------------------------- /src/saux/ssearch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ssearch.c 3 | * 4 | * Real-time string search using the Rabin-Karp algorithm. 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "ssearch.h" 11 | #include "scommon.h" 12 | 13 | #ifndef S_DISABLE_SEARCH_GUARANTEE 14 | #define S_ENABLE_FIND_CSUM_FAST_TO_SLOW_ALGORITHM_SWITCH 15 | #endif 16 | 17 | /* 18 | * ss_find_csum_* helpers 19 | */ 20 | #define FCSUM_FAST(p, q, i) ((unsigned char)q[i]) 21 | #define FCSUM_SLOW(p, q, i) \ 22 | ((2 * (1 + (unsigned char)p[i - 1])) + (unsigned char)q[i]) 23 | #define S_FPREPARECSUM(CSUMF, i) \ 24 | ((target += CSUMF(t, t, i)), current += CSUMF(s, s, i)) 25 | #define S_FWINDOW_MOVE(CSUMF, s, i) (CSUMF(s, s, i) - CSUMF(s, s, 1 + i - ts)) 26 | #define S_FSEARCH(CSUMF) \ 27 | (((current += S_FWINDOW_MOVE(CSUMF, s, 0)), s++, current) == target) 28 | #define S_FCSUM_RETURN_CHECK \ 29 | if (!memcmp(s - ts, t, ts)) \ 30 | return (size_t)((size_t)(s - s0) - ts) 31 | #define S_FCSUM_RETURN_CHECK_W_ALGORITHM_SWITCH \ 32 | if (!csum_collision_off) { \ 33 | csum_collision_off = (size_t)((size_t)(s - s0) - off); \ 34 | csum_collision_count = 1; \ 35 | } else { \ 36 | if ((size_t)(s - s0) - csum_collision_off > ts * 10) { \ 37 | csum_collision_off = (size_t)(s - s0); /* reset */ \ 38 | csum_collision_count = 1; \ 39 | } else { \ 40 | if (++csum_collision_count > (2 + ts / 2)) { \ 41 | return ss_find_csum_slow(s0, (size_t)(s - s0), \ 42 | ss, t, ts); \ 43 | } \ 44 | } \ 45 | } 46 | #ifdef S_ENABLE_FIND_CSUM_FAST_TO_SLOW_ALGORITHM_SWITCH 47 | #define S_FIND_CSUM_ALG_SWITCH_SETUP \ 48 | size_t csum_collision_off = 0, csum_collision_count = 0 49 | #define S_FIND_CSUM_ALG_SWITCH S_FCSUM_RETURN_CHECK_W_ALGORITHM_SWITCH 50 | #else 51 | #define S_FIND_CSUM_ALG_SWITCH_SETUP 52 | #define S_FIND_CSUM_ALG_SWITCH 53 | #endif 54 | 55 | /* 56 | * ss_find_csum_* templates for pipeline fill phase 57 | */ 58 | #ifdef S_ENABLE_FIND_CSUM_FIRST_CHAR_LOCATION_OPTIMIZATION 59 | #define S_FIND_SET_START \ 60 | size_t i; \ 61 | const char *stm1; \ 62 | unsigned int target, current; \ 63 | const char *s = (const char *)memchr(s0 + off, *t, ss - off); 64 | #else 65 | #define S_FIND_SET_START \ 66 | size_t i; \ 67 | const char *stm1; \ 68 | unsigned int target, current; \ 69 | const char *s = (const char *)(s0 + off); 70 | #endif 71 | #define S_FIND_CSUM_PIPELINE1(alg) \ 72 | S_FIND_SET_START; \ 73 | if (!s || (ss - (size_t)(s - s0)) < ts) \ 74 | return S_NPOS; \ 75 | i = 1; \ 76 | stm1 = s0 + ss - 1; \ 77 | target = 0, current = 0; 78 | #ifdef S_ENABLE_FIND_CSUM_INNER_LOOP_UNROLLING 79 | #define S_FIND_CSUM_PIPELINE2(alg) \ 80 | for (; (i + 4) < ts; i += 4) { \ 81 | S_FPREPARECSUM(alg, i); \ 82 | S_FPREPARECSUM(alg, i + 1); \ 83 | S_FPREPARECSUM(alg, i + 2); \ 84 | S_FPREPARECSUM(alg, i + 3); \ 85 | } 86 | #else 87 | #define S_FIND_CSUM_PIPELINE2(alg) 88 | #endif 89 | #define S_FIND_CSUM_PIPELINE3(alg) \ 90 | for (; i < ts; i++) { \ 91 | S_FPREPARECSUM(alg, i); \ 92 | } \ 93 | if (current == target && !memcmp(s, t, ts)) \ 94 | return (size_t)(s - s0); /* found: prefix */ \ 95 | s += ts; 96 | 97 | /* 98 | * ss_find_csum_* templates for search phase 99 | */ 100 | #ifdef S_ENABLE_FIND_CSUM_INNER_LOOP_UNROLLING 101 | #define S_FIND_CSUM_SEARCH1(alg, extra_check) \ 102 | for (; (s + 16) <= stm1;) { \ 103 | if ((S_FSEARCH(alg) || S_FSEARCH(alg) || S_FSEARCH(alg) \ 104 | || S_FSEARCH(alg) || S_FSEARCH(alg) || S_FSEARCH(alg) \ 105 | || S_FSEARCH(alg) || S_FSEARCH(alg) || S_FSEARCH(alg) \ 106 | || S_FSEARCH(alg) || S_FSEARCH(alg) || S_FSEARCH(alg) \ 107 | || S_FSEARCH(alg) || S_FSEARCH(alg) || S_FSEARCH(alg) \ 108 | || S_FSEARCH(alg))) { \ 109 | S_FCSUM_RETURN_CHECK; \ 110 | extra_check; \ 111 | } \ 112 | } 113 | #else 114 | #define S_FIND_CSUM_SEARCH1(alg, extra_check) 115 | #endif 116 | #define S_FIND_CSUM_SEARCH2(alg, extra_check) \ 117 | for (; s <= stm1;) { \ 118 | if (S_FSEARCH(alg)) { \ 119 | S_FCSUM_RETURN_CHECK; \ 120 | extra_check; \ 121 | } \ 122 | } 123 | 124 | size_t ss_find_csum_slow(const char *s0, size_t off, size_t ss, const char *t, 125 | size_t ts) 126 | { 127 | S_FIND_CSUM_PIPELINE1(FCSUM_SLOW); 128 | S_FIND_CSUM_PIPELINE2(FCSUM_SLOW); 129 | S_FIND_CSUM_PIPELINE3(FCSUM_SLOW); 130 | S_FIND_CSUM_SEARCH1(FCSUM_SLOW, {}); 131 | S_FIND_CSUM_SEARCH2(FCSUM_SLOW, {}); 132 | return S_NPOS; 133 | } 134 | 135 | size_t ss_find_csum_fast(const char *s0, size_t off, size_t ss, const char *t, 136 | size_t ts) 137 | { 138 | S_FIND_CSUM_ALG_SWITCH_SETUP; 139 | S_FIND_CSUM_PIPELINE1(FCSUM_FAST); 140 | S_FIND_CSUM_PIPELINE2(FCSUM_FAST); 141 | S_FIND_CSUM_PIPELINE3(FCSUM_FAST); 142 | S_FIND_CSUM_SEARCH1(FCSUM_FAST, S_FIND_CSUM_ALG_SWITCH); 143 | S_FIND_CSUM_SEARCH2(FCSUM_FAST, S_FIND_CSUM_ALG_SWITCH); 144 | return S_NPOS; 145 | } 146 | -------------------------------------------------------------------------------- /src/saux/ssearch.h: -------------------------------------------------------------------------------- 1 | #ifndef SSEARCH_H 2 | #define SSEARCH_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include "scommon.h" 8 | 9 | /* 10 | * ssearch.h 11 | * 12 | * Real-time string search using the Rabin-Karp algorithm. 13 | * 14 | * Features: 15 | * - Real-time search (O(n) time complexity). 16 | * - Search in raw data. 17 | * - Over 1 GB/s sustained speed on 3-way 3GHz OooE CPU (single thread). 18 | * 19 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 20 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 21 | * 22 | * O(n) string search using a rolling hash. Two hashes are used, one more 23 | * complex ((f(t-1) + 1) * 2 + f(t)), to ensure O(n) time, and othersimple 24 | * (sum of bytes), so the algorithm can start in the "fast" mode, and switch 25 | * to the O(n) compliant when collisons for a given period are above an 26 | * specific threshold. 27 | * 28 | * Being n the elements of the string and m the elements of the pattern to 29 | * be found: 30 | * - Worst time (proof pending): 31 | * m * k1 operations for computing pattern checksum + 32 | * n * k2 operations for computing/comparing current checksum 33 | * - Other observations: 34 | * - No input pre-processing required. 35 | * - Suitable for real-time: predictable worst time (ss_find_csum_slow()) 36 | * - Although is O(n), for "good cases" is ~2-10x slower than best O(m*n). 37 | * In corner cases, however, this algorithm outperforms all O(n*m) 38 | * algorithms. 39 | * - Cached and uncached speed is similar on OooE CPUs (more CPU than 40 | * RAM limited), i.e. the RAM bus is not saturated (multi-core CPUs). 41 | * Over 1 GB/s sustained search speed is achieved on modern 3GHz OooE 42 | * single thread. 43 | * - The FCSUM_SLOW ensures O(n), FCSUM_FAST is about twice as fast on 44 | * worst-case scenarios, but does not ensure O(n). The algorithm starts 45 | * with the fast version, and switches to the slow case on the first false 46 | * CSUM mismatch. 47 | * - Could be easily expanded for finding more than one pattern at once 48 | * (like any other Rabin-Karp algorithm implementation). 49 | * 50 | * ss_find_csum_fast: O(n), because it switches to ss_find_csum_slow() when 51 | * collisions get over specific threshold per period. 52 | * ss_find_csum_slow: O(n) (half the speed of ss_find_csum_fast in good cases, 53 | * and just a bit faster in worst cases -as the "fast" algorithm switch 54 | * requires recomputing again the hash of the target pattern-). 55 | * 56 | * References: 57 | * - Rabin-Karp search algorithm (search using a rolling hash) 58 | * - Raphael Javaux's fast_strstr algorithm (simple hash case: sum of bytes) 59 | * 60 | * Other functions, implemented as examples: 61 | * ss_find_bf: O(n*m), the slowest (brute force). 62 | * ss_find_bmh: O(n*m), good average (Boyer-Moore-Horspool). 63 | * ss_find_libc: relies on libc strstr(), so don't support raw data. 64 | * 65 | * For "good cases", ss_find_csum_fast is 2-10x slower than e.g. strstr() 66 | * found in glibc ("Two-Way String-Matching" algorithm, O(n*m)). However, for 67 | * worst-case scenarios, is faster (O(n) < O(n*m)). I.e. ss_find_csum_* is 68 | * suitable for real-time requirements, while strstr ("Two-Way") it is not. 69 | * In comparison to e.g. glibc memmem(), which performs similar to 70 | * ss_find_bf(), the ss_find_csum_fast() is much faster. 71 | */ 72 | 73 | /* 74 | * Togglable options 75 | * 76 | * S_ENABLE_FIND_CSUM_FIRST_CHAR_LOCATION_OPTIMIZATION: skips data not 77 | * matching with first target byte. Disable in case you want to avoid 78 | * linking memchr(). 79 | * 80 | * S_ENABLE_FIND_CSUM_INNER_LOOP_UNROLLING: loop unrolling for both the 81 | * initialization and search phases. Disable for reducing code size. 82 | * 83 | * S_ENABLE_FIND_CSUM_FAST_TO_SLOW_ALGORITHM_SWITCH: this enables the 84 | * check for switching between the fast and the "slow" (O(n) compliant) 85 | * algorithm. Don't disable this unless you already know beforehand 86 | * about the data being processing and willing to squeze for performance. 87 | * Warning: it is a bad idea to disable this without a good reason, 88 | * as this ensures real-time requirements. 89 | * 90 | * S_ENABLE_FIND_OTHER_EXAMPLES: additional implementations (brute force, 91 | * Boyer-Moore-Horspool, strstr wrapper). Disabling this could save some 92 | * space on devices with little memory (e.g. microcontrollers). 93 | * 94 | * Instruction cache observation: code is tiny, even with unrolling. 95 | */ 96 | 97 | #define S_ENABLE_FIND_CSUM_FIRST_CHAR_LOCATION_OPTIMIZATION 98 | #define S_ENABLE_FIND_CSUM_INNER_LOOP_UNROLLING 99 | #define S_ENABLE_FIND_CSUM_FAST_TO_SLOW_ALGORITHM_SWITCH 100 | 101 | #ifdef S_MINIMAL 102 | #undef S_ENABLE_FIND_CSUM_FIRST_CHAR_LOCATION_OPTIMIZATION 103 | #undef S_ENABLE_FIND_CSUM_INNER_LOOP_UNROLLING 104 | #endif 105 | 106 | size_t ss_find_csum_slow(const char *s0, size_t off, size_t ss, const char *t, size_t ts); 107 | size_t ss_find_csum_fast(const char *s0, size_t off, size_t ss, const char *t, size_t ts); 108 | 109 | #ifdef __cplusplus 110 | } /* extern "C" { */ 111 | #endif 112 | #endif /* SSEARCH_H */ 113 | -------------------------------------------------------------------------------- /src/saux/ssort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ssort.c 3 | * 4 | * Sorting algorithms 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "ssort.h" 11 | 12 | /* 13 | * Templates 14 | */ 15 | 16 | #define BUILD_COUNT_SORT_x8(FN, T, CNT_T, OFF) \ 17 | S_INLINE void FN(T *b, size_t elems) \ 18 | { \ 19 | size_t i, j; \ 20 | CNT_T cnt[256]; \ 21 | memset(cnt, 0, sizeof(cnt)); \ 22 | for (i = 0; i < elems; i++) \ 23 | cnt[b[i] + (OFF)]++; \ 24 | for (i = j = 0; j < 256 && i < elems; j++) \ 25 | if (cnt[j]) { \ 26 | memset(b + i, (int)(j - (OFF)), cnt[j]); \ 27 | i += cnt[j]; \ 28 | } \ 29 | } 30 | 31 | #define BUILD_SWAP(FN, T) \ 32 | S_INLINE void FN(T *b, size_t i, size_t j) \ 33 | { \ 34 | T tmp = b[i]; \ 35 | b[i] = b[j]; \ 36 | b[j] = tmp; \ 37 | } 38 | 39 | #define BUILD_SORT2(FN, T, SWAPF) \ 40 | S_INLINE void FN(T *b) \ 41 | { \ 42 | if (b[0] > b[1]) \ 43 | SWAPF(b, 0, 1); \ 44 | } 45 | 46 | #define BUILD_SORT3(FN, T, SWAPF, SORT2F) \ 47 | S_INLINE void FN(T *b) \ 48 | { \ 49 | if (b[0] > b[2]) \ 50 | SWAPF(b, 0, 2); \ 51 | SORT2F(b); \ 52 | } 53 | 54 | #define BUILD_SORT4(FN, T, SWAPF, SORT2F) \ 55 | S_INLINE void FN(T *b) \ 56 | { \ 57 | SORT2F(b); \ 58 | SORT2F(b + 2); \ 59 | if (b[2] < b[0]) \ 60 | SWAPF(b, 0, 2); \ 61 | SORT2F(b + 1); \ 62 | if (b[2] < b[1]) \ 63 | SWAPF(b, 1, 2); \ 64 | SORT2F(b + 2); \ 65 | } 66 | 67 | #define BUILD_MSD_RADIX_SORT(FN, T, TC, MSBF, SWPF, S2F, S3F, S4F, OFF) \ 68 | static void FN##_aux(TC acc, TC msd_bit, T *b, size_t elems) \ 69 | { \ 70 | TC aux; \ 71 | size_t i = 0, j = elems - 1; \ 72 | for (; i < elems; i++) { \ 73 | aux = (TC)b[i] + (OFF); \ 74 | if ((aux & msd_bit) != 0) { \ 75 | for (; (((TC)b[j] + (OFF)) & msd_bit) != 0 \ 76 | && i < j; \ 77 | j--) \ 78 | ; \ 79 | if (j <= i) \ 80 | break; \ 81 | SWPF(b, i, j); \ 82 | j--; \ 83 | } \ 84 | } \ 85 | acc &= ~msd_bit; \ 86 | if (acc) { \ 87 | size_t elems0 = i, elems1 = elems - elems0; \ 88 | if (elems0 > 4 || elems1 > 4) \ 89 | msd_bit = MSBF(acc); \ 90 | if (elems0 > 1) { \ 91 | if (elems0 > 4) \ 92 | FN##_aux(acc, msd_bit, b, elems0); \ 93 | else if (elems0 == 4) \ 94 | S4F(b); \ 95 | else if (elems0 == 3) \ 96 | S3F(b); \ 97 | else \ 98 | S2F(b); \ 99 | } \ 100 | if (elems1 > 1) { \ 101 | if (elems1 > 4) \ 102 | FN##_aux(acc, msd_bit, b + i, elems1); \ 103 | else if (elems1 == 4) \ 104 | S4F(b + i); \ 105 | else if (elems1 == 3) \ 106 | S3F(b + i); \ 107 | else \ 108 | S2F(b + i); \ 109 | } \ 110 | } \ 111 | } \ 112 | static void FN(T *b, size_t elems) \ 113 | { \ 114 | size_t i; \ 115 | TC acc = 0; \ 116 | for (i = 1; i < elems; i++) \ 117 | acc |= (((TC)b[i - 1] + (OFF)) ^ ((TC)b[i] + (OFF))); \ 118 | if (acc) \ 119 | FN##_aux(acc, MSBF(acc), b, elems); \ 120 | } 121 | 122 | #ifndef S_MINIMAL 123 | 124 | /* clang-format off */ 125 | 126 | BUILD_COUNT_SORT_x8(s_count_sort_i8, int8_t, size_t, 1<<7) 127 | BUILD_COUNT_SORT_x8(s_count_sort_u8, uint8_t, size_t, 0) 128 | BUILD_COUNT_SORT_x8(s_count_sort_i8_small, int8_t, uint8_t, 1<<7) 129 | BUILD_COUNT_SORT_x8(s_count_sort_u8_small, uint8_t, uint8_t, 0) 130 | BUILD_SWAP(s_swap_i16, int16_t) 131 | BUILD_SORT2(s_sort2_i16, int16_t, s_swap_i16) 132 | BUILD_SORT3(s_sort3_i16, int16_t, s_swap_i16, s_sort2_i16) 133 | BUILD_SORT4(s_sort4_i16, int16_t, s_swap_i16, s_sort2_i16) 134 | BUILD_SWAP(s_swap_u16, uint16_t) 135 | BUILD_SORT2(s_sort2_u16, uint16_t, s_swap_u16) 136 | BUILD_SORT3(s_sort3_u16, uint16_t, s_swap_u16, s_sort2_u16) 137 | BUILD_SORT4(s_sort4_u16, uint16_t, s_swap_u16, s_sort2_u16) 138 | BUILD_SWAP(s_swap_i32, int32_t) 139 | BUILD_SORT2(s_sort2_i32, int32_t, s_swap_i32) 140 | BUILD_SORT3(s_sort3_i32, int32_t, s_swap_i32, s_sort2_i32) 141 | BUILD_SORT4(s_sort4_i32, int32_t, s_swap_i32, s_sort2_i32) 142 | BUILD_SWAP(s_swap_u32, uint32_t) 143 | BUILD_SORT2(s_sort2_u32, uint32_t, s_swap_u32) 144 | BUILD_SORT3(s_sort3_u32, uint32_t, s_swap_u32, s_sort2_u32) 145 | BUILD_SORT4(s_sort4_u32, uint32_t, s_swap_u32, s_sort2_u32) 146 | BUILD_SWAP(s_swap_i64, int64_t) 147 | BUILD_SORT2(s_sort2_i64, int64_t, s_swap_i64) 148 | BUILD_SORT3(s_sort3_i64, int64_t, s_swap_i64, s_sort2_i64) 149 | BUILD_SORT4(s_sort4_i64, int64_t, s_swap_i64, s_sort2_i64) 150 | BUILD_SWAP(s_swap_u64, uint64_t) 151 | BUILD_SORT2(s_sort2_u64, uint64_t, s_swap_u64) 152 | BUILD_SORT3(s_sort3_u64, uint64_t, s_swap_u64, s_sort2_u64) 153 | BUILD_SORT4(s_sort4_u64, uint64_t, s_swap_u64, s_sort2_u64) 154 | BUILD_MSD_RADIX_SORT(s_msd_radix_sort_i16, int16_t, uint16_t, s_msb16, 155 | s_swap_i16, s_sort2_i16, s_sort3_i16, s_sort4_i16, 1<<15) 156 | BUILD_MSD_RADIX_SORT(s_msd_radix_sort_u16, uint16_t, uint16_t, s_msb16, 157 | s_swap_u16, s_sort2_u16, s_sort3_u16, s_sort4_u16, 0) 158 | BUILD_MSD_RADIX_SORT(s_msd_radix_sort_i32, int32_t, uint32_t, s_msb32, 159 | s_swap_i32, s_sort2_i32, s_sort3_i32, s_sort4_i32, 1UL<<31) 160 | BUILD_MSD_RADIX_SORT(s_msd_radix_sort_u32, uint32_t, uint32_t, s_msb32, 161 | s_swap_u32, s_sort2_u32, s_sort3_u32, s_sort4_u32, 0) 162 | BUILD_MSD_RADIX_SORT(s_msd_radix_sort_i64, int64_t, uint64_t, s_msb64, 163 | s_swap_i64, s_sort2_i64, s_sort3_i64, s_sort4_i64, 164 | (uint64_t)1<<63) 165 | BUILD_MSD_RADIX_SORT(s_msd_radix_sort_u64, uint64_t, uint64_t, s_msb64, 166 | s_swap_u64, s_sort2_u64, s_sort3_u64, s_sort4_u64, 0) 167 | 168 | /* 169 | * Sort functions 170 | */ 171 | 172 | #define SSORT_CHECK(b, elems) \ 173 | if (!b || elems <= 1) \ 174 | return 175 | 176 | void ssort_i8(int8_t *b, size_t elems) 177 | { 178 | SSORT_CHECK(b, elems); 179 | if (elems < 256) 180 | s_count_sort_i8_small(b, elems); 181 | else 182 | s_count_sort_i8(b, elems); 183 | } 184 | 185 | /* clang-format on */ 186 | 187 | void ssort_u8(uint8_t *b, size_t elems) 188 | { 189 | SSORT_CHECK(b, elems); 190 | if (elems < 256) 191 | s_count_sort_u8_small(b, elems); 192 | else 193 | s_count_sort_u8(b, elems); 194 | } 195 | 196 | void ssort_i16(int16_t *b, size_t elems) 197 | { 198 | SSORT_CHECK(b, elems); 199 | s_msd_radix_sort_i16(b, elems); 200 | } 201 | 202 | void ssort_u16(uint16_t *b, size_t elems) 203 | { 204 | SSORT_CHECK(b, elems); 205 | s_msd_radix_sort_u16(b, elems); 206 | } 207 | 208 | void ssort_i32(int32_t *b, size_t elems) 209 | { 210 | SSORT_CHECK(b, elems); 211 | s_msd_radix_sort_i32(b, elems); 212 | } 213 | 214 | void ssort_u32(uint32_t *b, size_t elems) 215 | { 216 | SSORT_CHECK(b, elems); 217 | s_msd_radix_sort_u32(b, elems); 218 | } 219 | 220 | void ssort_i64(int64_t *b, size_t elems) 221 | { 222 | SSORT_CHECK(b, elems); 223 | s_msd_radix_sort_i64(b, elems); 224 | } 225 | 226 | void ssort_u64(uint64_t *b, size_t elems) 227 | { 228 | SSORT_CHECK(b, elems); 229 | s_msd_radix_sort_u64(b, elems); 230 | } 231 | 232 | #endif /* #ifndef S_MINIMAL */ 233 | -------------------------------------------------------------------------------- /src/saux/ssort.h: -------------------------------------------------------------------------------- 1 | #ifndef SSORT_H 2 | #define SSORT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * ssort.h 9 | * 10 | * Sorting algorithms 11 | * 12 | * Features: 13 | * - Fast, in-place, 8-bit integer sort 14 | * - Algorithm: counting sort 15 | * - Space complexity: O(1) 16 | * - Time complexity: O(n) 17 | * - Fast, in-place, 16/32/64-bit integer sort 18 | * - Algorithm: MSD binary radix sort (with optimizations) 19 | * - Space complexity: O(1) 20 | * - Time complexity: O(n log n). The algorithm is pseudo O(n), as that 21 | * case only happens when having duplicated elements (e.g. if you 22 | * sort more than 2^16 16-bit elements, it would start being really O(n), 23 | * for that specific case). 24 | * 25 | * Copyright (c) 2015-2020 F. Aragon. All rights reserved. 26 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 27 | */ 28 | 29 | #include "scommon.h" 30 | 31 | typedef void (*ssort_f)(void *, size_t); 32 | 33 | void ssort_i8(int8_t *b, size_t elems); 34 | void ssort_u8(uint8_t *b, size_t elems); 35 | void ssort_i16(int16_t *b, size_t elems); 36 | void ssort_u16(uint16_t *b, size_t elems); 37 | void ssort_i32(int32_t *b, size_t elems); 38 | void ssort_u32(uint32_t *b, size_t elems); 39 | void ssort_i64(int64_t *b, size_t elems); 40 | void ssort_u64(uint64_t *b, size_t elems); 41 | 42 | #ifdef __cplusplus 43 | } /* extern "C" { */ 44 | #endif 45 | #endif /* SSORT_H */ 46 | -------------------------------------------------------------------------------- /src/saux/sstringo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sstringo.c 3 | * 4 | * In-place string optimizations. 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. Released under 7 | * the BSD 3-Clause License (see the doc/LICENSE file included). 8 | */ 9 | 10 | #include "sstringo.h" 11 | 12 | #ifdef S_ENABLE_SM_STRING_OPTIMIZATION 13 | 14 | S_INLINE const uint8_t *sso_dd_get_s2_raw(const srt_stringo *s) 15 | { 16 | const srt_string *s1 = (const srt_string *)s->kv.d.s_raw; 17 | return &s->kv.d.s_raw[0] + ss_size(s1) + sizeof(struct SDataSmall) + 1; 18 | } 19 | 20 | S_INLINE void sso1_set0(srt_stringo1 *so, const srt_string *s, srt_string *s0) 21 | { 22 | size_t ss; 23 | if (!so) 24 | return; 25 | if (!s) 26 | s = ss_void; 27 | ss = ss_size(s); 28 | if (ss <= OptStrMaxSize) { 29 | srt_string *s_out = (srt_string *)so->d.s_raw; 30 | ss_alloc_into_ext_buf(s_out, OptStrMaxSize); 31 | so->t = OptStr_D; 32 | ss_cpy(&s_out, s); 33 | } else { 34 | so->t = OptStr_I; 35 | if (s0) { 36 | so->i.s = s0; 37 | s0 = NULL; 38 | ss_cpy(&so->i.s, s); 39 | } else 40 | so->i.s = ss_dup(s); 41 | } 42 | ss_free(&s0); 43 | } 44 | 45 | S_INLINE void sso_set0(srt_stringo *so, const srt_string *s1, 46 | const srt_string *s2, srt_string *sa, srt_string *sb) 47 | { 48 | size_t s1s, s2s; 49 | srt_string *so1, *so2; 50 | if (!so) 51 | return; 52 | if (!s1) 53 | s1 = ss_void; 54 | if (!s2) 55 | s2 = ss_void; 56 | s1s = ss_size(s1); 57 | s2s = ss_size(s2); 58 | if (s1s + s2s <= OptStr_MaxSize_DD) { 59 | so1 = (srt_string *)so->kv.di.s_raw; 60 | ss_alloc_into_ext_buf(so1, OptStr_MaxSize_DI); 61 | ss_cpy(&so1, s1); 62 | so->t = OptStr_DD; 63 | so2 = (srt_string *)sso_get_s2(so); 64 | ss_alloc_into_ext_buf(so2, OptStr_MaxSize_DI - s1s); 65 | ss_cpy(&so2, s2); 66 | } else if (s1s <= OptStr_MaxSize_DI) { 67 | so1 = (srt_string *)so->kv.di.s_raw; 68 | ss_alloc_into_ext_buf(so1, OptStr_MaxSize_DI); 69 | ss_cpy(&so1, s1); 70 | if (sa || sb) { 71 | if (sa) { 72 | so->kv.di.si = sa; 73 | sa = NULL; 74 | } else { 75 | so->kv.di.si = sb; 76 | sb = NULL; 77 | } 78 | ss_cpy(&so->kv.di.si, s2); 79 | } else 80 | so->kv.di.si = ss_dup(s2); 81 | so->t = OptStr_DI; 82 | } else if (s2s <= OptStr_MaxSize_DI) { 83 | if (sa || sb) { 84 | if (sa) { 85 | so->kv.di.si = sa; 86 | sa = NULL; 87 | } else { 88 | so->kv.di.si = sb; 89 | sb = NULL; 90 | } 91 | ss_cpy(&so->kv.di.si, s1); 92 | } else 93 | so->kv.di.si = ss_dup(s1); 94 | so2 = (srt_string *)so->kv.di.s_raw; 95 | ss_alloc_into_ext_buf(so2, OptStr_MaxSize_DI); 96 | ss_cpy(&so2, s2); 97 | so->t = OptStr_ID; 98 | } else { 99 | if (sa) { 100 | so->kv.ii.s1 = sa; 101 | sa = NULL; 102 | ss_cpy(&so->kv.ii.s1, s1); 103 | } else 104 | so->kv.ii.s1 = ss_dup(s1); 105 | if (sb) { 106 | so->kv.ii.s2 = sb; 107 | sb = NULL; 108 | ss_cpy(&so->kv.ii.s2, s2); 109 | } else 110 | so->kv.ii.s2 = ss_dup(s2); 111 | so->t = OptStr_II; 112 | } 113 | ss_free(&sa); 114 | ss_free(&sb); 115 | } 116 | 117 | const srt_string *sso1_get(const srt_stringo1 *s) 118 | { 119 | RETURN_IF(!s, ss_void); 120 | RETURN_IF(s->t == OptStr_D, (const srt_string *)s->d.s_raw); 121 | RETURN_IF(s->t == OptStr_I, s->i.s); 122 | return ss_void; 123 | } 124 | 125 | const srt_string *sso_get(const srt_stringo *s) 126 | { 127 | RETURN_IF(!s || (s->k.t & OptStr_Null) != 0, ss_void); 128 | RETURN_IF((s->t & OptStr_2) == 0, sso1_get((const srt_stringo1 *)s)); 129 | RETURN_IF(s->t == OptStr_DD, (const srt_string *)s->kv.d.s_raw); 130 | RETURN_IF(s->t == OptStr_DI, (const srt_string *)s->kv.di.s_raw); 131 | RETURN_IF(s->t == OptStr_ID, (const srt_string *)s->kv.di.si); 132 | RETURN_IF(s->t == OptStr_II, (const srt_string *)s->kv.ii.s1); 133 | return ss_void; 134 | } 135 | 136 | const srt_string *sso_dd_get_s2(const srt_stringo *s) 137 | { 138 | RETURN_IF(!s || (s->t & OptStr_2) == 0, ss_void); 139 | return (const srt_string *)sso_dd_get_s2_raw(s); 140 | } 141 | 142 | const srt_string *sso_get_s2(const srt_stringo *s) 143 | { 144 | RETURN_IF(!s || (s->t & OptStr_2) == 0, ss_void); 145 | RETURN_IF(s->t == OptStr_ID, (const srt_string *)s->kv.di.s_raw); 146 | RETURN_IF(s->t == OptStr_DI, (const srt_string *)s->kv.di.si); 147 | RETURN_IF(s->t == OptStr_II, s->kv.ii.s2); 148 | return sso_dd_get_s2(s); /* OptStr_DD */ 149 | } 150 | 151 | void sso1_set(srt_stringo1 *so, const srt_string *s) 152 | { 153 | sso1_set0(so, s, NULL); 154 | } 155 | 156 | void sso_set(srt_stringo *so, const srt_string *s1, const srt_string *s2) 157 | { 158 | sso_set0(so, s1, s2, NULL, NULL); 159 | } 160 | 161 | void sso_update(srt_stringo *so, const srt_string *s, const srt_string *s2) 162 | { 163 | srt_string *s0, *s20; 164 | if (so) { 165 | if ((so->t & OptStr_Ix) != 0) { 166 | s0 = so->kv.di.si; 167 | s20 = NULL; 168 | } else if (so->t == OptStr_II) { 169 | s0 = so->kv.ii.s1; 170 | s20 = so->kv.ii.s2; 171 | } else 172 | s0 = s20 = NULL; 173 | sso_set0(so, s, s2, s0, s20); 174 | } 175 | } 176 | 177 | void sso1_update(srt_stringo1 *so, const srt_string *s) 178 | { 179 | srt_string *s0; 180 | if (so) { 181 | s0 = so->t == OptStr_I ? so->i.s : NULL; 182 | sso1_set0(so, s, s0); 183 | } 184 | } 185 | 186 | void sso1_setref(srt_stringo1 *so, const srt_string *s) 187 | { 188 | if (so) { 189 | so->t = OptStr_I; 190 | so->i.s = (srt_string *)s; /* CONSTNESS */ 191 | } 192 | } 193 | 194 | void sso_setref(srt_stringo *so, const srt_string *s1, const srt_string *s2) 195 | { 196 | if (so) { 197 | so->t = OptStr_II; 198 | so->kv.ii.s1 = (srt_string *)s1; /* CONSTNESS */ 199 | so->kv.ii.s2 = (srt_string *)s2; /* CONSTNESS */ 200 | } 201 | } 202 | 203 | void sso1_free(srt_stringo1 *so) 204 | { 205 | if (so && so->i.t == OptStr_I) { 206 | ss_free(&so->i.s); 207 | so->i.t |= OptStr_Null; 208 | } 209 | } 210 | 211 | void sso_free(srt_stringo *so) 212 | { 213 | if (!so) 214 | return; 215 | if (so->k.t == OptStr_I) 216 | ss_free(&so->k.i.s); 217 | else if (so->kv.t == OptStr_II) { 218 | ss_free(&so->kv.ii.s1); 219 | ss_free(&so->kv.ii.s2); 220 | } else if (so->kv.t == OptStr_DI) 221 | ss_free(&so->kv.di.si); 222 | so->k.t |= OptStr_Null; 223 | } 224 | 225 | /* 226 | * Duplication adjust: adjust sso string copied in bulk -e.g. with memcpy-, 227 | * so if using dynamic memory it duplicates the string references 228 | */ 229 | 230 | void sso_dupa(srt_stringo *s) 231 | { 232 | switch (s->t) { 233 | case OptStr_I: 234 | s->k.i.s = ss_dup(s->k.i.s); 235 | break; 236 | case OptStr_DI: 237 | case OptStr_ID: 238 | s->kv.di.si = ss_dup(s->kv.di.si); 239 | break; 240 | case OptStr_II: 241 | s->kv.ii.s1 = ss_dup(s->kv.ii.s1); 242 | s->kv.ii.s2 = ss_dup(s->kv.ii.s2); 243 | break; 244 | default: 245 | /* cases not using dynamic memory */ 246 | break; 247 | } 248 | } 249 | 250 | void sso_dupa1(srt_stringo1 *s) 251 | { 252 | if (s->t == OptStr_I) 253 | s->i.s = ss_dup(s->i.s); 254 | } 255 | 256 | #endif /* #ifdef S_ENABLE_SM_STRING_OPTIMIZATION */ 257 | -------------------------------------------------------------------------------- /src/saux/sstringo.h: -------------------------------------------------------------------------------- 1 | #ifndef SSTRINGO_H 2 | #define SSTRINGO_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * sstringo.h 9 | * 10 | * In-place string optimizations. 11 | * 12 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. Released under 13 | * the BSD 3-Clause License (see the doc/LICENSE file included). 14 | */ 15 | 16 | #include "../sstring.h" 17 | 18 | #ifndef S_DISABLE_SM_STRING_OPTIMIZATION 19 | #define S_ENABLE_SM_STRING_OPTIMIZATION 20 | #endif 21 | 22 | /* 23 | * Structures and types 24 | */ 25 | 26 | #ifdef S_ENABLE_SM_STRING_OPTIMIZATION 27 | 28 | /* 29 | * Up to 18-byte string when using direct storage 30 | */ 31 | #define OptStrRawSize 24 32 | #define OptStrAllocSize (OptStrRawSize - sizeof(uint8_t)) 33 | #define OptStrMaxSize (OptStrAllocSize - sizeof(struct SDataSmall) - 1) 34 | 35 | /* 36 | * Empty + non-empty: Empty + 50-byte string when using direct storage 37 | * 2 x non-empty: up to 45 bytes to be distributed between two strings 38 | */ 39 | #define OptStrRawSize2 48 40 | #define OptStrAllocSize2_DD (OptStrRawSize2 - sizeof(uint8_t)) 41 | #define OptStrAllocSize2_DI (OptStrAllocSize2_DD - sizeof(srt_string *)) 42 | #define OptStr_MaxSize_DD \ 43 | (OptStrAllocSize2_DD - 2 * (sizeof(struct SDataSmall) + 1)) 44 | #define OptStr_MaxSize_DI \ 45 | (OptStrAllocSize2_DI - sizeof(struct SDataSmall) - 1) 46 | 47 | #define OptStr_2 0x08 48 | #define OptStr_Ix 0x10 49 | #define OptStr_Null 0x20 50 | #define OptStr_D 1 /* OptStrRaw */ 51 | #define OptStr_I 2 /* OptStrI */ 52 | #define OptStr_DD (OptStr_2 | 3) /* OptStrRaw2 */ 53 | #define OptStr_DI (OptStr_2 | OptStr_Ix | 4) /* OptStrDI */ 54 | #define OptStr_ID (OptStr_2 | OptStr_Ix | 5) /* OptStrDI */ 55 | #define OptStr_II (OptStr_2 | 6) /* OptStrII */ 56 | 57 | struct OptStrRaw { 58 | uint8_t t; 59 | uint8_t s_raw[OptStrAllocSize]; 60 | }; 61 | 62 | struct OptStrI { 63 | uint8_t t; 64 | srt_string *s; 65 | }; 66 | 67 | struct OptStrRaw2 { 68 | uint8_t t; 69 | uint8_t s_raw[OptStrAllocSize2_DD]; 70 | }; 71 | 72 | struct OptStrDI { 73 | uint8_t t; 74 | uint8_t s_raw[OptStrAllocSize2_DI]; 75 | srt_string *si; 76 | }; 77 | 78 | struct OptStrII { 79 | uint8_t t; 80 | srt_string *s1; 81 | srt_string *s2; 82 | }; 83 | 84 | union OptStr1 { 85 | uint8_t t; 86 | struct OptStrRaw d; 87 | struct OptStrI i; 88 | }; 89 | 90 | union OptStr2 { 91 | uint8_t t; 92 | struct OptStrRaw2 d; 93 | struct OptStrDI di; 94 | struct OptStrII ii; 95 | }; 96 | 97 | union OptStr { 98 | uint8_t t; 99 | union OptStr1 k; 100 | union OptStr2 kv; 101 | }; 102 | 103 | typedef union OptStr1 srt_stringo1; /* one-string */ 104 | 105 | #else 106 | 107 | struct OptStr1 { 108 | srt_string *s; 109 | }; 110 | 111 | struct OptStr2 { 112 | srt_string *s1, *s2; 113 | }; 114 | 115 | union OptStr { 116 | struct OptStr1 k; 117 | struct OptStr2 kv; 118 | }; 119 | 120 | typedef struct OptStr1 srt_stringo1; /* one-string */ 121 | 122 | #endif 123 | 124 | typedef union OptStr srt_stringo; /* one or two strings sharing space */ 125 | 126 | #ifdef S_ENABLE_SM_STRING_OPTIMIZATION 127 | 128 | const srt_string *sso1_get(const srt_stringo1 *s); 129 | const srt_string *sso_get(const srt_stringo *s); 130 | const srt_string *sso_dd_get_s2(const srt_stringo *s); 131 | const srt_string *sso_get_s2(const srt_stringo *s); 132 | void sso1_set(srt_stringo1 *so, const srt_string *s); 133 | void sso_set(srt_stringo *so, const srt_string *s1, const srt_string *s2); 134 | void sso_update(srt_stringo *so, const srt_string *s, const srt_string *s2); 135 | void sso1_update(srt_stringo1 *so, const srt_string *s); 136 | void sso1_setref(srt_stringo1 *so, const srt_string *s); 137 | void sso_setref(srt_stringo *so, const srt_string *s1, const srt_string *s2); 138 | void sso1_free(srt_stringo1 *so); 139 | void sso_free(srt_stringo *so); 140 | void sso_dupa(srt_stringo *s); 141 | void sso_dupa1(srt_stringo1 *s); 142 | 143 | #else 144 | 145 | S_INLINE const srt_string *sso1_get(const srt_stringo1 *s) 146 | { 147 | return s ? s->s : ss_void; 148 | } 149 | 150 | S_INLINE const srt_string *sso_get(const srt_stringo *s) 151 | { 152 | return s ? s->k.s : ss_void; 153 | } 154 | 155 | S_INLINE const srt_string *sso_get_s2(const srt_stringo *s) 156 | { 157 | return s ? s->kv.s2 : ss_void; 158 | } 159 | 160 | S_INLINE void sso1_set(srt_stringo1 *so, const srt_string *s) 161 | { 162 | if (so) 163 | so->s = ss_dup(s); 164 | } 165 | 166 | S_INLINE void sso_set(srt_stringo *so, const srt_string *s1, 167 | const srt_string *s2) 168 | { 169 | if (so) { 170 | so->kv.s1 = ss_dup(s1); 171 | so->kv.s2 = ss_dup(s2); 172 | } 173 | } 174 | 175 | S_INLINE void sso1_update(srt_stringo1 *so, const srt_string *s) 176 | { 177 | if (so) 178 | ss_cpy(&so->s, s); 179 | } 180 | 181 | S_INLINE void sso_update(srt_stringo *so, const srt_string *s1, 182 | const srt_string *s2) 183 | { 184 | if (so) { 185 | ss_cpy(&so->kv.s1, s1); 186 | ss_cpy(&so->kv.s2, s2); 187 | } 188 | } 189 | 190 | S_INLINE void sso1_setref(srt_stringo1 *so, const srt_string *s) 191 | { 192 | if (so) 193 | so->s = (srt_string *)s; /* CONSTNESS */ 194 | } 195 | 196 | S_INLINE void sso_setref(srt_stringo *so, const srt_string *s1, 197 | const srt_string *s2) 198 | { 199 | if (so) { 200 | so->kv.s1 = (srt_string *)s1; /* CONSTNESS */ 201 | so->kv.s2 = (srt_string *)s2; /* CONSTNESS */ 202 | } 203 | } 204 | 205 | S_INLINE void sso1_free(srt_stringo1 *so) 206 | { 207 | if (so) 208 | ss_free(&so->s); 209 | } 210 | 211 | S_INLINE void sso_free(srt_stringo *so) 212 | { 213 | if (so) { 214 | ss_free(&so->kv.s1); 215 | ss_free(&so->kv.s2); 216 | } 217 | } 218 | 219 | S_INLINE void sso_dupa1(srt_stringo1 *s) 220 | { 221 | s->s = ss_dup(s->s); 222 | } 223 | 224 | S_INLINE void sso_dupa(srt_stringo *s) 225 | { 226 | s->kv.s1 = ss_dup(s->kv.s1); 227 | s->kv.s2 = ss_dup(s->kv.s2); 228 | } 229 | 230 | #endif /* #ifdef S_ENABLE_SM_STRING_OPTIMIZATION */ 231 | 232 | S_INLINE srt_bool sso1_eq(const srt_string *s, const srt_stringo1 *sso1) 233 | { 234 | return !ss_cmp(s, sso1_get(sso1)); 235 | } 236 | 237 | S_INLINE srt_bool sso_eq(const srt_string *s, const srt_stringo *sso) 238 | { 239 | return !ss_cmp(s, sso_get(sso)); 240 | } 241 | 242 | #ifdef __cplusplus 243 | } /* extern "C" { */ 244 | #endif 245 | #endif /* #ifndef SSTRINGO_H */ 246 | -------------------------------------------------------------------------------- /src/saux/stree.h: -------------------------------------------------------------------------------- 1 | #ifndef STREE_H 2 | #define STREE_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * stree.h 9 | * 10 | * #SHORTDOC self-balancing binary tree 11 | * 12 | * #DOC Balanced tree functions. Tree is implemented as Red-Black tree, 13 | * #DOC with up to 2^31 nodes. Internal representation is intended for 14 | * #DOC tight memory usage, being implemented as a vector, so pinter 15 | * #DOC usage is avoided. 16 | * 17 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 18 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 19 | */ 20 | 21 | #include "sdata.h" 22 | 23 | /* 24 | * Structures and types 25 | */ 26 | 27 | #define ST_NODE_BITS 31 28 | #define ST_NIL ((((uint32_t)1) << ST_NODE_BITS) - 1) 29 | #define ST_NDX_MAX (ST_NIL - 1) 30 | 31 | typedef uint32_t srt_tndx; 32 | 33 | typedef int (*srt_cmp)(const void *tree_node, const void *new_node); 34 | typedef void (*srt_tree_callback)(void *tree_node); 35 | 36 | struct S_Node { 37 | struct { 38 | srt_tndx is_red : 1; 39 | srt_tndx l : ST_NODE_BITS; 40 | } x; 41 | srt_tndx r; 42 | }; 43 | 44 | struct S_Tree { 45 | struct SDataFull d; 46 | srt_tndx root; 47 | srt_cmp cmp_f; 48 | }; 49 | 50 | typedef struct S_Node srt_tnode; 51 | typedef struct S_Tree srt_tree; 52 | 53 | struct STraverseParams { 54 | void *context; 55 | const srt_tree *t; 56 | srt_tndx c; 57 | ssize_t level; 58 | ssize_t max_level; 59 | }; 60 | 61 | typedef int (*st_traverse)(struct STraverseParams *p); 62 | typedef void (*srt_tree_rewrite)(srt_tnode *node, const srt_tnode *new_data, 63 | srt_bool existing); 64 | 65 | /* 66 | * Constants 67 | */ 68 | 69 | #define EMPTY_STN { { 0, ST_NIL }, ST_NIL } 70 | 71 | /* 72 | * Functions 73 | */ 74 | 75 | /* 76 | #NOTAPI: |Allocate tree (stack)|node compare function; node size; space preallocated to store n elements|allocated tree|O(1)|0;2| 77 | srt_vector *st_alloca(srt_cmp cmp_f, size_t elem_size, size_t max_size) 78 | */ 79 | #define st_alloca(cmp_f, elem_size, max_size) \ 80 | st_alloc_raw(cmp_f, S_TRUE, \ 81 | s_alloca(sd_alloc_size_raw(sizeof(srt_tree), elem_size, \ 82 | max_size)), \ 83 | elem_size, max_size) 84 | 85 | srt_tree *st_alloc_raw(srt_cmp cmp_f, srt_bool ext_buf, 86 | void *buffer, size_t elem_size, size_t max_size); 87 | 88 | /* #NOTAPI: |Allocate tree (heap)|compare function;element size;space preallocated to store n elements|allocated tree|O(1)|1;2| */ 89 | srt_tree *st_alloc(srt_cmp cmp_f, size_t elem_size, size_t init_size); 90 | 91 | SD_BUILDFUNCS_FULL(st, srt_tree, 0) 92 | 93 | /* 94 | #NOTAPI: |Free one or more trees (heap)|tree;more trees (optional)|-|O(1)|1;2| 95 | void st_free(srt_tree **t, ...) 96 | 97 | #NOTAPI: |Ensure space for extra elements|tree;number of extra eelements|extra size allocated|O(1)|0;2| 98 | size_t st_grow(srt_tree **t, size_t extra_elems) 99 | 100 | #NOTAPI: |Ensure space for elements|tree;absolute element reserve|reserved elements|O(1)|0;2| 101 | size_t st_reserve(srt_tree **t, size_t max_elems) 102 | 103 | #NOTAPI: |Free unused space|tree|same tree (optional usage)|O(1)|0;2| 104 | srt_tree *st_shrink(srt_tree **t) 105 | 106 | #NOTAPI: |Get tree size|tree|number of tree nodes|O(1)|0;2| 107 | size_t st_size(const srt_tree *t) 108 | 109 | #NOTAPI: |Set tree size (for integer-only trees) |tree;set tree number of elements|-|O(1)|0;2| 110 | void st_set_size(srt_tree *t, size_t s) 111 | 112 | #NOTAPI: |Equivalent to st_size|tree|number of tree nodes|O(1)|1;2| 113 | size_t st_len(const srt_tree *t) 114 | */ 115 | 116 | #ifdef S_USE_VA_ARGS 117 | #define st_free(...) st_free_aux(__VA_ARGS__, S_INVALID_PTR_VARG_TAIL) 118 | #else 119 | #define st_free(t) st_free_aux(t, S_INVALID_PTR_VARG_TAIL) 120 | #endif 121 | 122 | /* 123 | * Operations 124 | */ 125 | 126 | /* #NOTAPI: |Duplicate tree|tree|output tree|O(n)|0;2| */ 127 | srt_tree *st_dup(const srt_tree *t); 128 | 129 | /* #NOTAPI: |Insert element into tree|tree; element to insert|S_TRUE: OK, S_FALSE: error (not enough memory)|O(log n)|1;2| */ 130 | srt_bool st_insert(srt_tree **t, const srt_tnode *n); 131 | 132 | /* #NOTAPI: |Insert element into tree, with rewrite function (in case of key already written)|tree; element to insert; rewrite function (if NULL it will behave like st_insert()|S_TRUE: OK, S_FALSE: error (not enough memory)|O(log n)|1;2| */ 133 | srt_bool st_insert_rw(srt_tree **t, const srt_tnode *n, srt_tree_rewrite rw_f); 134 | 135 | /* #NOTAPI: |Delete tree element|tree; element to delete; node delete handling callback (optional if e.g. nodes use no extra dynamic memory references)|S_TRUE: found and deleted; S_FALSE: not found|O(log n)|1;2| */ 136 | srt_bool st_delete(srt_tree *t, const srt_tnode *n, srt_tree_callback callback); 137 | 138 | /* #NOTAPI: |Locate node|tree; node|Reference to the located node; NULL if not found|O(log n)|1;2| */ 139 | const srt_tnode *st_locate(const srt_tree *t, const srt_tnode *n); 140 | 141 | /* #NOTAPI: |Full tree traversal: pre-order|tree; traverse callback; callback context|Number of levels stepped down|O(n)|1;2| */ 142 | ssize_t st_traverse_preorder(const srt_tree *t, st_traverse f, void *context); 143 | 144 | /* #NOTAPI: |Full tree traversal: in-order|tree; traverse callback; callback context|Number of levels stepped down|O(n)|1;2| */ 145 | ssize_t st_traverse_inorder(const srt_tree *t, st_traverse f, void *context); 146 | 147 | /* #NOTAPI: |Full tree traversal: post-order|tree; traverse callback; callback context|Number of levels stepped down|O(n)|1;2| */ 148 | ssize_t st_traverse_postorder(const srt_tree *t, st_traverse f, void *context); 149 | 150 | /* #NOTAPI: |Bread-first tree traversal|tree; traverse callback; callback contest|Number of levels stepped down|O(n); Aux space: n/2 * sizeof(srt_tndx)|1;2| */ 151 | ssize_t st_traverse_levelorder(const srt_tree *t, st_traverse f, void *context); 152 | 153 | /* 154 | * Other 155 | */ 156 | 157 | /* #NOTAPI: |Tree check (debug purposes)|tree|S_TREE: OK, S_FALSE: breaks RB tree rules|O(n)|1;2| */ 158 | srt_bool st_assert(const srt_tree *t); 159 | 160 | /* 161 | * Inlined functions 162 | */ 163 | 164 | S_INLINE srt_tnode *get_node(srt_tree *t, srt_tndx node_id) 165 | { 166 | RETURN_IF(node_id == ST_NIL, NULL); 167 | return (srt_tnode *)st_elem_addr(t, node_id); 168 | } 169 | 170 | S_INLINE const srt_tnode *get_node_r(const srt_tree *t, srt_tndx node_id) 171 | { 172 | RETURN_IF(node_id == ST_NIL, NULL); 173 | return (const srt_tnode *)st_elem_addr_r(t, node_id); 174 | } 175 | 176 | /* #NOTAPI: |Fast unsorted enumeration|tree; element, 0 to n - 1, being n the number of elements|Reference to the located node; NULL if not found|O(1)|0;2| */ 177 | S_INLINE srt_tnode *st_enum(srt_tree *t, srt_tndx index) 178 | { 179 | ASSERT_RETURN_IF(!t, NULL); 180 | return get_node(t, index); 181 | } 182 | 183 | /* #NOTAPI: |Fast unsorted enumeration (read-only)|tree; element, 0 to n - 1, being n the number of elements|Reference to the located node; NULL if not found|O(1)|0;2| */ 184 | S_INLINE const srt_tnode *st_enum_r(const srt_tree *t, srt_tndx index) 185 | { 186 | ASSERT_RETURN_IF(!t, NULL); 187 | return get_node_r(t, index); 188 | } 189 | 190 | /* 191 | * Structure required for tree expansion from 192 | * other types (e.g. srt_map) 193 | */ 194 | 195 | enum STreeScanState { 196 | STS_ScanStart, 197 | STS_ScanLeft, 198 | STS_ScanRight, 199 | STS_ScanDone 200 | }; 201 | 202 | struct STreeScan { 203 | srt_tndx p, c; /* parent, current */ 204 | enum STreeScanState s; 205 | }; 206 | 207 | #ifdef __cplusplus 208 | } /* extern "C" { */ 209 | #endif 210 | 211 | #endif /* #ifndef STREE_H */ 212 | -------------------------------------------------------------------------------- /src/sbitset.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sbitset.c 3 | * 4 | * Bit set handling 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "sbitset.h" 11 | 12 | srt_bitset *sb_alloc_aux(srt_bitset *b) 13 | { 14 | sb_clear(b); 15 | return b; 16 | } 17 | 18 | void sb_clear(srt_bitset *b) 19 | { 20 | size_t nb; 21 | uint8_t *buf; 22 | srt_vector *v = (srt_vector *)b; 23 | if (v) { 24 | nb = sv_max_size(v); 25 | buf = (uint8_t *)sv_get_buffer(v); 26 | memset(buf, 0, nb); 27 | sv_set_size(v, nb); 28 | v->vx.cnt = 0; 29 | } 30 | } 31 | 32 | int sb_test_(const srt_bitset *b, size_t nth) 33 | { 34 | size_t pos, mask; 35 | const uint8_t *buf; 36 | pos = nth / 8; 37 | mask = (size_t)1 << (nth % 8); 38 | buf = (const uint8_t *)sv_get_buffer_r(b); 39 | return (buf[pos] & mask) ? 1 : 0; 40 | } 41 | 42 | void sb_set_(srt_bitset *b, size_t nth) 43 | { 44 | uint8_t *buf; 45 | size_t pos = nth / 8, mask = (size_t)1 << (nth % 8), pinc = pos + 1; 46 | if (pinc <= sv_size(b)) { /* BEHAVIOR: ignore out of range set */ 47 | buf = (uint8_t *)sv_get_buffer(b); 48 | if ((buf[pos] & mask) == 0) { 49 | buf[pos] |= mask; 50 | b->vx.cnt++; 51 | } 52 | } 53 | } 54 | 55 | void sb_reset_(srt_bitset *b, size_t nth, size_t pos) 56 | { 57 | uint8_t *buf = (uint8_t *)sv_get_buffer((srt_vector *)b); 58 | size_t mask = (size_t)1 << (nth % 8); 59 | if ((buf[pos] & mask) != 0) { 60 | buf[pos] &= ~mask; 61 | b->vx.cnt--; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/sbitset.h: -------------------------------------------------------------------------------- 1 | #ifndef SBITSET_H 2 | #define SBITSET_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * sbitset.h 9 | * 10 | * #SHORTDOC bit set (bit array) 11 | * 12 | * #DOC Functions allowing bit random access storage and bit counting. 13 | * #DOC Bit counting is optimized so, instead of per-call 'poppulation count', 14 | * #DOC it takes O(1) for the computation, as a record of bit set/clear is 15 | * #DOC kept. 16 | * 17 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 18 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 19 | * 20 | * Features: 21 | * - Fast: over 300 million bit set per second on i5-3330 @3GHz 22 | * - Very fast: O(1) bit "population count" (vs e.g. g++ O(n) std::bitset) 23 | * - Safe: bound checked 24 | * - Supports both stack and heap allocation 25 | * - Supports dynamic-size bit set (when using heap allocation) 26 | */ 27 | 28 | #include "svector.h" 29 | 30 | /* 31 | * Structures 32 | */ 33 | 34 | typedef srt_vector srt_bitset; /* Opaque structure (accessors are provided) */ 35 | /* (bitset is implemented using a vector) */ 36 | 37 | /* 38 | * Allocation 39 | */ 40 | 41 | #define SB_BITS2BYTES(n) (1 + n / 8) 42 | #define sb_alloc(n) \ 43 | sb_alloc_aux((srt_bitset *)sv_alloc(1, SB_BITS2BYTES(n), NULL)) 44 | #define sb_alloca(n) \ 45 | sb_alloc_aux((srt_bitset *)sv_alloca(1, SB_BITS2BYTES(n), NULL)) 46 | #define sb_dup(b) sv_dup(b) 47 | #define sb_free sv_free 48 | 49 | srt_bitset *sb_alloc_aux(srt_bitset *b); 50 | 51 | /* 52 | #API: |Allocate bitset (stack)|space preallocated to store n elements|bitset|O(n)|1;2| 53 | srt_bitset *sb_alloca(size_t initial_num_elems_reserve) 54 | 55 | #API: |Allocate bitset (heap)|space preallocated to store n elements|bitset|O(n)|1;2| 56 | srt_bitset *sb_alloc(size_t initial_num_elems_reserve) 57 | 58 | #API: |Free one or more bitsets (heap)|bitset; more bitsets (optional)|bitset|O(1)|1;2| 59 | srt_bitset *sb_free(srt_bitset **b, ...) 60 | 61 | #API: |Duplicate bitset|bitset|output bitset|O(n)|1;2| 62 | srt_bitset *sb_dup(const srt_bitset *src) 63 | */ 64 | 65 | /* 66 | * Accessors 67 | */ 68 | 69 | /* #API: |Reset bitset|bitset|-|O(1)|1;2| */ 70 | void sb_clear(srt_bitset *b); 71 | 72 | /* #API: |Number of bits set to 1|bitset|Map number of elements|O(1)|1;2| */ 73 | S_INLINE size_t sb_popcount(const srt_bitset *b) 74 | { 75 | return b ? b->vx.cnt : 0; 76 | } 77 | 78 | /* 79 | * Operations 80 | */ 81 | 82 | int sb_test_(const srt_bitset *b, size_t nth); 83 | 84 | /* #API: |Access to nth bit|bitset; bit offset|1 or 0|O(1)|1;2| */ 85 | S_INLINE int sb_test(const srt_bitset *b, size_t nth) 86 | { 87 | RETURN_IF(!b, 0); 88 | return sb_test_(b, nth); 89 | } 90 | 91 | void sb_set_(srt_bitset *b, size_t nth); 92 | 93 | /* #API: |Set nth bit to 1|bitset; bit offset||O(1)|1;2| */ 94 | S_INLINE void sb_set(srt_bitset **b, size_t nth) 95 | { 96 | if (b && *b) 97 | sb_set_(*b, nth); 98 | } 99 | 100 | void sb_reset_(srt_bitset *b, size_t nth, size_t pos); 101 | 102 | /* #API: |Set nth bit to 0|bitset; bit offset||O(1)|1;2| */ 103 | S_INLINE void sb_reset(srt_bitset **b, size_t nth) 104 | { 105 | if (b && *b) { 106 | size_t pos = nth / 8; 107 | if (pos < sv_size(*b)) { 108 | sb_reset_(*b, nth, pos); 109 | } 110 | } 111 | } 112 | 113 | /* #API: |Preallocated space left (number of 1 bit elements)|bitset|allocated space left (unit: bits)|O(1)|1;2| */ 114 | S_INLINE size_t sb_capacity(const srt_bitset *b) 115 | { 116 | return 8 * sv_capacity(b); 117 | } 118 | 119 | /* #API: |Ensure space for N 1-bit elements|bitset;absolute element reserve (unit: bits)|reserved elements|O(1)|1;2| */ 120 | S_INLINE size_t sb_reserve(srt_bitset **b, size_t max_elems) 121 | { 122 | return sv_reserve(b, 1 + max_elems / 8) * 8; 123 | } 124 | 125 | #ifdef __cplusplus 126 | } /* extern "C" { */ 127 | #endif 128 | #endif /* #ifndef SBITSET_H */ 129 | -------------------------------------------------------------------------------- /src/shset.c: -------------------------------------------------------------------------------- 1 | /* 2 | * shset.c 3 | * 4 | * Hash set handling 5 | * 6 | * Copyright (c) 2015-2020 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "shset.h" 11 | 12 | #define SHS_ITP_CNUM(TS) f(((const TS *)db)->k, context) 13 | #define SHS_ITP_CS f(sso1_get(&((const struct SHMapS *)db)->k), context) 14 | #define BUILD_SHS_ITP(FN, CBFT, ID, TS, COND) \ 15 | size_t FN(const srt_hset *hs, size_t begin, size_t end, CBFT f, \ 16 | void *context) \ 17 | { \ 18 | size_t cnt = 0, ms; \ 19 | const uint8_t *d0, *db, *de; \ 20 | RETURN_IF(!hs || ID != hs->d.sub_type, 0); \ 21 | ms = shs_size(hs); \ 22 | RETURN_IF(begin > ms || begin >= end, 0); \ 23 | if (end > ms) \ 24 | end = ms; \ 25 | RETURN_IF(!f, end - begin); \ 26 | d0 = shm_get_buffer_r(hs); \ 27 | db = d0 + hs->d.elem_size * begin; \ 28 | de = d0 + hs->d.elem_size * end; \ 29 | for (; db < de; db += hs->d.elem_size, cnt++) { \ 30 | if (!COND) \ 31 | break; \ 32 | } \ 33 | return cnt; \ 34 | } 35 | 36 | BUILD_SHS_ITP(shs_itp_i32, srt_hset_it_i32, SHS_I32, struct SHMapi, 37 | SHS_ITP_CNUM(struct SHMapi)) 38 | BUILD_SHS_ITP(shs_itp_u32, srt_hset_it_u32, SHS_U32, struct SHMapu, 39 | SHS_ITP_CNUM(struct SHMapu)) 40 | BUILD_SHS_ITP(shs_itp_i, srt_hset_it_i, SHS_I, struct SHMapI, 41 | SHS_ITP_CNUM(struct SHMapI)) 42 | BUILD_SHS_ITP(shs_itp_f, srt_hset_it_f, SHS_F, struct SHMapF, 43 | SHS_ITP_CNUM(struct SHMapF)) 44 | BUILD_SHS_ITP(shs_itp_d, srt_hset_it_d, SHS_D, struct SHMapD, 45 | SHS_ITP_CNUM(struct SHMapD)) 46 | BUILD_SHS_ITP(shs_itp_s, srt_hset_it_s, SHS_S, struct SHMapS, SHS_ITP_CS) 47 | -------------------------------------------------------------------------------- /src/shset.h: -------------------------------------------------------------------------------- 1 | #ifndef SHSET_H 2 | #define SHSET_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | * shset.h 9 | * 10 | * #SHORTDOC hash set handling (key-only storage) 11 | * 12 | * #DOC Set functions handle key-only storage, which is implemented as a 13 | * #DOC hash table (O(n), with O(1) amortized time complexity for insert/ 14 | * #DOC count/delete). 15 | * #DOC 16 | * #DOC 17 | * #DOC Supported set modes (enum eSHS_Type): 18 | * #DOC 19 | * #DOC 20 | * #DOC SHS_I32: int32_t key 21 | * #DOC 22 | * #DOC SHS_U32: uint32_t key 23 | * #DOC 24 | * #DOC SHS_I: int64_t key 25 | * #DOC 26 | * #DOC SHS_F: float (single-precision floating point) key 27 | * #DOC 28 | * #DOC SHS_D: double (double-precision floating point) key 29 | * #DOC 30 | * #DOC SHS_S: string key 31 | * #DOC 32 | * #DOC 33 | * #DOC Callback types for the shs_itp_*() functions: 34 | * #DOC 35 | * #DOC 36 | * #DOC typedef srt_bool (*srt_hset_it_i32)(int32_t k, void *context); 37 | * #DOC 38 | * #DOC typedef srt_bool (*srt_hset_it_u32)(uint32_t k, void *context); 39 | * #DOC 40 | * #DOC typedef srt_bool (*srt_hset_it_i)(int64_t k, void *context); 41 | * #DOC 42 | * #DOC typedef srt_bool (*srt_hset_it_f)(float k, void *context); 43 | * #DOC 44 | * #DOC typedef srt_bool (*srt_hset_it_d)(double k, void *context); 45 | * #DOC 46 | * #DOC typedef srt_bool (*srt_hset_it_s)(const srt_string *, void *context); 47 | * 48 | * Copyright (c) 2015-2020 F. Aragon. All rights reserved. 49 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 50 | */ 51 | 52 | #include "shmap.h" 53 | 54 | /* 55 | * Structures and types 56 | */ 57 | 58 | enum eSHS_Type { 59 | SHS_I32 = SHM0_I32, 60 | SHS_U32 = SHM0_U32, 61 | SHS_I = SHM0_I, 62 | SHS_F = SHM0_F, 63 | SHS_D = SHM0_D, 64 | SHS_S = SHM0_S 65 | }; 66 | 67 | typedef srt_hmap srt_hset; 68 | 69 | /* 70 | * Allocation 71 | */ 72 | 73 | #define shs_alloca shm_alloca 74 | /* 75 | #API: |Allocate hash set (stack)|set type; initial reserve|map|O(n)|1;2| 76 | srt_hset *shs_alloca(enum eSHS_Type t, size_t n); 77 | */ 78 | 79 | /* #API: |Allocate hash set (heap)|set type; initial reserve|hash set|O(n)|1;2| */ 80 | S_INLINE srt_hset *shs_alloc(enum eSHS_Type t, size_t init_size) 81 | { 82 | return shm_alloc_aux((int)t, init_size); 83 | } 84 | 85 | /* #API: |Ensure space for extra elements|hash set;number of extra elements|extra size allocated|O(1)|1;2| */ 86 | S_INLINE size_t shs_grow(srt_hset **hs, size_t extra_elems) 87 | { 88 | return shm_grow(hs, extra_elems); 89 | } 90 | 91 | /* #API: |Ensure space for elements|hash set;absolute element reserve|reserved elements|O(1)|1;2| */ 92 | S_INLINE size_t shs_reserve(srt_hset **hs, size_t max_elems) 93 | { 94 | return shm_reserve(hs, max_elems); 95 | } 96 | 97 | /* #API: |Make the hmap use the minimum possible memory|hash set|hash set reference (optional usage)|O(1) for allocators using memory remap; O(n) for naive allocators|1;2| */ 98 | S_INLINE srt_hset *shs_shrink(srt_hset **hs) 99 | { 100 | return shm_shrink(hs); 101 | } 102 | 103 | /* #API: |Get hmap size|map|hash set number of elements|O(1)|1;2| */ 104 | S_INLINE size_t shs_size(const srt_hset *hs) 105 | { 106 | return shm_size(hs); 107 | } 108 | 109 | /* #API: |Get hmap size|map|hash set current max number of elements|O(1)|1;2| */ 110 | S_INLINE size_t shs_max_size(const srt_hset *hs) 111 | { 112 | return shm_max_size(hs); 113 | } 114 | 115 | /* #API: |Allocated space|hash set|current allocated space (vector elements)|O(1)|1;2| */ 116 | S_INLINE size_t shs_capacity(const srt_hset *hs) 117 | { 118 | return shm_capacity(hs); 119 | } 120 | 121 | /* #API: |Preallocated space left|hash set|allocated space left|O(1)|1;2| */ 122 | S_INLINE size_t shs_capacity_left(const srt_hset *hs) 123 | { 124 | return shm_capacity_left(hs); 125 | } 126 | 127 | /* #API: |Tells if a hash set is empty (zero elements)|hash set|S_TRUE: empty; S_FALSE: not empty|O(1)|1;2| */ 128 | S_INLINE srt_bool shs_empty(const srt_hset *hs) 129 | { 130 | return shm_empty(hs); 131 | } 132 | 133 | /* #API: |Duplicate hash set|input hash setoutput hash set|O(n)|1;2| */ 134 | S_INLINE srt_hset *shs_dup(const srt_hset *src) 135 | { 136 | return shm_dup(src); 137 | } 138 | 139 | /* #API: |Clear/reset map (keeping map type)|hash set||O(1) for simple maps, O(n) for maps having nodes with strings|1;2| */ 140 | S_INLINE void shs_clear(srt_hset *hs) 141 | { 142 | shm_clear(hs); 143 | } 144 | 145 | /* 146 | #API: |Free one or more hash sets|hash set; more hash sets (optional)|-|O(1) for simple dmaps, O(n) for dmaps having nodes with strings|1;2| 147 | void shs_free(srt_hset **hs, ...) 148 | */ 149 | #ifdef S_USE_VA_ARGS 150 | #define shs_free(...) shm_free_aux(__VA_ARGS__, S_INVALID_PTR_VARG_TAIL) 151 | #else 152 | #define shs_free(hs) shm_free_aux(hs, S_INVALID_PTR_VARG_TAIL) 153 | #endif 154 | 155 | /* 156 | * Copy 157 | */ 158 | 159 | /* #API: |Overwrite map with a map copy|output map; input hash setoutput map reference (optional usage)|O(n)|1;2| */ 160 | S_INLINE srt_hset *shs_cpy(srt_hset **hs, const srt_hset *src) 161 | { 162 | return shm_cpy(hs, src); 163 | } 164 | 165 | /* 166 | * Existence check 167 | */ 168 | 169 | /* #API: |Map element count/check (SHS_U32)|hash set; key|S_TRUE: element found; S_FALSE: not in the hash set | O(n), O(1) average amortized|1;2| */ 170 | S_INLINE size_t shs_count_u32(const srt_hset *hs, uint32_t k) 171 | { 172 | return shm_count_u32(hs, k); 173 | } 174 | 175 | /* #API: |Map element count/check (SHS_I32)|hash set; key|S_TRUE: element found; S_FALSE: not in the hash set | O(n), O(1) average amortized|1;2| */ 176 | S_INLINE size_t shs_count_i32(const srt_hset *hs, int32_t k) 177 | { 178 | return shm_count_i32(hs, k); 179 | } 180 | 181 | /* #API: |Map element count/check (SHS_I)|hash set; key|S_TRUE: element found; S_FALSE: not in the hash set | O(n), O(1) average amortized|1;2| */ 182 | S_INLINE size_t shs_count_i(const srt_hset *hs, int64_t k) 183 | { 184 | return shm_count_i(hs, k); 185 | } 186 | 187 | /* #API: |Map element count/check (SHS_F)|hash set; key|S_TRUE: element found; S_FALSE: not in the hash set | O(n), O(1) average amortized|1;2| */ 188 | S_INLINE size_t shs_count_f(const srt_hset *hs, float k) 189 | { 190 | return shm_count_f(hs, k); 191 | } 192 | 193 | /* #API: |Map element count/check (SHS_D)|hash set; key|S_TRUE: element found; S_FALSE: not in the hash set | O(n), O(1) average amortized|1;2| */ 194 | S_INLINE size_t shs_count_d(const srt_hset *hs, double k) 195 | { 196 | return shm_count_d(hs, k); 197 | } 198 | 199 | /* #API: |Map element count/check (SHS_S)|hash set; key|S_TRUE: element found; S_FALSE: not in the hash set | O(n), O(1) average amortized|1;2| */ 200 | S_INLINE size_t shs_count_s(const srt_hset *hs, const srt_string *k) 201 | { 202 | return shm_count_s(hs, k); 203 | } 204 | 205 | /* 206 | * Insert 207 | */ 208 | 209 | /* #API: |Insert into hash set (SHS_I32)|hash set; key|S_TRUE: OK, S_FALSE: insertion error|O(n), O(1) average amortized|1;2| */ 210 | S_INLINE srt_bool shs_insert_i32(srt_hset **hs, int32_t k) 211 | { 212 | return shm_insert_i32(hs, k); 213 | } 214 | 215 | /* #API: |Insert into hash set (SHS_U32)|hash set; key|S_TRUE: OK, S_FALSE: insertion error|O(n), O(1) average amortized|1;2| */ 216 | S_INLINE srt_bool shs_insert_u32(srt_hset **hs, uint32_t k) 217 | { 218 | return shm_insert_u32(hs, k); 219 | } 220 | 221 | /* #API: |Insert into hash set (SHS_I)|hash set; key|S_TRUE: OK, S_FALSE: insertion error|O(n), O(1) average amortized|1;2| */ 222 | S_INLINE srt_bool shs_insert_i(srt_hset **hs, int64_t k) 223 | { 224 | return shm_insert_i(hs, k); 225 | } 226 | 227 | /* #API: |Insert into hash set (SHS_F)|hash set; key|S_TRUE: OK, S_FALSE: insertion error|O(n), O(1) average amortized|1;2| */ 228 | S_INLINE srt_bool shs_insert_f(srt_hset **hs, float k) 229 | { 230 | return shm_insert_f(hs, k); 231 | } 232 | 233 | /* #API: |Insert into hash set (SHS_D)|hash set; key|S_TRUE: OK, S_FALSE: insertion error|O(n), O(1) average amortized|1;2| */ 234 | S_INLINE srt_bool shs_insert_d(srt_hset **hs, double k) 235 | { 236 | return shm_insert_d(hs, k); 237 | } 238 | 239 | /* #API: |Insert into hash set (SHS_S)|hash set; key|S_TRUE: OK, S_FALSE: insertion error|O(n), O(1) average amortized|1;2| */ 240 | S_INLINE srt_bool shs_insert_s(srt_hset **hs, const srt_string *k) 241 | { 242 | return shm_insert_s(hs, k); 243 | } 244 | 245 | /* 246 | * Delete 247 | */ 248 | 249 | /* #API: |Delete map element (SHS_U32)|hash set; int32_t key|S_TRUE: found and deleted; S_FALSE: not found|O(n), O(1) average amortized|1;2| */ 250 | S_INLINE srt_bool shs_delete_u32(srt_hset *hs, uint32_t k) 251 | { 252 | return shm_delete_u32(hs, k); 253 | } 254 | 255 | /* #API: |Delete map element (SHS_I32)|hash set; int32_t key|S_TRUE: found and deleted; S_FALSE: not found|O(n), O(1) average amortized|1;2| */ 256 | S_INLINE srt_bool shs_delete_i32(srt_hset *hs, int32_t k) 257 | { 258 | return shm_delete_i32(hs, k); 259 | } 260 | 261 | /* #API: |Delete map element (SHS_I)|hash set; int64_t key|S_TRUE: found and deleted; S_FALSE: not found|O(n), O(1) average amortized|1;2| */ 262 | S_INLINE srt_bool shs_delete_i(srt_hset *hs, int64_t k) 263 | { 264 | return shm_delete_i(hs, k); 265 | } 266 | 267 | /* #API: |Delete map element (SHS_F)|hash set; float key|S_TRUE: found and deleted; S_FALSE: not found|O(n), O(1) average amortized|1;2| */ 268 | S_INLINE srt_bool shs_delete_f(srt_hset *hs, float k) 269 | { 270 | return shm_delete_f(hs, k); 271 | } 272 | 273 | /* #API: |Delete map element (SHS_D)|hash set; double key|S_TRUE: found and deleted; S_FALSE: not found|O(n), O(1) average amortized|1;2| */ 274 | S_INLINE srt_bool shs_delete_d(srt_hset *hs, double k) 275 | { 276 | return shm_delete_d(hs, k); 277 | } 278 | 279 | /* #API: |Delete map element (SHS_S)|hash set; string key|S_TRUE: found and deleted; S_FALSE: not found|O(n), O(1) average amortized|1;2| */ 280 | S_INLINE srt_bool shs_delete_s(srt_hset *hs, const srt_string *k) 281 | { 282 | return shm_delete_s(hs, k); 283 | } 284 | 285 | /* 286 | * Enumeration 287 | */ 288 | 289 | /* #API: |Enumerate set keys (SHS_I32)|hash set; element, 0 to n - 1|int32_t|O(1)|1;2| */ 290 | S_INLINE int32_t shs_it_i32(const srt_hset *hs, size_t i) 291 | { 292 | return shm_it_i32_k(hs, i); 293 | } 294 | 295 | /* #API: |Enumerate set keys (SHS_U32)|hash set; element, 0 to n - 1|uint32_t|O(1)|1;2| */ 296 | S_INLINE uint32_t shs_it_u32(const srt_hset *hs, size_t i) 297 | { 298 | return shm_it_u32_k(hs, i); 299 | } 300 | 301 | /* #API: |Enumerate set keys (SHS_I)|hash set; element, 0 to n - 1|int64_t|O(1)|1;2| */ 302 | S_INLINE int64_t shs_it_i(const srt_hset *hs, size_t i) 303 | { 304 | return shm_it_i_k(hs, i); 305 | } 306 | 307 | /* #API: |Enumerate set keys (SHS_F)|hash set; element, 0 to n - 1|int64_t|O(1)|0;1| */ 308 | S_INLINE float shs_it_f(const srt_hset *hs, size_t i) 309 | { 310 | return shm_it_f_k(hs, i); 311 | } 312 | 313 | /* #API: |Enumerate set keys (SHS_D)|hash set; element, 0 to n - 1|int64_t|O(1)|0;1| */ 314 | S_INLINE double shs_it_d(const srt_hset *hs, size_t i) 315 | { 316 | return shm_it_d_k(hs, i); 317 | } 318 | 319 | /* #API: |Enumerate set keys (SHS_S)|hash set; element, 0 to n - 1|string|O(1)|1;2| */ 320 | S_INLINE const srt_string *shs_it_s(const srt_hset *hs, size_t i) 321 | { 322 | return shm_it_s_k(hs, i); 323 | } 324 | 325 | /* 326 | * Enumeration, with callback helper 327 | */ 328 | 329 | typedef srt_bool (*srt_hset_it_i32)(int32_t k, void *context); 330 | typedef srt_bool (*srt_hset_it_u32)(uint32_t k, void *context); 331 | typedef srt_bool (*srt_hset_it_i)(int64_t k, void *context); 332 | typedef srt_bool (*srt_hset_it_f)(float k, void *context); 333 | typedef srt_bool (*srt_hset_it_d)(double k, void *context); 334 | typedef srt_bool (*srt_hset_it_s)(const srt_string *, void *context); 335 | 336 | /* #API: |Enumerate set elements in portions (SHS_I32)|set; index start; index end; callback function; callback function context|Elements processed|O(n)|1;2| */ 337 | size_t shs_itp_i32(const srt_hset *s, size_t begin, size_t end, srt_hset_it_i32 f, void *context); 338 | 339 | /* #API: |Enumerate set elements in portions (SHS_U32)|set; index start; index end; callback function; callback function context|Elements processed|O(n)|1;2| */ 340 | size_t shs_itp_u32(const srt_hset *s, size_t begin, size_t end, srt_hset_it_u32 f, void *context); 341 | 342 | /* #API: |Enumerate set elements in portions (SHS_I)|set; index start; index end; callback function; callback function context|Elements processed|O(n)|1;2| */ 343 | size_t shs_itp_i(const srt_hset *s, size_t begin, size_t end, srt_hset_it_i f, void *context); 344 | 345 | /* #API: |Enumerate set elements in portions (SHS_F)|set; index start; index end; callback function; callback function context|Elements processed|O(n)|1;2| */ 346 | size_t shs_itp_f(const srt_hset *s, size_t begin, size_t end, srt_hset_it_f f, void *context); 347 | 348 | /* #API: |Enumerate set elements in portions (SHS_D)|set; index start; index end; callback function; callback function context|Elements processed|O(n)|1;2| */ 349 | size_t shs_itp_d(const srt_hset *s, size_t begin, size_t end, srt_hset_it_d f, void *context); 350 | 351 | /* #API: |Enumerate set elements in portions (SHS_S)|set; index start; index end; callback function; callback function context|Elements processed|O(n)|1;2| */ 352 | size_t shs_itp_s(const srt_hset *s, size_t begin, size_t end, srt_hset_it_s f, void *context); 353 | 354 | #ifdef __cplusplus 355 | } /* extern "C" { */ 356 | #endif 357 | #endif /* #ifndef SHSET_H */ 358 | 359 | -------------------------------------------------------------------------------- /src/smset.c: -------------------------------------------------------------------------------- 1 | /* 2 | * smset.c 3 | * 4 | * Set handling. 5 | * 6 | * Copyright (c) 2015-2020 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "smset.h" 11 | #include "saux/scommon.h" 12 | 13 | SM_ENUM_INORDER_XX(sms_itr_i32, srt_set_it_i32, SM0_I32, int32_t, 14 | cmp_ni_i((const struct SMapi *)cn, kmin), 15 | cmp_ni_i((const struct SMapi *)cn, kmax), 16 | f(((const struct SMapi *)cn)->k, context)) 17 | 18 | SM_ENUM_INORDER_XX(sms_itr_u32, srt_set_it_u32, SM0_U32, uint32_t, 19 | cmp_nu_u((const struct SMapu *)cn, kmin), 20 | cmp_nu_u((const struct SMapu *)cn, kmax), 21 | f(((const struct SMapu *)cn)->k, context)) 22 | 23 | SM_ENUM_INORDER_XX(sms_itr_i, srt_set_it_i, SM0_I, int64_t, 24 | cmp_nI_I((const struct SMapI *)cn, kmin), 25 | cmp_nI_I((const struct SMapI *)cn, kmax), 26 | f(((const struct SMapI *)cn)->k, context)) 27 | 28 | SM_ENUM_INORDER_XX( 29 | sms_itr_s, srt_set_it_s, SM0_S, const srt_string *, 30 | cmp_ns_s((const struct SMapS *)cn, kmin), 31 | cmp_ns_s((const struct SMapS *)cn, kmax), 32 | f(sso_get((const srt_stringo *)&((const struct SMapS *)cn)->k), 33 | context)) 34 | 35 | SM_ENUM_INORDER_XX(sms_itr_f, srt_set_it_f, SM0_F, float, 36 | cmp_nF_F((const struct SMapF *)cn, kmin), 37 | cmp_nF_F((const struct SMapF *)cn, kmax), 38 | f(((const struct SMapF *)cn)->k, context)) 39 | 40 | SM_ENUM_INORDER_XX(sms_itr_d, srt_set_it_d, SM0_D, double, 41 | cmp_nD_D((const struct SMapD *)cn, kmin), 42 | cmp_nD_D((const struct SMapD *)cn, kmax), 43 | f(((const struct SMapD *)cn)->k, context)) 44 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # test/Makefile.am 3 | # 4 | # libsrt Automake template for tests and examples 5 | # 6 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | # 9 | 10 | MAINTAINERCLEANFILES = Makefile.in 11 | 12 | check_PROGRAMS = stest 13 | bin_PROGRAMS = bench counter counterpp enc histogram histogrampp imgc imgd 14 | TESTS = $(check_PROGRAMS) 15 | 16 | stest_SOURCES = stest.c 17 | stest_LDADD = ../src/libsrt.la 18 | 19 | bench_SOURCES = bench.cc 20 | bench_LDADD = ../src/libsrt.la 21 | 22 | counter_SOURCES = counter.c 23 | counter_LDADD = ../src/libsrt.la 24 | 25 | counterpp_SOURCES = counterpp.cc 26 | counterpp_LDADD = ../src/libsrt.la 27 | 28 | enc_SOURCES = enc.c 29 | enc_LDADD = ../src/libsrt.la 30 | 31 | histogram_SOURCES = histogram.c 32 | histogram_LDADD = ../src/libsrt.la 33 | 34 | histogrampp_SOURCES = histogrampp.cc 35 | histogrampp_LDADD = ../src/libsrt.la 36 | 37 | imgc_SOURCES = imgc.c imgtools.c 38 | imgc_LDADD = ../src/libsrt.la 39 | 40 | imgd_SOURCES = imgd.c imgtools.c 41 | imgd_LDADD = ../src/libsrt.la 42 | -------------------------------------------------------------------------------- /test/counter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * counter.c 3 | * 4 | * Code counting example using libsrt 5 | * 6 | * It shows how different data structures (bit set, set, hash set) behave 7 | * in memory usage and execution speed. 8 | * 9 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 10 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 11 | */ 12 | 13 | #include "counter.h" 14 | -------------------------------------------------------------------------------- /test/counter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * counter.h 3 | * 4 | * Code counting examples, one using libsrt, and the other using C++/STL 5 | * 6 | * This is a template for both the C and C++ versions. The C version 7 | * use libsrt types and functions, and the C++ use the STL library. The 8 | * purpose is to compare libsrt vs C++/STL. 9 | * 10 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 11 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 12 | */ 13 | 14 | #ifndef COUNTER_H 15 | #define COUNTER_H 16 | 17 | #include "../src/libsrt.h" 18 | #ifdef __cplusplus 19 | #include 20 | #include 21 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 22 | #define S_COUNTER_CPP_HS 23 | #include 24 | #endif 25 | #define CNT_TAG "C++" 26 | #define BS_COUNTER_SET(bs, val) bs->set(val) 27 | #define BS_COUNTER_POPCOUNT(bs) bs->count() 28 | #define BS_COUNTER_POPCOUNTi(bs) ((size_t)0) 29 | #define S_COUNTER_SET(s, val) s->insert(val) 30 | #define S_COUNTER_POPCOUNT(s) s->size() 31 | #define S_COUNTER_POPCOUNTi(s) s->size() 32 | #define HS_COUNTER_SET(hs, val) hs->insert(val) 33 | #define HS_COUNTER_POPCOUNT(hs) hs->size() 34 | #define HS_COUNTER_POPCOUNTi(hs) hs->size() 35 | #else 36 | #include "../src/libsrt.h" 37 | #define CNT_TAG "libsrt" 38 | #define BS_COUNTER_SET(bs, val) sb_set(&bs, val) 39 | #define BS_COUNTER_POPCOUNT(bs) sb_popcount(bs) 40 | #define BS_COUNTER_POPCOUNTi(bs) sb_popcount(bs) 41 | #define S_COUNTER_SET(s, val) sms_insert_u32(&s, val) 42 | #define S_COUNTER_POPCOUNT(s) sms_size(s) 43 | #define S_COUNTER_POPCOUNTi(s) sms_size(s) 44 | #define HS_COUNTER_SET(hs, val) shs_insert_u32(&hs, val) 45 | #define HS_COUNTER_POPCOUNT(hs) shs_size(hs) 46 | #define HS_COUNTER_POPCOUNTi(hs) shs_size(hs) 47 | #endif 48 | 49 | static int syntax_error(const char **argv, int exit_code) 50 | { 51 | const char *v0 = argv[0]; 52 | fprintf(stderr, 53 | "Code counter (" CNT_TAG " example). Returns: elements " 54 | "processed, unique elements\n\nSyntax: %s unit_size " 55 | "diff_max_stop [-bs|-s|-hs]\n(1 <= unit_size <= 4; " 56 | "diff_max_stop = 0: no max, != 0: max; -bs: bitset (default), " 57 | "-s: set, -hs: hash set)\n\n" 58 | "Examples (count colors, fast randomness test, etc.):\n" 59 | "%s 1 0 = climit) { \ 85 | l = 0; \ 86 | break; \ 87 | } \ 88 | } \ 89 | } while (l > 0) 90 | 91 | enum eCntMode { CM_BitSet, CM_Set, CM_HashSet }; 92 | 93 | int main(int argc, const char **argv) 94 | { 95 | #ifdef __cplusplus 96 | std::set *s = NULL; 97 | std::bitset<(uint32_t)-1> *bs = NULL; 98 | #ifdef S_COUNTER_CPP_HS 99 | std::unordered_set *hs = NULL; 100 | #endif 101 | #else 102 | srt_set *s = NULL; 103 | srt_hset *hs = NULL; 104 | srt_bitset *bs = NULL; 105 | #endif 106 | ssize_t i, l; 107 | enum eCntMode mode = CM_BitSet; 108 | unsigned char buf[3 * 4 * 128]; 109 | uint64_t count = 0, cmax, climit; 110 | int csize, exit_code = 0, climit0; 111 | if (argc < 3) 112 | return syntax_error(argv, 5); 113 | csize = atoi(argv[1]); 114 | climit0 = atoi(argv[2]); 115 | if (csize < 1 || csize > 4) 116 | return syntax_error(argv, 6); 117 | if (climit0 < 0) 118 | return syntax_error(argv, 7); 119 | if (argc >= 4) { 120 | if (!strcmp(argv[3], "-s")) 121 | mode = CM_Set; 122 | else if (!strcmp(argv[3], "-hs")) 123 | mode = CM_HashSet; 124 | } 125 | cmax = (uint64_t)1 << (csize * 8); 126 | climit = climit0 ? S_MIN((uint64_t)climit0, cmax) : cmax; 127 | switch (mode) { 128 | case CM_BitSet: 129 | #ifdef __cplusplus 130 | bs = new std::bitset<(uint32_t)-1>(); 131 | #else 132 | bs = sb_alloc(cmax); 133 | #endif 134 | break; 135 | case CM_Set: 136 | #ifdef __cplusplus 137 | s = new std::set(); 138 | #else 139 | s = sms_alloc(SMS_U32, 0); 140 | #endif 141 | break; 142 | case CM_HashSet: 143 | #ifdef __cplusplus 144 | #ifdef S_COUNTER_CPP_HS 145 | hs = new std::unordered_set(); 146 | #else 147 | fprintf(stderr, 148 | "std::unordered_set not available, build it " 149 | "with CPP0X=1 or CPP11=1\n"); 150 | return 1; 151 | #endif 152 | #else 153 | hs = shs_alloc(SHS_U32, 0); 154 | #endif 155 | break; 156 | } 157 | switch (csize << 4 | mode) { 158 | case 1 << 4 | CM_BitSet: 159 | CNTLOOP(csize, buf, l, BS, i, count, climit, bs, 1, buf[i]); 160 | break; 161 | case 2 << 4 | CM_BitSet: 162 | CNTLOOP(csize, buf, l, BS, i, count, climit, bs, 2, 163 | (uint32_t)buf[i] << 8 | (uint32_t)buf[i + 1]); 164 | break; 165 | case 3 << 4 | CM_BitSet: 166 | CNTLOOP(csize, buf, l, BS, i, count, climit, bs, 3, 167 | (uint32_t)buf[i] << 16 | (uint32_t)buf[i + 1] << 8 168 | | (uint32_t)buf[i + 2]); 169 | break; 170 | case 4 << 4 | CM_BitSet: 171 | CNTLOOP(csize, buf, l, BS, i, count, climit, bs, 4, 172 | (uint32_t)buf[i] << 24 | (uint32_t)buf[i + 1] << 16 173 | | (uint32_t)buf[i + 2] << 8 174 | | (uint32_t)buf[i + 3]); 175 | break; 176 | case 1 << 4 | CM_Set: 177 | CNTLOOP(csize, buf, l, S, i, count, climit, s, 1, buf[i]); 178 | break; 179 | case 2 << 4 | CM_Set: 180 | CNTLOOP(csize, buf, l, S, i, count, climit, s, 2, 181 | (uint32_t)buf[i] << 8 | (uint32_t)buf[i + 1]); 182 | break; 183 | case 3 << 4 | CM_Set: 184 | CNTLOOP(csize, buf, l, S, i, count, climit, s, 3, 185 | (uint32_t)buf[i] << 16 | (uint32_t)buf[i + 1] << 8 186 | | (uint32_t)buf[i + 2]); 187 | break; 188 | case 4 << 4 | CM_Set: 189 | CNTLOOP(csize, buf, l, S, i, count, climit, s, 4, 190 | (uint32_t)buf[i] << 24 | (uint32_t)buf[i + 1] << 16 191 | | (uint32_t)buf[i + 2] << 8 192 | | (uint32_t)buf[i + 3]); 193 | break; 194 | #if !defined(__cplusplus) || defined(S_COUNTER_CPP_HS) 195 | case 1 << 4 | CM_HashSet: 196 | CNTLOOP(csize, buf, l, HS, i, count, climit, hs, 1, buf[i]); 197 | break; 198 | case 2 << 4 | CM_HashSet: 199 | CNTLOOP(csize, buf, l, HS, i, count, climit, hs, 2, 200 | (uint32_t)buf[i] << 8 | (uint32_t)buf[i + 1]); 201 | break; 202 | case 3 << 4 | CM_HashSet: 203 | CNTLOOP(csize, buf, l, HS, i, count, climit, hs, 3, 204 | (uint32_t)(buf[i] << 16 | (uint32_t)buf[i + 1] << 8 205 | | (uint32_t)buf[i + 2])); 206 | break; 207 | case 4 << 4 | CM_HashSet: 208 | CNTLOOP(csize, buf, l, HS, i, count, climit, hs, 4, 209 | (uint32_t)buf[i] << 24 | (uint32_t)buf[i + 1] << 16 210 | | (uint32_t)buf[i + 2] << 8 211 | | (uint32_t)buf[i + 3]); 212 | break; 213 | #endif 214 | } 215 | if (bs) { 216 | printf(FMT_U ", " FMT_ZU "\n", count, BS_COUNTER_POPCOUNT(bs)); 217 | #ifdef __cplusplus 218 | delete bs; 219 | #else 220 | sb_free(&bs); 221 | #endif 222 | } else if (s) { 223 | printf(FMT_U ", " FMT_ZU "\n", count, S_COUNTER_POPCOUNT(s)); 224 | #ifdef __cplusplus 225 | delete s; 226 | #else 227 | sm_free(&s); 228 | #endif 229 | } else { 230 | #ifdef __cplusplus 231 | #ifdef S_COUNTER_CPP_HS 232 | printf(FMT_U ", " FMT_ZU "\n", count, HS_COUNTER_POPCOUNT(hs)); 233 | delete hs; 234 | #endif 235 | #else 236 | printf(FMT_U ", " FMT_ZU "\n", count, HS_COUNTER_POPCOUNT(hs)); 237 | shs_free(&hs); 238 | #endif 239 | } 240 | return exit_code; 241 | } 242 | 243 | #endif /* #ifndef COUNTER_H */ 244 | -------------------------------------------------------------------------------- /test/counterpp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * counterpp.c 3 | * 4 | * Code counting example using C++ 5 | * 6 | * It shows how different data structures (std::bitset/set/unordered_set) 7 | * behave in memory usage and execution speed. 8 | * 9 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 10 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 11 | */ 12 | 13 | #include "counter.h" 14 | -------------------------------------------------------------------------------- /test/enc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * enc.c 3 | * 4 | * Buffer encoding/decoding example using libsrt 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #include "../src/libsrt.h" 11 | #include "../src/saux/senc.h" /* for debug stats */ 12 | 13 | #define LZHBUF_SIZE S_NPOS /* -ezh high compression: infinite buffer size */ 14 | #define LZBUF_SIZE 1000000 /* -ez fast compression: 1 MB buffer size */ 15 | #define IBUF_SIZE (3 * 4 * 2 * 1024) /* 3 * 4 because of LCM for base64 */ 16 | #define ESC_MAX_SIZE 16 /* maximum size for an escape sequence: 16 bytes */ 17 | 18 | static int syntax_error(const char **argv, const int exit_code) 19 | { 20 | const char *v0 = argv[0]; 21 | fprintf(stderr, 22 | "Buffer encoding/decoding (libsrt example)\n\n" 23 | "Syntax: %s [-eb|-db|-eh|-eH|-dh|-ex|-dx|-ej|-dj|" 24 | "-eu|-du|-ez|-dz|-crc32|-adler32|-fnv|-fnv1a]\n\nExamples:\n" 25 | "%s -eb out.b64\n%s -db out\n" 26 | "%s -eh out.hex\n%s -eH out.HEX\n" 27 | "%s -dh out\n%s -dh out\n" 28 | "%s -ex out.xml.esc\n%s -dx out\n" 29 | "%s -ej out.json.esc\n%s -dj out\n" 30 | "%s -eu out.url.esc\n%s -du out\n" 31 | "%s -ez in.lz\n%s -dz out\n" 32 | "%s -ezh in.lz\n%s -dz out\n" 33 | "%s -crc32 out\n" 34 | "%s -adler32 out\n" 35 | "%s -fnv1 out\n" 36 | "%s -fnv1a out\n" 37 | "%s -mh3_32 out\n", 38 | v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, 39 | v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0); 40 | return exit_code; 41 | } 42 | 43 | int main(int argc, const char **argv) 44 | { 45 | srt_bool done; 46 | const char *b; 47 | srt_string_ref ref; 48 | const uint8_t *dlepc; 49 | int exit_code = 0, cf; 50 | uint8_t esc, dle[S_PK_U64_MAX_BYTES], *dlep; 51 | size_t lmax = 0, li = 0, lo = 0, j, l, l2, ss0, off; 52 | uint32_t acc = 0; 53 | uint32_t (*f32)(const srt_string *, uint32_t, size_t, size_t) = NULL; 54 | srt_string *in = NULL, *out = NULL; 55 | srt_string *(*ss_codec1_f)(srt_string **, const srt_string *) = NULL; 56 | srt_string *(*ss_codec2_f)(srt_string **, const srt_string *) = NULL; 57 | srt_string *(*ss_codec3_f)(srt_string **, const srt_string *) = NULL; 58 | srt_string *(*ss_codec4_f)(srt_string **, const srt_string *) = NULL; 59 | size_t lzbufsize = LZBUF_SIZE; 60 | if (argc < 2) 61 | return syntax_error(argv, 1); 62 | if (!strncmp(argv[1], "-crc32", 6)) { 63 | acc = S_CRC32_INIT; 64 | f32 = ss_crc32r; 65 | } else if (!strncmp(argv[1], "-adler32", 8)) { 66 | acc = S_ADLER32_INIT; 67 | f32 = ss_adler32r; 68 | } else if (!strncmp(argv[1], "-fnv1", 6)) { 69 | acc = S_FNV1_INIT; 70 | f32 = ss_fnv1r; 71 | } else if (!strncmp(argv[1], "-fnv1a", 7)) { 72 | acc = S_FNV1_INIT; 73 | f32 = ss_fnv1ar; 74 | } else if (!strncmp(argv[1], "-mh3_32", 8)) { 75 | acc = S_MH3_32_INIT; 76 | f32 = ss_mh3_32r; 77 | } 78 | if (f32) { 79 | in = ss_alloca(IBUF_SIZE); 80 | while (ss_read(&in, stdin, IBUF_SIZE)) 81 | acc = f32(in, acc, 0, S_NPOS); 82 | printf("%08x\n", acc); 83 | return 0; 84 | } 85 | if (!strncmp(argv[1], "-eb", 3)) 86 | ss_codec1_f = ss_enc_b64; 87 | else if (!strncmp(argv[1], "-db", 4)) 88 | ss_codec1_f = ss_dec_b64; 89 | else if (!strncmp(argv[1], "-eh", 4)) 90 | ss_codec1_f = ss_enc_hex; 91 | else if (!strncmp(argv[1], "-eH", 4)) 92 | ss_codec1_f = ss_enc_HEX; 93 | else if (!strncmp(argv[1], "-dh", 4)) 94 | ss_codec1_f = ss_dec_hex; 95 | else if (!strncmp(argv[1], "-ex", 4)) 96 | ss_codec1_f = ss_enc_esc_xml; 97 | else if (!strncmp(argv[1], "-dx", 4)) 98 | ss_codec2_f = ss_dec_esc_xml; 99 | else if (!strncmp(argv[1], "-ej", 4)) 100 | ss_codec1_f = ss_enc_esc_json; 101 | else if (!strncmp(argv[1], "-dj", 4)) 102 | ss_codec2_f = ss_dec_esc_json; 103 | else if (!strncmp(argv[1], "-eu", 4)) 104 | ss_codec1_f = ss_enc_esc_url; 105 | else if (!strncmp(argv[1], "-du", 4)) 106 | ss_codec2_f = ss_dec_esc_url; 107 | else if (!strncmp(argv[1], "-ezh", 5)) { 108 | ss_codec3_f = ss_enc_lzh; 109 | lzbufsize = LZHBUF_SIZE; 110 | } else if (!strncmp(argv[1], "-ez", 4)) 111 | ss_codec3_f = ss_enc_lz; 112 | else if (!strncmp(argv[1], "-dz", 4)) 113 | ss_codec4_f = ss_dec_lz; 114 | else 115 | return syntax_error(argv, 2); 116 | esc = ss_codec2_f == ss_dec_esc_xml 117 | ? '&' 118 | : ss_codec2_f == ss_dec_esc_json ? '\\' : '%'; 119 | cf = ss_codec1_f 120 | ? 1 121 | : ss_codec2_f ? 2 : ss_codec3_f ? 3 : ss_codec4_f ? 4 : 0; 122 | done = S_FALSE; 123 | ss_reserve(&in, IBUF_SIZE); 124 | while (!done) { 125 | switch (cf) { 126 | case 1: 127 | case 2: 128 | ss0 = ss_size(in); 129 | ss_cat_read(&in, stdin, IBUF_SIZE); 130 | l = ss_size(in); 131 | li += (l - ss0); 132 | if (!l) { 133 | done = S_TRUE; 134 | continue; 135 | } 136 | if (ss_codec1_f) { 137 | ss_codec1_f(&out, in); 138 | ss_clear(in); 139 | break; 140 | } 141 | /* For codecs handling escape characters it is 142 | * necessary to check the escape sequence is not cut 143 | * at boundaries. 144 | */ 145 | b = ss_get_buffer_r(in); 146 | off = 0; 147 | if (l > ESC_MAX_SIZE) 148 | for (j = (size_t)(l - ESC_MAX_SIZE + 1); j < l; 149 | j++) 150 | if (b[j] == esc && b[j - 1] != esc) { 151 | off = (size_t)(l - j); 152 | break; 153 | } 154 | l -= off; 155 | ss_codec2_f(&out, ss_ref_buf(&ref, b, l)); 156 | if (off > 0) 157 | ss_cpy_substr(&in, in, l, S_NPOS); 158 | else 159 | ss_clear(in); 160 | break; 161 | case 3: /* data compression */ 162 | ss_cpy_read(&in, stdin, lzbufsize); 163 | l = ss_size(in); 164 | if (!l) { 165 | done = S_TRUE; 166 | continue; 167 | } 168 | li += l; 169 | ss_codec3_f(&out, in); 170 | lmax = ss_size(out); 171 | dlep = dle; 172 | s_st_pk_u64(&dlep, lmax); 173 | /* dyn LE size */ 174 | l = (size_t)(dlep > dle ? dlep - dle : 0); 175 | if (!fwrite(dle, 1, l, stdout) || ferror(stdout)) { 176 | fprintf(stderr, "Write error\n"); 177 | exit_code = 6; 178 | done = S_TRUE; 179 | continue; 180 | } 181 | lo += l; 182 | ss_clear(in); 183 | break; 184 | case 4: /* data decompression */ 185 | l = fread(dle, 1, 1, stdin); 186 | if (!l || ferror(stdin)) { 187 | done = S_TRUE; 188 | continue; 189 | } 190 | li += l; 191 | l = s_pk_u64_size(dle); 192 | if (!l) { 193 | done = S_TRUE; 194 | continue; 195 | } 196 | if (l > 1) { 197 | l2 = fread(dle + 1, 1, l - 1, stdin); 198 | li += l2; 199 | if (l != (l2 + 1)) { 200 | exit_code = 2; 201 | fprintf(stderr, "Format error\n"); 202 | done = S_TRUE; 203 | continue; 204 | } 205 | l = l2 + 1; 206 | } 207 | dlepc = dle; 208 | lmax = s_ld_pk_u64(&dlepc, l); 209 | ss_cpy_read(&in, stdin, lmax); 210 | l = ss_size(in); 211 | li += l; 212 | if (l != lmax || ferror(stdin)) { 213 | fprintf(stderr, "Read error\n"); 214 | exit_code = 4; 215 | done = S_TRUE; 216 | continue; 217 | } 218 | ss_codec4_f(&out, in); 219 | break; 220 | default: 221 | fprintf(stderr, "Logic error\n"); 222 | exit_code = 8; 223 | done = S_TRUE; 224 | continue; 225 | } 226 | if (ss_write(stdout, out, 0, S_NPOS) < 0) { 227 | fprintf(stderr, "Write error\n"); 228 | exit_code = 6; 229 | break; 230 | } 231 | lo += ss_size(out); 232 | ss_clear(out); 233 | } 234 | fprintf(stderr, "in: " FMT_ZU " bytes, out: " FMT_ZU " bytes\n", li, 235 | lo); 236 | #ifdef S_USE_VA_ARGS 237 | ss_free(&in, &out); 238 | #else 239 | ss_free(&in); 240 | ss_free(&out); 241 | #endif 242 | return exit_code; 243 | } 244 | -------------------------------------------------------------------------------- /test/histogram.c: -------------------------------------------------------------------------------- 1 | /* 2 | * histogram.c 3 | * 4 | * Histogram example using libsrt 5 | * 6 | * It shows how different data structures (map and hash map) behave in 7 | * memory usage and execution speed. 8 | * 9 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 10 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 11 | */ 12 | 13 | #include "histogram.h" 14 | -------------------------------------------------------------------------------- /test/histogram.h: -------------------------------------------------------------------------------- 1 | /* 2 | * histogram.h 3 | * 4 | * Histogram examples, one using libsrt, and the other using C++/STL 5 | * 6 | * This is a template for both the C and C++ versions. The C version 7 | * use libsrt types and functions, and the C++ use the STL library. The 8 | * purpose is to compare libsrt vs C++/STL. 9 | * 10 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 11 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 12 | */ 13 | 14 | #ifndef HISTOGRAM_H 15 | #define HISTOGRAM_H 16 | 17 | #include "../src/libsrt.h" 18 | #ifdef __cplusplus 19 | #include 20 | #define S_M64 m64 21 | #define S_HM64 hm64 22 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 23 | #define S_HISTOGRAM_CPP_HM 24 | #include 25 | #endif 26 | #define HIST_TAG "C++" 27 | #else 28 | #define S_M64 m 29 | #define S_HM64 hm 30 | #define HIST_TAG "libsrt" 31 | #endif 32 | 33 | static int syntax_error(const char **argv, int exit_code) 34 | { 35 | const char *v0 = argv[0]; 36 | fprintf(stderr, 37 | "Histogram (" HIST_TAG " example). Returns: list of elements " 38 | "and its count\n\nSyntax: %s element_size [-hm|-m] " 39 | "# (1 <= element_size <= 8; -hm: use a hash map (default), " 40 | "-m: use a map -slower-)\n\nExamples:\n" 41 | "%s 1 h.txt # (1-byte element h. e.g. 8bpp bitmap)\n" 42 | "%s 2 h.txt # (2-byte element h. e.g. 16bpp bitmap)\n" 43 | "%s 3 h.txt # (3-byte element h. e.g. 24bpp bitmap)\n" 44 | "%s 4 h.txt # (4-byte element h. e.g. 32bpp bitmap)\n" 45 | "%s 5 h.txt # (5-byte element histogram)\n" 46 | "%s 6 h.txt # (6-byte element histogram)\n" 47 | "%s 7 h.txt # (7-byte element histogram)\n" 48 | "%s 8 h.txt # (8-byte element histogram)\n" 49 | "%s 8 -m h.txt # (8-byte element histogram, using a map " 50 | "instead of a hash map)\nhead -c 256MB h.txt # Check random gen. quality\n", 52 | v0, v0, v0, v0, v0, v0, v0, v0, v0, v0, v0); 53 | return exit_code; 54 | } 55 | 56 | #ifdef __cplusplus 57 | #define S_HIST_INC(f, m, key, inc, T) (*m)[key] += ((T)(inc)) 58 | #else 59 | #define S_HIST_INC(f, m, key, inc, T) f(&m, key, ((T)(inc))) 60 | 61 | static srt_bool cb32(uint32_t k, uint32_t v, void *context) 62 | { 63 | S_UNUSED(context); 64 | printf("%08x %u\n", (unsigned)k, (unsigned)v); 65 | return S_TRUE; 66 | } 67 | 68 | static srt_bool cb64(int64_t k, int64_t v, void *context) 69 | { 70 | unsigned vh = (unsigned)(v / 1000000000), 71 | vl = (unsigned)(v % 1000000000); 72 | S_UNUSED(context); 73 | if (vh) 74 | printf("%08x%08x %u%u\n", (unsigned)(k >> 32), (unsigned)k, vh, 75 | vl); 76 | else 77 | printf("%08x%08x %u\n", (unsigned)(k >> 32), (unsigned)k, vl); 78 | return S_TRUE; 79 | } 80 | #endif 81 | 82 | /* 83 | * Local optimization: instead of calling N times to the map for the case of 84 | * repeated elements, we keep the count and set the counter for all the 85 | * repeated elements at once (3x speed-up for non random data) 86 | */ 87 | #define CNTLOOP(i, l, csize, buf, rep_cnt, m, inc, k, ki, kip, f, T) \ 88 | do { \ 89 | l = fread(buf, 1, sizeof(buf), stdin); \ 90 | l = (l / (size_t)csize) * (size_t)csize; \ 91 | rep_cnt = 0; \ 92 | for (i = 0; i < l; i += inc) { \ 93 | ki = k; \ 94 | if (ki == kip) { \ 95 | rep_cnt++; \ 96 | continue; \ 97 | } \ 98 | if (rep_cnt) { \ 99 | S_HIST_INC(f, m, kip, rep_cnt, T); \ 100 | rep_cnt = 0; \ 101 | } \ 102 | kip = ki; \ 103 | S_HIST_INC(f, m, ki, 1, T); \ 104 | } \ 105 | if (rep_cnt) \ 106 | S_HIST_INC(f, m, kip, rep_cnt, T); \ 107 | } while (l > 0) 108 | 109 | enum eHistMode { HM_Map, HM_HashMap }; 110 | 111 | int main(int argc, const char **argv) 112 | { 113 | #ifdef __cplusplus 114 | std::map *m = NULL; 115 | std::map *m64 = NULL; 116 | #ifdef S_HISTOGRAM_CPP_HM 117 | std::unordered_map *hm = NULL; 118 | std::unordered_map *hm64 = NULL; 119 | #endif 120 | #else 121 | srt_map *m = NULL; 122 | srt_hmap *hm = NULL; 123 | #endif 124 | int csize, exit_code; 125 | enum eHistMode mode = HM_HashMap; 126 | size_t i, l, rep_cnt = 0; 127 | uint32_t k32 = 0, kp32 = 0; 128 | int64_t k64 = 0, kp64 = 0; 129 | uint8_t buf[2 * 3 * 4 * 5 * 7 * 16]; /* buffer size: LCM(1..8) */ 130 | if (argc < 2) 131 | return syntax_error(argv, 5); 132 | if (argc >= 3) { 133 | if (!strcmp(argv[2], "-m")) 134 | mode = HM_Map; 135 | else if (!strcmp(argv[2], "-hm")) 136 | mode = HM_HashMap; 137 | else 138 | syntax_error(argv, 6); 139 | } 140 | csize = atoi(argv[1]); 141 | if (csize < 1 || csize > 8) 142 | return syntax_error(argv, 6); 143 | exit_code = 0; 144 | if (mode == HM_HashMap) { 145 | #ifdef __cplusplus 146 | #ifdef S_HISTOGRAM_CPP_HM 147 | if (csize <= 4) 148 | hm = new std::unordered_map(); 149 | else 150 | hm64 = new std::unordered_map(); 151 | #else 152 | fprintf(stderr, 153 | "std::unordered_map not available, build it " 154 | "with CPP0X=1 or CPP11=1\n"); 155 | #endif 156 | #else 157 | hm = shm_alloc(csize <= 4 ? SHM_UU32 : SHM_II, 0); 158 | #endif 159 | } else { 160 | #ifdef __cplusplus 161 | if (csize <= 4) 162 | m = new std::map(); 163 | else 164 | m64 = new std::map(); 165 | #else 166 | m = sm_alloc(csize <= 4 ? SM_UU32 : SM_II, 0); 167 | #endif 168 | } 169 | switch ((unsigned)csize << 4 | mode) { 170 | case 1 << 4 | HM_Map: 171 | CNTLOOP(i, l, csize, buf, rep_cnt, m, 1, buf[i], k32, kp32, 172 | sm_inc_uu32, uint32_t); 173 | break; 174 | case 2 << 4 | HM_Map: 175 | CNTLOOP(i, l, csize, buf, rep_cnt, m, 2, S_LD_LE_U16(buf + i), 176 | k32, kp32, sm_inc_uu32, uint32_t); 177 | break; 178 | case 3 << 4 | HM_Map: 179 | CNTLOOP(i, l, csize, buf, rep_cnt, m, 3, 180 | S_LD_LE_U32(buf + i) & 0xffffff, k32, kp32, 181 | sm_inc_uu32, uint32_t); 182 | break; 183 | case 4 << 4 | HM_Map: 184 | CNTLOOP(i, l, csize, buf, rep_cnt, m, 4, S_LD_LE_U32(buf + i), 185 | k32, kp32, sm_inc_uu32, uint32_t); 186 | break; 187 | case 5 << 4 | HM_Map: 188 | CNTLOOP(i, l, csize, buf, rep_cnt, S_M64, 5, 189 | (int64_t)S_LD_LE_U64(buf + i) & 0xffffffffffLL, k64, 190 | kp64, sm_inc_ii, int64_t); 191 | break; 192 | case 6 << 4 | HM_Map: 193 | CNTLOOP(i, l, csize, buf, rep_cnt, S_M64, 6, 194 | (int64_t)S_LD_LE_U64(buf + i) & 0xffffffffffffLL, k64, 195 | kp64, sm_inc_ii, int64_t); 196 | break; 197 | case 7 << 4 | HM_Map: 198 | CNTLOOP(i, l, csize, buf, rep_cnt, S_M64, 7, 199 | (int64_t)S_LD_LE_U64(buf + i) & 0xffffffffffffffLL, k64, 200 | kp64, sm_inc_ii, int64_t); 201 | break; 202 | case 8 << 4 | HM_Map: 203 | CNTLOOP(i, l, csize, buf, rep_cnt, S_M64, 8, 204 | (int64_t)S_LD_LE_U64(buf + i), k64, kp64, sm_inc_ii, 205 | int64_t); 206 | break; 207 | #if !defined(__cplusplus) || defined(S_HISTOGRAM_CPP_HM) 208 | case 1 << 4 | HM_HashMap: 209 | CNTLOOP(i, l, csize, buf, rep_cnt, hm, 1, buf[i], k32, kp32, 210 | shm_inc_uu32, uint32_t); 211 | break; 212 | case 2 << 4 | HM_HashMap: 213 | CNTLOOP(i, l, csize, buf, rep_cnt, hm, 2, S_LD_LE_U16(buf + i), 214 | k32, kp32, shm_inc_uu32, uint32_t); 215 | break; 216 | case 3 << 4 | HM_HashMap: 217 | CNTLOOP(i, l, csize, buf, rep_cnt, hm, 3, 218 | S_LD_LE_U32(buf + i) & 0xffffff, k32, kp32, 219 | shm_inc_uu32, uint32_t); 220 | break; 221 | case 4 << 4 | HM_HashMap: 222 | CNTLOOP(i, l, csize, buf, rep_cnt, hm, 4, S_LD_LE_U32(buf + i), 223 | k32, kp32, shm_inc_uu32, uint32_t); 224 | break; 225 | case 5 << 4 | HM_HashMap: 226 | CNTLOOP(i, l, csize, buf, rep_cnt, S_HM64, 5, 227 | (int64_t)S_LD_LE_U64(buf + i) & 0xffffffffffLL, k64, 228 | kp64, shm_inc_ii, int64_t); 229 | break; 230 | case 6 << 4 | HM_HashMap: 231 | CNTLOOP(i, l, csize, buf, rep_cnt, S_HM64, 6, 232 | (int64_t)S_LD_LE_U64(buf + i) & 0xffffffffffffLL, k64, 233 | kp64, shm_inc_ii, int64_t); 234 | break; 235 | case 7 << 4 | HM_HashMap: 236 | CNTLOOP(i, l, csize, buf, rep_cnt, S_HM64, 7, 237 | (int64_t)S_LD_LE_U64(buf + i) & 0xffffffffffffffLL, k64, 238 | kp64, shm_inc_ii, int64_t); 239 | break; 240 | case 8 << 4 | HM_HashMap: 241 | CNTLOOP(i, l, csize, buf, rep_cnt, S_HM64, 8, 242 | (int64_t)S_LD_LE_U64(buf + i), k64, kp64, shm_inc_ii, 243 | int64_t); 244 | break; 245 | #endif 246 | default: 247 | break; 248 | } 249 | #ifdef __cplusplus 250 | #ifdef S_HISTOGRAM_CPP_HM 251 | if (hm || hm64) { 252 | if (hm) { 253 | std::unordered_map::iterator it = 254 | hm->begin(); 255 | for (; it != hm->end(); it++) 256 | printf("%08x %u\n", (unsigned)it->first, 257 | (unsigned)it->second); 258 | delete hm; 259 | } else { 260 | std::unordered_map::iterator it = 261 | hm64->begin(); 262 | for (; it != hm64->end(); it++) 263 | printf("%016" PRIx64 " %02" PRIx64 "\n", 264 | it->first, it->second); 265 | delete hm; 266 | delete hm64; 267 | } 268 | } else 269 | #endif 270 | #else 271 | if (hm) { 272 | if (csize <= 4) 273 | shm_itp_uu32(hm, 0, S_NPOS, cb32, NULL); 274 | else 275 | shm_itp_ii(hm, 0, S_NPOS, cb64, NULL); 276 | shm_free(&hm); 277 | } else 278 | #endif 279 | { 280 | #ifdef __cplusplus 281 | if (m) { 282 | std::map::iterator it = m->begin(); 283 | for (; it != m->end(); it++) 284 | printf("%08x %u\n", (unsigned)it->first, 285 | (unsigned)it->second); 286 | delete m; 287 | } else { 288 | std::map::iterator it = 289 | m64->begin(); 290 | for (; it != m64->end(); it++) 291 | printf("%016" PRIx64 " %" PRIx64 "\n", 292 | it->first, it->second); 293 | delete m64; 294 | } 295 | #else 296 | if (csize <= 4) 297 | sm_itr_uu32(m, 0, UINT32_MAX, cb32, NULL); 298 | else 299 | sm_itr_ii(m, INT64_MIN, INT64_MAX, cb64, NULL); 300 | sm_free(&m); 301 | #endif 302 | } 303 | return exit_code; 304 | } 305 | 306 | #endif /* #ifndef HISTOGRAM_H */ 307 | -------------------------------------------------------------------------------- /test/histogrampp.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * histogrampp.cc 3 | * 4 | * Histogram example using C++ 5 | * 6 | * It shows how different data structures (std::map/unordered_map) behave in 7 | * memory usage and execution speed. 8 | * 9 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 10 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 11 | */ 12 | 13 | #include "histogram.h" 14 | 15 | -------------------------------------------------------------------------------- /test/imgc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imgc.c 3 | * 4 | * Image processing example using libsrt 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | * 9 | * Observations: 10 | * - In order to have PNG and JPEG support: make imgc HAS_JPG=1 HAS_PNG=1 11 | */ 12 | 13 | #include "imgtools.h" 14 | 15 | static int exit_with_error(const char **argv, const char *msg, int exit_code); 16 | 17 | int main(int argc, const char **argv) 18 | { 19 | size_t in_size = 0, enc_bytes, rgb_bytes; 20 | ssize_t written; 21 | struct RGB_Info ri; 22 | srt_string *iobuf = NULL, *rgb_buf = NULL; 23 | int exit_code = 1; 24 | FILE *fin = NULL, *fout = NULL; 25 | const char *exit_msg = "not enough parameters"; 26 | int filter = F_None; 27 | enum ImgTypes t_in, t_out; 28 | srt_bool ro; 29 | 30 | #define IMGC_XTEST(test, m, c) \ 31 | if (test) { \ 32 | exit_msg = m; \ 33 | exit_code = c; \ 34 | break; \ 35 | } 36 | 37 | for (;;) { 38 | if (argc < 2) 39 | break; 40 | if (argc > 3) { 41 | filter = atoi(argv[3]); 42 | IMGC_XTEST(filter >= F_NumElems, "invalid filter", 10); 43 | } 44 | ro = argc < 3 ? S_TRUE : S_FALSE; 45 | t_in = file_type(argv[1]); 46 | t_out = ro ? IMG_none : file_type(argv[2]); 47 | IMGC_XTEST(t_in == IMG_error || t_out == IMG_error, 48 | "invalid parameters", t_in == IMG_error ? 2 : 3); 49 | 50 | fin = fopen(argv[1], "rb"); 51 | iobuf = ss_dup_read(fin, MAX_FILE_SIZE); 52 | in_size = ss_size(iobuf); 53 | IMGC_XTEST(!in_size, "input read error", 4); 54 | 55 | rgb_bytes = any2rgb(&rgb_buf, &ri, iobuf, t_in); 56 | IMGC_XTEST(!rgb_bytes, "can not process input file", 5); 57 | 58 | if (ro) 59 | printf("%s: ", argv[1]); 60 | enc_bytes = rgb2type(&iobuf, t_out, rgb_buf, &ri, filter); 61 | IMGC_XTEST(!enc_bytes, "output file encoding error", 6); 62 | 63 | fout = fopen(argv[2], "wb+"); 64 | written = ro ? 0 : ss_write(fout, iobuf, 0, ss_size(iobuf)); 65 | IMGC_XTEST(!ro 66 | && (written < 0 67 | || (size_t)written != ss_size(iobuf)), 68 | "write error", 7); 69 | 70 | exit_code = 0; 71 | if (!ro) 72 | IF_DEBUG_IMGC(fprintf( 73 | stderr, 74 | "%s (%ix%i %ibpp %ich) %u bytes" 75 | " > %s %u bytes\n", 76 | argv[1], (int)ri.width, (int)ri.height, 77 | (int)ri.bpp, (int)ri.chn, (unsigned)in_size, 78 | argv[2], (unsigned)ss_size(iobuf))); 79 | break; 80 | } 81 | #ifdef S_USE_VA_ARGS 82 | ss_free(&iobuf, &rgb_buf); 83 | #else 84 | ss_free(&iobuf); 85 | ss_free(&rgb_buf); 86 | #endif 87 | if (fin) 88 | fclose(fin); 89 | if (fout) 90 | fclose(fout); 91 | return exit_code ? exit_with_error(argv, exit_msg, exit_code) : 0; 92 | } 93 | 94 | static int exit_with_error(const char **argv, const char *msg, int exit_code) 95 | { 96 | const char *v0 = argv[0]; 97 | fprintf(stderr, 98 | "Image conversion (libsrt example)\n\n" 99 | "Error [%i]: %s\nSyntax: %s in." FMT_IMGS_IN " [out." 100 | FMT_IMGS_OUT " [filter]]\n" 101 | "Filters: 0 none, 1 left->right DPCM, 2 reverse of (1), " 102 | "3 left->right xor DPCM,\n\t 4 reverse of (3), 5 up->down DPCM" 103 | ", 6 reverse of (5),\n\t 7 up->down xor DPCM, 8 reverse of (7)" 104 | ", 9 left/up/up-left average DPCM,\n\t 10 reverse of (9), " 105 | "11 Paeth DPCM, 12 reverse of (11),\n\t 13 red substract, 14 " 106 | "reverse of (13), 15 green substract, 16 reverse\n\t of (15), " 107 | "17 blue substract, 18 reverse of (17)\n\n" 108 | "Examples:\n" 109 | "%s input.pgm # Show image statistics\n" 110 | IF_PNG("%s input.png output.ppm # Convert png to ppm\n") 111 | IF_JPG("%s input.jpg output.tga # Convert jpg to tga\n") 112 | "%s input.ppm output.tga # Convert ppm to tga\n" 113 | "%s input.ppm output.tga 5 # Convert ppm to tga + filter\n", 114 | exit_code, msg, v0, v0, IF_PNG(v0 MY_COMMA) IF_JPG(v0 MY_COMMA) 115 | v0, v0); 116 | return exit_code; 117 | } 118 | -------------------------------------------------------------------------------- /test/imgd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imgd.c 3 | * 4 | * Image comparison/diff example using libsrt 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | * 9 | * Observations: 10 | * - In order to have PNG and JPEG support: make imgc HAS_JPG=1 HAS_PNG=1 11 | */ 12 | 13 | #include "imgtools.h" 14 | 15 | static int exit_with_error(const char **argv, const char *msg, int exit_code); 16 | 17 | int main(int argc, const char **argv) 18 | { 19 | size_t in_size = 0, enc_bytes, rgb1_bytes, rgb2_bytes; 20 | ssize_t written; 21 | struct RGB_Info ri1, ri2; 22 | srt_string *iobuf = NULL, *rgb1_buf = NULL, *rgb2_buf = NULL, 23 | *rgb3_buf = NULL; 24 | int exit_code = 2; 25 | FILE *fin = NULL, *fout = NULL; 26 | const char *exit_msg = "not enough parameters"; 27 | srt_bool ro; 28 | enum ImgTypes t_in1, t_in2, t_out; 29 | 30 | #define IMGC_XTEST(test, m, c) \ 31 | if (test) { \ 32 | exit_msg = m; \ 33 | exit_code = c; \ 34 | break; \ 35 | } 36 | 37 | for (;;) { 38 | if (argc < 2) 39 | break; 40 | ro = argc < 3 ? S_TRUE : S_FALSE; 41 | t_in1 = file_type(argv[1]); 42 | t_in2 = file_type(argv[2]); 43 | t_out = argc < 4 ? IMG_none : file_type(argv[3]); 44 | IMGC_XTEST(t_in1 == IMG_error || t_in2 == IMG_error 45 | || t_out == IMG_error, 46 | "invalid parameters", 47 | t_in1 == IMG_error || t_in2 == IMG_error ? 3 : 4); 48 | 49 | fin = fopen(argv[1], "rb"); 50 | iobuf = ss_dup_read(fin, MAX_FILE_SIZE); 51 | in_size = ss_size(iobuf); 52 | IMGC_XTEST(!in_size, "input #1 read error", 5); 53 | 54 | rgb1_bytes = any2rgb(&rgb1_buf, &ri1, iobuf, t_in1); 55 | IMGC_XTEST(!rgb1_bytes, "can not process input file #1", 6); 56 | 57 | fclose(fin); 58 | fin = fopen(argv[2], "rb"); 59 | ss_read(&iobuf, fin, MAX_FILE_SIZE); 60 | in_size = ss_size(iobuf); 61 | IMGC_XTEST(!in_size, "input #2 read error", 7); 62 | 63 | rgb2_bytes = any2rgb(&rgb2_buf, &ri2, iobuf, t_in2); 64 | IMGC_XTEST(!rgb2_bytes, "can not process input file #2", 8); 65 | 66 | IMGC_XTEST(ss_size(rgb1_buf) != ss_size(rgb2_buf), 67 | "can not process input file #2", 9); 68 | 69 | exit_code = rgbdiff(&rgb3_buf, rgb1_buf, &ri1, rgb2_buf, &ri2) 70 | ? 1 71 | : 0; 72 | 73 | if (exit_code == 1) 74 | fprintf(stderr, "Image files %s and %s differ\n", 75 | argv[1], argv[2]); 76 | 77 | if (t_out != IMG_none) { 78 | enc_bytes = 79 | rgb2type(&iobuf, t_out, rgb3_buf, &ri1, F_None); 80 | IMGC_XTEST(!enc_bytes, "output file encoding error", 81 | 10); 82 | 83 | fout = fopen(argv[3], "wb+"); 84 | written = ss_write(fout, iobuf, 0, ss_size(iobuf)); 85 | 86 | IMGC_XTEST(!ro 87 | && (written < 0 88 | || (size_t)written 89 | != ss_size(iobuf)), 90 | "write error", 11); 91 | } 92 | break; 93 | } 94 | #ifdef S_USE_VA_ARGS 95 | ss_free(&iobuf, &rgb1_buf, &rgb2_buf, &rgb3_buf); 96 | #else 97 | ss_free(&iobuf); 98 | ss_free(&rgb1_buf); 99 | ss_free(&rgb2_buf); 100 | ss_free(&rgb3_buf); 101 | #endif 102 | if (fin) 103 | fclose(fin); 104 | if (fout) 105 | fclose(fout); 106 | return exit_code > 1 ? exit_with_error(argv, exit_msg, exit_code) : 0; 107 | } 108 | 109 | static int exit_with_error(const char **argv, const char *msg, int exit_code) 110 | { 111 | const char *v0 = argv[0]; 112 | fprintf(stderr, 113 | "Image diff (libsrt example)\n\n" 114 | "Error [%i]: %s\nSyntax: %s in1." FMT_IMGS_IN " in2." 115 | FMT_IMGS_IN " [out." FMT_IMGS_OUT "]\nExit code 0: matching " 116 | "images, not 0: not matching or syntax error\n\nExamples:\n" 117 | IF_PNG("%s i1.png i2.png o.ppm # i1.png vs i2.png to o.ppm\n") 118 | IF_JPG("%s i1.jpg i2.jpg o.tga # i1.jpg vs i2.jpg to o.tga\n") 119 | "%s i1.ppm i2.tga o.tga # i1.ppm vs i2.tga to o.tga\n", 120 | exit_code, msg, v0, IF_PNG(v0 MY_COMMA) IF_JPG(v0 MY_COMMA) v0); 121 | return exit_code; 122 | } 123 | -------------------------------------------------------------------------------- /test/imgtools.h: -------------------------------------------------------------------------------- 1 | /* 2 | * imgtools.h 3 | * 4 | * Image processing example using libsrt 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | * 9 | * Observations: 10 | * - In order to have PNG and JPEG support: make imgc HAS_JPG=1 HAS_PNG=1 11 | */ 12 | 13 | #ifndef IMGTOOLS_H 14 | #define IMGTOOLS_H 15 | 16 | #include "../src/libsrt.h" 17 | #include "rgbi.h" 18 | 19 | #define DEBUG_IMGC 20 | #define MY_COMMA , 21 | #define FMT_IMGS(a) "{tga|ppm|pgm" IF_PNG("|png") IF_JPG("|jpg|jpeg") a "}" 22 | #define FMT_IMGS_IN FMT_IMGS("") 23 | #define FMT_IMGS_OUT FMT_IMGS("|raw") 24 | #define MAX_FILE_SIZE (1024 * 1024 * 1024) 25 | 26 | #ifdef DEBUG_IMGC 27 | #define IF_DEBUG_IMGC(a) a 28 | #else 29 | #define IF_DEBUG_IMGC(a) 30 | #endif 31 | #ifdef HAS_PNG 32 | #include 33 | #include 34 | #define IF_PNG(a) a 35 | #else 36 | #define IF_PNG(a) 37 | #endif 38 | #ifdef HAS_JPG 39 | #include 40 | #define IF_JPG(a) a 41 | #else 42 | #define IF_JPG(a) 43 | #endif 44 | 45 | enum ImgTypes { 46 | IMG_error, 47 | IMG_tga, 48 | IMG_ppm, 49 | IMG_pgm, 50 | IMG_png, 51 | IMG_jpg, 52 | IMG_raw, 53 | IMG_ll1, 54 | IMG_none 55 | }; 56 | 57 | enum Filters { 58 | F_None, 59 | F_HDPCM, 60 | F_HRDPCM, 61 | F_HDXOR, 62 | F_HRDXOR, 63 | F_VDPCM, 64 | F_VRDPCM, 65 | F_VDXOR, 66 | F_VRDXOR, 67 | F_AVG3, 68 | F_RAVG3, 69 | F_PAETH, 70 | F_RPAETH, 71 | F_RSUB, 72 | F_RRSUB, 73 | F_GSUB, 74 | F_RGSUB, 75 | F_BSUB, 76 | F_RBSUB, 77 | F_NumElems 78 | }; 79 | 80 | size_t any2rgb(srt_string **rgb, struct RGB_Info *ri, const srt_string *in, 81 | enum ImgTypes in_type); 82 | size_t rgb2type(srt_string **out, enum ImgTypes out_type, const srt_string *rgb, 83 | const struct RGB_Info *ri, int filter); 84 | enum ImgTypes file_type(const char *file_name); 85 | int rgbdiff(srt_string **out, const srt_string *rgb0, 86 | const struct RGB_Info *ri0, const srt_string *rgb1, 87 | const struct RGB_Info *ri1); 88 | 89 | #endif /* IMGTOOLS_H */ 90 | -------------------------------------------------------------------------------- /test/rgbi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rgbi.h 3 | * 4 | * RGB bitmap description. Image processing example for libsrt. 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #ifndef RGBI_H 11 | #define RGBI_H 12 | 13 | #include "../src/libsrt.h" 14 | 15 | struct RGB_Info { 16 | size_t width, height, bpp, Bpp, chn, bpc, Bpc, row_size, bmp_size; 17 | }; 18 | 19 | S_INLINE srt_bool rgbi_valid(const struct RGB_Info *ri) 20 | { 21 | return ri && ri->chn > 0 && ri->bpp >= 8 && ri->Bpp > 0 && ri->width > 0 22 | && ri->height > 0 && ri->row_size > 0 23 | ? S_TRUE 24 | : S_FALSE; 25 | } 26 | 27 | S_INLINE void rgbi_set(struct RGB_Info *i, size_t w, size_t h, size_t b, 28 | size_t c) 29 | { 30 | if (i) { 31 | i->width = w; 32 | i->height = h; 33 | i->bpp = b; 34 | i->Bpp = b / 8; 35 | i->chn = c; 36 | i->bpc = b / c; 37 | i->Bpc = i->Bpp / c; 38 | i->row_size = (w * b) / 8; 39 | i->bmp_size = i->row_size * h; 40 | } 41 | } 42 | 43 | S_INLINE srt_bool rgbi_cmp(const struct RGB_Info *a, const struct RGB_Info *b) 44 | { 45 | return a && b && a->width == b->width && a->height == b->height 46 | && a->bpp == b->bpp && a->chn == b->chn && a->bpc == b->bpc; 47 | } 48 | 49 | /* 50 | * Pixel packing is related to counting colors and fast pixel comparisons. 51 | */ 52 | 53 | S_INLINE unsigned short rgbi_pack2(const unsigned char *p) 54 | { 55 | return S_LD_LE_U16(p); 56 | } 57 | 58 | S_INLINE unsigned rgbi_pack3(const unsigned char *rgb) 59 | { 60 | return rgbi_pack2(rgb) | ((unsigned)rgb[2] & 0xff) << 8; 61 | } 62 | 63 | S_INLINE unsigned rgbi_pack4(const unsigned char *rgba) 64 | { 65 | return S_LD_LE_U32(rgba); 66 | } 67 | 68 | S_INLINE uint64_t rgbi_pack6(const unsigned char *rgb) 69 | { 70 | return S_LD_LE_U32(rgb) | ((uint64_t)S_LD_LE_U16(rgb + 4)) << 32; 71 | } 72 | 73 | S_INLINE uint64_t rgbi_pack8(const unsigned char *rgba) 74 | { 75 | return S_LD_LE_U32(rgba) | ((uint64_t)S_LD_LE_U32(rgba + 4)) << 32; 76 | } 77 | 78 | /* TODO: check if the compiler is able to optimize this properly */ 79 | S_INLINE 80 | uint64_t rgbi_get(const char *buf, size_t x, size_t y, size_t rs, size_t ps) 81 | { 82 | const unsigned char *b = (const unsigned char *)buf; 83 | switch (ps) { 84 | case 1: 85 | return (unsigned char)b[y * rs + x]; 86 | case 2: 87 | return rgbi_pack2(b + y * rs + x * ps); 88 | case 3: 89 | return rgbi_pack3(b + y * rs + x * ps); 90 | case 4: 91 | return rgbi_pack4(b + y * rs + x * ps); 92 | case 6: 93 | return rgbi_pack6(b + y * rs + x * ps); 94 | case 8: 95 | return rgbi_pack8(b + y * rs + x * ps); 96 | default: 97 | break; 98 | } 99 | return 0; 100 | } 101 | 102 | #endif /* RGBI_H */ 103 | -------------------------------------------------------------------------------- /test/utf8_examples.h: -------------------------------------------------------------------------------- 1 | /* 2 | * utf8_examples.h 3 | * 4 | * UTF8 constants used by libsrt tests and examples 5 | * 6 | * Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | * Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | */ 9 | 10 | #ifndef UTF8_EXAMPLES_H 11 | #define UTF8_EXAMPLES_H 12 | 13 | #define U8_C_N_TILDE_D1 "\xc3\x91" 14 | #define U8_S_N_TILDE_F1 "\xc3\xb1" 15 | #define U8_S_I_DOTLESS_131 "\xc4\xb1" /* Turkish small I without dot */ 16 | #define U8_C_I_DOTTED_130 "\xc4\xb0" /* Turkish capital I with dot */ 17 | #define U8_C_G_BREVE_11E "\xc4\x9e" 18 | #define U8_S_G_BREVE_11F "\xc4\x9f" 19 | #define U8_C_S_CEDILLA_15E "\xc5\x9e" 20 | #define U8_S_S_CEDILLA_15F "\xc5\x9f" 21 | #define U8_CENT_00A2 "\xc2\xa2" 22 | #define U8_EURO_20AC "\xe2\x82\xac" 23 | #define U8_HAN_24B62 "\xf0\xa4\xad\xa2" 24 | #define U8_HAN_611B "\xe6\x84\x9b" 25 | 26 | #define U8_MIX1 \ 27 | U8_C_N_TILDE_D1 U8_S_N_TILDE_F1 U8_S_I_DOTLESS_131 U8_C_I_DOTTED_130 \ 28 | U8_C_G_BREVE_11E U8_S_G_BREVE_11F U8_C_S_CEDILLA_15E \ 29 | U8_S_S_CEDILLA_15F U8_CENT_00A2 U8_EURO_20AC \ 30 | U8_HAN_24B62 31 | #define U8_MIX_28_bytes U8_MIX1 U8_HAN_611B 32 | 33 | #define U8_MANY_UNDERSCORES \ 34 | "____________________________________________________________________" \ 35 | "____________________________________________________________________" \ 36 | "____________________________________________________________________" \ 37 | "____________________________________________________________________" 38 | 39 | #endif /* UTF8_EXAMPLES_H */ 40 | -------------------------------------------------------------------------------- /utl/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | # AccessModifierOffset: -2 5 | AlignAfterOpenBracket: true 6 | # AlignConsecutiveAssignments: false 7 | # AlignConsecutiveDeclarations: false 8 | # AlignEscapedNewlines: Right 9 | # AlignOperands: true 10 | AlignEscapedNewlinesLeft: false 11 | AlignTrailingComments: true 12 | AllowAllParametersOfDeclarationOnNextLine: false 13 | # AllowShortBlocksOnASingleLine: false 14 | # AllowShortCaseLabelsOnASingleLine: false 15 | AllowShortFunctionsOnASingleLine: false 16 | AllowShortIfStatementsOnASingleLine: false 17 | AllowShortLoopsOnASingleLine: false 18 | # AlwaysBreakAfterDefinitionReturnType: None 19 | # AlwaysBreakAfterReturnType: None 20 | AlwaysBreakBeforeMultilineStrings: true 21 | BreakBeforeBinaryOperators: NonAssignment 22 | BreakBeforeBraces: Linux 23 | # BreakBeforeTernaryOperators: true 24 | BreakStringLiterals: false 25 | # BreakStringLiterals: true 26 | ContinuationIndentWidth: 8 27 | IndentCaseLabels: false 28 | IndentWidth: 8 29 | MaxEmptyLinesToKeep: 1 30 | SortIncludes: true 31 | SpaceAfterCStyleCast: false 32 | UseTab: Always 33 | TabWidth: 8 34 | -------------------------------------------------------------------------------- /utl/c2doc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # doc.py 4 | # 5 | # Automatic documentation generator. 6 | # 7 | # Example: doc/c2doc.py < src/sstring.h > output.html 8 | # 9 | # Tag syntax example from src/smap.h: 10 | # /* #API: |Insert into uint32-uint32 map|map; key; value|S_TRUE: OK, S_FALSE: insertion error|O(log n)|1;2| */ 11 | # srt_sbool sm_uu32_insert(srt_map **m, uint32_t k, uint32_t v); 12 | # 13 | # /* #API: |a|b|c|d|e| */ 14 | # return_type function_name(param1, ..., paramN); 15 | # 16 | # a: function description 17 | # b: function parameters, separated by ";" 18 | # c: return value (optional, if none, put "-") 19 | # d: time and space complexity (space complexity being optional if no 20 | # extra space), separated by ";" 21 | # e: implementation status, separated by ";" 22 | # #1, code coverage: 23 | # 0 basic coverage (Coverity, clang analyzer) 24 | # 1 covered by test (test + Valgrind) 25 | # 2 covered by proof 26 | # #2, code quality: 27 | # 0 not reviewed 28 | # 1 reviewed: with pending problems 29 | # 2 reviewed: clean (-Wall, style) 30 | # 3 reviewed: clean, secure (security risk checked) 31 | # 4 reviewed: clean, secure, state of the art (speed and space) 32 | # 33 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 34 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 35 | # 36 | 37 | import sys 38 | 39 | # functions 40 | 41 | def mkdoc( apidoc, proto ) : 42 | api_tokens = apidoc.split('|') 43 | fun_desc = api_tokens[1] 44 | fun_params_desc = api_tokens[2].split(';') 45 | fun_ret_desc = api_tokens[3] 46 | fun_o = api_tokens[4].split(';') if len(api_tokens) > 4 else [] 47 | fun_status = api_tokens[5].split(';') if len(api_tokens) > 5 else [] 48 | tmp = proto.split('('); 49 | split_char = '*' if tmp[0].find('*') >= 0 else ' ' 50 | tmp2 = tmp[0].split(split_char) 51 | fun_name = tmp2[len(tmp2) - 1] 52 | fun_ret = tmp[0].split(fun_name)[0] #.strip() 53 | fun_params = tmp[1].split(')')[0].split(',') 54 | if len(fun_params) != len(fun_params_desc) : 55 | sys.stderr.write('Syntax error: "' + fun_name + \ 56 | ' incomplete parameters (number of arguments ' + \ 57 | 'in prototype and description mismatch)\n') 58 | sys.exit(1) 59 | doc = [] 60 | doc.append([fun_name, fun_desc]) 61 | doc.append([fun_params, fun_params_desc]) 62 | doc.append([fun_ret, fun_ret_desc]) 63 | doc.append(fun_o) 64 | doc.append(fun_status) 65 | return doc 66 | 67 | def atoi(a) : 68 | try : 69 | return int(a) 70 | except ValueError: 71 | return 0 72 | 73 | def fmt_coverage(c) : 74 | return '[' + str(c) + '/2] ' + \ 75 | ('basic (Coverity, clang analyzer)' if c == 0 else \ 76 | 'test covered (test + Valgrind)' if c == 1 else \ 77 | 'proof covered' if c == 2 else '?') 78 | 79 | def fmt_quality(q) : 80 | return '[' + str(q) + '/4] ' + \ 81 | ('not reviewed' if q == 0 else \ 82 | 'reviewed, with quality issues' if q == 1 else \ 83 | 'reviewed, clean (-Wall, style, speed)' if q == 2 else '?') 84 | 85 | def fundoc2html( doc ) : 86 | fun_name = doc[0][0] 87 | fun_desc = doc[0][1] 88 | fun_params = doc[1][0] 89 | fun_params_desc = doc[1][1] 90 | fun_ret = doc[2][0].replace('static ', '') 91 | fun_ret_desc = doc[2][1] 92 | fun_o = doc[3][0] if len(doc) > 3 and len(doc[3]) >= 1 else '' 93 | fun_os = doc[3][1] if len(doc) > 3 and len(doc[3]) >= 2 else '' 94 | fun_coverage = atoi(doc[4][0]) if len(doc) > 4 and len(doc[4]) > 0 else 0 95 | fun_quality = atoi(doc[4][1]) if len(doc) > 4 and len(doc[4]) > 1 else 0 96 | proto = '' + fun_ret + '' + fun_name + '(' 97 | i = 0 98 | while i < len(fun_params) : 99 | proto += '' + fun_params[i].strip() + '' 100 | if i != len(fun_params) - 1 : 101 | proto += ', ' 102 | i += 1 103 | proto += ')

' 104 | params = '' 105 | i = 0 106 | params += '
    ' 107 | params += '
  • ' + fun_desc + '
  • ' 108 | while i < len(fun_params) : 109 | params += '
  • ' + fun_params[i].strip() + ': ' + \ 110 | fun_params_desc[i] + '
  • ' 111 | i += 1 112 | if len(fun_ret_desc) : 113 | params += '
  • Return (' + fun_ret.strip() + '): ' + fun_ret_desc + '
  • ' 114 | params += '
  • Time complexity: ' + (fun_o.strip() if len(fun_o) > 0 else '(pending)') + '
  • ' 115 | params += '
  • Space complexity: ' + (fun_os.strip() if len(fun_os) > 0 else 'no extra space') + '
  • ' 116 | params += '
  • Coverage: ' + fmt_coverage(fun_coverage) + '
  • ' 117 | params += '
  • Quality: ' + fmt_quality(fun_quality) + '
  • ' 118 | params += '

' 119 | return proto + params + '
' 120 | 121 | def doc2html( doc, title, header, overview ) : 122 | if len(doc) > 0 : 123 | # Sort functions by name: 124 | doc.sort(key = lambda x: (x[0][0])) 125 | # Index: 126 | cols = 6 127 | rows = len(doc) // cols + (1 if len(doc) % cols != 0 else 0) 128 | ctitle = header + ": " + title if len(header) > 0 else title 129 | out = '' + ctitle + '

' + ctitle + '


' 130 | out += overview + '

' 131 | out += '' 132 | for i in range(0, rows) : 133 | out += '' 134 | for j in range(0, cols) : 135 | ndx = j * rows + i 136 | if ndx < len(doc) : 137 | fname = doc[ndx][0][0] 138 | out += '' 139 | out += '' 140 | out += '
 ' + fname + ' 


' 141 | # Functions: 142 | for i in range(0, len(doc)) : 143 | out += fundoc2html( doc[i] ) + '\n' 144 | out += '\n' 145 | return out 146 | 147 | def getparagraphs( lines, tgt, max_para ) : 148 | out = '' 149 | para = 0 150 | for i in range(0, len(lines)) : 151 | off = lines[i].find(tgt) 152 | if off >= 0 : 153 | next_chunk = lines[i][off + len(tgt):] 154 | if len(next_chunk) <= 1 : 155 | para = para + 1 156 | next_chunk = '
' 157 | if para >= max_para : 158 | break 159 | out += next_chunk 160 | 161 | return str.replace(out, '\t', 162 | '        ') 163 | 164 | def getinclude( lines ) : 165 | return getparagraphs( lines, '#INCLUDE', 1 ) 166 | 167 | def gettitle( lines ) : 168 | return getparagraphs( lines, '#SHORTDOC', 1 ) 169 | 170 | def getoverview ( lines ) : 171 | return getparagraphs( lines, '#DOC', 100 ) 172 | 173 | # main 174 | 175 | lines = sys.stdin.readlines() 176 | i = 0 177 | num_lines = len(lines) - 1 178 | doc = [] 179 | 180 | while i < num_lines : 181 | api = lines[i].replace('\n', '') 182 | if api.find('#API:') < 0 : 183 | i += 1 184 | continue 185 | i += 1 186 | if i == num_lines : 187 | break 188 | while i < num_lines : 189 | fun = lines[i].replace('\n', '') 190 | if fun.find('#API') >= 0 : 191 | fun = '' 192 | break 193 | i += 1 194 | if fun.find('(') >= 0 : 195 | break 196 | if (len(fun) > 0 ) : 197 | doc.append(mkdoc(api, fun.replace('S_INLINE ', ''))) 198 | 199 | header = '' 200 | title = gettitle(lines) 201 | overview = getoverview(lines) 202 | 203 | if len(header) == 0 : 204 | header = sys.argv[1] if len(sys.argv) > 1 else '' 205 | 206 | print ( doc2html( doc, title, header, overview ) ) 207 | 208 | -------------------------------------------------------------------------------- /utl/check_style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # check_style.sh 4 | # 5 | # Simple C code style check 6 | # - Look for lines larger than 80 characters 7 | # 8 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 9 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 10 | # 11 | 12 | if (( $(cat $* | expand | grep '.\{81\}' | wc -l) > 0 )) ; then 13 | cat $* | expand | grep '.\{81\}' | while read line ; do 14 | echo -e -n "\t" ; echo "$line" 15 | done 16 | echo -n "[over 80 characters] " 17 | exit 1 18 | fi 19 | 20 | if (( $(grep 'switch (' $* | grep -v { | wc -l) > 0 )) ; then 21 | grep 'switch (' $* | grep -v { | while read line ; do 22 | echo -e -n "\t" ; echo "$line" 23 | done 24 | echo -n "[switch without { in same line] " 25 | exit 2 26 | fi 27 | 28 | if (( $(cat $* | wc -l) != $(cat $* | sed '/^$/N;/^\n$/D' | wc -l) )) ; then 29 | echo -n "[consecutive blank lines] " 30 | exit 2 31 | fi 32 | 33 | exit 0 # ok 34 | 35 | -------------------------------------------------------------------------------- /utl/format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # format.sh 4 | # 5 | # libsrt code formatting 6 | # 7 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 8 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 9 | # 10 | 11 | cp .clang-format .. 12 | cd .. 13 | find . -iname '*\.c' | while read file ; do 14 | clang-format-5.0 -i $file 15 | done 16 | rm .clang-format 17 | -------------------------------------------------------------------------------- /utl/m4/mode.m4: -------------------------------------------------------------------------------- 1 | # 2 | # m4/mode.m4 3 | # 4 | # libsrt m4 build configuration macros 5 | # 6 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 7 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 8 | # 9 | 10 | # Develoment (debug) / release mode switch 11 | 12 | AC_MSG_CHECKING("Build mode selection") 13 | 14 | AC_ARG_ENABLE(debug, 15 | AS_HELP_STRING([--enable-debug], [turn on debug mode [default=no]]), 16 | , enable_debug=no) 17 | 18 | AC_ARG_ENABLE(profiling, 19 | AS_HELP_STRING([--enable-profiling], [turn on profiling mode [default=no]]), 20 | , enable_profiling=no) 21 | 22 | AC_ARG_ENABLE(vargs, 23 | AS_HELP_STRING([--enable-vargs], [Enable variable-argument support [default=yes]]), 24 | , enable_vargs=yes) 25 | 26 | AC_ARG_ENABLE(crc32, 27 | AS_HELP_STRING([--enable-crc], [valid bytes per loop: 0, 1, 2, 4, 8, 12, 16 [default=12]]), 28 | , enable_crc=12) 29 | 30 | AC_ARG_ENABLE(stropt, 31 | AS_HELP_STRING([--enable-stropt], [map/set/hmap/set string optimization [default=yes]]), 32 | , enable_stropt=yes) 33 | 34 | AC_ARG_ENABLE(onsearch, 35 | AS_HELP_STRING([--enable-onsearch], [O(n) string search complexity -disabling it you could get minor speed boost in most cases, and slowdowns in corner some corner cases- [default=yes]]), 36 | , enable_onsearch=yes) 37 | 38 | AC_ARG_ENABLE(leopt, 39 | AS_HELP_STRING([--enable-leopt], [Allow Little Endian optimizations, if available [default=yes]]), 40 | , enable_leopt=yes) 41 | 42 | AC_ARG_ENABLE(egrowth, 43 | AS_HELP_STRING([--enable-egrowth], [Heuristic -geometric- resize grow [default=yes]]), 44 | , enable_egrowth=yes) 45 | 46 | AC_ARG_ENABLE(slowrealloc, 47 | AS_HELP_STRING([--enable-slowrealloc], [force realloc using memory copy [default=no]]), 48 | , enable_slowrealloc=no) 49 | 50 | AC_ARG_WITH(libpng, 51 | AS_HELP_STRING([--with-libpng], [enable libpng usage]), 52 | [with_libpng=$withval], 53 | [with_libpng='no']) 54 | 55 | AC_ARG_WITH(libjpeg, 56 | AS_HELP_STRING([--with-libjpeg], [enable libjpeg usage]), 57 | [with_libjpeg=$withval], 58 | [with_libjpeg='no']) 59 | 60 | if test "$enable_profiling" = "yes"; then 61 | CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage -g -pg" 62 | CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage -g -pg" 63 | LDFLAGS="$LDFLAGS -lgcov -coverage" 64 | fi 65 | 66 | if test "$enable_debug" = "yes"; then 67 | CFLAGS="$CFLAGS -g -O0" 68 | CXXFLAGS="$CXXFLAGS -g -O0" 69 | AC_DEFINE([DEBUG], [], []) 70 | AC_MSG_RESULT(yes) 71 | else 72 | CFLAGS="$CFLAGS -O3" 73 | CXXFLAGS="$CXXFLAGS -O3" 74 | AC_DEFINE([NDEBUG], [], []) 75 | AC_MSG_RESULT(no) 76 | fi 77 | 78 | if test "$enable_vargs" == "no"; then 79 | CFLAGS="$CFLAGS -DS_NO_VARGS" 80 | CXXFLAGS="$CXXFLAGS -DS_NO_VARGS" 81 | fi 82 | 83 | if test "$enable_crc" != "12"; then 84 | CFLAGS="$CFLAGS -DS_CRC32_SLC=$enable_crc32" 85 | CXXFLAGS="$CXXFLAGS -DS_CRC32_SLC=$enable_crc32" 86 | fi 87 | 88 | if test "$enable_stropt" == "no"; then 89 | CFLAGS="$CFLAGS -DS_DISABLE_SM_STRING_OPTIMIZATION" 90 | CXXFLAGS="$CXXFLAGS -DS_DISABLE_SM_STRING_OPTIMIZATION" 91 | fi 92 | 93 | if test "$enable_onsearch" == "no"; then 94 | CFLAGS="$CFLAGS -DS_DISABLE_SEARCH_GUARANTEE" 95 | CXXFLAGS="$CXXFLAGS -DS_DISABLE_SEARCH_GUARANTEE" 96 | fi 97 | 98 | if test "$enable_leopt" == "no"; then 99 | CFLAGS="$CFLAGS -DS_DISABLE_LE_OPTIMIZATIONS" 100 | CXXFLAGS="$CXXFLAGS -DS_DISABLE_LE_OPTIMIZATIONS" 101 | fi 102 | 103 | if test "$enable_egrowth" == "no"; then 104 | CFLAGS="$CFLAGS -DSD_DISABLE_HEURISTIC_GROWTH" 105 | CXXFLAGS="$CXXFLAGS -DSD_DISABLE_HEURISTIC_GROWTH" 106 | fi 107 | 108 | if test "$enable_slowrealloc" == "yes"; then 109 | CFLAGS="$CFLAGS -DS_FORCE_REALLOC_COPY" 110 | CXXFLAGS="$CXXFLAGS -DS_FORCE_REALLOC_COPY" 111 | fi 112 | 113 | have_libpng='no' 114 | LIBPNG_LIBS='' 115 | if test "$with_libpng" != 'no'; then 116 | AC_MSG_CHECKING(for LIBPNG support ) 117 | AC_MSG_RESULT() 118 | failed=0 119 | passed=0 120 | AC_CHECK_HEADER([libpng/png.h],[passed=`expr $passed + 1`],[failed=`expr $failed + 1`]) 121 | AC_CHECK_LIB([png],[png_write_image],[passed=`expr $passed + 1`],[failed=`expr $failed + 1`],) 122 | AC_MSG_CHECKING(if libpng png_write_image is available) 123 | if test $passed -gt 0; then 124 | if test $failed -gt 0; then 125 | AC_MSG_RESULT(no -- some components failed test) 126 | have_libpng='no (failed tests)' 127 | else 128 | LIBPNG_LIBS='-lpng' 129 | LIBS="$LIBPNG_LIBS $LIBS" 130 | AC_DEFINE(HAS_PNG,1,Define if you have libpng) 131 | AC_MSG_RESULT(yes) 132 | have_libpng='yes' 133 | fi 134 | else 135 | AC_MSG_RESULT(no) 136 | fi 137 | fi 138 | 139 | have_libjpeg='no' 140 | LIBJPEG_LIBS='' 141 | if test "$with_libjpeg" != 'no'; then 142 | AC_MSG_CHECKING(for LIBJPEG support ) 143 | AC_MSG_RESULT() 144 | failed=0 145 | passed=0 146 | AC_CHECK_HEADER([jpeglib.h],[passed=`expr $passed + 1`],[failed=`expr $failed + 1`]) 147 | AC_CHECK_LIB([jpeg],[jpeg_write_scanlines],[passed=`expr $passed + 1`],[failed=`expr $failed + 1`],) 148 | AC_MSG_CHECKING(if libjpeg jpeg_write_scanlines is available) 149 | if test $passed -gt 0; then 150 | if test $failed -gt 0; then 151 | AC_MSG_RESULT(no -- some components failed test) 152 | have_libjpeg='no (failed tests)' 153 | else 154 | LIBJPEG_LIBS='-ljpeg' 155 | LIBS="$LIBJPEG_LIBS $LIBS" 156 | AC_DEFINE(HAS_JPG,1,Define if you have libjpeg) 157 | AC_MSG_RESULT(yes) 158 | have_libjpeg='yes' 159 | fi 160 | else 161 | AC_MSG_RESULT(no) 162 | fi 163 | fi 164 | 165 | AM_CONDITIONAL(DEBUG, test "$enable_debug" = yes) 166 | -------------------------------------------------------------------------------- /utl/mk_doc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # mk_doc.sh 4 | # 5 | # libsrt documentation generation 6 | # 7 | # Copyright (c) 2015-2019 F. Aragon. All rights reserved. 8 | # Released under the BSD 3-Clause License (see the doc/LICENSE) 9 | # 10 | 11 | if [ $# != 2 ] ; then 12 | echo "Syntax: $0 src_path out_path" >&2 13 | echo "Example: $0 src out_doc" >&2 14 | exit 1 15 | fi 16 | 17 | SRC_PATH=$1 18 | DOC_PATH_OUT=$2 19 | ERRORS=0 20 | mkdir "$DOC_PATH_OUT" 2>/dev/null 21 | 22 | if [ ! -e "$DOC_PATH_OUT" ] ; then 23 | echo "Path $1 not found" >&2 24 | exit 2 25 | fi 26 | 27 | INDEX="$DOC_PATH_OUT/libsrt.html" 28 | 29 | C2DOC_PY=$(echo $0 | sed 's/mk_doc.sh/c2doc.py/g') 30 | 31 | if [ "$C2DOC_PY" == "$0" ] ; then 32 | echo "Error: this file name must be 'mk_doc.sh'" 33 | exit 1 34 | fi 35 | 36 | echo "libsrt

libsrt documentation
" \ 39 | "
" > "$INDEX" 40 | README_PATH=README 41 | if [ ! -f "$README_PATH"* ] ; then 42 | if [ -f "../$README_PATH"* ] ; then 43 | README_PATH="../$README_PATH" 44 | else 45 | if [ -f "../../$README_PATH"* ] ; then 46 | README_PATH="../../$README_PATH" 47 | fi 48 | fi 49 | fi 50 | grep "is a C library" "$README_PATH"* >> "$INDEX" 51 | 52 | echo "

" >> "$INDEX" 53 | for i in $SRC_PATH/*\.h ; do 54 | if ! grep '#API' "$i" >/dev/null 2>/dev/null ; then 55 | continue 56 | fi 57 | II=$(echo $i | sed 's/\/\//\//g') 58 | TGT=$(echo $i | awk -F '/' '{print $NF}') 59 | echo -n "$II: " >&2 60 | TGT_HTML="$DOC_PATH_OUT/$TGT.html" 61 | INC=$i 62 | if echo "$INC" | grep '/' 2>/dev/null >/dev/null ; then 63 | INC=$(echo "$INC" | awk -F '/' '{print $NF}') 64 | fi 65 | if $C2DOC_PY "$INC" < "$i" >"$TGT_HTML" 66 | then 67 | echo "OK" >&2 68 | if (( $(wc -l <"$TGT_HTML") > 2 )) ; then 69 | DESC=$(grep '#SHORTDOC' "$i" | \ 70 | awk -F '#SHORTDOC ' '{print $2}' | head -1) 71 | if [ "$DESC" = "" ] ; then DESC=$TGT ; fi 72 | if [ ! "$INC" = "" ] ; then INC="$INC: " ; fi 73 | echo '
'"$INC"''"$DESC"\ 74 | '
' >> "$INDEX" 75 | fi 76 | else ERRORS=$((ERRORS + 1)) 77 | fi 78 | done 79 | echo '' >> "$INDEX" 80 | 81 | exit $ERRORS 82 | 83 | -------------------------------------------------------------------------------- /win/vs2013/stest.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2013 for Windows Desktop 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stest", "stest.vcxproj", "{E08239B4-1430-443C-8FC8-C31EE7AFFEA8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Debug|Win32.Build.0 = Debug|Win32 18 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Debug|x64.ActiveCfg = Debug|x64 19 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Debug|x64.Build.0 = Debug|x64 20 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Release|Win32.ActiveCfg = Release|Win32 21 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Release|Win32.Build.0 = Release|Win32 22 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Release|x64.ActiveCfg = Release|x64 23 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /win/vs2013/stest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {E08239B4-1430-443C-8FC8-C31EE7AFFEA8} 23 | libsrt 24 | 25 | 26 | 27 | Application 28 | true 29 | v120 30 | NotSet 31 | 32 | 33 | Application 34 | true 35 | v120 36 | NotSet 37 | 38 | 39 | Application 40 | false 41 | v120 42 | true 43 | NotSet 44 | 45 | 46 | Application 47 | false 48 | v120 49 | true 50 | NotSet 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | true 70 | $(SolutionDir)$(Configuration)\ 71 | $(SolutionDir)stest_$(Configuration)\tmp\ 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | $(SolutionDir)$(Configuration)\ 79 | $(SolutionDir)stest_$(Configuration)\tmp\ 80 | 81 | 82 | true 83 | 84 | 85 | 86 | Level3 87 | Disabled 88 | true 89 | CompileAsC 90 | true 91 | MultiThreadedDebug 92 | 93 | 94 | true 95 | 96 | 97 | 98 | 99 | Level3 100 | Disabled 101 | true 102 | CompileAsC 103 | true 104 | MultiThreadedDebug 105 | 106 | 107 | true 108 | 109 | 110 | 111 | 112 | Level3 113 | MaxSpeed 114 | true 115 | true 116 | true 117 | CompileAsC 118 | true 119 | MultiThreaded 120 | NoListing 121 | AnySuitable 122 | true 123 | false 124 | false 125 | None 126 | 127 | 128 | false 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | Level3 136 | MaxSpeed 137 | true 138 | true 139 | true 140 | CompileAsC 141 | true 142 | MultiThreaded 143 | 144 | 145 | true 146 | true 147 | true 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 | --------------------------------------------------------------------------------