Compare commits
5 Commits
e7b5d2ea4d
...
4fe839df19
Author | SHA1 | Date | |
---|---|---|---|
4fe839df19 | |||
3f00c79d45 | |||
0461fc185e | |||
013f5bf943 | |||
b62f67d2c7 |
91
c/Makefile
91
c/Makefile
@@ -1,6 +1,6 @@
|
||||
# Tools Makefile
|
||||
#
|
||||
# Copyright (C) 2022 Bruno Raoult ("br")
|
||||
# Copyright (C) 2023 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
@@ -10,81 +10,50 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
SHELL := /bin/bash
|
||||
CC := gcc
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
SHELL := /bin/bash
|
||||
CC := gcc
|
||||
BEAR := bear
|
||||
|
||||
CFLAGS += -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
|
||||
#CFLAGS += -pg
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
#CFLAGS += -mno-tbm
|
||||
|
||||
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||
CPPFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||
CPPFLAGS += -DDEBUG_POOL # memory pools management
|
||||
|
||||
INCDIR := ./include
|
||||
LIBDIR := ./lib
|
||||
OBJDIR := ./obj
|
||||
BRLIBDIR := ./brlib
|
||||
|
||||
LIBNAME := br_$(shell uname -m)
|
||||
LIB := lib$(LIBNAME)
|
||||
SLIB := $(LIBDIR)/$(LIB).a
|
||||
DLIB := $(LIBDIR)/$(LIB).so
|
||||
LIBSRC := $(wildcard *.c)
|
||||
LIBOBJ := $(addprefix $(OBJDIR)/,$(patsubst %.c,%.o,$(LIBSRC)))
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
LDLIB := -l$(LIB)
|
||||
#LIB := lib$(LIBNAME)
|
||||
|
||||
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
.PHONY: all libs clean dirs bear
|
||||
all: brlib
|
||||
|
||||
all: libs
|
||||
#export LD_LIBRARY_PATH = $(LIBDIR)
|
||||
|
||||
libs: dirs $(DLIB) $(SLIB)
|
||||
.PHONY: all brlib clean
|
||||
|
||||
dirs: $(LIBDIR) $(OBJDIR)
|
||||
all: brlib
|
||||
|
||||
$(LIBDIR) $(OBJDIR):
|
||||
@echo creating $@ directory.
|
||||
@mkdir $@
|
||||
brlib:
|
||||
$(MAKE) -C $(BRLIBDIR)
|
||||
|
||||
bear ccls:
|
||||
@echo building ccls language server compilation database
|
||||
$(MAKE) -C $(BRLIBDIR) ccls
|
||||
|
||||
clean:
|
||||
@echo deleting $(OBJDIR) and $(LIBDIR) directories.
|
||||
@$(RM) -rf $(LIBDIR) $(OBJDIR)
|
||||
|
||||
$(SLIB): $(LIBOBJ)
|
||||
@echo building $@ static library.
|
||||
@$(AR) $(ARFLAGS) -o $@ $^
|
||||
|
||||
$(DLIB): CFLAGS += -fPIC
|
||||
$(DLIB): LDFLAGS += -shared
|
||||
$(DLIB): $(LIBOBJ)
|
||||
@echo building $@ shared library.
|
||||
@$(CC) $(LDFLAGS) $^ -o $@
|
||||
|
||||
.c:
|
||||
@echo compiling $<
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||
|
||||
#.c.o:
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@echo compiling $<.
|
||||
@$(CC) -c $(CFLAGS) $(LDFLAGS) -I $(INCDIR) -o $@ $<
|
||||
|
||||
.c.s:
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
||||
|
||||
bear: clean
|
||||
@echo building ccls language server compilation database
|
||||
@bear -- make
|
||||
@echo cleaning brlib.
|
||||
@$(MAKE) -C $(BRLIBDIR) clean
|
||||
|
281
c/brlib/Makefile
Normal file
281
c/brlib/Makefile
Normal file
@@ -0,0 +1,281 @@
|
||||
# brlib Makefile - GNU make only
|
||||
#
|
||||
# Copyright (C) 2021-2023 Bruno Raoult ("br")
|
||||
# Licensed under the GNU General Public License v3.0 or later.
|
||||
# Some rights reserved. See COPYING.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with this
|
||||
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
#
|
||||
|
||||
# important to know where exactly is project root dir
|
||||
ROOTDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
SHELL := /bin/bash
|
||||
CC := gcc
|
||||
LD := ld
|
||||
BEAR := bear
|
||||
TOUCH := touch
|
||||
RM := rm
|
||||
RMDIR := rmdir
|
||||
|
||||
SRCDIR := ./src
|
||||
INCDIR := ./include
|
||||
OBJDIR := ./obj
|
||||
LIBDIR := ./lib
|
||||
BINDIR := ./bin
|
||||
DEPDIR := ./dep
|
||||
|
||||
SRC := $(wildcard $(SRCDIR)/*.c) # brlib sources
|
||||
SRC_FN := $(notdir $(SRC)) # source basename
|
||||
OBJ := $(addprefix $(OBJDIR)/,$(SRC_FN:.c=.o))
|
||||
|
||||
LIB := br_$(shell uname -m) # library name
|
||||
SLIB := $(addsuffix .a, $(LIBDIR)/lib$(LIB)) # static lib
|
||||
DLIB := $(addsuffix .so, $(LIBDIR)/lib$(LIB)) # dynamic lib
|
||||
|
||||
DEP_FN := $(SRC_FN) $(LIBSRC_FN)
|
||||
DEP := $(addprefix $(DEPDIR)/,$(DEP_FN:.c=.d))
|
||||
|
||||
##################################### emacs projectile/ccls
|
||||
PRJROOT := .projectile
|
||||
CCLSROOT := .ccls-root
|
||||
CCLSCMDS := compile_commands.json
|
||||
|
||||
##################################### pre-processor flags
|
||||
CPPFLAGS := -I$(INCDIR)
|
||||
#CPPFLAGS += -DDEBUG # global
|
||||
CPPFLAGS += -DDEBUG_DEBUG # enable log() functions
|
||||
#CPPFLAGS += -DDEBUG_DEBUG_C # log() funcs debug
|
||||
PPFLAGS += -DDEBUG_DEBUG # activate logs funcs
|
||||
CPPFLAGS += -DDEBUG_POOL # mem pools
|
||||
|
||||
# remove extraneous spaces (due to spaces before comments)
|
||||
CPPFLAGS := $(strip $(CPPFLAGS))
|
||||
|
||||
##################################### compiler flags
|
||||
CFLAGS := -std=gnu11
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -march=native
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -Wno-unused-result
|
||||
CFLAGS += -fPIC
|
||||
# for gprof
|
||||
#CFLAGS += -pg
|
||||
# Next one may be useful for valgrind (some invalid instructions)
|
||||
# CFLAGS += -mno-tbm
|
||||
|
||||
CFLAGS := $(strip $(CFLAGS))
|
||||
|
||||
##################################### archiver/linker/dependency flags
|
||||
ARFLAGS := rcs
|
||||
LDFLAGS := -L$(LIBDIR)
|
||||
DEPFLAGS = -MMD -MP -MF $(DEPDIR)/$*.d
|
||||
|
||||
##################################### General targets
|
||||
.PHONY: all compile clean cleanall
|
||||
|
||||
all: libs
|
||||
|
||||
compile: objs
|
||||
|
||||
clean: cleandep cleanobj cleanlib cleanbin
|
||||
|
||||
cleanall: clean cleandepdir cleanobjdir cleanlibdir cleanbindir
|
||||
|
||||
# setup emacs projectile/ccls
|
||||
emacs: emacs-setup
|
||||
# update compile-commands.json
|
||||
ccls: $(CCLSCMDS)
|
||||
|
||||
##################################### cleaning functions
|
||||
# rmfiles - deletes a list of files in a directory if they exist.
|
||||
# $(1): the directory
|
||||
# $(2): the list of files to delete
|
||||
# $(3): The string to include in action output - "cleaning X files."
|
||||
# see: https://stackoverflow.com/questions/6783243/functions-in-makefiles
|
||||
#
|
||||
# Don't use wildcard like "$(DIR)/*.o", so we can control mismatches between
|
||||
# list and actual files in directory.
|
||||
# See rmdir below.
|
||||
define rmfiles
|
||||
@#echo "rmfiles=+$(1)+"
|
||||
$(eval $@_EXIST = $(wildcard $(1)))
|
||||
@#echo "existfile=+${$@_EXIST}+"
|
||||
@if [[ -n "${$@_EXIST}" ]]; then \
|
||||
echo "cleaning $(2) files." ; \
|
||||
$(RM) ${$@_EXIST} ; \
|
||||
fi
|
||||
endef
|
||||
|
||||
# rmdir - deletes a directory if it exists.
|
||||
# $(1): the directory
|
||||
# $(2): The string to include in action output - "removing X dir."
|
||||
#
|
||||
# Don't use $(RM) -rf, to control unexpected dep files.
|
||||
# See rmfile above.
|
||||
define rmdir
|
||||
@#echo "rmdir +$(1)+"
|
||||
$(eval $@_EXIST = $(wildcard $(1)))
|
||||
@#echo "existdir=+${$@_EXIST}+"
|
||||
@if [[ -n "${$@_EXIST}" ]]; then \
|
||||
echo "removing $(2) dir." ; \
|
||||
$(RMDIR) ${$@_EXIST} ; \
|
||||
fi
|
||||
endef
|
||||
|
||||
##################################### dirs creation
|
||||
.PHONY: alldirs
|
||||
|
||||
ALLDIRS := $(DEPDIR) $(OBJDIR) $(LIBDIR) $(BINDIR)
|
||||
|
||||
alldirs: $(ALLDIRS)
|
||||
|
||||
# Here, we have something like:
|
||||
# a: a
|
||||
# a will be built if (1) older than a, or (2) does not exist. Here only (2).
|
||||
$(ALLDIRS): $@
|
||||
@echo creating $@ directory.
|
||||
@mkdir -p $@
|
||||
|
||||
##################################### Dependencies files
|
||||
.PHONY: cleandep cleandepdir
|
||||
|
||||
-include $(wildcard $(DEP))
|
||||
|
||||
# Don't use $(DEPDIR)/*.d, to control mismatches between dep and src files.
|
||||
# See second rule below.
|
||||
cleandep:
|
||||
$(call rmfiles,$(DEP),depend)
|
||||
@#echo cleaning dependency files.
|
||||
@#$(RM) -f $(DEP)
|
||||
|
||||
cleandepdir:
|
||||
$(call rmdir,$(DEPDIR),depend)
|
||||
@#[ -d $(DEPDIR) ] && echo cleaning depend files && $(RM) -f $(DEP) || true
|
||||
|
||||
##################################### objects
|
||||
.PHONY: objs cleanobj cleanobjdir
|
||||
|
||||
objs: $(OBJ)
|
||||
|
||||
cleanobj:
|
||||
$(call rmfiles,$(OBJ),brlib object)
|
||||
|
||||
cleanobjdir:
|
||||
$(call rmdir,$(OBJDIR),brlib objects)
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) $(DEPDIR)
|
||||
@echo compiling $< "->" $@.
|
||||
$(CC) -c $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||
|
||||
##################################### brlib libraries
|
||||
.PHONY: libs cleanlib cleanlibdir
|
||||
|
||||
libs: $(DLIB) $(SLIB)
|
||||
|
||||
cleanlib:
|
||||
$(call rmfiles,$(DLIB) $(SLIB),library)
|
||||
|
||||
cleanlibdir:
|
||||
$(call rmdir,$(LIBDIR),libraries)
|
||||
|
||||
#$(DLIB): CFLAGS += -fPIC
|
||||
$(DLIB): LDFLAGS += -shared
|
||||
$(DLIB): $(OBJ) | $(LIBDIR)
|
||||
@echo "building $@ shared library ($?)."
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $? -o $@
|
||||
|
||||
$(SLIB): $(OBJ) | $(LIBDIR)
|
||||
@echo "building $@ static library ($?)."
|
||||
$(AR) $(ARFLAGS) $@ $? > /dev/null
|
||||
|
||||
##################################### brchess binaries
|
||||
.PHONY: targets cleanbin cleanbindir
|
||||
|
||||
targets: $(TARGET)
|
||||
|
||||
cleanbin:
|
||||
$(call rmfiles,$(TARGET),binary)
|
||||
|
||||
cleanbindir:
|
||||
$(call rmdir,$(BINDIR),binaries)
|
||||
|
||||
##################################### pre-processed (.i) and assembler (.s) output
|
||||
%.i: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -E $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||
|
||||
%.s: %.c
|
||||
@echo generating $@
|
||||
@$(CC) -S -fverbose-asm $(CPPFLAGS) $(CFLAGS) $< -o $@
|
||||
|
||||
##################################### LSP (ccls)
|
||||
.PHONY: emacs-setup
|
||||
|
||||
PRJROOT := .projectile
|
||||
CCLSROOT := .ccls-root
|
||||
CCLSFILE := .ccls
|
||||
CCLSCMDS := compile_commands.json
|
||||
|
||||
emacs-setup: $(PRJROOT) $(CCLSROOT) $(CCLSCMDS)
|
||||
|
||||
#$(CCLSFILE):
|
||||
# @echo "creating CCLS's $@ project root file."
|
||||
# echo '%compile_commands.json' > $@
|
||||
|
||||
$(CCLSROOT) $(PRJROOT):
|
||||
@if [[ $(@) = $(PRJROOT) ]] ; \
|
||||
then \
|
||||
echo "creating Emacs's projectile root file." ; \
|
||||
else \
|
||||
echo "creating Emacs's ccls root file." ; \
|
||||
fi
|
||||
@$(TOUCH) $@
|
||||
|
||||
# generate compile_commands.json.
|
||||
# TODO: add includes and Makefile dependencies.
|
||||
# also, if cclsfile is newer than sources, no need to clean objects file
|
||||
# (and to run bear).
|
||||
# maybe run cleanobj cleanlibobj in commands ?
|
||||
$(CCLSCMDS): cleanobj $(SRC) | $(CCLSROOT)
|
||||
@echo "Generating ccls compile commands file ($@)."
|
||||
@$(BEAR) -- make compile
|
||||
|
||||
#.PHONY: bear
|
||||
#bear: cleanobj cleanlibobj Makefile | $(CCLSROOT)
|
||||
# @$(BEAR) -- make compile
|
||||
|
||||
##################################### valgrind (mem check)
|
||||
.PHONY: memcheck
|
||||
|
||||
VALGRIND := valgrind
|
||||
VALGRINDFLAGS := --leak-check=full --show-leak-kinds=all
|
||||
VALGRINDFLAGS += --track-origins=yes --sigill-diagnostics=yes
|
||||
VALGRINDFLAGS += --quiet --show-error-list=yes
|
||||
VALGRINDFLAGS += --log-file=valgrind.out
|
||||
# We need to suppress libreadline leaks here. See :
|
||||
# https://stackoverflow.com/questions/72840015
|
||||
VALGRINDFLAGS += --suppressions=etc/libreadline.supp
|
||||
|
||||
memcheck: targets
|
||||
@$(VALGRIND) $(VALGRINDFLAGS) $(BINDIR)/brchess
|
||||
|
||||
##################################### Makefile debug
|
||||
.PHONY: showflags wft
|
||||
|
||||
showflags:
|
||||
@echo CFLAGS: "$(CFLAGS)"
|
||||
@echo CPPFLAGS: $(CPPFLAGS)
|
||||
@echo DEPFLAGS: $(DEPFLAGS)
|
||||
@echo LDFLAGS: $(LDFLAGS)
|
||||
|
||||
wtf:
|
||||
@printf "ROOTDIR=+%s+\n\n" "$(ROOTDIR)"
|
||||
@printf "OBJDIR=%s\n\n" "$(OBJDIR)"
|
||||
@printf "OBJ=%s\n\n" "$(OBJ)"
|
@@ -1,6 +1,6 @@
|
||||
/* debug.h - debug/log management.
|
||||
*
|
||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
* Copyright (C) 2021-2023 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
@@ -14,29 +14,45 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <bits.h>
|
||||
#include <br.h>
|
||||
|
||||
#define NANOSEC 1000000000 /* nano sec in sec */
|
||||
#define MILLISEC 1000000 /* milli sec in sec */
|
||||
|
||||
#define _unused __attribute__((__unused__))
|
||||
#define _printf __attribute__ ((format (printf, 6, 7)))
|
||||
|
||||
#ifdef DEBUG_DEBUG
|
||||
void debug_init(u32 level);
|
||||
void debug_level_set(u32 level);
|
||||
u32 debug_level_get(void);
|
||||
void _printf debug(u32 level, bool timestamp,
|
||||
u32 indent, const char *src,
|
||||
u32 line, const char *fmt, ...);
|
||||
|
||||
void debug_init(int level, FILE *stream, bool flush);
|
||||
void debug_level_set(int level);
|
||||
int debug_level_get(void);
|
||||
void debug_stream_set(FILE *stream);
|
||||
long long debug_timer_elapsed(void);
|
||||
void debug_flush_set(bool flush);
|
||||
void _printf debug(int level, bool timestamp,
|
||||
int indent, const char *src,
|
||||
int line, const char *fmt, ...);
|
||||
|
||||
#else /* DEBUG_DEBUG */
|
||||
static inline void debug_init(_unused u32 level) {}
|
||||
static inline void debug_level_set(_unused u32 level) {}
|
||||
static inline void _printf debug(_unused u32 level, _unused bool timestamp,
|
||||
_unused u32 indent, _unused const char *src,
|
||||
_unused u32 line, _unused const char *fmt, ...) {}
|
||||
|
||||
static inline void debug_init(__unused int level,
|
||||
__unused FILE *stream,
|
||||
__unused bool flush) {}
|
||||
static inline void debug_level_set(__unused int level) {}
|
||||
static inline int debug_level_get(void) {return 0;}
|
||||
static inline void debug_stream_set(__unused FILE *stream) {}
|
||||
static inline long long debug_timer_elapsed(void) {return 0LL;}
|
||||
static inline void debug_flush_set(__unused bool level) {}
|
||||
static inline void _printf debug(__unused int level, __unused bool timestamp,
|
||||
__unused int indent, __unused const char *src,
|
||||
__unused int line, __unused const char *fmt, ...) {}
|
||||
|
||||
#endif /* DEBUG_DEBUG */
|
||||
#undef _unused
|
||||
|
||||
#undef _printf
|
||||
|
||||
/**
|
145
c/brlib/src/debug.c
Normal file
145
c/brlib/src/debug.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/* debug.c - debug/log management
|
||||
*
|
||||
* Copyright (C) 2021-2023 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef DEBUG_DEBUG
|
||||
#define DEBUG_DEBUG
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
static long long timer_start; /* in nanosecond */
|
||||
static int level = 0; /* output log when < level */
|
||||
static int flush = false; /* force flush after logs */
|
||||
static FILE *stream = NULL; /* stream to use */
|
||||
|
||||
/**
|
||||
* debug_level_set() - set debug level.
|
||||
* @_level: debug level (integer).
|
||||
*/
|
||||
void debug_level_set(int _level)
|
||||
{
|
||||
level = _level;
|
||||
# ifdef DEBUG_DEBUG_C
|
||||
log(0, "debug level set to %u\n", level);
|
||||
# endif
|
||||
}
|
||||
|
||||
/**
|
||||
* debug_level_get() - get debug level.
|
||||
* @return: current level debug (integer).
|
||||
*/
|
||||
int debug_level_get(void)
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
void debug_stream_set(FILE *_stream)
|
||||
{
|
||||
stream = _stream;
|
||||
# ifdef DEBUG_DEBUG_C
|
||||
log(0, "stream set to %d\n", stream? fileno(stream): -1);
|
||||
# endif
|
||||
}
|
||||
|
||||
void debug_flush_set(bool _flush)
|
||||
{
|
||||
flush = _flush;
|
||||
# ifdef DEBUG_DEBUG_C
|
||||
log(0, "debug flush %s.\n", flush? "set": "unset");
|
||||
# endif
|
||||
}
|
||||
|
||||
void debug_init(int _level, FILE *_stream, bool _flush)
|
||||
{
|
||||
struct timespec timer;
|
||||
|
||||
debug_stream_set(_stream);
|
||||
debug_level_set(_level);
|
||||
debug_flush_set(_flush);
|
||||
if (!clock_gettime(CLOCK_MONOTONIC, &timer)) {
|
||||
timer_start = timer.tv_sec * NANOSEC + timer.tv_nsec;
|
||||
}
|
||||
else {
|
||||
timer_start = 0;
|
||||
}
|
||||
log(0, "timer started.\n");
|
||||
}
|
||||
|
||||
long long debug_timer_elapsed(void)
|
||||
{
|
||||
struct timespec timer;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &timer);
|
||||
return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* debug() - log function
|
||||
* @lev: log level
|
||||
* @timestamp: boolean, print timestamp if true
|
||||
* @indent: indent level (2 spaces each)
|
||||
* @src: source file/func name (or NULL)
|
||||
* @line: line number
|
||||
*/
|
||||
void debug(int lev, bool timestamp, int indent, const char *src,
|
||||
int line, const char *fmt, ...)
|
||||
{
|
||||
if (!stream || lev > level)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
|
||||
if (indent)
|
||||
fprintf(stream, "%*s", 2*(indent-1), "");
|
||||
|
||||
if (timestamp) {
|
||||
long long diff = debug_timer_elapsed();
|
||||
fprintf(stream, "%lld.%03lld ", diff/NANOSEC, (diff/1000000)%1000);
|
||||
fprintf(stream, "%010lld ", diff);
|
||||
}
|
||||
|
||||
if (src) {
|
||||
if (line)
|
||||
fprintf(stream, "[%s:%u] ", src, line);
|
||||
else
|
||||
fprintf(stream, "[%s] ", src);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stream, fmt, ap);
|
||||
va_end(ap);
|
||||
if (flush)
|
||||
fflush(stream);
|
||||
}
|
||||
|
||||
#ifdef BIN_debug
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int foo=1;
|
||||
debug_init(5);
|
||||
|
||||
log(0, "log0=%d\n", foo++);
|
||||
log(1, "log1=%d\n", foo++);
|
||||
log(2, "log2=%d\n", foo++);
|
||||
log_i(2, "log_i 2=%d\n", foo++);
|
||||
log_i(5, "log_i 5=%d\n", foo++);
|
||||
log_i(6, "log_i 6=%d\n", foo++);
|
||||
log_it(4, "log_it 4=%d\n", foo++);
|
||||
log_f(1, "log_f 5=%d\n", foo++);
|
||||
}
|
||||
#endif
|
155
c/brlib/todo/asm/unaligned.h
Normal file
155
c/brlib/todo/asm/unaligned.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_GENERIC_UNALIGNED_H
|
||||
#define __ASM_GENERIC_UNALIGNED_H
|
||||
|
||||
/*
|
||||
* This is the most generic implementation of unaligned accesses
|
||||
* and should work almost anywhere.
|
||||
*/
|
||||
#include <linux/unaligned/packed_struct.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define __get_unaligned_t(type, ptr) ({ \
|
||||
const struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
|
||||
__pptr->x; \
|
||||
})
|
||||
|
||||
#define __put_unaligned_t(type, val, ptr) do { \
|
||||
struct { type x; } __packed *__pptr = (typeof(__pptr))(ptr); \
|
||||
__pptr->x = (val); \
|
||||
} while (0)
|
||||
|
||||
#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
|
||||
#define put_unaligned(val, ptr) __put_unaligned_t(typeof(*(ptr)), (val), (ptr))
|
||||
|
||||
static inline u16 get_unaligned_le16(const void *p)
|
||||
{
|
||||
return le16_to_cpu(__get_unaligned_t(__le16, p));
|
||||
}
|
||||
|
||||
static inline u32 get_unaligned_le32(const void *p)
|
||||
{
|
||||
return le32_to_cpu(__get_unaligned_t(__le32, p));
|
||||
}
|
||||
|
||||
static inline u64 get_unaligned_le64(const void *p)
|
||||
{
|
||||
return le64_to_cpu(__get_unaligned_t(__le64, p));
|
||||
}
|
||||
|
||||
static inline void put_unaligned_le16(u16 val, void *p)
|
||||
{
|
||||
__put_unaligned_t(__le16, cpu_to_le16(val), p);
|
||||
}
|
||||
|
||||
static inline void put_unaligned_le32(u32 val, void *p)
|
||||
{
|
||||
__put_unaligned_t(__le32, cpu_to_le32(val), p);
|
||||
}
|
||||
|
||||
static inline void put_unaligned_le64(u64 val, void *p)
|
||||
{
|
||||
__put_unaligned_t(__le64, cpu_to_le64(val), p);
|
||||
}
|
||||
|
||||
static inline u16 get_unaligned_be16(const void *p)
|
||||
{
|
||||
return be16_to_cpu(__get_unaligned_t(__be16, p));
|
||||
}
|
||||
|
||||
static inline u32 get_unaligned_be32(const void *p)
|
||||
{
|
||||
return be32_to_cpu(__get_unaligned_t(__be32, p));
|
||||
}
|
||||
|
||||
static inline u64 get_unaligned_be64(const void *p)
|
||||
{
|
||||
return be64_to_cpu(__get_unaligned_t(__be64, p));
|
||||
}
|
||||
|
||||
static inline void put_unaligned_be16(u16 val, void *p)
|
||||
{
|
||||
__put_unaligned_t(__be16, cpu_to_be16(val), p);
|
||||
}
|
||||
|
||||
static inline void put_unaligned_be32(u32 val, void *p)
|
||||
{
|
||||
__put_unaligned_t(__be32, cpu_to_be32(val), p);
|
||||
}
|
||||
|
||||
static inline void put_unaligned_be64(u64 val, void *p)
|
||||
{
|
||||
__put_unaligned_t(__be64, cpu_to_be64(val), p);
|
||||
}
|
||||
|
||||
static inline u32 __get_unaligned_be24(const u8 *p)
|
||||
{
|
||||
return p[0] << 16 | p[1] << 8 | p[2];
|
||||
}
|
||||
|
||||
static inline u32 get_unaligned_be24(const void *p)
|
||||
{
|
||||
return __get_unaligned_be24(p);
|
||||
}
|
||||
|
||||
static inline u32 __get_unaligned_le24(const u8 *p)
|
||||
{
|
||||
return p[0] | p[1] << 8 | p[2] << 16;
|
||||
}
|
||||
|
||||
static inline u32 get_unaligned_le24(const void *p)
|
||||
{
|
||||
return __get_unaligned_le24(p);
|
||||
}
|
||||
|
||||
static inline void __put_unaligned_be24(const u32 val, u8 *p)
|
||||
{
|
||||
*p++ = val >> 16;
|
||||
*p++ = val >> 8;
|
||||
*p++ = val;
|
||||
}
|
||||
|
||||
static inline void put_unaligned_be24(const u32 val, void *p)
|
||||
{
|
||||
__put_unaligned_be24(val, p);
|
||||
}
|
||||
|
||||
static inline void __put_unaligned_le24(const u32 val, u8 *p)
|
||||
{
|
||||
*p++ = val;
|
||||
*p++ = val >> 8;
|
||||
*p++ = val >> 16;
|
||||
}
|
||||
|
||||
static inline void put_unaligned_le24(const u32 val, void *p)
|
||||
{
|
||||
__put_unaligned_le24(val, p);
|
||||
}
|
||||
|
||||
static inline void __put_unaligned_be48(const u64 val, u8 *p)
|
||||
{
|
||||
*p++ = val >> 40;
|
||||
*p++ = val >> 32;
|
||||
*p++ = val >> 24;
|
||||
*p++ = val >> 16;
|
||||
*p++ = val >> 8;
|
||||
*p++ = val;
|
||||
}
|
||||
|
||||
static inline void put_unaligned_be48(const u64 val, void *p)
|
||||
{
|
||||
__put_unaligned_be48(val, p);
|
||||
}
|
||||
|
||||
static inline u64 __get_unaligned_be48(const u8 *p)
|
||||
{
|
||||
return (u64)p[0] << 40 | (u64)p[1] << 32 | (u64)p[2] << 24 |
|
||||
p[3] << 16 | p[4] << 8 | p[5];
|
||||
}
|
||||
|
||||
static inline u64 get_unaligned_be48(const void *p)
|
||||
{
|
||||
return __get_unaligned_be48(p);
|
||||
}
|
||||
|
||||
#endif /* __ASM_GENERIC_UNALIGNED_H */
|
61
c/brlib/todo/circ_buf.c
Normal file
61
c/brlib/todo/circ_buf.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* See Documentation/core-api/circular-buffers.rst for more information.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define CIRC_BUF(name, type, bits) \
|
||||
struct s##name { \
|
||||
type buf[1 << (bits)]; \
|
||||
int head; \
|
||||
int tail; \
|
||||
} name = { \
|
||||
{ 0 }, \
|
||||
0, \
|
||||
0 };
|
||||
|
||||
struct circ_buf {
|
||||
char *buf;
|
||||
int head;
|
||||
int tail;
|
||||
};
|
||||
|
||||
/* Return count in buffer. */
|
||||
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
|
||||
|
||||
/* Return space available, 0..size-1. We always leave one free char
|
||||
as a completely full buffer has head == tail, which is the same as
|
||||
empty. */
|
||||
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
|
||||
|
||||
/* Return count up to the end of the buffer. Carefully avoid
|
||||
accessing head and tail more than once, so they can change
|
||||
underneath us without returning inconsistent results. */
|
||||
#define CIRC_CNT_TO_END(head,tail,size) \
|
||||
({int end = (size) - (tail); \
|
||||
int n = ((head) + end) & ((size)-1); \
|
||||
n < end ? n : end;})
|
||||
|
||||
/* Return space available up to the end of the buffer. */
|
||||
#define CIRC_SPACE_TO_END(head,tail,size) \
|
||||
({int end = (size) - 1 - (head); \
|
||||
int n = (end + (tail)) & ((size)-1); \
|
||||
n <= end ? n : end+1;})
|
||||
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int size = 5;
|
||||
|
||||
if (ac > 8) {
|
||||
size = atoi(*(av + 1));
|
||||
}
|
||||
printf("size-%d\n", size);
|
||||
|
||||
CIRC_BUF(foo, int, 5);
|
||||
printf("sizeof(elt)=%lu\n", sizeof(foo.buf[0]));
|
||||
printf("sizeof(buf)=%lu\n", sizeof(foo.buf));
|
||||
|
||||
}
|
44
c/brlib/todo/circ_buf.h
Normal file
44
c/brlib/todo/circ_buf.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* See Documentation/core-api/circular-buffers.rst for more information.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_CIRC_BUF_H
|
||||
#define _LINUX_CIRC_BUF_H 1
|
||||
|
||||
#define CIRC_BUF(name, type, bits) \
|
||||
struct s##name { \
|
||||
type buf[1 << (bits)]; \
|
||||
int head; \
|
||||
int tail; \
|
||||
};
|
||||
|
||||
struct circ_buf {
|
||||
char *buf;
|
||||
int head;
|
||||
int tail;
|
||||
};
|
||||
|
||||
/* Return count in buffer. */
|
||||
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
|
||||
|
||||
/* Return space available, 0..size-1. We always leave one free char
|
||||
as a completely full buffer has head == tail, which is the same as
|
||||
empty. */
|
||||
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
|
||||
|
||||
/* Return count up to the end of the buffer. Carefully avoid
|
||||
accessing head and tail more than once, so they can change
|
||||
underneath us without returning inconsistent results. */
|
||||
#define CIRC_CNT_TO_END(head,tail,size) \
|
||||
({int end = (size) - (tail); \
|
||||
int n = ((head) + end) & ((size)-1); \
|
||||
n < end ? n : end;})
|
||||
|
||||
/* Return space available up to the end of the buffer. */
|
||||
#define CIRC_SPACE_TO_END(head,tail,size) \
|
||||
({int end = (size) - 1 - (head); \
|
||||
int n = (end + (tail)) & ((size)-1); \
|
||||
n <= end ? n : end+1;})
|
||||
|
||||
#endif /* _LINUX_CIRC_BUF_H */
|
8
c/brlib/todo/hashtest.c
Normal file
8
c/brlib/todo/hashtest.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include "hash.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("foo\n");
|
||||
return 1;
|
||||
}
|
253
c/brlib/todo/list_sort.c
Normal file
253
c/brlib/todo/list_sort.c
Normal file
@@ -0,0 +1,253 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
/*
|
||||
* Taken from linux kernel: lib/list_sort.c
|
||||
*/
|
||||
#include "list_sort.h"
|
||||
#include "list.h"
|
||||
#include "bits.h"
|
||||
#include "likely.h"
|
||||
|
||||
/*
|
||||
* Returns a list organized in an intermediate format suited
|
||||
* to chaining of merge() calls: null-terminated, no reserved or
|
||||
* sentinel head node, "prev" links not maintained.
|
||||
*/
|
||||
__attribute__((nonnull(2,3,4)))
|
||||
static struct list_head *merge(void *priv, list_cmp_func_t cmp,
|
||||
struct list_head *a, struct list_head *b)
|
||||
{
|
||||
struct list_head *head, **tail = &head;
|
||||
|
||||
for (;;) {
|
||||
/* if equal, take 'a' -- important for sort stability */
|
||||
if (cmp(priv, a, b) <= 0) {
|
||||
*tail = a;
|
||||
tail = &a->next;
|
||||
a = a->next;
|
||||
if (!a) {
|
||||
*tail = b;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*tail = b;
|
||||
tail = &b->next;
|
||||
b = b->next;
|
||||
if (!b) {
|
||||
*tail = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Combine final list merge with restoration of standard doubly-linked
|
||||
* list structure. This approach duplicates code from merge(), but
|
||||
* runs faster than the tidier alternatives of either a separate final
|
||||
* prev-link restoration pass, or maintaining the prev links
|
||||
* throughout.
|
||||
*/
|
||||
__attribute__((nonnull(2,3,4,5)))
|
||||
static void merge_final(void *priv, list_cmp_func_t cmp, struct list_head *head,
|
||||
struct list_head *a, struct list_head *b)
|
||||
{
|
||||
struct list_head *tail = head;
|
||||
u8 count = 0;
|
||||
|
||||
for (;;) {
|
||||
/* if equal, take 'a' -- important for sort stability */
|
||||
if (cmp(priv, a, b) <= 0) {
|
||||
tail->next = a;
|
||||
a->prev = tail;
|
||||
tail = a;
|
||||
a = a->next;
|
||||
if (!a)
|
||||
break;
|
||||
} else {
|
||||
tail->next = b;
|
||||
b->prev = tail;
|
||||
tail = b;
|
||||
b = b->next;
|
||||
if (!b) {
|
||||
b = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish linking remainder of list b on to tail */
|
||||
tail->next = b;
|
||||
do {
|
||||
/*
|
||||
* If the merge is highly unbalanced (e.g. the input is
|
||||
* already sorted), this loop may run many iterations.
|
||||
* Continue callbacks to the client even though no
|
||||
* element comparison is needed, so the client's cmp()
|
||||
* routine can invoke cond_resched() periodically.
|
||||
*/
|
||||
if (unlikely(!++count))
|
||||
cmp(priv, b, b);
|
||||
b->prev = tail;
|
||||
tail = b;
|
||||
b = b->next;
|
||||
} while (b);
|
||||
|
||||
/* And the final links to make a circular doubly-linked list */
|
||||
tail->next = head;
|
||||
head->prev = tail;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_sort - sort a list
|
||||
* @priv: private data, opaque to list_sort(), passed to @cmp
|
||||
* @head: the list to sort
|
||||
* @cmp: the elements comparison function
|
||||
*
|
||||
* The comparison function @cmp must return > 0 if @a should sort after
|
||||
* @b ("@a > @b" if you want an ascending sort), and <= 0 if @a should
|
||||
* sort before @b *or* their original order should be preserved. It is
|
||||
* always called with the element that came first in the input in @a,
|
||||
* and list_sort is a stable sort, so it is not necessary to distinguish
|
||||
* the @a < @b and @a == @b cases.
|
||||
*
|
||||
* This is compatible with two styles of @cmp function:
|
||||
* - The traditional style which returns <0 / =0 / >0, or
|
||||
* - Returning a boolean 0/1.
|
||||
* The latter offers a chance to save a few cycles in the comparison
|
||||
* (which is used by e.g. plug_ctx_cmp() in block/blk-mq.c).
|
||||
*
|
||||
* A good way to write a multi-word comparison is::
|
||||
*
|
||||
* if (a->high != b->high)
|
||||
* return a->high > b->high;
|
||||
* if (a->middle != b->middle)
|
||||
* return a->middle > b->middle;
|
||||
* return a->low > b->low;
|
||||
*
|
||||
*
|
||||
* This mergesort is as eager as possible while always performing at least
|
||||
* 2:1 balanced merges. Given two pending sublists of size 2^k, they are
|
||||
* merged to a size-2^(k+1) list as soon as we have 2^k following elements.
|
||||
*
|
||||
* Thus, it will avoid cache thrashing as long as 3*2^k elements can
|
||||
* fit into the cache. Not quite as good as a fully-eager bottom-up
|
||||
* mergesort, but it does use 0.2*n fewer comparisons, so is faster in
|
||||
* the common case that everything fits into L1.
|
||||
*
|
||||
*
|
||||
* The merging is controlled by "count", the number of elements in the
|
||||
* pending lists. This is beautifully simple code, but rather subtle.
|
||||
*
|
||||
* Each time we increment "count", we set one bit (bit k) and clear
|
||||
* bits k-1 .. 0. Each time this happens (except the very first time
|
||||
* for each bit, when count increments to 2^k), we merge two lists of
|
||||
* size 2^k into one list of size 2^(k+1).
|
||||
*
|
||||
* This merge happens exactly when the count reaches an odd multiple of
|
||||
* 2^k, which is when we have 2^k elements pending in smaller lists,
|
||||
* so it's safe to merge away two lists of size 2^k.
|
||||
*
|
||||
* After this happens twice, we have created two lists of size 2^(k+1),
|
||||
* which will be merged into a list of size 2^(k+2) before we create
|
||||
* a third list of size 2^(k+1), so there are never more than two pending.
|
||||
*
|
||||
* The number of pending lists of size 2^k is determined by the
|
||||
* state of bit k of "count" plus two extra pieces of information:
|
||||
*
|
||||
* - The state of bit k-1 (when k == 0, consider bit -1 always set), and
|
||||
* - Whether the higher-order bits are zero or non-zero (i.e.
|
||||
* is count >= 2^(k+1)).
|
||||
*
|
||||
* There are six states we distinguish. "x" represents some arbitrary
|
||||
* bits, and "y" represents some arbitrary non-zero bits:
|
||||
* 0: 00x: 0 pending of size 2^k; x pending of sizes < 2^k
|
||||
* 1: 01x: 0 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k
|
||||
* 2: x10x: 0 pending of size 2^k; 2^k + x pending of sizes < 2^k
|
||||
* 3: x11x: 1 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k
|
||||
* 4: y00x: 1 pending of size 2^k; 2^k + x pending of sizes < 2^k
|
||||
* 5: y01x: 2 pending of size 2^k; 2^(k-1) + x pending of sizes < 2^k
|
||||
* (merge and loop back to state 2)
|
||||
*
|
||||
* We gain lists of size 2^k in the 2->3 and 4->5 transitions (because
|
||||
* bit k-1 is set while the more significant bits are non-zero) and
|
||||
* merge them away in the 5->2 transition. Note in particular that just
|
||||
* before the 5->2 transition, all lower-order bits are 11 (state 3),
|
||||
* so there is one list of each smaller size.
|
||||
*
|
||||
* When we reach the end of the input, we merge all the pending
|
||||
* lists, from smallest to largest. If you work through cases 2 to
|
||||
* 5 above, you can see that the number of elements we merge with a list
|
||||
* of size 2^k varies from 2^(k-1) (cases 3 and 5 when x == 0) to
|
||||
* 2^(k+1) - 1 (second merge of case 5 when x == 2^(k-1) - 1).
|
||||
*/
|
||||
__attribute__((nonnull(2,3)))
|
||||
void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp)
|
||||
{
|
||||
struct list_head *list = head->next, *pending = NULL;
|
||||
size_t count = 0; /* Count of pending */
|
||||
|
||||
if (list == head->prev) /* Zero or one elements */
|
||||
return;
|
||||
|
||||
/* Convert to a null-terminated singly-linked list. */
|
||||
head->prev->next = NULL;
|
||||
|
||||
/*
|
||||
* Data structure invariants:
|
||||
* - All lists are singly linked and null-terminated; prev
|
||||
* pointers are not maintained.
|
||||
* - pending is a prev-linked "list of lists" of sorted
|
||||
* sublists awaiting further merging.
|
||||
* - Each of the sorted sublists is power-of-two in size.
|
||||
* - Sublists are sorted by size and age, smallest & newest at front.
|
||||
* - There are zero to two sublists of each size.
|
||||
* - A pair of pending sublists are merged as soon as the number
|
||||
* of following pending elements equals their size (i.e.
|
||||
* each time count reaches an odd multiple of that size).
|
||||
* That ensures each later final merge will be at worst 2:1.
|
||||
* - Each round consists of:
|
||||
* - Merging the two sublists selected by the highest bit
|
||||
* which flips when count is incremented, and
|
||||
* - Adding an element from the input as a size-1 sublist.
|
||||
*/
|
||||
do {
|
||||
size_t bits;
|
||||
struct list_head **tail = &pending;
|
||||
|
||||
/* Find the least-significant clear bit in count */
|
||||
for (bits = count; bits & 1; bits >>= 1)
|
||||
tail = &(*tail)->prev;
|
||||
/* Do the indicated merge */
|
||||
if (likely(bits)) {
|
||||
struct list_head *a = *tail, *b = a->prev;
|
||||
|
||||
a = merge(priv, cmp, b, a);
|
||||
/* Install the merged result in place of the inputs */
|
||||
a->prev = b->prev;
|
||||
*tail = a;
|
||||
}
|
||||
|
||||
/* Move one element from input list to pending */
|
||||
list->prev = pending;
|
||||
pending = list;
|
||||
list = list->next;
|
||||
pending->next = NULL;
|
||||
count++;
|
||||
} while (list);
|
||||
|
||||
/* End of input; merge together all the pending lists. */
|
||||
list = pending;
|
||||
pending = pending->prev;
|
||||
for (;;) {
|
||||
struct list_head *next = pending->prev;
|
||||
|
||||
if (!next)
|
||||
break;
|
||||
list = merge(priv, cmp, pending, list);
|
||||
pending = next;
|
||||
}
|
||||
/* The final merge, rebuilding prev links */
|
||||
merge_final(priv, cmp, head, pending, list);
|
||||
}
|
20
c/brlib/todo/list_sort.h
Normal file
20
c/brlib/todo/list_sort.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/*
|
||||
* Taken from linux kernel: lib/list_sort.c
|
||||
*/
|
||||
|
||||
#ifndef _BR_LIST_SORT_H
|
||||
#define _BR_LIST_SORT_H
|
||||
|
||||
//#include <linux/types.h>
|
||||
|
||||
struct list_head;
|
||||
|
||||
typedef int __attribute__((nonnull(2,3))) (*list_cmp_func_t)(void *,
|
||||
const struct list_head *, const struct list_head *);
|
||||
|
||||
__attribute__((nonnull(2,3)))
|
||||
void list_sort(void *priv, struct list_head *head, list_cmp_func_t cmp);
|
||||
|
||||
#endif /* _BR_LIST_SORT */
|
46
c/brlib/todo/packed_struct.h
Normal file
46
c/brlib/todo/packed_struct.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H
|
||||
#define _LINUX_UNALIGNED_PACKED_STRUCT_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct __una_u16 { u16 x; } __packed;
|
||||
struct __una_u32 { u32 x; } __packed;
|
||||
struct __una_u64 { u64 x; } __packed;
|
||||
|
||||
static inline u16 __get_unaligned_cpu16(const void *p)
|
||||
{
|
||||
const struct __una_u16 *ptr = (const struct __una_u16 *)p;
|
||||
return ptr->x;
|
||||
}
|
||||
|
||||
static inline u32 __get_unaligned_cpu32(const void *p)
|
||||
{
|
||||
const struct __una_u32 *ptr = (const struct __una_u32 *)p;
|
||||
return ptr->x;
|
||||
}
|
||||
|
||||
static inline u64 __get_unaligned_cpu64(const void *p)
|
||||
{
|
||||
const struct __una_u64 *ptr = (const struct __una_u64 *)p;
|
||||
return ptr->x;
|
||||
}
|
||||
|
||||
static inline void __put_unaligned_cpu16(u16 val, void *p)
|
||||
{
|
||||
struct __una_u16 *ptr = (struct __una_u16 *)p;
|
||||
ptr->x = val;
|
||||
}
|
||||
|
||||
static inline void __put_unaligned_cpu32(u32 val, void *p)
|
||||
{
|
||||
struct __una_u32 *ptr = (struct __una_u32 *)p;
|
||||
ptr->x = val;
|
||||
}
|
||||
|
||||
static inline void __put_unaligned_cpu64(u64 val, void *p)
|
||||
{
|
||||
struct __una_u64 *ptr = (struct __una_u64 *)p;
|
||||
ptr->x = val;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_UNALIGNED_PACKED_STRUCT_H */
|
489
c/brlib/todo/xxhash.c
Normal file
489
c/brlib/todo/xxhash.c
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet.
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* 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
|
||||
* OWNER 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.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
//#include <linux/compiler.h>
|
||||
// #include <linux/kernel.h>
|
||||
#include "xxhash.h"
|
||||
#include "bits.h"
|
||||
#include "asm/unaligned.h"
|
||||
|
||||
/*-*************************************
|
||||
* Macros
|
||||
**************************************/
|
||||
#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
|
||||
#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
# define XXH_CPU_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# define XXH_CPU_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/*-*************************************
|
||||
* Constants
|
||||
**************************************/
|
||||
static const uint32_t PRIME32_1 = 2654435761U;
|
||||
static const uint32_t PRIME32_2 = 2246822519U;
|
||||
static const uint32_t PRIME32_3 = 3266489917U;
|
||||
static const uint32_t PRIME32_4 = 668265263U;
|
||||
static const uint32_t PRIME32_5 = 374761393U;
|
||||
|
||||
static const uint64_t PRIME64_1 = 11400714785074694791ULL;
|
||||
static const uint64_t PRIME64_2 = 14029467366897019727ULL;
|
||||
static const uint64_t PRIME64_3 = 1609587929392839161ULL;
|
||||
static const uint64_t PRIME64_4 = 9650029242287828579ULL;
|
||||
static const uint64_t PRIME64_5 = 2870177450012600261ULL;
|
||||
|
||||
/*-**************************
|
||||
* Utils
|
||||
***************************/
|
||||
void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
/*-***************************
|
||||
* Simple Hash Functions
|
||||
****************************/
|
||||
static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
|
||||
{
|
||||
seed += input * PRIME32_2;
|
||||
seed = xxh_rotl32(seed, 13);
|
||||
seed *= PRIME32_1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *b_end = p + len;
|
||||
uint32_t h32;
|
||||
|
||||
if (len >= 16) {
|
||||
const uint8_t *const limit = b_end - 16;
|
||||
uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
uint32_t v2 = seed + PRIME32_2;
|
||||
uint32_t v3 = seed + 0;
|
||||
uint32_t v4 = seed - PRIME32_1;
|
||||
|
||||
do {
|
||||
v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
} while (p <= limit);
|
||||
|
||||
h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
|
||||
xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
|
||||
} else {
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (uint32_t)len;
|
||||
|
||||
while (p + 4 <= b_end) {
|
||||
h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
|
||||
{
|
||||
acc += input * PRIME64_2;
|
||||
acc = xxh_rotl64(acc, 31);
|
||||
acc *= PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
|
||||
{
|
||||
val = xxh64_round(0, val);
|
||||
acc ^= val;
|
||||
acc = acc * PRIME64_1 + PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
uint64_t h64;
|
||||
|
||||
if (len >= 32) {
|
||||
const uint8_t *const limit = b_end - 32;
|
||||
uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
uint64_t v2 = seed + PRIME64_2;
|
||||
uint64_t v3 = seed + 0;
|
||||
uint64_t v4 = seed - PRIME64_1;
|
||||
|
||||
do {
|
||||
v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
} while (p <= limit);
|
||||
|
||||
h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
h64 = xxh64_merge_round(h64, v1);
|
||||
h64 = xxh64_merge_round(h64, v2);
|
||||
h64 = xxh64_merge_round(h64, v3);
|
||||
h64 = xxh64_merge_round(h64, v4);
|
||||
|
||||
} else {
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (uint64_t)len;
|
||||
|
||||
while (p + 8 <= b_end) {
|
||||
const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
|
||||
h64 ^= k1;
|
||||
h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (p + 4 <= b_end) {
|
||||
h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
/*-**************************************************
|
||||
* Advanced Hash Functions
|
||||
***************************************************/
|
||||
void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
|
||||
{
|
||||
/* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
struct xxh32_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state.v2 = seed + PRIME32_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME32_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
}
|
||||
|
||||
void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
|
||||
{
|
||||
/* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
struct xxh64_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state.v2 = seed + PRIME64_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME64_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
}
|
||||
|
||||
int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state->total_len_32 += (uint32_t)len;
|
||||
state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
|
||||
|
||||
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* some data left from previous update */
|
||||
const uint32_t *p32 = state->mem32;
|
||||
|
||||
memcpy((uint8_t *)(state->mem32) + state->memsize, input,
|
||||
16 - state->memsize);
|
||||
|
||||
state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= b_end - 16) {
|
||||
const uint8_t *const limit = b_end - 16;
|
||||
uint32_t v1 = state->v1;
|
||||
uint32_t v2 = state->v2;
|
||||
uint32_t v3 = state->v3;
|
||||
uint32_t v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
} while (p <= limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < b_end) {
|
||||
memcpy(state->mem32, p, (size_t)(b_end-p));
|
||||
state->memsize = (uint32_t)(b_end-p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t xxh32_digest(const struct xxh32_state *state)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)state->mem32;
|
||||
const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
|
||||
state->memsize;
|
||||
uint32_t h32;
|
||||
|
||||
if (state->large_len) {
|
||||
h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
|
||||
xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
|
||||
} else {
|
||||
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += state->total_len_32;
|
||||
|
||||
while (p + 4 <= b_end) {
|
||||
h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* tmp buffer is full */
|
||||
uint64_t *p64 = state->mem64;
|
||||
|
||||
memcpy(((uint8_t *)p64) + state->memsize, input,
|
||||
32 - state->memsize);
|
||||
|
||||
state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
|
||||
|
||||
p += 32 - state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p + 32 <= b_end) {
|
||||
const uint8_t *const limit = b_end - 32;
|
||||
uint64_t v1 = state->v1;
|
||||
uint64_t v2 = state->v2;
|
||||
uint64_t v3 = state->v3;
|
||||
uint64_t v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
} while (p <= limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < b_end) {
|
||||
memcpy(state->mem64, p, (size_t)(b_end-p));
|
||||
state->memsize = (uint32_t)(b_end - p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t xxh64_digest(const struct xxh64_state *state)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)state->mem64;
|
||||
const uint8_t *const b_end = (const uint8_t *)state->mem64 +
|
||||
state->memsize;
|
||||
uint64_t h64;
|
||||
|
||||
if (state->total_len >= 32) {
|
||||
const uint64_t v1 = state->v1;
|
||||
const uint64_t v2 = state->v2;
|
||||
const uint64_t v3 = state->v3;
|
||||
const uint64_t v4 = state->v4;
|
||||
|
||||
h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
h64 = xxh64_merge_round(h64, v1);
|
||||
h64 = xxh64_merge_round(h64, v2);
|
||||
h64 = xxh64_merge_round(h64, v3);
|
||||
h64 = xxh64_merge_round(h64, v4);
|
||||
} else {
|
||||
h64 = state->v3 + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (uint64_t)state->total_len;
|
||||
|
||||
while (p + 8 <= b_end) {
|
||||
const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
|
||||
h64 ^= k1;
|
||||
h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (p + 4 <= b_end) {
|
||||
h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
259
c/brlib/todo/xxhash.h
Normal file
259
c/brlib/todo/xxhash.h
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet.
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * 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.
|
||||
*
|
||||
* 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
|
||||
* OWNER 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.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. This program is dual-licensed; you may select
|
||||
* either version 2 of the GNU General Public License ("GPL") or BSD license
|
||||
* ("BSD").
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/*
|
||||
* Notice extracted from xxHash homepage:
|
||||
*
|
||||
* xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
* It also successfully passes all tests from the SMHasher suite.
|
||||
*
|
||||
* Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2
|
||||
* Duo @3GHz)
|
||||
*
|
||||
* Name Speed Q.Score Author
|
||||
* xxHash 5.4 GB/s 10
|
||||
* CrapWow 3.2 GB/s 2 Andrew
|
||||
* MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
* SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
* SBox 1.4 GB/s 9 Bret Mulvey
|
||||
* Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
* SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
* CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
* FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
* CRC32 0.43 GB/s 9
|
||||
* MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
* SHA1-32 0.28 GB/s 10
|
||||
*
|
||||
* Q.Score is a measure of quality of the hash function.
|
||||
* It depends on successfully passing SMHasher test set.
|
||||
* 10 is a perfect score.
|
||||
*
|
||||
* A 64-bits version, named xxh64 offers much better speed,
|
||||
* but for 64-bits applications only.
|
||||
* Name Speed on 64 bits Speed on 32 bits
|
||||
* xxh64 13.8 GB/s 1.9 GB/s
|
||||
* xxh32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H
|
||||
#define XXHASH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*-****************************
|
||||
* Simple Hash Functions
|
||||
*****************************/
|
||||
|
||||
/**
|
||||
* xxh32() - calculate the 32-bit hash of the input with a given seed.
|
||||
*
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
*
|
||||
* Return: The 32-bit hash of the data.
|
||||
*/
|
||||
uint32_t xxh32(const void *input, size_t length, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh64() - calculate the 64-bit hash of the input with a given seed.
|
||||
*
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* This function runs 2x faster on 64-bit systems, but slower on 32-bit systems.
|
||||
*
|
||||
* Return: The 64-bit hash of the data.
|
||||
*/
|
||||
uint64_t xxh64(const void *input, size_t length, uint64_t seed);
|
||||
|
||||
/**
|
||||
* xxhash() - calculate wordsize hash of the input with a given seed
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* If the hash does not need to be comparable between machines with
|
||||
* different word sizes, this function will call whichever of xxh32()
|
||||
* or xxh64() is faster.
|
||||
*
|
||||
* Return: wordsize hash of the data.
|
||||
*/
|
||||
|
||||
static inline unsigned long xxhash(const void *input, size_t length,
|
||||
uint64_t seed)
|
||||
{
|
||||
#if BITS_PER_LONG == 64
|
||||
return xxh64(input, length, seed);
|
||||
#else
|
||||
return xxh32(input, length, seed);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*-****************************
|
||||
* Streaming Hash Functions
|
||||
*****************************/
|
||||
|
||||
/*
|
||||
* These definitions are only meant to allow allocation of XXH state
|
||||
* statically, on stack, or in a struct for example.
|
||||
* Do not use members directly.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct xxh32_state - private xxh32 state, do not use members directly
|
||||
*/
|
||||
struct xxh32_state {
|
||||
uint32_t total_len_32;
|
||||
uint32_t large_len;
|
||||
uint32_t v1;
|
||||
uint32_t v2;
|
||||
uint32_t v3;
|
||||
uint32_t v4;
|
||||
uint32_t mem32[4];
|
||||
uint32_t memsize;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xxh32_state - private xxh64 state, do not use members directly
|
||||
*/
|
||||
struct xxh64_state {
|
||||
uint64_t total_len;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t v4;
|
||||
uint64_t mem64[4];
|
||||
uint32_t memsize;
|
||||
};
|
||||
|
||||
/**
|
||||
* xxh32_reset() - reset the xxh32 state to start a new hashing operation
|
||||
*
|
||||
* @state: The xxh32 state to reset.
|
||||
* @seed: Initialize the hash state with this seed.
|
||||
*
|
||||
* Call this function on any xxh32_state to prepare for a new hashing operation.
|
||||
*/
|
||||
void xxh32_reset(struct xxh32_state *state, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh32_update() - hash the data given and update the xxh32 state
|
||||
*
|
||||
* @state: The xxh32 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh32_reset() call xxh32_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh32_digest() - produce the current xxh32 hash
|
||||
*
|
||||
* @state: Produce the current xxh32 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh32_digest(), and
|
||||
* generate new hashes later on, by calling xxh32_digest() again.
|
||||
*
|
||||
* Return: The xxh32 hash stored in the state.
|
||||
*/
|
||||
uint32_t xxh32_digest(const struct xxh32_state *state);
|
||||
|
||||
/**
|
||||
* xxh64_reset() - reset the xxh64 state to start a new hashing operation
|
||||
*
|
||||
* @state: The xxh64 state to reset.
|
||||
* @seed: Initialize the hash state with this seed.
|
||||
*/
|
||||
void xxh64_reset(struct xxh64_state *state, uint64_t seed);
|
||||
|
||||
/**
|
||||
* xxh64_update() - hash the data given and update the xxh64 state
|
||||
* @state: The xxh64 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh64_reset() call xxh64_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
int xxh64_update(struct xxh64_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh64_digest() - produce the current xxh64 hash
|
||||
*
|
||||
* @state: Produce the current xxh64 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh64_digest(), and
|
||||
* generate new hashes later on, by calling xxh64_digest() again.
|
||||
*
|
||||
* Return: The xxh64 hash stored in the state.
|
||||
*/
|
||||
uint64_t xxh64_digest(const struct xxh64_state *state);
|
||||
|
||||
/*-**************************
|
||||
* Utils
|
||||
***************************/
|
||||
|
||||
/**
|
||||
* xxh32_copy_state() - copy the source state into the destination state
|
||||
*
|
||||
* @src: The source xxh32 state.
|
||||
* @dst: The destination xxh32 state.
|
||||
*/
|
||||
void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
|
||||
|
||||
/**
|
||||
* xxh64_copy_state() - copy the source state into the destination state
|
||||
*
|
||||
* @src: The source xxh64 state.
|
||||
* @dst: The destination xxh64 state.
|
||||
*/
|
||||
void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
|
||||
|
||||
#endif /* XXHASH_H */
|
111
c/debug.c
111
c/debug.c
@@ -1,111 +0,0 @@
|
||||
/* debug.c - debug/log management
|
||||
*
|
||||
* Copyright (C) 2021-2022 Bruno Raoult ("br")
|
||||
* Licensed under the GNU General Public License v3.0 or later.
|
||||
* Some rights reserved. See COPYING.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this
|
||||
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef DEBUG_DEBUG
|
||||
#define DEBUG_DEBUG
|
||||
#endif
|
||||
|
||||
#include "bits.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define NANOSEC 1000000000 /* nano sec in sec */
|
||||
#define MILLISEC 1000000 /* milli sec in sec */
|
||||
|
||||
static long long timer_start; /* in nanosecond */
|
||||
static u32 debug_level=0;
|
||||
|
||||
void debug_level_set(u32 level)
|
||||
{
|
||||
debug_level = level;
|
||||
|
||||
log(1, "debug level set to %u\n", level);
|
||||
}
|
||||
|
||||
void debug_init(u32 level)
|
||||
{
|
||||
struct timespec timer;
|
||||
|
||||
debug_level_set(level);
|
||||
if (!clock_gettime(CLOCK_MONOTONIC, &timer)) {
|
||||
timer_start = timer.tv_sec * NANOSEC + timer.tv_nsec;
|
||||
}
|
||||
else {
|
||||
timer_start = 0;
|
||||
}
|
||||
log(0, "timer started.\n");
|
||||
}
|
||||
|
||||
inline static long long timer_elapsed()
|
||||
{
|
||||
struct timespec timer;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &timer);
|
||||
return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start;
|
||||
}
|
||||
|
||||
/* void debug - log function
|
||||
* @timestamp : boolean
|
||||
* @indent : indent level (2 spaces each)
|
||||
* @src : source file/func name (or NULL)
|
||||
* @line : line number
|
||||
*/
|
||||
void debug(u32 level, bool timestamp, u32 indent, const char *src,
|
||||
u32 line, const char *fmt, ...)
|
||||
{
|
||||
if (level > debug_level)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
|
||||
if (indent)
|
||||
printf("%*s", 2*(indent-1), "");
|
||||
|
||||
if (timestamp) {
|
||||
long long diff = timer_elapsed();
|
||||
printf("%lld.%03lld ", diff/NANOSEC, (diff/1000000)%1000);
|
||||
printf("%010lld ", diff);
|
||||
}
|
||||
|
||||
if (src) {
|
||||
if (line)
|
||||
printf("[%s:%u] ", src, line);
|
||||
else
|
||||
printf("[%s] ", src);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef BIN_debug
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int foo=1;
|
||||
debug_init(5);
|
||||
|
||||
log(0, "log0=%d\n", foo++);
|
||||
log(1, "log1=%d\n", foo++);
|
||||
log(2, "log2=%d\n", foo++);
|
||||
log_i(2, "log_i 2=%d\n", foo++);
|
||||
log_i(5, "log_i 5=%d\n", foo++);
|
||||
log_i(6, "log_i 6=%d\n", foo++);
|
||||
log_it(4, "log_it 4=%d\n", foo++);
|
||||
log_f(1, "log_f 5=%d\n", foo++);
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user