├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── basekit ├── BStream.c ├── BStream.h ├── BStreamTag.c ├── BStreamTag.h ├── Base.h ├── Common.c ├── Common.h ├── Common_inline.h ├── ConvertUTF.c ├── ConvertUTF.h ├── Date.c ├── Date.h ├── Datum.c ├── Datum.h ├── Duration.c ├── Duration.h ├── DynLib.c ├── DynLib.h ├── List.c ├── List.h ├── List_inline.h ├── MainArgs.c ├── MainArgs.h ├── PHash.c ├── PHash.h ├── PHash_inline.h ├── PortableGettimeofday.c ├── PortableGettimeofday.h ├── PortableSnprintf.c ├── PortableStdint.h ├── PortableStrlcpy.c ├── PortableStrlcpy.h ├── PortableStrptime.c ├── PortableStrptime.h ├── PortableTruncate.c ├── PortableTruncate.h ├── PortableUsleep.c ├── PortableUsleep.h ├── RandomGen.c ├── RandomGen.h ├── SHash.c ├── SHash.h ├── SHash_inline.h ├── Sorting.c ├── Sorting.h ├── Stack.c ├── Stack.h ├── Stack_inline.h ├── UArray.c ├── UArray.h ├── UArray_character.c ├── UArray_character.h ├── UArray_format.c ├── UArray_format.h ├── UArray_math.c ├── UArray_math.h ├── UArray_path.c ├── UArray_path.h ├── UArray_stream.c ├── UArray_stream.h ├── UArray_string.c ├── UArray_string.h ├── UArray_utf.c ├── UArray_utf.h └── simd_cph │ ├── LICENSE.txt │ ├── docs │ └── LICENSE.txt │ ├── include │ ├── simd_cp.h │ ├── simd_cp_arm-iwmmx.h │ ├── simd_cp_emu.h │ └── simd_cp_x86.h │ ├── simd_cph.readme │ └── test │ ├── Makefile │ ├── test_simd.c │ └── test_simd_emu ├── client └── skbus.c ├── cross-arm-linux-gnueabihf.cmake ├── debug.txt ├── jfile ├── JFile.c └── JFile.h ├── mgr ├── array-heap.c ├── array-heap.h ├── coroutine.h ├── daemonize.c ├── dbapi.c ├── dbus.c ├── skipd.c ├── skipd.h ├── unix-echo-client.c └── unix-echo-server.c ├── skipdb ├── SkipDB.c ├── SkipDB.h ├── SkipDBCursor.c ├── SkipDBCursor.h ├── SkipDBRecord.c └── SkipDBRecord.h ├── tests ├── check.sh ├── env.c ├── example.c ├── jftest.c ├── remove.sh ├── skiplist.c ├── test.c ├── test.sh ├── test2.c └── udbtest.c └── udb ├── UDB.c ├── UDB.h ├── UDBIndex.c ├── UDBIndex.h ├── UDBRecord.c ├── UDBRecord.h ├── UDBRecords.c └── UDBRecords.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | 34 | cscope.* 35 | tags 36 | build 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(skipdbv2) 2 | CMAKE_MINIMUM_REQUIRED (VERSION 2.8) 3 | ADD_DEFINITIONS(-Os -g -Wstrict-prototypes -Wall -falign-loops=16 -DBUILDING_SKIPDB_DLL) 4 | 5 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 6 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 7 | set(LIBEV_LIBRARIES CACHE PATH "Path to the libev library") 8 | set(LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory") 9 | 10 | #INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src) 11 | 12 | if ("${LIBEV_INCLUDE_DIRS}" STREQUAL "") 13 | set(LIBEV_LIBRARIES ev) 14 | endif() 15 | 16 | INCLUDE_DIRECTORIES(${LIBEV_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/basekit/simd_cph/include ${PROJECT_SOURCE_DIR}/basekit ${PROJECT_SOURCE_DIR}/jfile ${PROJECT_SOURCE_DIR}/udb ${PROJECT_SOURCE_DIR}/skipdb) 17 | FILE(GLOB_RECURSE BASEKIT_SRC ${PROJECT_SOURCE_DIR}/basekit/*.c) 18 | FILE(GLOB_RECURSE FILE_SRC ${PROJECT_SOURCE_DIR}/jfile/*.c) 19 | FILE(GLOB_RECURSE UDB_SRC ${PROJECT_SOURCE_DIR}/udb/*.c) 20 | FILE(GLOB_RECURSE SKIPDB_SRC ${PROJECT_SOURCE_DIR}/skipdb/*.c) 21 | FILE(GLOB_RECURSE MGR_SRC ${PROJECT_SOURCE_DIR}/mgr/*.c) 22 | FILE(GLOB_RECURSE CLIENT_SRC ${PROJECT_SOURCE_DIR}/client/*.c) 23 | 24 | #set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /opt/brcm-arm/usr/lib) 25 | 26 | ADD_LIBRARY(skipdb STATIC ${BASEKIT_SRC} ${FILE_SRC} ${UDB_SRC} ${SKIPDB_SRC}) 27 | 28 | #INCLUDE_DIRECTORIES(${LIBEV_LIBRARIES}) 29 | 30 | ADD_EXECUTABLE(test ./tests/test.c) 31 | TARGET_LINK_LIBRARIES(test skipdb m ${LIBEV_LIBRARIES}) 32 | 33 | ADD_EXECUTABLE(test2 ./tests/test2.c) 34 | TARGET_LINK_LIBRARIES(test2 skipdb m ${LIBEV_LIBRARIES}) 35 | 36 | ADD_EXECUTABLE(jftest ./tests/jftest.c) 37 | TARGET_LINK_LIBRARIES(jftest skipdb m ${LIBEV_LIBRARIES}) 38 | 39 | ADD_EXECUTABLE(udbtest ./tests/udbtest.c) 40 | TARGET_LINK_LIBRARIES(udbtest skipdb m ${LIBEV_LIBRARIES}) 41 | 42 | ADD_EXECUTABLE(example ./tests/example.c) 43 | TARGET_LINK_LIBRARIES(example skipdb m ${LIBEV_LIBRARIES}) 44 | 45 | #ADD_EXECUTABLE(skiplist ./tests/skiplist) 46 | 47 | ADD_EXECUTABLE(skipd ${PROJECT_SOURCE_DIR}/mgr/skipd.c ${PROJECT_SOURCE_DIR}/mgr/daemonize.c) 48 | TARGET_LINK_LIBRARIES(skipd skipdb m ${LIBEV_LIBRARIES}) 49 | 50 | ADD_EXECUTABLE(dbus ${PROJECT_SOURCE_DIR}/mgr/dbus.c) 51 | TARGET_LINK_LIBRARIES(dbus ${LIBEV_LIBRARIES}) 52 | 53 | ADD_EXECUTABLE(dbapi ${PROJECT_SOURCE_DIR}/mgr/dbapi.c) 54 | TARGET_LINK_LIBRARIES(dbapi ${LIBEV_LIBRARIES}) 55 | 56 | #ADD_EXECUTABLE(env ${PROJECT_SOURCE_DIR}/tests/env.c) 57 | #TARGET_LINK_LIBRARIES(env ${LIBEV_LIBRARIES}) 58 | 59 | #ADD_EXECUTABLE(server ${PROJECT_SOURCE_DIR}/mgr/array-heap.c ${PROJECT_SOURCE_DIR}/mgr/unix-echo-server.c) 60 | #ADD_EXECUTABLE(client ${PROJECT_SOURCE_DIR}/mgr/array-heap.c ${PROJECT_SOURCE_DIR}/mgr/unix-echo-client.c) 61 | #TARGET_LINK_LIBRARIES(server skipdb m ${LIBEV_LIBRARIES}) 62 | #TARGET_LINK_LIBRARIES(client skipdb m ${LIBEV_LIBRARIES}) 63 | 64 | ADD_EXECUTABLE(skbus ${CLIENT_SRC}) 65 | TARGET_LINK_LIBRARIES(skbus m ${LIBEV_LIBRARIES}) 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, janson 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # skipdbv2 2 | rewrite and fix for https://github.com/stevedekorte/skipdb 3 | 嵌入式 k/v 数据库,编译大小只有 300k。可以代替nvram,并有nvram更强大的功能。[详细说明](http://koolshare.cn/thread-4850-1-1.html) 4 | 为了在嵌入式下更少的占用jffs的空间。建议最多使用配置条目为1w。(merlin正常使用nvram的配置条目为2000条) 5 | 当jffs占用大于8M时,会进行一次refresh,重新计算空间。 6 | 7 | # 速度 8 | * 写15000条数据需要6s 9 | * time ./test.sh #测试脚本在tests目录 10 | * real 0m6.697s 11 | 12 | # 实现功能有: 13 | 14 | * dbus set key=value 15 | * dbus ram key=value 16 | * dbus replace key=value 17 | * dbus get key 18 | * dbus list key 19 | * dbus delay key tick path_of_shell.sh #定时运行脚本,脚本情使用绝对路径 20 | * dbus time key H:M:S path_of_shell.sh #绝对时间运行脚本,脚本情使用绝对路径 21 | * dbus export key #将配置导入到脚本 22 | * dbus update key #将脚本配置保存到数据库 23 | * dbus inc key=value #增加数值 24 | * dbus desc key=value #减去数值 25 | * dbus event name path_of_shell.sh #注册一个事件脚本 26 | * dbus fire name #触发一个事件脚本 27 | 28 | # 编译方法 29 | * 依赖库 libev,需要自行编译或安装 30 | * cd skipdb 31 | * mkdir build 32 | * cd build 33 | * cmake .. 34 | * make 35 | 36 | # 执行方法 37 | * skipd -d /path/of/data 38 | * dbus command params 39 | -------------------------------------------------------------------------------- /basekit/BStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright 3 | Steve Dekorte, 2004 4 | license 5 | BSD revised 6 | description 7 | A Binary Stream that supports tagged items. 8 | */ 9 | 10 | #ifndef BSTREAM_DEFINED 11 | #define BSTREAM_DEFINED 1 12 | 13 | #include "Common.h" 14 | #include "UArray.h" 15 | #include "BStreamTag.h" 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | //typedef struct UArray UArray; 22 | 23 | typedef struct 24 | { 25 | UArray *ba; 26 | size_t index; 27 | unsigned char ownsUArray; 28 | UArray *tmp; 29 | UArray *errorBa; 30 | int flipEndian; 31 | unsigned char *typeBuf; 32 | } BStream; 33 | 34 | /* 35 | #define BStream_ba_(self, v) self->ba = v; 36 | #define BStream_ba(self) (self->ba) 37 | 38 | #define BStream_index_(self, v) self->index = v; 39 | #define BStream_index(self) (self->index) 40 | 41 | #define BStream_ownsUArray_(self, v) self->ownsUArray = v; 42 | #define BStream_ownsUArray(self) (self->ownsUArray) 43 | 44 | #define BStream_tmp_(self, v) self->tmp = v; 45 | #define BStream_tmp(self) (self->tmp) 46 | 47 | #define BStream_errorBa_(self, v) self->errorBa = v; 48 | #define BStream_errorBa(self) (self->errorBa) 49 | 50 | #define BStream_flipEndian_(self, v) self->flipEndian = v; 51 | #define BStream_flipEndian(self) (self->flipEndian) 52 | 53 | #define BStream_typeBuf_(self, v) self->typeBuf = v; 54 | #define BStream_typeBufs(self) (self->typeBuf) 55 | */ 56 | 57 | BASEKIT_API BStream *BStream_new(void); 58 | BASEKIT_API BStream *BStream_clone(BStream *self); 59 | BASEKIT_API void BStream_free(BStream *self); 60 | 61 | BASEKIT_API char *BStream_errorString(BStream *self); 62 | BASEKIT_API void BStream_setUArray_(BStream *self, UArray *ba); 63 | BASEKIT_API void BStream_setData_length_(BStream *self, unsigned char *data, size_t length); 64 | BASEKIT_API UArray *BStream_byteArray(BStream *self); 65 | BASEKIT_API void BStream_empty(BStream *self); 66 | BASEKIT_API int BStream_isEmpty(BStream *self); 67 | 68 | // writing -------------------------------------- 69 | 70 | BASEKIT_API void BStream_writeByte_(BStream *self, unsigned char v); 71 | 72 | BASEKIT_API void BStream_writeUint8_(BStream *self, uint8_t v); 73 | BASEKIT_API void BStream_writeUint32_(BStream *self, uint32_t v); 74 | BASEKIT_API void BStream_writeInt32_(BStream *self, int32_t v); 75 | #if !defined(__SYMBIAN32__) 76 | BASEKIT_API void BStream_writeInt64_(BStream *self, int64_t v); 77 | #endif 78 | BASEKIT_API void BStream_writeDouble_(BStream *self, double v); 79 | BASEKIT_API void BStream_writeData_length_(BStream *self, const unsigned char *data, size_t length); 80 | BASEKIT_API void BStream_writeCString_(BStream *self, const char *s); 81 | BASEKIT_API void BStream_writeUArray_(BStream *self, UArray *ba); 82 | 83 | // reading -------------------------------------- 84 | 85 | BASEKIT_API unsigned char BStream_readByte(BStream *self); 86 | 87 | BASEKIT_API uint8_t BStream_readUint8(BStream *self); 88 | BASEKIT_API uint32_t BStream_readUint32(BStream *self); 89 | BASEKIT_API int32_t BStream_readInt32(BStream *self); 90 | #if !defined(__SYMBIAN32__) 91 | BASEKIT_API int64_t BStream_readInt64(BStream *self); 92 | #endif 93 | BASEKIT_API double BStream_readDouble(BStream *self); 94 | BASEKIT_API uint8_t *BStream_readDataOfLength_(BStream *self, size_t length); 95 | BASEKIT_API void BStream_readUArray_(BStream *self, UArray *b); 96 | BASEKIT_API UArray *BStream_readUArray(BStream *self); 97 | BASEKIT_API const char *BStream_readCString(BStream *self); 98 | 99 | // tagged writing -------------------------------------- 100 | 101 | BASEKIT_API void BStream_writeTaggedUint8_(BStream *self, uint8_t v); 102 | BASEKIT_API void BStream_writeTaggedUint32_(BStream *self, uint32_t v); 103 | BASEKIT_API void BStream_writeTaggedInt32_(BStream *self, int32_t v); 104 | #if !defined(__SYMBIAN32__) 105 | BASEKIT_API void BStream_writeTaggedInt64_(BStream *self, int64_t v); 106 | #endif 107 | BASEKIT_API void BStream_writeTaggedDouble_(BStream *self, double v); 108 | BASEKIT_API void BStream_writeTaggedData_length_(BStream *self, const unsigned char *data, size_t length); 109 | BASEKIT_API void BStream_writeTaggedCString_(BStream *self, const char *s); 110 | BASEKIT_API void BStream_writeTaggedUArray_(BStream *self, UArray *ba); 111 | 112 | // tagged reading -------------------------------------- 113 | 114 | BASEKIT_API uint8_t BStream_readTaggedUint8(BStream *self); 115 | BASEKIT_API uint32_t BStream_readTaggedUint32(BStream *self); 116 | BASEKIT_API int32_t BStream_readTaggedInt32(BStream *self); 117 | #if !defined(__SYMBIAN32__) 118 | BASEKIT_API int64_t BStream_readTaggedInt64(BStream *self); 119 | #endif 120 | BASEKIT_API double BStream_readTaggedDouble(BStream *self); 121 | BASEKIT_API void BStream_readTaggedUArray_(BStream *self, UArray *b); 122 | BASEKIT_API UArray *BStream_readTaggedUArray(BStream *self); 123 | BASEKIT_API const char *BStream_readTaggedCString(BStream *self); 124 | 125 | BASEKIT_API void BStream_show(BStream *self); 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | #endif 131 | 132 | -------------------------------------------------------------------------------- /basekit/BStreamTag.c: -------------------------------------------------------------------------------- 1 | /* 2 | copyright 3 | Steve Dekorte, 2004 4 | license 5 | BSD revised 6 | */ 7 | 8 | #include "BStreamTag.h" 9 | #include 10 | 11 | /* 12 | unsigned int isArray : 1; 13 | unsigned int type : 2; 14 | unsigned int byteCount : 5; 15 | */ 16 | 17 | BStreamTag BStreamTag_FromUnsignedChar(unsigned char c) 18 | { 19 | // we need to do this because bit fields are compiler dependent 20 | BStreamTag t; 21 | t.isArray = c >> 7; 22 | t.type = ( c << 1) >> 6; 23 | t.byteCount = ( c << 3 ) >> 3; 24 | return t; 25 | } 26 | 27 | unsigned char BStreamTag_asUnsignedChar(BStreamTag *self) 28 | { 29 | BStreamTag t = *self; 30 | unsigned char c = 0; 31 | c = c | t.isArray << 7; 32 | c = c | t.type << 5; 33 | c = c | t.byteCount; 34 | return c; 35 | } 36 | 37 | // ----------------------------------------------------- 38 | 39 | BStreamTag BStreamTag_TagArray_type_byteCount_(unsigned int a, unsigned int t, unsigned int b) 40 | { 41 | BStreamTag self; 42 | self.isArray = a; 43 | self.type = t; 44 | self.byteCount = b; 45 | return self; 46 | } 47 | 48 | int BStreamTag_isEqual_(BStreamTag *self, BStreamTag *other) 49 | { 50 | return (BStreamTag_asUnsignedChar(self) == BStreamTag_asUnsignedChar(other)); 51 | } 52 | 53 | void BStreamTag_print(BStreamTag *self) 54 | { 55 | printf("[Tag "); 56 | printf("isArray: %i ", self->isArray); 57 | printf("type: %i ", self->type); 58 | printf("byteCount: %i", self->byteCount); 59 | printf("]"); 60 | } 61 | 62 | char *BStreamTag_typeName(BStreamTag *self) 63 | { 64 | switch (self->type) 65 | { 66 | case BSTREAM_UNSIGNED_INT: 67 | return "uint"; 68 | case BSTREAM_SIGNED_INT: 69 | return "int"; 70 | case BSTREAM_FLOAT: 71 | return "float"; 72 | case BSTREAM_POINTER: 73 | return "pointer"; 74 | } 75 | 76 | return "UNKNOWN TYPE"; 77 | } 78 | -------------------------------------------------------------------------------- /basekit/BStreamTag.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright 3 | Steve Dekorte, 2004 4 | license 5 | BSD revised 6 | */ 7 | 8 | #ifndef BSTREAMTAG_DEFINED 9 | #define BSTREAMTAG_DEFINED 1 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define BSTREAM_UNSIGNED_INT 0 16 | #define BSTREAM_SIGNED_INT 1 17 | #define BSTREAM_FLOAT 2 18 | #define BSTREAM_POINTER 3 19 | 20 | typedef struct 21 | { 22 | unsigned int isArray : 1; 23 | unsigned int type : 2; // 0 = unsigned int, 1 = signed int, 2 = float, 3 = pointer 24 | unsigned int byteCount : 5; // number of bytes in data value(s) 25 | } BStreamTag; 26 | 27 | // values in network byte order / big endian 28 | 29 | BStreamTag BStreamTag_FromUnsignedChar(unsigned char c); 30 | unsigned char BStreamTag_asUnsignedChar(BStreamTag *self); 31 | BStreamTag BStreamTag_TagArray_type_byteCount_(unsigned int a, unsigned int t, unsigned int b); 32 | int BStreamTag_isEqual_(BStreamTag *self, BStreamTag *other); 33 | void BStreamTag_print(BStreamTag *self); 34 | 35 | char *BStreamTag_typeName(BStreamTag *self); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /basekit/Base.h: -------------------------------------------------------------------------------- 1 | #ifndef IOBASE_DEFINED 2 | #define IOBASE_DEFINED 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /basekit/Common.h: -------------------------------------------------------------------------------- 1 | 2 | //metadoc Common copyright Steve Dekorte 2002 3 | //metadoc Common license BSD revised 4 | /*metadoc Common description 5 | This is a header that all other source files should include. 6 | These defines are helpful for doing OS specific checks in the code. 7 | */ 8 | 9 | 10 | #ifndef IOCOMMON_DEFINED 11 | #define IOCOMMON_DEFINED 1 12 | 13 | /*#define LOW_MEMORY_SYSTEM 1*/ 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #if defined (__SVR4) && defined (__sun) 20 | #include 21 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 22 | #include 23 | #elif !defined(__SYMBIAN32__) && !defined(_MSC_VER) && !defined(__NeXT__) 24 | #include 25 | #else 26 | typedef unsigned char uint8_t; 27 | typedef signed char int8_t; 28 | typedef unsigned short uint16_t; 29 | typedef signed short int16_t; 30 | typedef unsigned long uint32_t; 31 | typedef signed long int32_t; 32 | /* 33 | typedef unsigned long uint64_t; 34 | typedef signed long int64_t; 35 | */ 36 | typedef unsigned long long uint64_t; 37 | typedef long long int64_t; 38 | #endif 39 | 40 | /* Windows stuff */ 41 | 42 | #if defined(WIN32) || defined(__WINS__) || defined(__MINGW32__) || defined(_MSC_VER) 43 | #define inline __inline 44 | #define snprintf _snprintf 45 | #define usleep(x) Sleep(((x)+999)/1000) 46 | 47 | #define HAS_FIBERS 1 48 | 49 | #define ON_WINDOWS 1 50 | 51 | // Enable fibers 52 | #ifndef _WIN32_WINNT 53 | #define _WIN32_WINNT 0x0400 54 | #endif 55 | 56 | // this also includes windows.h 57 | #include 58 | 59 | #if !defined(__MINGW32__) 60 | #if defined(BUILDING_BASEKIT_DLL) || defined(BUILDING_IOVMALL_DLL) 61 | #define BASEKIT_API __declspec(dllexport) 62 | #else 63 | #define BASEKIT_API __declspec(dllimport) 64 | #endif 65 | #else 66 | #define BASEKIT_API 67 | #endif 68 | /* 69 | #ifndef _SYS_STDINT_H_ 70 | #include "PortableStdint.h" 71 | #endif 72 | */ 73 | 74 | #if !defined(__MINGW32__) 75 | /* disable compile warnings which are always treated 76 | as errors in my dev settings */ 77 | 78 | #pragma warning( disable : 4244 ) 79 | /* warning C4244: 'function' : conversion from 'double ' to 'int ', possible loss of data */ 80 | 81 | #pragma warning( disable : 4996 ) 82 | /* warning C4996: 'function' : This function or variable may be unsafe. Consider using 'function_s' instead */ 83 | 84 | #pragma warning( disable : 4018 ) 85 | /* warning C4018: 'operator' : signed/unsigned mismatch */ 86 | 87 | /*#pragma warning( disable : 4090 ) */ 88 | /* warning C4090: 'function' : different 'const' qualifiers */ 89 | 90 | /*#pragma warning( disable : 4024 )*/ 91 | /* warning C4024: different types for formal and actual parameter */ 92 | 93 | /*#pragma warning( disable : 4761 ) */ 94 | /* warning C4761: integral size mismatch in argument; conversion supplied */ 95 | 96 | /*#pragma warning( disable : 4047 ) */ 97 | /* warning C4047: '=' : 'char *' differs in levels of indirection from 'int ' */ 98 | #define ARCHITECTURE_x86 1 99 | #endif 100 | 101 | /* io_malloc, io_realloc, io_free undefined */ 102 | #if !defined(__SYMBIAN32__) 103 | #include 104 | 105 | /* strlen undefined */ 106 | #include 107 | #include /* for calloc */ 108 | #endif 109 | #else 110 | 111 | // Not on windows so define this away 112 | #define BASEKIT_API 113 | 114 | #endif 115 | 116 | /* 117 | [DBCS Enabling] 118 | 119 | DBCS (Short for Double-Byte Character Set), a character set that uses two-byte (16-bit) characters. Some languages, such as Chinese, Japanese and Korean (CJK), have writing schemes with many different characters that cannot be represented with single-byte codes such as ASCII and EBCDIC. 120 | 121 | In CJK world, CES (Character Encoding Scheme) and CCS (Coded Character Set) are actually different concept(one CES may contain multiple CCS). 122 | For example, EUC-JP is a CES which includes CCS of ASCII and JIS X 0208 (optionally JIS X 0201 Kana and JIS X 0212). 123 | 124 | In Japanese (because I am Japanese), 125 | While EUC-JP and UTF-8 Map ASCII unchanged, ShiftJIS not (However ShiftJIS is de facto standard in Japan). For example, {0x95, 0x5c} represents one character. in ASCII, second byte(0x5c) is back slash character. 126 | */ 127 | 128 | /* 129 | check whether double-byte character. supported only ShiftJIS. 130 | if you want to use ShiftJIS characters in string literal, set compiler option -DDBCS_ENABLED=1. 131 | */ 132 | 133 | #if DBCS_ENABLED 134 | #define ismbchar(c) ISSJIS((unsigned char)c) 135 | #define mbcharlen(c) 2 136 | #define ISSJIS(c) ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc)) 137 | #else 138 | #define ismbchar(c) 0 139 | #define mbcharlen(c) 1 140 | #endif /* DBCS_ENABLED */ 141 | 142 | #ifdef __cplusplus 143 | extern "C" { 144 | #endif 145 | 146 | //#define IO_CHECK_ALLOC 147 | 148 | #ifdef IO_CHECK_ALLOC 149 | BASEKIT_API size_t io_memsize(void *ptr); 150 | 151 | #define io_malloc(size) io_real_malloc(size, __FILE__, __LINE__) 152 | BASEKIT_API void *io_real_malloc(size_t size, char *file, int line); 153 | 154 | #define io_calloc(count, size) io_real_calloc(count, size, __FILE__, __LINE__) 155 | BASEKIT_API void *io_real_calloc(size_t count, size_t size, char *file, int line); 156 | 157 | #define io_realloc(ptr, size) io_real_realloc(ptr, size, __FILE__, __LINE__) 158 | BASEKIT_API void *io_real_realloc(void *ptr, size_t newSize, char *file, int line); 159 | 160 | BASEKIT_API void io_free(void *ptr); 161 | BASEKIT_API void io_show_mem(char *s); 162 | BASEKIT_API size_t io_maxAllocatedBytes(void); 163 | BASEKIT_API void io_resetMaxAllocatedBytes(void); 164 | BASEKIT_API size_t io_frees(void); 165 | BASEKIT_API size_t io_allocs(void); 166 | BASEKIT_API size_t io_allocatedBytes(void); 167 | 168 | BASEKIT_API void io_showUnfreed(void); 169 | #else 170 | #define io_memsize 171 | #define io_malloc malloc 172 | #define io_calloc calloc 173 | #define io_realloc io_freerealloc 174 | #define io_free free 175 | #define io_show_mem 176 | 177 | #define io_maxAllocatedBytes() 0 178 | #define io_frees() 0 179 | #define io_allocs() 0 180 | #define io_allocatedBytes() 0 181 | #define io_resetMaxAllocatedBytes() 182 | #endif 183 | 184 | BASEKIT_API void *cpalloc(const void *p, size_t size); 185 | BASEKIT_API void *io_freerealloc(void *p, size_t size); 186 | 187 | int io_isBigEndian(void); 188 | BASEKIT_API uint32_t io_uint32InBigEndian(uint32_t i); 189 | 190 | #ifdef __cplusplus 191 | } 192 | #endif 193 | 194 | #endif 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /basekit/Common_inline.h: -------------------------------------------------------------------------------- 1 | 2 | //metadoc Common copyright Steve Dekorte 2002 3 | //metadoc Common license BSD revised 4 | /*metadoc Common description 5 | You may need to add an entry for your C compiler. 6 | */ 7 | 8 | /* 9 | Trick to get inlining to work with various compilers 10 | Kudos to Daniel A. Koepke 11 | */ 12 | 13 | #undef IO_DECLARE_INLINES 14 | #undef IOINLINE 15 | 16 | /* 17 | #if defined(__cplusplus) 18 | #ifdef IO_IN_C_FILE 19 | #else 20 | #define IO_DECLARE_INLINES 21 | #define IOINLINE extern inline 22 | #endif 23 | #else 24 | */ 25 | 26 | #if defined(__APPLE__) 27 | #include "TargetConditionals.h" 28 | #endif 29 | 30 | #if defined __XCODE__ && (TARGET_ASPEN_SIMULATOR || TARGET_OS_ASPEN) 31 | #define NON_EXTERN_INLINES 32 | #else 33 | #if defined __GNUC__ && __GNUC__ >= 4 34 | //#define NON_EXTERN_INLINES 35 | #endif 36 | #endif 37 | 38 | #ifdef NON_EXTERN_INLINES 39 | 40 | #ifdef IO_IN_C_FILE 41 | // in .c 42 | #define IO_DECLARE_INLINES 43 | #define IOINLINE 44 | #else 45 | // in .h 46 | #define IO_DECLARE_INLINES 47 | #define IOINLINE inline 48 | #endif 49 | 50 | #else 51 | 52 | #ifdef IO_IN_C_FILE 53 | // in .c 54 | #define IO_DECLARE_INLINES 55 | #define IOINLINE inline 56 | #else 57 | // in .h 58 | #define IO_DECLARE_INLINES 59 | #define IOINLINE extern inline 60 | #endif 61 | 62 | #endif 63 | 64 | /* 65 | #endif 66 | */ 67 | -------------------------------------------------------------------------------- /basekit/ConvertUTF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001-2004 Unicode, Inc. 3 | * 4 | * Disclaimer 5 | * 6 | * This source code is provided as is by Unicode, Inc. No claims are 7 | * made as to fitness for any particular purpose. No warranties of any 8 | * kind are expressed or implied. The recipient agrees to determine 9 | * applicability of information provided. If this file has been 10 | * purchased on magnetic or optical media from Unicode, Inc., the 11 | * sole remedy for any claim will be exchange of defective media 12 | * within 90 days of receipt. 13 | * 14 | * Limitations on Rights to Redistribute This Code 15 | * 16 | * Unicode, Inc. hereby grants the right to io_freely use the information 17 | * supplied in this file in the creation of products supporting the 18 | * Unicode Standard, and to make copies of this file in any form 19 | * for internal or external distribution as long as this notice 20 | * remains attached. 21 | */ 22 | 23 | /* --------------------------------------------------------------------- 24 | 25 | Conversions between UTF32, UTF-16, and UTF-8. Header file. 26 | 27 | Several funtions are included here, forming a complete set of 28 | conversions between the three formats. UTF-7 is not included 29 | here, but is handled in a separate source file. 30 | 31 | Each of these routines takes pointers to input buffers and output 32 | buffers. The input buffers are const. 33 | 34 | Each routine converts the text between *sourceStart and sourceEnd, 35 | putting the result into the buffer between *targetStart and 36 | targetEnd. Note: the end pointers are *after* the last item: e.g. 37 | *(sourceEnd - 1) is the last item. 38 | 39 | The return result indicates whether the conversion was successful, 40 | and if not, whether the problem was in the source or target buffers. 41 | (Only the first encountered problem is indicated.) 42 | 43 | After the conversion, *sourceStart and *targetStart are both 44 | updated to point to the end of last text successfully converted in 45 | the respective buffers. 46 | 47 | Input parameters: 48 | sourceStart - pointer to a pointer to the source buffer. 49 | The contents of this are modified on return so that 50 | it points at the next thing to be converted. 51 | targetStart - similarly, pointer to pointer to the target buffer. 52 | sourceEnd, targetEnd - respectively pointers to the ends of the 53 | two buffers, for overflow checking only. 54 | 55 | These conversion functions take a ConversionFlags argument. When this 56 | flag is set to strict, both irregular sequences and isolated surrogates 57 | will cause an error. When the flag is set to lenient, both irregular 58 | sequences and isolated surrogates are converted. 59 | 60 | Whether the flag is strict or lenient, all illegal sequences will cause 61 | an error return. This includes sequences such as: , , 62 | or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code 63 | must check for illegal sequences. 64 | 65 | When the flag is set to lenient, characters over 0x10FFFF are converted 66 | to the replacement character; otherwise (when the flag is set to strict) 67 | they constitute an error. 68 | 69 | Output parameters: 70 | The value "sourceIllegal" is returned from some routines if the input 71 | sequence is malformed. When "sourceIllegal" is returned, the source 72 | value will point to the illegal value that caused the problem. E.g., 73 | in UTF-8 when a sequence is malformed, it points to the start of the 74 | malformed sequence. 75 | 76 | Author: Mark E. Davis, 1994. 77 | Rev History: Rick McGowan, fixes & updates May 2001. 78 | Fixes & updates, Sept 2001. 79 | 80 | ------------------------------------------------------------------------ */ 81 | 82 | /* --------------------------------------------------------------------- 83 | The following 4 definitions are compiler-specific. 84 | The C standard does not guarantee that wchar_t has at least 85 | 16 bits, so wchar_t is no less portable than unsigned short! 86 | All should be unsigned values to avoid sign extension during 87 | bit mask & shift operations. 88 | ------------------------------------------------------------------------ */ 89 | 90 | typedef unsigned long UTF32; /* at least 32 bits */ 91 | typedef unsigned short UTF16; /* at least 16 bits */ 92 | typedef unsigned char UTF8; /* typically 8 bits */ 93 | typedef unsigned char Boolean; /* 0 or 1 */ 94 | 95 | /* Some fundamental constants */ 96 | #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD 97 | #define UNI_MAX_BMP (UTF32)0x0000FFFF 98 | #define UNI_MAX_UTF16 (UTF32)0x0010FFFF 99 | #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF 100 | #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF 101 | 102 | typedef enum { 103 | conversionOK, /* conversion successful */ 104 | sourceExhausted, /* partial character in source, but hit end */ 105 | targetExhausted, /* insuff. room in target for conversion */ 106 | sourceIllegal /* source sequence is illegal/malformed */ 107 | } ConversionResult; 108 | 109 | typedef enum { 110 | strictConversion = 0, 111 | lenientConversion 112 | } ConversionFlags; 113 | 114 | /* This is for C++ and does no harm in C */ 115 | #ifdef __cplusplus 116 | extern "C" { 117 | #endif 118 | 119 | ConversionResult ConvertUTF8toUTF16 ( 120 | const UTF8** sourceStart, const UTF8* sourceEnd, 121 | UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); 122 | 123 | ConversionResult ConvertUTF16toUTF8 ( 124 | const UTF16** sourceStart, const UTF16* sourceEnd, 125 | UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); 126 | 127 | ConversionResult ConvertUTF8toUTF32 ( 128 | const UTF8** sourceStart, const UTF8* sourceEnd, 129 | UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); 130 | 131 | ConversionResult ConvertUTF32toUTF8 ( 132 | const UTF32** sourceStart, const UTF32* sourceEnd, 133 | UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); 134 | 135 | ConversionResult ConvertUTF16toUTF32 ( 136 | const UTF16** sourceStart, const UTF16* sourceEnd, 137 | UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); 138 | 139 | ConversionResult ConvertUTF32toUTF16 ( 140 | const UTF32** sourceStart, const UTF32* sourceEnd, 141 | UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); 142 | 143 | Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | /* --------------------------------------------------------------------- */ 150 | -------------------------------------------------------------------------------- /basekit/Date.h: -------------------------------------------------------------------------------- 1 | //metadoc Date copyright Steve Dekorte 2002 2 | //metadoc Date license BSD revised 3 | 4 | #include "Base.h" 5 | 6 | #ifndef DATE_DEFINED 7 | #define DATE_DEFINED 1 8 | 9 | #include "Common.h" 10 | #include "Duration.h" 11 | #include "PortableGettimeofday.h" 12 | #include 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | typedef struct 19 | { 20 | struct timeval tv; 21 | struct timezone tz; 22 | } Date; 23 | 24 | BASEKIT_API double Date_SecondsFrom1970ToNow(void); 25 | 26 | BASEKIT_API Date *Date_new(void); 27 | BASEKIT_API void Date_copy_(Date *self, const Date *other); 28 | BASEKIT_API void Date_free(Date *self); 29 | BASEKIT_API int Date_compare(const Date *self, const Date *other); 30 | 31 | BASEKIT_API void Date_now(Date *self); 32 | BASEKIT_API void Date_setToLocalTimeZone(Date *self); 33 | BASEKIT_API double Date_Clock(void); 34 | 35 | BASEKIT_API void Date_fromLocalTime_(Date *self, struct tm *t); 36 | BASEKIT_API void Date_fromTime_(Date *self, time_t t); 37 | BASEKIT_API time_t Date_asTime(const Date *self); 38 | 39 | // zone 40 | 41 | BASEKIT_API void Date_setToLocalTimeZone(Date *self); 42 | struct timezone Date_timeZone(const Date *self); 43 | BASEKIT_API void Date_setTimeZone_(Date *self, struct timezone tz); 44 | BASEKIT_API void Date_convertToTimeZone_(Date *self, struct timezone tz); 45 | 46 | // components 47 | 48 | BASEKIT_API void Date_setYear_(Date *self, long y); 49 | BASEKIT_API long Date_year(const Date *self); 50 | 51 | BASEKIT_API void Date_setMonth_(Date *self, int m); 52 | BASEKIT_API int Date_month(const Date *self); 53 | 54 | BASEKIT_API void Date_setDay_(Date *self, int d); 55 | BASEKIT_API int Date_day(const Date *self); 56 | 57 | BASEKIT_API void Date_setHour_(Date *self, int h); 58 | BASEKIT_API int Date_hour(const Date *self); 59 | 60 | BASEKIT_API void Date_setMinute_(Date *self, int m); 61 | BASEKIT_API int Date_minute(const Date *self); 62 | 63 | BASEKIT_API void Date_setSecond_(Date *self, double s); 64 | BASEKIT_API double Date_second(const Date *self); 65 | 66 | BASEKIT_API unsigned char Date_isDaylightSavingsTime(const Date *self); 67 | BASEKIT_API int Date_isLeapYear(const Date *self); 68 | 69 | // seconds 70 | 71 | BASEKIT_API double Date_asSeconds(const Date *self); 72 | BASEKIT_API void Date_fromSeconds_(Date *self, double s); 73 | 74 | BASEKIT_API void Date_addSeconds_(Date *self, double s); 75 | BASEKIT_API double Date_secondsSince_(const Date *self, const Date *other); 76 | 77 | // format 78 | 79 | BASEKIT_API void Date_fromString_format_(Date *self, const char *s, const char *format); 80 | 81 | // durations 82 | 83 | BASEKIT_API Duration *Date_newDurationBySubtractingDate_(const Date *self, const Date *other); 84 | BASEKIT_API void Date_addDuration_(Date *self, const Duration *d); 85 | BASEKIT_API void Date_subtractDuration_(Date *self, const Duration *d); 86 | 87 | BASEKIT_API double Date_secondsSinceNow(const Date *self); 88 | 89 | BASEKIT_API UArray *Date_asString(const Date *self, const char *format); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | #endif 95 | -------------------------------------------------------------------------------- /basekit/Datum.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("Datum") 5 | */ 6 | 7 | #ifndef Datum_DEFINED 8 | #define Datum_DEFINED 1 9 | 10 | #include "Common.h" 11 | #include 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | //#define PID_TYPE uint32_t 18 | #define PID_TYPE size_t 19 | #define PID_FORMAT "zi" 20 | 21 | typedef struct 22 | { 23 | PID_TYPE size; 24 | unsigned char *data; 25 | } Datum; 26 | 27 | BASEKIT_API PID_TYPE Datum_size(Datum *self); 28 | BASEKIT_API unsigned char *Datum_data(Datum *self); 29 | 30 | // return stack allocated datums 31 | 32 | BASEKIT_API Datum Datum_FromData_length_(unsigned char *data, PID_TYPE size); 33 | BASEKIT_API Datum Datum_FromCString_(const char *s); 34 | //Datum Datum_FromPid_(PID_TYPE pid); 35 | BASEKIT_API Datum Datum_Empty(void); 36 | 37 | BASEKIT_API Datum Datum_datumAt_(Datum *self, size_t i); 38 | BASEKIT_API Datum *Datum_newFrom_to_(Datum *self, size_t start, size_t end); 39 | 40 | // comparison 41 | 42 | BASEKIT_API int Datum_compare_length_(Datum *self, Datum *other, size_t limit); 43 | BASEKIT_API int Datum_compare_(Datum *self, Datum *other); 44 | BASEKIT_API int Datum_compareCString_(Datum *self, const char *s); 45 | BASEKIT_API int Datum_beginsWith_(Datum *self, Datum *other); 46 | BASEKIT_API int Datum_endsWith_(Datum *self, Datum *other); 47 | BASEKIT_API size_t Datum_matchingPrefixSizeWith_(Datum *self, Datum *other); 48 | 49 | BASEKIT_API long Datum_find_(Datum *self, void *delimsList, size_t startIndex); 50 | BASEKIT_API void *Datum_split_(Datum *self, void *delims); /* returns a List */ 51 | 52 | //int Datum_next(Datum *self); 53 | 54 | BASEKIT_API unsigned int Datum_hash(Datum *self); 55 | 56 | typedef int (DatumDetectWithFunc)(void *, Datum *); /* 1 = match, -1 = break */ 57 | BASEKIT_API int Datum_detect_with_(Datum *self, DatumDetectWithFunc *func, void *target); 58 | 59 | #include "UArray.h" 60 | 61 | BASEKIT_API Datum Datum_FromUArray_(UArray *ba); 62 | BASEKIT_API void *Datum_asUArray(Datum *self); 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | #endif 68 | -------------------------------------------------------------------------------- /basekit/Duration.c: -------------------------------------------------------------------------------- 1 | //metadoc Duration copyright Steve Dekorte 2002 2 | //metadoc Duration license BSD revised 3 | 4 | #define DURATION_C 5 | #include "Duration.h" 6 | #undef DURATION_C 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | typedef struct 13 | { 14 | double years; 15 | double days; 16 | double hours; 17 | double minutes; 18 | double seconds; 19 | } DurationComponents; 20 | 21 | Duration *Duration_new(void) 22 | { 23 | Duration *self = (Duration *)io_calloc(1, sizeof(Duration)); 24 | return self; 25 | } 26 | 27 | Duration *Duration_newWithSeconds_(double s) 28 | { 29 | Duration *self = Duration_new(); 30 | self->seconds = s; 31 | return self; 32 | } 33 | 34 | void Duration_copy_(Duration *self, const Duration *other) 35 | { 36 | memcpy(self, other, sizeof(Duration)); 37 | } 38 | 39 | void Duration_free(Duration *self) 40 | { 41 | io_free(self); 42 | } 43 | 44 | int Duration_compare(const Duration *self, const Duration *other) 45 | { 46 | if (self->seconds == other->seconds) 47 | { 48 | return 0; 49 | } 50 | 51 | return self->seconds > other->seconds ? 1 : -1; 52 | } 53 | 54 | // components -------------------------------------------------------- 55 | 56 | #define SECONDS_IN_YEAR (60 * 60 * 24 * 365) 57 | #define SECONDS_IN_DAY (60 * 60 * 24) 58 | #define SECONDS_IN_HOUR (60 * 60) 59 | #define SECONDS_IN_MINUTE (60) 60 | 61 | DurationComponents Duration_asComponents(const Duration *self) 62 | { 63 | DurationComponents c; 64 | double t = self->seconds; 65 | c.years = (int)(t / SECONDS_IN_YEAR); t -= (int)(c.years * SECONDS_IN_YEAR); 66 | c.days = (int)(t / SECONDS_IN_DAY); t -= (int)(c.days * SECONDS_IN_DAY); 67 | c.hours = (int)(t / SECONDS_IN_HOUR); t -= (int)(c.hours * SECONDS_IN_HOUR); 68 | c.minutes = (int)(t / SECONDS_IN_MINUTE); t -= (int)(c.minutes * SECONDS_IN_MINUTE); 69 | c.seconds = (t); 70 | return c; 71 | } 72 | 73 | void Duration_fromComponents_(Duration *self, DurationComponents c) 74 | { 75 | double t = c.years * SECONDS_IN_YEAR; 76 | t += c.days * SECONDS_IN_DAY; 77 | t += c.hours * SECONDS_IN_HOUR; 78 | t += c.minutes * SECONDS_IN_MINUTE; 79 | t += c.seconds; 80 | self->seconds = t; 81 | } 82 | 83 | // years -------------------------------------------------------- 84 | 85 | int Duration_years(const Duration *self) 86 | { 87 | return (int)Duration_asComponents(self).years; 88 | } 89 | 90 | void Duration_setYears_(Duration *self, double y) 91 | { 92 | DurationComponents c = Duration_asComponents(self); 93 | c.years = y; 94 | Duration_fromComponents_(self, c); 95 | } 96 | 97 | // days -------------------------------------------------------- 98 | 99 | int Duration_days(const Duration *self) 100 | { 101 | return (int)Duration_asComponents(self).days; 102 | } 103 | 104 | void Duration_setDays_(Duration *self, double d) 105 | { 106 | DurationComponents c = Duration_asComponents(self); 107 | c.days = d; 108 | Duration_fromComponents_(self, c); 109 | } 110 | 111 | // hours -------------------------------------------------------- 112 | 113 | int Duration_hours(const Duration *self) 114 | { 115 | return (int)Duration_asComponents(self).hours; 116 | } 117 | 118 | void Duration_setHours_(Duration *self, double m) 119 | { 120 | DurationComponents c = Duration_asComponents(self); 121 | c.hours = m; 122 | Duration_fromComponents_(self, c); 123 | } 124 | 125 | // minutes -------------------------------------------------------- 126 | 127 | int Duration_minutes(const Duration *self) 128 | { 129 | return (int)Duration_asComponents(self).minutes; 130 | } 131 | 132 | void Duration_setMinutes_(Duration *self, double m) 133 | { 134 | DurationComponents c = Duration_asComponents(self); 135 | c.minutes = m; 136 | Duration_fromComponents_(self, c); 137 | } 138 | 139 | // seconds -------------------------------------------------------- 140 | 141 | double Duration_seconds(const Duration *self) 142 | { 143 | return Duration_asComponents(self).seconds; 144 | } 145 | 146 | void Duration_setSeconds_(Duration *self, double s) 147 | { 148 | DurationComponents c = Duration_asComponents(self); 149 | c.seconds = s; 150 | Duration_fromComponents_(self, c); 151 | } 152 | 153 | // total seconds -------------------------------------------------------- 154 | 155 | double Duration_asSeconds(const Duration *self) 156 | { 157 | return self->seconds; 158 | } 159 | 160 | void Duration_fromSeconds_(Duration *self, double s) 161 | { 162 | self->seconds = s; 163 | } 164 | 165 | // strings -------------------------------------------------------- 166 | 167 | UArray *Duration_asUArrayWithFormat_(const Duration *self, const char *format) 168 | { 169 | DurationComponents c = Duration_asComponents(self); 170 | char s[128]; 171 | UArray *ba = UArray_newWithCString_(format?format:"%Y years %d days %H:%M:%S"); 172 | 173 | snprintf(s, 128, "%i", (int)c.years); 174 | UArray_replaceCString_withCString_(ba, "%Y", s); 175 | 176 | snprintf(s, 128, "%04i", (int)c.years); 177 | UArray_replaceCString_withCString_(ba, "%y", s); 178 | 179 | snprintf(s, 128, "%02i", (int)c.days); 180 | UArray_replaceCString_withCString_(ba, "%d", s); 181 | 182 | snprintf(s, 128, "%02i", (int)c.hours); 183 | UArray_replaceCString_withCString_(ba, "%H", s); 184 | 185 | snprintf(s, 128, "%02i", (int)c.minutes); 186 | UArray_replaceCString_withCString_(ba, "%M", s); 187 | 188 | snprintf(s, 128, "%02f", c.seconds); 189 | UArray_replaceCString_withCString_(ba, "%S", s); 190 | 191 | return ba; 192 | } 193 | 194 | void Duration_print(const Duration *self) 195 | { 196 | UArray *ba = Duration_asUArrayWithFormat_(self, NULL); 197 | UArray_print(ba); 198 | UArray_free(ba); 199 | } 200 | 201 | // math -------------------------------------------------------- 202 | 203 | void Duration_add_(Duration *self, const Duration *other) 204 | { 205 | self->seconds += other->seconds; 206 | } 207 | 208 | void Duration_subtract_(Duration *self, const Duration *other) 209 | { 210 | self->seconds -= other->seconds; 211 | } 212 | 213 | -------------------------------------------------------------------------------- /basekit/Duration.h: -------------------------------------------------------------------------------- 1 | //metadoc Duration copyright Steve Dekorte 2002 2 | //metadoc Duration license BSD revised 3 | 4 | #ifndef DURATION_DEFINED 5 | #define DURATION_DEFINED 1 6 | 7 | #include "Common.h" 8 | #include "UArray.h" 9 | #include "PortableGettimeofday.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef struct 16 | { 17 | double seconds; 18 | } Duration; 19 | 20 | BASEKIT_API Duration *Duration_new(void); 21 | BASEKIT_API Duration *Duration_newWithSeconds_(double s); 22 | BASEKIT_API Duration *Duration_clone(const Duration *self); 23 | BASEKIT_API void Duration_copy_(Duration *self, const Duration *other); 24 | 25 | BASEKIT_API void Duration_free(Duration *self); 26 | BASEKIT_API int Duration_compare(const Duration *self, const Duration *other); 27 | 28 | // components 29 | 30 | BASEKIT_API int Duration_years(const Duration *self); 31 | BASEKIT_API void Duration_setYears_(Duration *self, double y); 32 | 33 | BASEKIT_API int Duration_days(const Duration *self); 34 | BASEKIT_API void Duration_setDays_(Duration *self, double d); 35 | 36 | BASEKIT_API int Duration_hours(const Duration *self); 37 | BASEKIT_API void Duration_setHours_(Duration *self, double m); 38 | 39 | BASEKIT_API int Duration_minutes(const Duration *self); 40 | BASEKIT_API void Duration_setMinutes_(Duration *self, double m); 41 | 42 | BASEKIT_API double Duration_seconds(const Duration *self); 43 | BASEKIT_API void Duration_setSeconds_(Duration *self, double s); 44 | 45 | // total seconds 46 | 47 | BASEKIT_API double Duration_asSeconds(const Duration *self); 48 | BASEKIT_API void Duration_fromSeconds_(Duration *self, double s); 49 | 50 | // strings 51 | 52 | BASEKIT_API UArray *Duration_asUArrayWithFormat_(const Duration *self, const char *format); 53 | BASEKIT_API void Duration_print(const Duration *self); 54 | 55 | // math 56 | 57 | BASEKIT_API void Duration_add_(Duration *self, const Duration *other); 58 | BASEKIT_API void Duration_subtract_(Duration *self, const Duration *other); 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | #endif 64 | -------------------------------------------------------------------------------- /basekit/DynLib.c: -------------------------------------------------------------------------------- 1 | /* 2 | //metadoc DynLib license BSD revised 3 | /*metadoc DynLib history 4 | based on DllHandle.c, contributed by Daniel A. Koepke 5 | Reorg, Steve Dekorte, 2003-08-30 6 | Window fix, Chuck Adams, 2004-02-06 7 | */ 8 | 9 | #include "Base.h" 10 | #include "DynLib.h" 11 | #include "PortableStrlcpy.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) 18 | #include 19 | 20 | #define RTLD_NOW 0 /* don't support link flags */ 21 | #define RTLD_GLOBAL 0 22 | 23 | static void *dlopen(const char *path, int mode) 24 | { 25 | void *result; 26 | result = (void *)LoadLibraryEx(path, NULL, 0); 27 | if (result) 28 | SetLastError(ERROR_SUCCESS); 29 | 30 | return result; 31 | } 32 | 33 | static int dlclose(void *handle) 34 | { 35 | return FreeLibrary((HANDLE)handle); 36 | } 37 | 38 | static const char *dlerror(void) 39 | { 40 | // XXX this will leak the error string 41 | 42 | LPSTR buf; 43 | DWORD err; 44 | err = GetLastError(); 45 | if (err == ERROR_SUCCESS) 46 | return (char*)0; 47 | 48 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER 49 | | FORMAT_MESSAGE_IGNORE_INSERTS 50 | | FORMAT_MESSAGE_FROM_SYSTEM, 51 | NULL, err, 52 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 53 | (LPSTR)&buf, 0, NULL); 54 | return buf; 55 | } 56 | 57 | static void *dlsym(void *handle, const char *symbol) 58 | { 59 | return (void*)GetProcAddress((HANDLE)handle, symbol); 60 | } 61 | 62 | 63 | #else 64 | #include 65 | #endif 66 | 67 | DynLib *DynLib_new(void) 68 | { 69 | DynLib *self = (DynLib *)io_calloc(1, sizeof(DynLib)); 70 | DynLib_setPath_(self, ""); 71 | return self; 72 | } 73 | 74 | void DynLib_free(DynLib *self) 75 | { 76 | //DynLib_close(self); 77 | if (self->path) io_free(self->path); 78 | if (self->initFuncName) io_free(self->initFuncName); 79 | if (self->freeFuncName) io_free(self->freeFuncName); 80 | if (self->error) io_free(self->error); 81 | io_free(self); 82 | } 83 | 84 | void DynLib_setPath_(DynLib *self, const char *path) 85 | { 86 | size_t len = strlen(path); 87 | char *ptr = (char*)io_realloc(self->path, len + 1); 88 | PortableStrlcpy(ptr, path, len + 1); 89 | self->path = ptr; 90 | } 91 | 92 | char *DynLib_path(DynLib *self) 93 | { 94 | return self->path; 95 | } 96 | 97 | void DynLib_setInitFuncName_(DynLib *self, const char *name) 98 | { 99 | size_t len = strlen(name); 100 | char* ptr = (char*)io_realloc(self->initFuncName, len + 1); 101 | PortableStrlcpy(ptr, name, len + 1); 102 | self->initFuncName = ptr; 103 | } 104 | 105 | char *DynLib_initFuncName(DynLib *self) 106 | { 107 | return self->initFuncName; 108 | } 109 | 110 | void DynLib_setInitArg_(DynLib *self, void *arg) 111 | { 112 | self->initArg = arg; 113 | } 114 | 115 | void DynLib_setFreeFuncName_(DynLib *self, const char *name) 116 | { 117 | size_t len = strlen(name); 118 | char* ptr = (char*)io_realloc(self->freeFuncName, len + 1); 119 | PortableStrlcpy(ptr, name, len + 1); 120 | self->freeFuncName = ptr; 121 | } 122 | 123 | char *DynLib_freeFuncName(DynLib *self) 124 | { 125 | return self->freeFuncName; 126 | } 127 | 128 | void DynLib_setFreeArg_(DynLib *self, void *arg) 129 | { 130 | self->freeArg = arg; 131 | } 132 | 133 | void DynLib_setError_(DynLib *self,const char *error) 134 | { 135 | if (error) 136 | { 137 | self->error = strcpy((char *)io_realloc(self->error, strlen(error)+1), error); 138 | } 139 | else 140 | { 141 | if (self->error) io_free(self->error); 142 | self->error = NULL; 143 | } 144 | } 145 | 146 | char *DynLib_error(DynLib *self) 147 | { 148 | return self->error; 149 | } 150 | 151 | void DynLib_updateError(DynLib *self) 152 | { 153 | DynLib_setError_(self, dlerror()); 154 | } 155 | 156 | unsigned char DynLib_hasError(DynLib *self) 157 | { 158 | return self->error != NULL; 159 | } 160 | 161 | void DynLib_open(DynLib *self) 162 | { 163 | self->handle = dlopen(self->path, RTLD_NOW | RTLD_GLOBAL); /* RTLD_LAZY); */ 164 | //self->handle = dlopen(self->path, RTLD_NOW | RTLD_LAZY); 165 | DynLib_updateError(self); 166 | 167 | if (DynLib_hasError(self)) 168 | { 169 | return; 170 | } 171 | 172 | if (self->initFuncName) 173 | { 174 | void *f = DynLib_pointerForSymbolName_(self, self->initFuncName); 175 | 176 | if (!f) 177 | { 178 | DynLib_setError_(self, "init function not found"); 179 | return; 180 | } 181 | 182 | if (self->initArg) 183 | { 184 | //printf("DynLib: opening with 1 arg %p\n", self->initArg); 185 | (*(DynLibOneArgFunction *)f)(self->initArg); 186 | } 187 | else 188 | { 189 | (*(DynLibNoArgFunction *)f)(); 190 | } 191 | } 192 | } 193 | 194 | unsigned char DynLib_isOpen(DynLib *self) 195 | { 196 | return self->handle != NULL; 197 | } 198 | 199 | void DynLib_close(DynLib *self) 200 | { 201 | if (self->freeFuncName) 202 | { 203 | void *f = DynLib_pointerForSymbolName_(self, self->freeFuncName); 204 | 205 | if (!f) 206 | { 207 | DynLib_setError_(self, "io_free function not found"); 208 | return; 209 | } 210 | 211 | if (self->freeArg) 212 | { 213 | (*(DynLibOneArgFunction *)f)(self->freeArg); 214 | } 215 | else 216 | { 217 | (*(DynLibNoArgFunction *)f)(); 218 | } 219 | } 220 | 221 | if (self->handle) 222 | { 223 | dlclose(self->handle); 224 | } 225 | 226 | self->handle = NULL; 227 | } 228 | 229 | void *DynLib_pointerForSymbolName_(DynLib *self, const char *symbolName) 230 | { 231 | DynLib_setError_(self, dlerror()); 232 | return dlsym(self->handle, symbolName); 233 | } 234 | 235 | -------------------------------------------------------------------------------- /basekit/DynLib.h: -------------------------------------------------------------------------------- 1 | /* based on DynLib.c contributed by Daniel A. Koepke 2 | * Reorg, Steve Dekorte, 2003-08-30 3 | * See _BSDLicense.txt 4 | */ 5 | 6 | #ifndef DYNLIB_DEFINED 7 | #define DYNLIB_DEFINED 1 8 | 9 | #include "Common.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | typedef void DynLibNoArgFunction(void); 16 | typedef void DynLibOneArgFunction(void *arg); 17 | 18 | typedef struct 19 | { 20 | char *path; 21 | char *initFuncName; 22 | void *initArg; 23 | char *freeFuncName; 24 | void *freeArg; 25 | char *error; 26 | void *handle; 27 | int refCount; 28 | } DynLib; 29 | 30 | BASEKIT_API DynLib *DynLib_new(void); 31 | BASEKIT_API void DynLib_free(DynLib *self); 32 | 33 | BASEKIT_API void DynLib_setPath_(DynLib *self, const char *path); 34 | BASEKIT_API char *DynLib_path(DynLib *self); 35 | 36 | BASEKIT_API void DynLib_setInitFuncName_(DynLib *self, const char *name); 37 | BASEKIT_API char *DynLib_initFuncName(DynLib *self); 38 | BASEKIT_API void DynLib_setInitArg_(DynLib *self, void *arg); 39 | 40 | BASEKIT_API void DynLib_setFreeFuncName_(DynLib *self, const char *name); 41 | BASEKIT_API char *DynLib_freeFuncName(DynLib *self); 42 | BASEKIT_API void DynLib_setFreeArg_(DynLib *self, void *arg); 43 | 44 | BASEKIT_API void DynLib_setError_(DynLib *self, const char *path); 45 | BASEKIT_API char *DynLib_error(DynLib *self); 46 | 47 | BASEKIT_API void DynLib_open(DynLib *self); 48 | BASEKIT_API unsigned char DynLib_isOpen(DynLib *self); 49 | BASEKIT_API void DynLib_close(DynLib *self); 50 | BASEKIT_API void *DynLib_pointerForSymbolName_(DynLib *self, const char *symbolName); 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | #endif 56 | -------------------------------------------------------------------------------- /basekit/List.c: -------------------------------------------------------------------------------- 1 | //metadoc List copyright Steve Dekorte 2002 2 | //metadoc List license BSD revised 3 | 4 | #define LIST_C 5 | #include "List.h" 6 | #undef LIST_C 7 | #include 8 | 9 | List *List_new(void) 10 | { 11 | List *self = (List *)io_calloc(1, sizeof(List)); 12 | self->size = 0; 13 | self->memSize = sizeof(void *)*LIST_START_SIZE; 14 | self->items = (void **)io_calloc(1, self->memSize); 15 | return self; 16 | } 17 | 18 | List *List_clone(const List *self) 19 | { 20 | List *child = List_new(); 21 | List_copy_(child, self); 22 | /* 23 | List *child = cpalloc(self, sizeof(List)); 24 | child->items = cpalloc(self->items, self->memSize); 25 | */ 26 | return child; 27 | } 28 | 29 | static size_t indexWrap(long index, size_t size) 30 | { 31 | if (index < 0) 32 | { 33 | index = size - index; 34 | 35 | if (index < 0) 36 | { 37 | index = 0; 38 | } 39 | } 40 | 41 | if (index > (int)size) 42 | { 43 | index = size; 44 | } 45 | 46 | return (size_t)index; 47 | } 48 | 49 | void List_sliceInPlace(List* self, long startIndex, long endIndex) 50 | { 51 | size_t i, size = List_size(self); 52 | List *tmp = List_new(); 53 | size_t start = indexWrap(startIndex, size); 54 | size_t end = indexWrap(endIndex, size); 55 | 56 | for (i = start; i < size && i < end + 1; i ++) 57 | { 58 | List_append_(tmp, List_at_(self, i)); 59 | } 60 | 61 | List_copy_(self, tmp); 62 | List_free(tmp); 63 | } 64 | 65 | List *List_cloneSlice(const List *self, long startIndex, long endIndex) 66 | { 67 | List *child = List_clone(self); 68 | List_sliceInPlace(child, startIndex, endIndex); 69 | return child; 70 | } 71 | 72 | void List_free(List *self) 73 | { 74 | //printf("List_free(%p)\n", (void *)self); 75 | io_free(self->items); 76 | io_free(self); 77 | } 78 | 79 | UArray List_asStackAllocatedUArray(List *self) 80 | { 81 | UArray a = UArray_stackAllocedEmptyUArray(); 82 | a.itemType = CTYPE_uintptr_t; 83 | a.itemSize = sizeof(uintptr_t); 84 | a.size = self->size; 85 | a.data = (uint8_t *)(self->items); 86 | return a; 87 | } 88 | 89 | size_t List_memorySize(const List *self) 90 | { 91 | return sizeof(List) + (self->size * sizeof(void *)); 92 | } 93 | 94 | void List_removeAll(List *self) 95 | { 96 | self->size = 0; 97 | List_compactIfNeeded(self); 98 | } 99 | 100 | void List_copy_(List *self, const List *otherList) 101 | { 102 | if (self == otherList || (!otherList->size && !self->size)) 103 | { 104 | return; 105 | } 106 | 107 | List_preallocateToSize_(self, otherList->size); 108 | memmove(self->items, otherList->items, sizeof(void *) * (otherList->size)); 109 | self->size = otherList->size; 110 | } 111 | 112 | int List_equals_(const List *self, const List *otherList) 113 | { 114 | return (self->size == otherList->size && 115 | memcmp(self->items, otherList->items, sizeof(void *) * self->size) == 0); 116 | } 117 | 118 | /* --- sizing ------------------------------------------------ */ 119 | 120 | void List_setSize_(List *self, size_t index) 121 | { 122 | List_ifNeededSizeTo_(self, index); 123 | self->size = index; 124 | } 125 | 126 | void List_preallocateToSize_(List *self, size_t index) 127 | { 128 | size_t s = index * sizeof(void *); 129 | 130 | if (s >= self->memSize) 131 | { 132 | size_t newSize = self->memSize * LIST_RESIZE_FACTOR; 133 | 134 | if (s > newSize) 135 | { 136 | newSize = s; 137 | } 138 | 139 | self->items = (void **)io_realloc(self->items, newSize); 140 | memset(self->items + self->size, 0, (newSize - (self->size*sizeof(void *)))); 141 | self->memSize = newSize; 142 | } 143 | } 144 | 145 | void List_compact(List *self) 146 | { 147 | self->memSize = self->size * sizeof(void *); 148 | self->items = (void **)io_realloc(self->items, self->memSize); 149 | } 150 | 151 | // ----------------------------------------------------------- 152 | 153 | void List_print(const List *self) 154 | { 155 | size_t i; 156 | 157 | printf("List <%p> [%i bytes]\n", (void *)self, (int)self->memSize); 158 | 159 | for (i = 0; i < self->size; i ++) 160 | { 161 | printf("%i: %p\n", i, (void *)self->items[i]); 162 | } 163 | 164 | printf("\n"); 165 | } 166 | 167 | // enumeration ----------------------------------------- 168 | 169 | void List_do_(List *self, ListDoCallback *callback) 170 | { 171 | LIST_FOREACH(self, i, v, if (v) (*callback)(v)); 172 | } 173 | 174 | void List_do_with_(List *self, ListDoWithCallback *callback, void *arg) 175 | { 176 | LIST_FOREACH(self, i, v, if (v) (*callback)(v, arg)); 177 | } 178 | 179 | void List_mapInPlace_(List *self, ListCollectCallback *callback) 180 | { 181 | void **items = self->items; 182 | LIST_FOREACH(self, i, v, items[i] = (*callback)(v)); 183 | } 184 | 185 | List *List_map_(List *self, ListCollectCallback *callback) 186 | { 187 | List *r = List_new(); 188 | LIST_FOREACH(self, i, v, List_append_(r, (*callback)(v));); 189 | return r; 190 | } 191 | 192 | List *List_select_(List *self, ListSelectCallback *callback) 193 | { 194 | List *r = List_new(); 195 | LIST_FOREACH(self, i, v, if ((*callback)(v)) List_append_(r, v)); 196 | return r; 197 | } 198 | 199 | void *List_detect_(List *self, ListDetectCallback *callback) 200 | { 201 | LIST_FOREACH(self, i, v, if (v && (*callback)(v)) return v; ); 202 | return NULL; 203 | } 204 | 205 | void *List_anyOne(const List *self) 206 | { 207 | size_t i; 208 | 209 | if (self->size == 0) 210 | { 211 | return (void *)NULL; 212 | } 213 | 214 | if (self->size == 1) 215 | { 216 | return LIST_AT_(self, 0); 217 | } 218 | 219 | i = (rand() >> 4) % (self->size); // without the shift, just get a sequence! 220 | 221 | return LIST_AT_(self, i); 222 | } 223 | 224 | void List_shuffle(List *self) 225 | { 226 | size_t i, j; 227 | 228 | for (i = 0; i < self->size - 1; i ++) 229 | { 230 | j = i + rand() % (self->size - i); 231 | List_swap_with_(self, i, j); 232 | } 233 | } 234 | 235 | void *List_removeLast(List *self) 236 | { 237 | void *item = List_at_(self, self->size - 1); 238 | 239 | if (item) 240 | { 241 | self->size --; 242 | List_compactIfNeeded(self); 243 | } 244 | 245 | return item; 246 | } 247 | 248 | -------------------------------------------------------------------------------- /basekit/List.h: -------------------------------------------------------------------------------- 1 | //metadoc List copyright Steve Dekorte 2002 2 | //metadoc List license BSD revised 3 | /*metadoc List description 4 | List - an array of void pointers 5 | User is responsible for io_freeing items 6 | */ 7 | 8 | #ifndef LIST_DEFINED 9 | #define LIST_DEFINED 1 10 | 11 | #include "Common.h" 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #ifdef LOW_MEMORY_SYSTEM 21 | #define LIST_START_SIZE 1 22 | #define LIST_RESIZE_FACTOR 2 23 | #else 24 | #define LIST_START_SIZE 1 25 | #define LIST_RESIZE_FACTOR 2 26 | #endif 27 | 28 | #define LIST_AT_(self, n) self->items[n] 29 | 30 | 31 | typedef void (ListDoCallback)(void *); 32 | typedef void (ListDoWithCallback)(void *, void *); 33 | typedef void *(ListCollectCallback)(void *); 34 | typedef int (ListSelectCallback)(void *); 35 | typedef int (ListDetectCallback)(void *); 36 | typedef int (ListSortCallback)(const void *, const void *); 37 | typedef int (ListCompareFunc)(const void *, const void *); 38 | 39 | typedef struct 40 | { 41 | void **items; 42 | size_t size; 43 | size_t memSize; 44 | } List; 45 | 46 | typedef struct 47 | { 48 | List *list; 49 | size_t index; 50 | } ListCursor; 51 | 52 | BASEKIT_API List *List_new(void); 53 | BASEKIT_API List *List_clone(const List *self); 54 | BASEKIT_API List *List_cloneSlice(const List *self, long startIndex, long endIndex); 55 | 56 | BASEKIT_API void List_free(List *self); 57 | BASEKIT_API void List_removeAll(List *self); 58 | BASEKIT_API void List_copy_(List *self, const List *otherList); 59 | BASEKIT_API int List_equals_(const List *self, const List *otherList); 60 | BASEKIT_API size_t List_memorySize(const List *self); 61 | 62 | #include "UArray.h" 63 | 64 | BASEKIT_API UArray List_asStackAllocatedUArray(List *self); 65 | 66 | // sizing 67 | 68 | BASEKIT_API void List_preallocateToSize_(List *self, size_t index); 69 | BASEKIT_API void List_setSize_(List *self, size_t index); 70 | BASEKIT_API void List_compact(List *self); 71 | 72 | // utility 73 | 74 | BASEKIT_API void List_print(const List *self); 75 | BASEKIT_API void List_sliceInPlace(List *self, long startIndex, long endIndex); 76 | 77 | // enumeration 78 | 79 | BASEKIT_API void List_do_(List *self, ListDoCallback *callback); 80 | BASEKIT_API void List_do_with_(List *self, ListDoWithCallback *callback, void *arg); 81 | 82 | BASEKIT_API List *List_map_(List *self, ListCollectCallback *callback); 83 | BASEKIT_API void List_mapInPlace_(List *self, ListCollectCallback *callback); 84 | BASEKIT_API void *List_detect_(List *self, ListDetectCallback *callback); 85 | BASEKIT_API List *List_select_(List *self, ListSelectCallback *callback); 86 | 87 | BASEKIT_API void *List_anyOne(const List *self); 88 | BASEKIT_API void List_shuffle(List *self); 89 | BASEKIT_API void *List_removeLast(List *self); 90 | 91 | #include "List_inline.h" 92 | 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | #endif 97 | -------------------------------------------------------------------------------- /basekit/MainArgs.c: -------------------------------------------------------------------------------- 1 | //metadoc MainArgs copyright Steve Dekorte 2002 2 | //metadoc MainArgs license BSD revised 3 | 4 | #include "Base.h" 5 | #include 6 | #include 7 | #include 8 | #include "MainArgs.h" 9 | #include "PortableStrlcpy.h" 10 | 11 | MainArgs *MainArgs_new(void) 12 | { 13 | MainArgs *self = (MainArgs *)io_calloc(1, sizeof(MainArgs)); 14 | return self; 15 | } 16 | 17 | void MainArgs_free(MainArgs *self) 18 | { 19 | if (self->argv) 20 | { 21 | int i; 22 | 23 | for (i = 0; i < self->argc; i ++) 24 | { 25 | io_free((char *)(self->argv[i])); 26 | } 27 | 28 | io_free((void*)(self->argv)); 29 | } 30 | 31 | io_free(self); 32 | } 33 | 34 | void MainArgs_argc_argv_(MainArgs *self, int argc, const char **argv) 35 | { 36 | int i; 37 | 38 | self->argc = argc; 39 | // copy by reference since args should be retained on 40 | // the C stack until the program exits 41 | 42 | self->argv = (const char **)io_calloc(1, sizeof(char *)*argc); 43 | 44 | for (i = 0; i < argc; i ++) 45 | { 46 | const char *s = argv[i]; 47 | size_t len = strlen(s); 48 | char *ptr = (char *)io_calloc(1, len + 1); 49 | PortableStrlcpy(ptr, s, len + 1); 50 | self->argv[i] = ptr; 51 | 52 | //self->argv[i] = strcpy((char *)io_calloc(1, strlen(s)+1), s); 53 | /*printf("argv[%i] = '%s'\n", i, s);*/ 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /basekit/MainArgs.h: -------------------------------------------------------------------------------- 1 | //metadoc MainArgs copyright Steve Dekorte 2002 2 | //metadoc MainArgs license BSD revised 3 | /*metadoc MainArgs description 4 | Structure for copying and storing command line arguments.") 5 | */ 6 | 7 | #ifndef MAINARGS_DEFINED 8 | #define MAINARGS_DEFINED 1 9 | 10 | #include "Common.h" 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | typedef struct 17 | { 18 | int argc; 19 | const char **argv; 20 | } MainArgs; 21 | 22 | BASEKIT_API MainArgs *MainArgs_new(void); 23 | BASEKIT_API void MainArgs_free(MainArgs *self); 24 | 25 | BASEKIT_API void MainArgs_argc_argv_(MainArgs *self, int argc, const char **argv); 26 | #define MainArgs_argCount(self) self->argc 27 | #define MainArgs_argAt_(self, index) self->argv[index] 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | #endif 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /basekit/PHash.h: -------------------------------------------------------------------------------- 1 | //metadoc PHash copyright Steve Dekorte 2002, Marc Fauconneau 2007 2 | //metadoc PHash license BSD revised 3 | /*metadoc PHash description 4 | PHash - Cuckoo Hash 5 | keys and values are references (they are not copied or freed) 6 | key pointers are assumed unique 7 | */ 8 | 9 | #ifndef PHASH_DEFINED 10 | #define PHASH_DEFINED 1 11 | 12 | #include "Common.h" 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | typedef struct 22 | { 23 | void *key; 24 | void *value; 25 | } PHashRecord; 26 | 27 | 28 | typedef struct 29 | { 30 | PHashRecord *records; // contains the two tables 31 | 32 | unsigned int log2tableSize; // log2(tableSize) 33 | unsigned int tableSize; // total number of records per table 34 | unsigned int numKeys; // number of used records 35 | 36 | unsigned int mask; // hash bit mask 37 | PHashRecord nullRecord; // for lookup misses 38 | unsigned int balance; // to balance tables 39 | } PHash; 40 | 41 | //#define PHash_mask(self) (self->tableSize-1) 42 | #define PHash_maxLoops(self) (self->tableSize) 43 | #define PHash_maxKeys(self) (self->tableSize) 44 | 45 | BASEKIT_API void PHash_print(PHash *self); // to debug 46 | 47 | BASEKIT_API PHash *PHash_new(void); 48 | BASEKIT_API void PHash_free(PHash *self); 49 | BASEKIT_API PHash *PHash_clone(PHash *self); 50 | BASEKIT_API void PHash_copy_(PHash *self, PHash *other); 51 | 52 | BASEKIT_API PHashRecord* PHash_cuckoo_(PHash *self, PHashRecord* record); 53 | BASEKIT_API void PHash_grow(PHash *self); 54 | BASEKIT_API void PHash_growWithRecord(PHash *self, PHashRecord* record); 55 | 56 | BASEKIT_API size_t PHash_memorySize(PHash *self); 57 | BASEKIT_API void PHash_compact(PHash *self); 58 | 59 | //BASEKIT_API unsigned int PHash_count(PHash *self); 60 | BASEKIT_API unsigned int PHash_countRecords_size_(unsigned char *records, unsigned int size); 61 | 62 | BASEKIT_API void *PHash_firstKeyForValue_(PHash *self, void *v); 63 | 64 | // --- perform -------------------------------------------------- 65 | 66 | BASEKIT_API void PHash_removeValue_(PHash *self, void *value); 67 | 68 | #include "PHash_inline.h" 69 | 70 | #ifdef __cplusplus 71 | } 72 | #endif 73 | #endif 74 | 75 | -------------------------------------------------------------------------------- /basekit/PHash_inline.h: -------------------------------------------------------------------------------- 1 | //metadoc PHash copyright Steve Dekorte 2002, Marc Fauconneau 2007 2 | //metadoc PHash license BSD revised 3 | /*metadoc PHash description 4 | PHash - Cuckoo Hash 5 | keys and values are references (they are not copied or freed) 6 | key pointers are assumed unique 7 | */ 8 | 9 | #ifdef PHASH_C 10 | #define IO_IN_C_FILE 11 | #endif 12 | #include "Common_inline.h" 13 | #ifdef IO_DECLARE_INLINES 14 | 15 | #include 16 | 17 | #define PHASH_RECORDS_AT_(self, tableIndex, index) (self->records + self->tableSize*tableIndex + index) 18 | #define PHASH_RECORDS_AT_HASH_(self, tableIndex, hash) \ 19 | (self->records + self->tableSize*tableIndex + (hash & self->mask)) 20 | 21 | IOINLINE unsigned int PHash_count(PHash *self) 22 | { 23 | return self->numKeys; 24 | } 25 | 26 | IOINLINE void PHashRecord_swap(PHashRecord* r1, PHashRecord* r2) 27 | { 28 | PHashRecord t = *r1; 29 | *r1 = *r2; 30 | *r2 = t; 31 | } 32 | 33 | #define PHashKey_value(k) k 34 | 35 | /* 36 | IOINLINE void *PHashKey_value(void *key) 37 | { 38 | return key; 39 | } 40 | */ 41 | 42 | IOINLINE unsigned int PHashKey_isEqual_(void *key1, void *key2) 43 | { 44 | // return key2 && (PHashKey_value(key1) == PHashKey_value(key2)); 45 | return key1 == key2; 46 | } 47 | 48 | // simple hash functions, should be enough for pointers 49 | IOINLINE unsigned int PHash_hash(PHash *self, void *key) 50 | { 51 | intptr_t k = (intptr_t)PHashKey_value(key); 52 | return k^(k>>4); 53 | } 54 | 55 | IOINLINE unsigned int PHash_hash_more(PHash *self, unsigned int hash) 56 | { 57 | return hash ^ (hash >> self->log2tableSize); 58 | } 59 | 60 | // ----------------------------------- 61 | 62 | IOINLINE void PHash_clean(PHash *self) 63 | { 64 | memset(self->records, 0, sizeof(PHashRecord) * self->tableSize * 2); 65 | self->numKeys = 0; 66 | } 67 | 68 | IOINLINE PHashRecord *PHash_recordAt_(PHash *self, void *key) 69 | { 70 | unsigned int hash; 71 | PHashRecord *record; 72 | 73 | hash = PHash_hash(self, key); 74 | record = PHASH_RECORDS_AT_HASH_(self, 0, hash); 75 | 76 | // we try the second location 77 | hash = PHash_hash_more(self, hash); 78 | record = (key == record->key) ? record : PHASH_RECORDS_AT_HASH_(self, 1, hash); 79 | 80 | return (key == record->key) ? record : &self->nullRecord; 81 | } 82 | 83 | IOINLINE void *PHash_at_(PHash *self, void *key) 84 | { 85 | return PHash_recordAt_(self, key)->value; 86 | } 87 | 88 | IOINLINE unsigned char PHash_at_update_(PHash *self, void *key, void *value) 89 | { 90 | PHashRecord *record = PHash_recordAt_(self, key); 91 | 92 | if (record->key) 93 | { 94 | // already a matching key, replace it 95 | if (PHashKey_isEqual_(key, record->key)) 96 | { 97 | if (record->value == value) 98 | { 99 | return 0; // return 0 if no change 100 | } 101 | 102 | record->value = value; 103 | return 1; 104 | } 105 | } 106 | 107 | return 0; 108 | } 109 | 110 | IOINLINE void PHash_at_put_(PHash *self, void *key, void *value) 111 | { 112 | PHashRecord thisRecord; 113 | PHashRecord *record; 114 | 115 | record = PHash_recordAt_(self, key); 116 | 117 | // already a matching key, replace it 118 | if (record != &self->nullRecord && PHashKey_isEqual_(key, record->key)) 119 | { 120 | record->value = value; 121 | return; 122 | } 123 | 124 | thisRecord.key = key; 125 | thisRecord.value = value; 126 | 127 | record = PHash_cuckoo_(self, &thisRecord); 128 | 129 | if (!record) // collision 130 | { 131 | PHash_growWithRecord(self, &thisRecord); 132 | } 133 | else 134 | { 135 | *record = thisRecord; 136 | self->numKeys ++; 137 | if (self->numKeys > PHash_maxKeys(self)) 138 | PHash_grow(self); 139 | } 140 | } 141 | 142 | IOINLINE void PHash_removeKey_(PHash *self, void *key) 143 | { 144 | PHashRecord *record = PHash_recordAt_(self, key); 145 | void *rkey = record->key; 146 | 147 | if (rkey && PHashKey_value(rkey) == PHashKey_value(key)) 148 | { 149 | self->numKeys --; 150 | memset(record, 0, sizeof(PHashRecord)); 151 | } 152 | } 153 | 154 | // --- enumeration -------------------------------------------------- 155 | 156 | #define PHASH_FOREACH(self, pkey, pvalue, code) \ 157 | {\ 158 | PHash *_self = (self);\ 159 | unsigned int _i, _j, _size = _self->tableSize;\ 160 | void * pkey;\ 161 | void * pvalue;\ 162 | \ 163 | for (_j = 0; _j < 2; _j ++)\ 164 | for (_i = 0; _i < _size; _i ++)\ 165 | {\ 166 | PHashRecord *_record = PHASH_RECORDS_AT_(_self, _j, _i);\ 167 | if (_record->key)\ 168 | {\ 169 | pkey = _record->key;\ 170 | pvalue = _record->value;\ 171 | code;\ 172 | }\ 173 | }\ 174 | } 175 | 176 | /* 177 | typedef BASEKIT_API void (PHashDoCallback)(void *); 178 | 179 | IOINLINE void PHash_do_(PHash *self, PHashDoCallback *callback) 180 | { PHASH_FOREACH(self, k, v, (*callback)(v)); } 181 | 182 | IOINLINE void *PHash_detect_(PHash *self, PHashDetectCallback *callback) 183 | { PHASH_FOREACH(self, k, v, if ((*callback)(v)) return k; ); return NULL; } 184 | 185 | IOINLINE void PHash_doOnKeys_(PHash *self, PHashDoCallback *callback) 186 | { PHASH_FOREACH(self, k, v, (*callback)(k)); } 187 | 188 | IOINLINE void PHash_doOnKeyAndValue_(PHash *self, PHashDoCallback *callback) 189 | { PHASH_FOREACH(self, k, v, (*callback)(k); (*callback)(v);); } 190 | */ 191 | 192 | #undef IO_IN_C_FILE 193 | #endif 194 | -------------------------------------------------------------------------------- /basekit/PortableGettimeofday.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "PortableGettimeofday.h" 5 | 6 | #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) 7 | 8 | #if defined(__MINGW32__) && (3 < __MINGW32_MAJOR_VERSION || 3 == __MINGW32_MAJOR_VERSION && 9 < __MINGW32_MINOR_VERSION) 9 | #else 10 | 11 | #ifndef IO_ADDON_Sockets 12 | void gettimeofday(struct timeval *tv, struct timezone *tz) 13 | { 14 | TIME_ZONE_INFORMATION zoneInfo; 15 | 16 | struct _timeb timeb; 17 | _ftime_s(&timeb); 18 | 19 | tv->tv_sec = (long) timeb.time; 20 | tv->tv_usec = (long) (timeb.millitm * 1000); 21 | 22 | if (GetTimeZoneInformation(&zoneInfo) != TIME_ZONE_ID_INVALID) 23 | { 24 | tz->tz_minuteswest = zoneInfo.Bias; 25 | tz->tz_dsttime = 0; 26 | } 27 | else 28 | { 29 | tz->tz_minuteswest = 0; 30 | tz->tz_dsttime = 0; 31 | } 32 | } 33 | #endif 34 | #endif 35 | #else 36 | 37 | /* just to make compiler happy */ 38 | void PortableGettimeOfday(void) 39 | { 40 | } 41 | 42 | #endif 43 | 44 | double secondsSince1970(void) 45 | { 46 | double result; 47 | struct timeval tv; 48 | struct timezone tz; 49 | gettimeofday(&tv, &tz); 50 | result = tv.tv_sec; 51 | result += tv.tv_usec / 1000000.0; 52 | return result; 53 | } 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /basekit/PortableGettimeofday.h: -------------------------------------------------------------------------------- 1 | #ifndef PORTABLEGETTIMEOFDAY_DEFINED 2 | #define PORTABLEGETTIMEOFDAY_DEFINED 1 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(_MSC_VER) 9 | #if defined(_MSC_VER) 10 | #include 11 | /*struct timeval 12 | { 13 | long tv_sec; 14 | long tv_usec; 15 | };*/ 16 | #else 17 | /* for MingW */ 18 | #include 19 | #endif 20 | 21 | #if defined(__MINGW32__) && (3 < __MINGW32_MAJOR_VERSION || 3 == __MINGW32_MAJOR_VERSION && 9 < __MINGW32_MINOR_VERSION) 22 | #else 23 | struct timezone 24 | { 25 | int tz_minuteswest; /* of Greenwich */ 26 | int tz_dsttime; /* type of dst correction to apply */ 27 | }; 28 | 29 | #include "Common.h" 30 | BASEKIT_API extern void gettimeofday(struct timeval *tv, struct timezone *tz); 31 | #endif 32 | 33 | #else 34 | #include 35 | #endif 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | 43 | double secondsSince1970(void); 44 | -------------------------------------------------------------------------------- /basekit/PortableStdint.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2001 Mike Barcroft 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | * 26 | * $FreeBSD: src/sys/sys/stdint.h,v 1.4 2002/08/21 16:20:01 mike Exp $ 27 | */ 28 | 29 | #ifndef _SYS_STDINT_H_ 30 | #define _SYS_STDINT_H_ 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #ifndef _INT8_T_DECLARED 38 | typedef __int8_t int8_t; 39 | #define _INT8_T_DECLARED 40 | #endif 41 | 42 | #ifndef _INT16_T_DECLARED 43 | typedef __int16_t int16_t; 44 | #define _INT16_T_DECLARED 45 | #endif 46 | 47 | #ifndef _INT32_T_DECLARED 48 | typedef __int32_t int32_t; 49 | #define _INT32_T_DECLARED 50 | #endif 51 | 52 | #ifndef _INT64_T_DECLARED 53 | typedef __int64_t int64_t; 54 | #define _INT64_T_DECLARED 55 | #endif 56 | 57 | #ifndef _UINT8_T_DECLARED 58 | typedef __uint8_t uint8_t; 59 | #define _UINT8_T_DECLARED 60 | #endif 61 | 62 | #ifndef _UINT16_T_DECLARED 63 | typedef __uint16_t uint16_t; 64 | #define _UINT16_T_DECLARED 65 | #endif 66 | 67 | #ifndef _UINT32_T_DECLARED 68 | typedef __uint32_t uint32_t; 69 | #define _UINT32_T_DECLARED 70 | #endif 71 | 72 | #ifndef _UINT64_T_DECLARED 73 | typedef __uint64_t uint64_t; 74 | #define _UINT64_T_DECLARED 75 | #endif 76 | 77 | typedef __int_least8_t int_least8_t; 78 | typedef __int_least16_t int_least16_t; 79 | typedef __int_least32_t int_least32_t; 80 | typedef __int_least64_t int_least64_t; 81 | 82 | typedef __uint_least8_t uint_least8_t; 83 | typedef __uint_least16_t uint_least16_t; 84 | typedef __uint_least32_t uint_least32_t; 85 | typedef __uint_least64_t uint_least64_t; 86 | 87 | typedef __int_fast8_t int_fast8_t; 88 | typedef __int_fast16_t int_fast16_t; 89 | typedef __int_fast32_t int_fast32_t; 90 | typedef __int_fast64_t int_fast64_t; 91 | 92 | typedef __uint_fast8_t uint_fast8_t; 93 | typedef __uint_fast16_t uint_fast16_t; 94 | typedef __uint_fast32_t uint_fast32_t; 95 | typedef __uint_fast64_t uint_fast64_t; 96 | 97 | typedef __intmax_t intmax_t; 98 | typedef __uintmax_t uintmax_t; 99 | 100 | #ifndef _INTPTR_T_DECLARED 101 | typedef __intptr_t intptr_t; 102 | typedef __uintptr_t uintptr_t; 103 | #define _INTPTR_T_DECLARED 104 | #endif 105 | 106 | #endif /* !_SYS_STDINT_H_ */ 107 | -------------------------------------------------------------------------------- /basekit/PortableStrlcpy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998 Todd C. Miller 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. The name of the author may not be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 18 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include "PortableStrlcpy.h" 30 | 31 | /* 32 | * Copy src to string dest of size len. At most len-1 characters 33 | * will be copied. Always NUL terminates (unless len == 0). 34 | * Returns strlen(src); if retval >= len, truncation occurred. 35 | */ 36 | size_t PortableStrlcpy(char* dest, const char* src, size_t len) 37 | { 38 | char* d = dest; 39 | const char* s = src; 40 | size_t n = len; 41 | 42 | /* Copy as many bytes as will fit */ 43 | if (n != 0 && --n != 0) 44 | { 45 | do 46 | { 47 | if ((*d++ = *s++) == 0) 48 | break; 49 | } while (--n != 0); 50 | } 51 | 52 | /* Not enough room in dest, add NUL and traverse rest of src */ 53 | if (n == 0) 54 | { 55 | if (len != 0) 56 | *d = '\0'; /* NUL-terminate dest */ 57 | while (*s++); 58 | } 59 | 60 | return (s - src - 1); /* count doesn't include NUL */ 61 | } 62 | -------------------------------------------------------------------------------- /basekit/PortableStrlcpy.h: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include // size_t on windows 3 | #else 4 | #include // size_t 5 | #endif 6 | 7 | #define strlcpy(d, s, l) PortableStrlcpy((d), (s), (l)) 8 | 9 | size_t PortableStrlcpy(char*, const char*, size_t); 10 | -------------------------------------------------------------------------------- /basekit/PortableStrptime.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /*#ifdef IO_NEEDS_STRPTIME */ 8 | char *io_strptime(char *buf, char *fmt, struct tm *tm); 9 | /*#endif*/ 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif 14 | -------------------------------------------------------------------------------- /basekit/PortableTruncate.c: -------------------------------------------------------------------------------- 1 | 2 | #include "PortableTruncate.h" 3 | 4 | 5 | int PortableTruncate_justHereToAvoidRanlibWarning(void) { return 0; } 6 | 7 | #ifdef _WIN32 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // Win32 truncate by Mike Austin 15 | 16 | int truncate(const char *path, long length) 17 | { 18 | HANDLE file = CreateFile(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 19 | FILE_SHARE_WRITE | FILE_SHARE_READ, NULL); 20 | 21 | if (file == INVALID_HANDLE_VALUE) 22 | { 23 | return -1; 24 | } 25 | 26 | if (SetFilePointer(file, length, NULL, FILE_BEGIN) == 0xFFFFFFFF || !SetEndOfFile(file)) 27 | { 28 | CloseHandle(file); 29 | return -1; 30 | } 31 | 32 | CloseHandle(file); 33 | return 0; 34 | } 35 | 36 | #endif 37 | 38 | #if defined(__SYMBIAN32__) 39 | int truncate(const char* path, long length) 40 | { 41 | // TODO: Implement for Symbian 42 | return -1; 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /basekit/PortableTruncate.h: -------------------------------------------------------------------------------- 1 | 2 | #ifdef __cplusplus 3 | extern "C" { 4 | #endif 5 | 6 | 7 | #ifdef _WIN32 8 | #include "Common.h" 9 | 10 | BASEKIT_API int truncate(const char *path, long length); 11 | 12 | #else 13 | 14 | #include 15 | 16 | #endif 17 | 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /basekit/PortableUsleep.c: -------------------------------------------------------------------------------- 1 | int PortableUsleep_justHereToAvoidRanlibWarning(void) { return 0; } 2 | 3 | #ifdef WIN32 4 | #include 5 | 6 | int usleep(unsigned int us) 7 | { 8 | static LARGE_INTEGER freq; 9 | static int initted = 0; 10 | LARGE_INTEGER s, e, d; 11 | 12 | if (!initted) 13 | { 14 | QueryPerformanceFrequency(&freq); 15 | initted = 1; 16 | } 17 | 18 | QueryPerformanceCounter(&s); 19 | d.QuadPart = freq.QuadPart * ((double)us / 1000000.0); 20 | 21 | do 22 | { 23 | QueryPerformanceCounter(&e); 24 | } while (e.QuadPart - s.QuadPart < d.QuadPart); 25 | 26 | return 0; 27 | 28 | } 29 | 30 | #endif 31 | 32 | 33 | -------------------------------------------------------------------------------- /basekit/PortableUsleep.h: -------------------------------------------------------------------------------- 1 | 2 | #ifdef ON_WINDOWS 3 | #include 4 | #ifndef WIN32 5 | int usleep (unsigned int us); 6 | #endif 7 | #else 8 | #include 9 | #endif 10 | 11 | -------------------------------------------------------------------------------- /basekit/RandomGen.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef RANDOMGEN_DEFINED 4 | #define RANDOMGEN_DEFINED 1 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #include "Common.h" 11 | 12 | #define RANDOMGEN_N 624 13 | 14 | typedef struct 15 | { 16 | unsigned long mt[RANDOMGEN_N]; // the array for the state vector 17 | int mti; // mti==N+1 means mt[N] is not initialized 18 | double y2; // guassian 19 | int use_last; // guassian 20 | } RandomGen; 21 | 22 | BASEKIT_API RandomGen *RandomGen_new(void); 23 | BASEKIT_API void RandomGen_free(RandomGen *self); 24 | 25 | BASEKIT_API void RandomGen_setSeed(RandomGen *self, unsigned long seed); 26 | BASEKIT_API void RandomGen_chooseRandomSeed(RandomGen *self); 27 | 28 | // generates a random number on between 0.0 and 1.0 29 | BASEKIT_API double RandomGen_randomDouble(RandomGen *self); 30 | 31 | BASEKIT_API int RandomGen_randomInt(RandomGen *self); 32 | 33 | BASEKIT_API double RandomGen_gaussian(RandomGen *self, double mean, double standardDeviation); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | #endif 39 | -------------------------------------------------------------------------------- /basekit/SHash.h: -------------------------------------------------------------------------------- 1 | 2 | //metadoc SHash copyright Steve Dekorte 2002, Marc Fauconneau 2007 3 | //metadoc SHash license BSD revised 4 | /*metadoc SHash description 5 | SHash - Cuckoo Hash 6 | keys and values are references (they are not copied or freed) 7 | key pointers are assumed unique 8 | */ 9 | 10 | #ifndef SHASH_DEFINED 11 | #define SHASH_DEFINED 1 12 | 13 | #include "Common.h" 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | typedef struct 23 | { 24 | void *key; 25 | void *value; 26 | } SHashRecord; 27 | 28 | typedef int (SHashKeysEqualCallback)(void *, void *); 29 | typedef intptr_t (SHashHashforKeyCallback)(void *); 30 | 31 | typedef struct 32 | { 33 | SHashRecord *records; // contains the two tables 34 | 35 | unsigned int log2tableSize; // log2(tableSize) 36 | unsigned int tableSize; // total number of records per table 37 | unsigned int numKeys; // number of used records 38 | 39 | unsigned int mask; // hash bit mask 40 | SHashRecord nullRecord; // for lookup misses 41 | unsigned int balance; // to balance tables 42 | SHashKeysEqualCallback *keysEqual; 43 | SHashHashforKeyCallback *hashForKey; 44 | 45 | } SHash; 46 | 47 | //#define SHash_mask(self) (self->tableSize-1) 48 | #define SHash_maxLoops(self) (self->tableSize < 20 ? self->tableSize : 20) 49 | #define SHash_maxKeys(self) (self->tableSize) 50 | #define SHash_setKeysEqualCallback(self, v) (self->keysEqual = v) 51 | #define SHash_setHashForKeyCallback(self, v) (self->hashForKey = v) 52 | 53 | BASEKIT_API void SHash_print(SHash *self); // to debug 54 | 55 | BASEKIT_API SHash *SHash_new(void); 56 | BASEKIT_API void SHash_free(SHash *self); 57 | BASEKIT_API SHash *SHash_clone(SHash *self); 58 | BASEKIT_API void SHash_copy_(SHash *self, SHash *other); 59 | 60 | BASEKIT_API SHashRecord* SHash_cuckoo_(SHash *self, SHashRecord* record); 61 | BASEKIT_API void SHash_grow(SHash *self); 62 | BASEKIT_API void SHash_growWithRecord(SHash *self, SHashRecord* record); 63 | 64 | BASEKIT_API size_t SHash_memorySize(SHash *self); 65 | BASEKIT_API void SHash_compact(SHash *self); 66 | 67 | //BASEKIT_API unsigned int SHash_count(SHash *self); 68 | BASEKIT_API unsigned int SHash_countRecords_size_(unsigned char *records, unsigned int size); 69 | 70 | BASEKIT_API void *SHash_firstKeyForValue_(SHash *self, void *v); 71 | 72 | BASEKIT_API void SHash_removeValue_(SHash *self, void *value); 73 | 74 | #include "SHash_inline.h" 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | #endif 80 | 81 | -------------------------------------------------------------------------------- /basekit/SHash_inline.h: -------------------------------------------------------------------------------- 1 | //metadoc SHash copyright Steve Dekorte 2002, Marc Fauconneau 2007 2 | //metadoc SHash license BSD revised 3 | /*metadoc SHash description 4 | SHash - Cuckoo Hash 5 | keys and values are references (they are not copied or freed) 6 | key pointers are assumed unique 7 | */ 8 | 9 | #ifdef SHASH_C 10 | #define IO_IN_C_FILE 11 | #endif 12 | #include "Common_inline.h" 13 | #ifdef IO_DECLARE_INLINES 14 | 15 | #include 16 | 17 | #define SHASH_RECORDS_AT_(self, tableIndex, index) (self->records + self->tableSize*tableIndex + index) 18 | #define SHASH_RECORDS_AT_HASH_(self, tableIndex, hash) \ 19 | (self->records + self->tableSize*tableIndex + (hash & self->mask)) 20 | 21 | IOINLINE unsigned int SHash_count(SHash *self) 22 | { 23 | return self->numKeys; 24 | } 25 | 26 | IOINLINE void SHashRecord_swap(SHashRecord* r1, SHashRecord* r2) 27 | { 28 | SHashRecord t = *r1; 29 | *r1 = *r2; 30 | *r2 = t; 31 | } 32 | 33 | IOINLINE unsigned int SHash_keysAreEqual_(SHash *self, void *key1, void *key2) 34 | { 35 | return key2 && self->keysEqual(key1, key2); 36 | } 37 | 38 | // simple hash functions, should be enough for pointers 39 | 40 | IOINLINE unsigned int SHash_hash(SHash *self, void *key) 41 | { 42 | intptr_t k = self->hashForKey(key); 43 | return k ^ (k >> 4); 44 | } 45 | 46 | IOINLINE unsigned int SHash_hash_more(SHash *self, unsigned int hash) 47 | { 48 | return hash ^ (hash >> self->log2tableSize); 49 | } 50 | 51 | // ----------------------------------- 52 | 53 | IOINLINE void SHash_clean(SHash *self) 54 | { 55 | memset(self->records, 0, sizeof(SHashRecord) * self->tableSize * 2); 56 | self->numKeys = 0; 57 | } 58 | 59 | IOINLINE SHashRecord *SHash_recordAt_(SHash *self, void *key) 60 | { 61 | unsigned int hash; 62 | SHashRecord *record; 63 | 64 | // try first location 65 | 66 | hash = SHash_hash(self, key); 67 | record = SHASH_RECORDS_AT_HASH_(self, 0, hash); 68 | if (SHash_keysAreEqual_(self, key, record->key)) { return record; } 69 | 70 | // try second location 71 | 72 | hash = SHash_hash_more(self, hash); 73 | record = SHASH_RECORDS_AT_HASH_(self, 1, hash); 74 | if (SHash_keysAreEqual_(self, key, record->key)) { return record; } 75 | 76 | return &self->nullRecord; 77 | } 78 | 79 | IOINLINE void *SHash_at_(SHash *self, void *key) 80 | { 81 | return SHash_recordAt_(self, key)->value; 82 | } 83 | 84 | IOINLINE int SHashKey_hasKey_(SHash *self, void *key) 85 | { 86 | return SHash_at_(self, key) != NULL; 87 | } 88 | 89 | IOINLINE void SHash_at_put_(SHash *self, void *key, void *value) 90 | { 91 | SHashRecord thisRecord; 92 | SHashRecord *record; 93 | 94 | record = SHash_recordAt_(self, key); 95 | 96 | // already a matching key, replace it 97 | if (record != &self->nullRecord && SHash_keysAreEqual_(self, key, record->key)) 98 | { 99 | record->value = value; 100 | return; 101 | } 102 | 103 | thisRecord.key = key; 104 | thisRecord.value = value; 105 | 106 | record = SHash_cuckoo_(self, &thisRecord); 107 | 108 | if (!record) // collision 109 | { 110 | SHash_growWithRecord(self, &thisRecord); 111 | //printf("grow due to key collision: SHash_%p numKeys %i \ttableSize %i \tratio %f\n", (void *)self, self->numKeys, self->tableSize, (float) self->numKeys / (float) self->tableSize); 112 | } 113 | else 114 | { 115 | *record = thisRecord; 116 | self->numKeys ++; 117 | if (self->numKeys > SHash_maxKeys(self)) 118 | { 119 | SHash_grow(self); 120 | //printf("grow due to full table: SHash_%p numKeys %i \ttableSize %i \tratio %f\n", (void *)self, self->numKeys, self->tableSize, (float) self->numKeys / (float) self->tableSize); 121 | } 122 | } 123 | 124 | } 125 | 126 | IOINLINE void SHash_removeKey_(SHash *self, void *key) 127 | { 128 | SHashRecord *record = SHash_recordAt_(self, key); 129 | void *rkey = record->key; 130 | 131 | if (rkey && SHash_keysAreEqual_(self, rkey, key)) 132 | { 133 | self->numKeys --; 134 | memset(record, 0, sizeof(SHashRecord)); 135 | } 136 | } 137 | 138 | // --- enumeration -------------------------------------------------- 139 | 140 | #define SHASH_FOREACH(self, pkey, pvalue, code) \ 141 | {\ 142 | SHash *_self = (self);\ 143 | unsigned int _i, _j, _size = _self->tableSize;\ 144 | void * pkey;\ 145 | void * pvalue;\ 146 | \ 147 | for (_j = 0; _j < 2; _j ++)\ 148 | for (_i = 0; _i < _size; _i ++)\ 149 | {\ 150 | SHashRecord *_record = SHASH_RECORDS_AT_(_self, _j, _i);\ 151 | if (_record->key)\ 152 | {\ 153 | pkey = _record->key;\ 154 | pvalue = _record->value;\ 155 | code;\ 156 | }\ 157 | }\ 158 | } 159 | 160 | /* 161 | typedef BASEKIT_API void (SHashDoCallback)(void *); 162 | IOINLINE void SHash_do_(SHash *self, SHashDoCallback *callback) 163 | { SHASH_FOREACH(self, k, v, (*callback)(v)); } 164 | 165 | IOINLINE void SHash_doOnKeys_(SHash *self, SHashDoCallback *callback) 166 | { SHASH_FOREACH(self, k, v, (*callback)(k)); } 167 | 168 | IOINLINE void SHash_doOnKeyAndValue_(SHash *self, SHashDoCallback *callback) 169 | { SHASH_FOREACH(self, k, v, (*callback)(k); (*callback)(v);); } 170 | */ 171 | 172 | #undef IO_IN_C_FILE 173 | #endif 174 | -------------------------------------------------------------------------------- /basekit/Sorting.c: -------------------------------------------------------------------------------- 1 | #include "Sorting.h" 2 | 3 | typedef struct 4 | { 5 | void *context; 6 | SDSortCompareCallback *comp; 7 | SDSortSwapCallback *swap; 8 | } SDSort; 9 | 10 | int Sorting_isSorted(SDSort *self, size_t size); 11 | void Sorting_quickSort(SDSort *self, size_t lb, size_t ub); 12 | int Sorting_quickSortRearrange(SDSort *self, size_t lb, size_t ub); 13 | 14 | void Sorting_context_comp_swap_size_type_(void *context, 15 | SDSortCompareCallback *comp, 16 | SDSortSwapCallback *swap, 17 | size_t size, 18 | SDSortType type) 19 | { 20 | SDSort q; 21 | SDSort *self = &q; 22 | 23 | self->context = context; 24 | self->comp = comp; 25 | self->swap = swap; 26 | 27 | switch (type) 28 | { 29 | case SDQuickSort: 30 | if (!Sorting_isSorted(self, size)) Sorting_quickSort(self, 0, size-1); 31 | break; 32 | } 33 | } 34 | 35 | int Sorting_isSorted(SDSort *self, size_t size) 36 | { 37 | SDSortCompareCallback *comp = self->comp; 38 | void *context = self->context; 39 | size_t i; 40 | 41 | for (i = 0; i + 1 < size; i ++) 42 | { 43 | if ((*comp)(context, i, i + 1) > 0) 44 | { 45 | return 0; 46 | } 47 | } 48 | 49 | return 1; 50 | } 51 | 52 | void Sorting_quickSort(SDSort *self, size_t lb, size_t ub) 53 | { 54 | if (lb < ub) 55 | { 56 | int j = Sorting_quickSortRearrange(self, lb, ub); 57 | 58 | if (j) 59 | { 60 | Sorting_quickSort(self, lb, j - 1); 61 | } 62 | 63 | Sorting_quickSort(self, j + 1, ub); 64 | } 65 | } 66 | 67 | int Sorting_quickSortRearrange(SDSort *self, size_t lb, size_t ub) 68 | { 69 | SDSortCompareCallback *comp = self->comp; 70 | SDSortSwapCallback *swap = self->swap; 71 | void *context = self->context; 72 | 73 | do { 74 | while (ub > lb && (*comp)(context, ub, lb) >= 0) 75 | { 76 | ub --; 77 | } 78 | 79 | if (ub != lb) 80 | { 81 | (*swap)(context, ub, lb); 82 | 83 | while (lb < ub && (*comp)(context, lb, ub) <= 0) 84 | { 85 | lb ++; 86 | } 87 | 88 | if (lb != ub) 89 | { 90 | (*swap)(context, lb, ub); 91 | } 92 | } 93 | } while (lb != ub); 94 | 95 | return lb; 96 | } 97 | -------------------------------------------------------------------------------- /basekit/Sorting.h: -------------------------------------------------------------------------------- 1 | #include "Common.h" 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | The reason for using this instead of C's qsort is 9 | that we need more context information than just the 10 | two objects if we want to do something like use an 11 | Io block to do the comparison and using globals is 12 | unacceptable for several reasons. 13 | */ 14 | 15 | typedef enum 16 | { 17 | SDQuickSort 18 | //SDShellSort 19 | } SDSortType; 20 | 21 | typedef int (SDSortCompareCallback)(void *context, int i, int j); 22 | typedef void (SDSortSwapCallback)(void *context, int i, int j); 23 | 24 | BASEKIT_API void Sorting_context_comp_swap_size_type_(void *context, 25 | SDSortCompareCallback *comp, 26 | SDSortSwapCallback *swap, 27 | size_t size, 28 | SDSortType type); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /basekit/Stack.c: -------------------------------------------------------------------------------- 1 | //metadoc Stack copyright Steve Dekorte 2002 2 | //metadoc Stack license BSD revised 3 | /*metadoc Stack description 4 | Notes: first element of items is always 0x0. 5 | */ 6 | 7 | #define STACK_C 8 | #include "Stack.h" 9 | #undef STACK_C 10 | #if !defined(_MSC_VER) 11 | #include 12 | #endif 13 | 14 | Stack *Stack_new(void) 15 | { 16 | // size is the number of pointers, including the starting NULL. 17 | int size = STACK_START_SIZE; 18 | Stack *self = (Stack *)io_calloc(1, sizeof(Stack)); 19 | self->items = (void **)io_calloc(1, size*sizeof(void *)); 20 | // memEnd points past the end of the items memory block. 21 | self->memEnd = self->items + size; 22 | self->top = self->items; 23 | //self->lastMark = self->items; 24 | return self; 25 | } 26 | 27 | void Stack_free(Stack *self) 28 | { 29 | io_free(self->items); 30 | io_free(self); 31 | } 32 | 33 | Stack *Stack_clone(const Stack *self) 34 | { 35 | Stack *s = (Stack *)cpalloc(self, sizeof(Stack)); 36 | 37 | ptrdiff_t nItems = self->top - self->items; 38 | ptrdiff_t size = nItems + 1; 39 | 40 | s->items = (void **)cpalloc(self->items, size*sizeof(void *)); 41 | s->memEnd = s->items + size; 42 | s->top = s->items + nItems; 43 | return s; 44 | } 45 | 46 | void Stack_copy_(Stack *self, const Stack *other) 47 | { 48 | ptrdiff_t nItems = self->top - self->items; 49 | ptrdiff_t size = nItems + 1; 50 | ptrdiff_t sizeInBytes = size*sizeof(void *); 51 | 52 | self->items = (void **)io_realloc(self->items, sizeInBytes); 53 | memcpy(self->items, other->items, sizeInBytes); 54 | self->memEnd = self->items + size; 55 | self->top = self->items + nItems; 56 | } 57 | 58 | 59 | // stack -------------------------------------------------- 60 | 61 | size_t Stack_memorySize(const Stack *self) 62 | { 63 | return sizeof(Stack) + (self->memEnd - self->items); 64 | } 65 | 66 | void Stack_compact(Stack *self) 67 | { 68 | int oldSize = (1 + self->top - self->items)*sizeof(void *); 69 | self->items = (void **)io_realloc(self->items, oldSize); 70 | } 71 | 72 | void Stack_resize(Stack *self) 73 | { 74 | int oldSize = (self->memEnd - self->items)*sizeof(void *); 75 | int newSize = oldSize*STACK_RESIZE_FACTOR; 76 | int i = self->top - self->items; 77 | self->items = (void **)io_realloc(self->items, newSize); 78 | self->top = self->items + i; 79 | self->memEnd = self->items + (newSize/sizeof(void *)); 80 | } 81 | 82 | // sizing ------------------------------------------------ 83 | 84 | void Stack_do_on_(const Stack *self, StackDoOnCallback *callback, void *target) 85 | { 86 | Stack *stack = Stack_newCopyWithNullMarks(self); 87 | int i; 88 | 89 | for(i = 0; i < Stack_count(stack) - 1; i ++) 90 | { 91 | void *v = Stack_at_(stack, i); 92 | if (v) (*callback)(target, v); 93 | } 94 | 95 | Stack_free(stack); 96 | } 97 | 98 | void Stack_makeMarksNull(Stack *self) 99 | { 100 | ptrdiff_t mark = self->lastMark; 101 | 102 | while (mark) 103 | { 104 | ptrdiff_t nextMark = (ptrdiff_t)self->items[mark]; 105 | self->items[mark] = NULL; 106 | mark = nextMark; 107 | } 108 | } 109 | 110 | Stack *Stack_newCopyWithNullMarks(const Stack *self) 111 | { 112 | Stack *newStack = Stack_clone(self); 113 | Stack_makeMarksNull(newStack); 114 | return newStack; 115 | } 116 | 117 | void Stack_popToMark_(Stack *self, intptr_t mark) 118 | { 119 | while (self->lastMark && self->lastMark != mark) 120 | { 121 | Stack_popMark(self); 122 | } 123 | 124 | if (self->lastMark == 0) 125 | { 126 | printf("Stack error: unable to find mark %p in %p\n", (void *)mark, (void *)self); 127 | exit(1); 128 | } 129 | 130 | Stack_popMark(self); 131 | } 132 | 133 | List *Stack_asList(const Stack *self) // slow 134 | { 135 | List *list = List_new(); 136 | Stack_do_on_(self, (StackDoOnCallback *)List_append_, list); 137 | return list; 138 | } 139 | -------------------------------------------------------------------------------- /basekit/Stack.h: -------------------------------------------------------------------------------- 1 | //metadoc Stack copyright Steve Dekorte 2002 2 | //metadoc Stack license BSD revised 3 | /*metadoc Stack description 4 | Stack - array of void pointers 5 | supports setting marks - when a mark is popped, 6 | all stack items above it are popped as well 7 | 8 | Designed to optimize push, pushMark and popMark 9 | at the expense of pop (since pop requires a mark check) 10 | */ 11 | 12 | #ifndef STACK_DEFINED 13 | #define STACK_DEFINED 1 14 | 15 | #include "Common.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "List.h" 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #ifdef LOW_MEMORY_SYSTEM 27 | #define STACK_START_SIZE 512 28 | #define STACK_RESIZE_FACTOR 2 29 | #else 30 | #define STACK_START_SIZE 512 31 | #define STACK_RESIZE_FACTOR 2 32 | #endif 33 | 34 | typedef void (StackDoCallback)(void *); 35 | typedef void (StackDoOnCallback)(void *, void *); 36 | 37 | //#define STACK_POP_CALLBACK 38 | 39 | #ifdef STACK_POP_CALLBACK 40 | typedef void (StackPopCallback)(void *); 41 | #endif 42 | 43 | typedef struct 44 | { 45 | void **items; 46 | void **memEnd; 47 | void **top; 48 | intptr_t lastMark; 49 | 50 | #ifdef STACK_POP_CALLBACK 51 | StackPopCallback *popCallback; 52 | #endif 53 | } Stack; 54 | 55 | #define Stack_popCallback_(self, callback) self->popCallback = callback; 56 | 57 | BASEKIT_API Stack *Stack_new(void); 58 | BASEKIT_API void Stack_free(Stack *self); 59 | BASEKIT_API Stack *Stack_clone(const Stack *self); 60 | BASEKIT_API void Stack_copy_(Stack *self, const Stack *other); 61 | 62 | BASEKIT_API size_t Stack_memorySize(const Stack *self); 63 | BASEKIT_API void Stack_compact(Stack *self); 64 | 65 | BASEKIT_API void Stack_resize(Stack *self); 66 | 67 | BASEKIT_API void Stack_popToMark_(Stack *self, intptr_t mark); 68 | 69 | // not high performance 70 | 71 | BASEKIT_API void Stack_makeMarksNull(Stack *self); 72 | BASEKIT_API Stack *Stack_newCopyWithNullMarks(const Stack *self); 73 | BASEKIT_API void Stack_do_on_(const Stack *self, StackDoOnCallback *callback, void *target); 74 | 75 | BASEKIT_API List *Stack_asList(const Stack *self); 76 | 77 | #include "Stack_inline.h" 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | #endif 83 | -------------------------------------------------------------------------------- /basekit/Stack_inline.h: -------------------------------------------------------------------------------- 1 | //metadoc Stack copyright Steve Dekorte 2002 2 | //metadoc Stack license BSD revised 3 | /*metadoc Stack description 4 | Stack - array of void pointers 5 | supports setting marks - when a mark is popped, 6 | all stack items above it are popped as well 7 | */ 8 | 9 | #ifdef STACK_C 10 | #define IO_IN_C_FILE 11 | #endif 12 | #include "Common_inline.h" 13 | #ifdef IO_DECLARE_INLINES 14 | 15 | IOINLINE void Stack_do_(const Stack *self, StackDoCallback *callback) 16 | { 17 | void **itemP = self->top; 18 | intptr_t mark = self->lastMark; 19 | 20 | while (itemP > self->items) 21 | { 22 | if (itemP - self->items == mark) 23 | { 24 | mark = (intptr_t)(*itemP); 25 | } 26 | else 27 | { 28 | (*callback)(*itemP); 29 | } 30 | 31 | itemP --; 32 | } 33 | } 34 | 35 | IOINLINE void Stack_doUntilMark_(const Stack *self, StackDoCallback *callback) 36 | { 37 | void **itemP = self->top; 38 | intptr_t mark = self->lastMark; 39 | 40 | while (itemP > self->items) 41 | { 42 | if (itemP - self->items == mark) 43 | { 44 | return; 45 | } 46 | else 47 | { 48 | (*callback)(*itemP); 49 | } 50 | 51 | itemP --; 52 | } 53 | } 54 | 55 | IOINLINE void Stack_clear(Stack *self) 56 | { 57 | self->top = self->items; 58 | self->lastMark = 0; 59 | } 60 | 61 | IOINLINE size_t Stack_totalSize(const Stack *self) 62 | { 63 | return (self->top - self->items); 64 | } 65 | 66 | IOINLINE int Stack_count(const Stack *self) 67 | { 68 | return (self->top - self->items); 69 | } 70 | 71 | IOINLINE void Stack_push_(Stack *self, void *item) 72 | { 73 | self->top ++; 74 | 75 | if (self->top == self->memEnd) 76 | { 77 | Stack_resize(self); 78 | } 79 | 80 | *(self->top) = item; 81 | } 82 | 83 | IOINLINE void Stack_pushMark(Stack *self) 84 | { 85 | Stack_push_(self, (void *)self->lastMark); 86 | self->lastMark = self->top - self->items; 87 | } 88 | 89 | IOINLINE intptr_t Stack_pushMarkPoint(Stack *self) 90 | { 91 | Stack_push_(self, (void *)self->lastMark); 92 | self->lastMark = self->top - self->items; 93 | return self->lastMark; 94 | } 95 | 96 | IOINLINE void *Stack_pop(Stack *self) 97 | { 98 | void *top = *(self->top); 99 | 100 | if (self->items != self->top) 101 | { 102 | #ifdef STACK_POP_CALLBACK 103 | if(self->popCallback) self->popCallback(*(self->top)); 104 | #endif 105 | self->top --; 106 | } 107 | 108 | return top; 109 | } 110 | 111 | IOINLINE void Stack_popMark(Stack *self) 112 | { 113 | #ifdef STACK_POP_CALLBACK 114 | if(self->popCallback) Stack_doUntilMark_(self, self->popCallback); 115 | #endif 116 | 117 | self->top = self->items + self->lastMark - 1; 118 | 119 | if (self->lastMark) 120 | { 121 | self->lastMark = (intptr_t)(self->items[self->lastMark]); 122 | } 123 | } 124 | 125 | IOINLINE int Stack_popMarkPoint_(Stack *self, intptr_t mark) 126 | { 127 | while (self->lastMark && self->lastMark != mark) 128 | { 129 | Stack_popMark(self); 130 | } 131 | 132 | if (self->lastMark != mark) 133 | { 134 | return 0; 135 | } 136 | 137 | Stack_popMark(self); 138 | return 1; 139 | } 140 | 141 | IOINLINE void Stack_clearTop(Stack *self) 142 | { 143 | Stack_popMark(self); 144 | Stack_pushMark(self); 145 | //self->top = self->items + self->lastMark; 146 | } 147 | 148 | IOINLINE void *Stack_top(const Stack *self) 149 | { 150 | return *(self->top); 151 | } 152 | 153 | IOINLINE void *Stack_at_(const Stack *self, int i) 154 | { 155 | return self->items[i + 1]; 156 | } 157 | 158 | 159 | 160 | #undef IO_IN_C_FILE 161 | #endif 162 | 163 | -------------------------------------------------------------------------------- /basekit/UArray_character.c: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | #include "UArray.h" 7 | #include 8 | 9 | // set 10 | 11 | #define UARRAY_IOP(OP) \ 12 | void UArray_ ## OP (UArray *self) { UARRAY_FOREACHASSIGN(self, i, v, OP((int)v)); } 13 | 14 | UARRAY_IOP(isalnum); 15 | UARRAY_IOP(isalpha); 16 | UARRAY_IOP(iscntrl); 17 | UARRAY_IOP(isdigit); 18 | UARRAY_IOP(isgraph); 19 | UARRAY_IOP(islower); 20 | UARRAY_IOP(isprint); 21 | UARRAY_IOP(ispunct); 22 | UARRAY_IOP(isspace); 23 | UARRAY_IOP(isupper); 24 | UARRAY_IOP(isxdigit); 25 | 26 | UARRAY_IOP(tolower); 27 | UARRAY_IOP(toupper); 28 | 29 | BASEKIT_API int UArray_isLowercase(UArray *self) 30 | { 31 | UARRAY_INTFOREACH(self, i, v, if(v != tolower(v)) return 0); 32 | return 1; 33 | } 34 | 35 | BASEKIT_API int UArray_isUppercase(UArray *self) 36 | { 37 | UARRAY_INTFOREACH(self, i, v, if(v != toupper(v)) return 0); 38 | return 1; 39 | } 40 | -------------------------------------------------------------------------------- /basekit/UArray_character.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | BASEKIT_API void UArray_isalnum(UArray *self); 7 | BASEKIT_API void UArray_isalpha(UArray *self); 8 | BASEKIT_API void UArray_iscntrl(UArray *self); 9 | BASEKIT_API void UArray_isdigit(UArray *self); 10 | BASEKIT_API void UArray_isgraph(UArray *self); 11 | BASEKIT_API void UArray_islower(UArray *self); 12 | BASEKIT_API void UArray_isprint(UArray *self); 13 | BASEKIT_API void UArray_ispunct(UArray *self); 14 | BASEKIT_API void UArray_isspace(UArray *self); 15 | BASEKIT_API void UArray_isupper(UArray *self); 16 | BASEKIT_API void UArray_isxdigit(UArray *self); 17 | BASEKIT_API void UArray_tolower(UArray *self); 18 | BASEKIT_API void UArray_toupper(UArray *self); 19 | 20 | BASEKIT_API int UArray_isLowercase(UArray *self); 21 | BASEKIT_API int UArray_isUppercase(UArray *self); 22 | -------------------------------------------------------------------------------- /basekit/UArray_format.c: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | #include "UArray.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | UArray *UArray_newWithFormat_(const char *format, ...) 13 | { 14 | UArray *self; 15 | va_list ap; 16 | va_start(ap, format); 17 | self = UArray_newWithVargs_(format, ap); 18 | va_end(ap); 19 | return self; 20 | } 21 | 22 | UArray *UArray_newWithVargs_(const char *format, va_list ap) 23 | { 24 | UArray *self = UArray_new(); 25 | UArray_fromVargs_(self, format,ap); 26 | return self; 27 | } 28 | 29 | UArray *UArray_fromFormat_(UArray *self, const char *format, ...) 30 | { 31 | va_list ap; 32 | va_start(ap, format); 33 | UArray_fromVargs_(self, format, ap); 34 | va_end(ap); 35 | return self; 36 | } 37 | 38 | void UArray_fromVargs_(UArray *self, const char *format, va_list ap) 39 | { 40 | while (*format) 41 | { 42 | if (*format == '%') 43 | { 44 | format ++; 45 | 46 | if (*format == 's') 47 | { 48 | char *s = va_arg(ap, char *); 49 | if (!s) { printf("UArray_fromVargs_ missing param"); return; } 50 | UArray_appendCString_(self, s); 51 | } 52 | else if (*format == 'i' || *format == 'd') 53 | { 54 | int i = va_arg(ap, int); 55 | char s[100]; 56 | 57 | snprintf(s, 100, "%i", i); 58 | UArray_appendCString_(self, s); 59 | } 60 | else if (*format == 'f') 61 | { 62 | double d = va_arg(ap, double); 63 | char s[100]; 64 | 65 | snprintf(s, 100, "%f", d); 66 | UArray_appendCString_(self, s); 67 | } 68 | else if (*format == 'p') 69 | { 70 | void *p = va_arg(ap, void *); 71 | char s[100]; 72 | 73 | snprintf(s, 100, "%p", p); 74 | UArray_appendCString_(self, s); 75 | } 76 | // new format command for a given number adding spaces 77 | else if (*format == '#') 78 | { 79 | int n, i = va_arg(ap, int); 80 | char *s = " "; 81 | 82 | for (n = 0; n < i; n ++) 83 | { 84 | UArray_appendCString_(self, s); 85 | } 86 | } 87 | } 88 | else 89 | { 90 | char s[2]; 91 | 92 | snprintf(s, 2, "%c", *format); 93 | UArray_appendCString_(self, s); 94 | } 95 | 96 | format ++; 97 | } 98 | } 99 | 100 | UArray *UArray_asNewHexStringUArray(UArray *self) 101 | { 102 | size_t i, newSize = self->size * 2; 103 | UArray *ba = UArray_new(); 104 | UArray_setSize_(ba, newSize); 105 | 106 | for(i = 0; i < self->size; i ++) 107 | { 108 | int v = UArray_longAt_(self, i); 109 | char *s = (char *)(ba->data + i * 2); 110 | 111 | if (v < 16) 112 | { 113 | snprintf(s, newSize, "0%x", (int)v); 114 | } 115 | else 116 | { 117 | snprintf(s, newSize, "%x", (int)v); 118 | } 119 | } 120 | 121 | return ba; 122 | } 123 | -------------------------------------------------------------------------------- /basekit/UArray_format.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | BASEKIT_API UArray *UArray_newWithFormat_(const char *format, ...); 7 | BASEKIT_API UArray *UArray_newWithVargs_(const char *format, va_list ap); 8 | BASEKIT_API UArray *UArray_fromFormat_(UArray *self, const char *format, ...); 9 | BASEKIT_API void UArray_fromVargs_(UArray *self, const char *format, va_list ap); 10 | 11 | BASEKIT_API UArray *UArray_asNewHexStringUArray(UArray *self); 12 | -------------------------------------------------------------------------------- /basekit/UArray_math.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | // set 7 | 8 | BASEKIT_API void UArray_clear(UArray *self); 9 | BASEKIT_API void UArray_setItemsToLong_(UArray *self, long x); 10 | BASEKIT_API void UArray_setItemsToDouble_(UArray *self, double x); 11 | BASEKIT_API void UArray_rangeFill(UArray *self); 12 | BASEKIT_API void UArray_negate(const UArray *self); 13 | 14 | // basic vector math 15 | 16 | BASEKIT_API void UArray_add_(UArray *self, const UArray *other); 17 | BASEKIT_API void UArray_subtract_(UArray *self, const UArray *other); 18 | BASEKIT_API void UArray_multiply_(UArray *self, const UArray *other); 19 | BASEKIT_API void UArray_divide_(UArray *self, const UArray *other); 20 | BASEKIT_API double UArray_dotProduct_(const UArray *self, const UArray *other); 21 | 22 | // basic scalar math 23 | 24 | BASEKIT_API void UArray_addScalarDouble_(UArray *self, double v); 25 | BASEKIT_API void UArray_subtractScalarDouble_(UArray *self, double v); 26 | BASEKIT_API void UArray_multiplyScalarDouble_(UArray *self, double v); 27 | BASEKIT_API void UArray_divideScalarDouble_(UArray *self, double v); 28 | 29 | // bitwise logic 30 | 31 | BASEKIT_API void UArray_bitwiseOr_(UArray *self, const UArray *other); 32 | BASEKIT_API void UArray_bitwiseAnd_(UArray *self, const UArray *other); 33 | BASEKIT_API void UArray_bitwiseXor_(UArray *self, const UArray *other); 34 | BASEKIT_API void UArray_bitwiseNot(UArray *self); 35 | 36 | // bitwise ops 37 | 38 | BASEKIT_API void UArray_setAllBitsTo_(UArray *self, uint8_t aBool); 39 | BASEKIT_API uint8_t UArray_byteAt_(UArray *self, size_t i); 40 | BASEKIT_API int UArray_bitAt_(UArray *self, size_t i); 41 | BASEKIT_API void UArray_setBit_at_(UArray *self, int b, size_t i); 42 | BASEKIT_API UArray * UArray_asBits(const UArray *self); 43 | BASEKIT_API size_t UArray_bitCount(UArray *self); 44 | 45 | // boolean logic 46 | 47 | BASEKIT_API void UArray_logicalOr_(UArray *self, const UArray *other); 48 | BASEKIT_API void UArray_logicalAnd_(UArray *self, const UArray *other); 49 | 50 | // trigonometry 51 | 52 | BASEKIT_API void UArray_sin(UArray *self); 53 | BASEKIT_API void UArray_cos(UArray *self); 54 | BASEKIT_API void UArray_tan(UArray *self); 55 | 56 | BASEKIT_API void UArray_asin(UArray *self); 57 | BASEKIT_API void UArray_acos(UArray *self); 58 | BASEKIT_API void UArray_atan(UArray *self); 59 | 60 | //void UArray_atan2(UArray *self, const UArray *other); 61 | 62 | BASEKIT_API void UArray_sinh(UArray *self); 63 | BASEKIT_API void UArray_cosh(UArray *self); 64 | BASEKIT_API void UArray_tanh(UArray *self); 65 | 66 | BASEKIT_API void UArray_exp(UArray *self); 67 | BASEKIT_API void UArray_log(UArray *self); 68 | BASEKIT_API void UArray_log10(UArray *self); 69 | 70 | //void UArray_pow(UArray *self, const UArray *other); 71 | 72 | BASEKIT_API void UArray_sqrt(UArray *self); 73 | BASEKIT_API void UArray_ceil(UArray *self); 74 | BASEKIT_API void UArray_floor(UArray *self); 75 | BASEKIT_API void UArray_abs(UArray *self); 76 | BASEKIT_API void UArray_round(UArray *self); 77 | 78 | //void UArray_ldexp(UArray *self, const UArray *other); 79 | //void UArray_fmod(UArray *self, const UArray *other); 80 | 81 | BASEKIT_API void UArray_square(UArray *self); 82 | BASEKIT_API void UArray_normalize(UArray *self); 83 | 84 | BASEKIT_API void UArray_crossProduct_(UArray *self, const UArray *other); 85 | BASEKIT_API double UArray_distanceTo_(const UArray *self, const UArray *other); 86 | 87 | // extras 88 | 89 | BASEKIT_API double UArray_sumAsDouble(const UArray *self); 90 | BASEKIT_API double UArray_productAsDouble(const UArray *self); 91 | BASEKIT_API double UArray_arithmeticMeanAsDouble(const UArray *self); 92 | BASEKIT_API double UArray_arithmeticMeanSquareAsDouble(const UArray *self); 93 | BASEKIT_API double UArray_maxAsDouble(const UArray *self); 94 | BASEKIT_API double UArray_minAsDouble(const UArray *self); 95 | BASEKIT_API void UArray_Max(UArray *self, const UArray *other); 96 | BASEKIT_API void UArray_Min(UArray *self, const UArray *other); 97 | 98 | // hash 99 | 100 | BASEKIT_API void UArray_changed(UArray *self); 101 | BASEKIT_API uintptr_t UArray_calcHash(UArray *self); 102 | BASEKIT_API uintptr_t UArray_hash(UArray *self); 103 | BASEKIT_API int UArray_equalsWithHashCheck_(UArray *self, UArray *other); 104 | 105 | // indexes 106 | 107 | BASEKIT_API void UArray_duplicateIndexes(UArray *self); 108 | BASEKIT_API void UArray_removeOddIndexes(UArray *self); 109 | BASEKIT_API void UArray_removeEvenIndexes(UArray *self); 110 | 111 | BASEKIT_API void UArray_reverseItemByteOrders(UArray *self); 112 | 113 | -------------------------------------------------------------------------------- /basekit/UArray_path.c: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | #include "UArray.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void UArray_appendPath_(UArray *self, const UArray *path) 13 | { 14 | const UArray sep = UArray_stackAllocedWithCString_(IO_PATH_SEPARATOR); 15 | 16 | int selfEndsWithSep = IS_PATH_SEPERATOR(UArray_lastLong(self)); 17 | int pathStartsWithSep = IS_PATH_SEPERATOR(UArray_firstLong(path)); 18 | 19 | if (!selfEndsWithSep && !pathStartsWithSep) 20 | { 21 | if(self->size != 0) UArray_append_(self, &sep); 22 | UArray_append_(self, path); 23 | } 24 | else if (selfEndsWithSep && pathStartsWithSep) 25 | { 26 | const UArray pathPart = UArray_stackRange(path, 1, path->size - 1); 27 | UArray_append_(self, &pathPart); 28 | } 29 | else 30 | { 31 | UArray_append_(self, path); 32 | } 33 | } 34 | 35 | void UArray_removeLastPathComponent(UArray *self) 36 | { 37 | UArray seps = UArray_stackAllocedWithCString_(IO_PATH_SEPARATORS); 38 | long pos = UArray_findLastPathComponent(self); 39 | if (pos) pos --; 40 | UArray_setSize_(self, pos); 41 | } 42 | 43 | void UArray_clipBeforeLastPathComponent(UArray *self) 44 | { 45 | long pos = UArray_findLastPathComponent(self); 46 | 47 | if (pos != -1) 48 | { 49 | UArray_removeRange(self, 0, pos); 50 | } 51 | } 52 | 53 | long UArray_findLastPathComponent(const UArray *self) 54 | { 55 | if (self->size) 56 | { 57 | UArray seps = UArray_stackAllocedWithCString_(IO_PATH_SEPARATORS); 58 | UArray s = UArray_stackRange(self, 0, self->size); 59 | long pos = 0; 60 | 61 | while (s.size && (pos = UArray_rFindAnyValue_(&s, &seps)) == s.size - 1) 62 | { 63 | s.size = pos; 64 | } 65 | 66 | if (pos == -1) { pos = 0; } else { pos ++; } 67 | return pos; 68 | } 69 | 70 | return 0; 71 | } 72 | 73 | UArray *UArray_lastPathComponent(const UArray *self) 74 | { 75 | long pos = UArray_findLastPathComponent(self); 76 | return UArray_range(self, pos, self->size - pos); 77 | } 78 | 79 | long UArray_findPathExtension(UArray *self) 80 | { 81 | UArray dot = UArray_stackAllocedWithCString_(IO_PATH_SEPARATOR_DOT); 82 | return UArray_rFind_(self, &dot); 83 | } 84 | 85 | void UArray_removePathExtension(UArray *self) 86 | { 87 | long pos = UArray_findPathExtension(self); 88 | 89 | if (pos != -1) 90 | { 91 | UArray_setSize_(self, pos); 92 | } 93 | } 94 | 95 | UArray *UArray_pathExtension(UArray *self) 96 | { 97 | long pos = UArray_findPathExtension(self); 98 | 99 | if (pos == -1 || pos == self->size - 1) 100 | { 101 | return UArray_newWithCString_copy_("", 1); 102 | } 103 | 104 | return UArray_range(self, pos + 1, self->size - pos - 1); 105 | } 106 | 107 | UArray *UArray_fileName(UArray *self) 108 | { 109 | long extPos = UArray_findLastPathComponent(self); 110 | long dotPos = UArray_findPathExtension(self); 111 | 112 | //if (extPos == -1) { extPos = 0; } else { extPos ++; } 113 | if (dotPos == -1) dotPos = self->size; 114 | 115 | return UArray_range(self, extPos, dotPos - extPos); 116 | } 117 | 118 | // to/from os path - always returns a copy 119 | 120 | int UArray_OSPathSeparatorIsUnixSeparator(void) 121 | { 122 | return strcmp(OS_PATH_SEPARATOR, "/") == 0; 123 | } 124 | 125 | UArray *UArray_asOSPath(UArray *self) 126 | { 127 | UArray *a = UArray_clone(self); 128 | UArray_replaceCString_withCString_(a, IO_PATH_SEPARATOR, OS_PATH_SEPARATOR); 129 | return a; 130 | } 131 | 132 | UArray *UArray_asUnixPath(UArray *self) 133 | { 134 | UArray *a = UArray_clone(self); 135 | UArray_replaceCString_withCString_(a, OS_PATH_SEPARATOR, IO_PATH_SEPARATOR); 136 | return a; 137 | } 138 | 139 | -------------------------------------------------------------------------------- /basekit/UArray_path.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | // internally, Io always uses a forward slash "/" for path separators, 7 | // but on Windows, back slashes are also tolerated as path separators. 8 | #if defined(DOS) || defined(ON_WINDOWS) 9 | #define OS_PATH_SEPARATOR "\\" 10 | #define IO_PATH_SEPARATORS "\\/" 11 | #else 12 | #define OS_PATH_SEPARATOR "/" 13 | #define IO_PATH_SEPARATORS "/" 14 | #endif 15 | 16 | #define IO_PATH_SEPARATOR "/" 17 | #define IO_PATH_SEPARATOR_DOT "." 18 | 19 | 20 | #ifdef ON_WINDOWS 21 | #define IS_PATH_SEPERATOR(ch) ((ch == '/') || (ch == '\\')) 22 | #else 23 | #define IS_PATH_SEPERATOR(ch) (ch == '/') 24 | #endif 25 | 26 | 27 | BASEKIT_API void UArray_appendPath_(UArray *self, const UArray *path); 28 | 29 | // last component 30 | 31 | BASEKIT_API void UArray_removeLastPathComponent(UArray *self); 32 | BASEKIT_API void UArray_clipBeforeLastPathComponent(UArray *self); 33 | BASEKIT_API long UArray_findLastPathComponent(const UArray *self); 34 | BASEKIT_API UArray *UArray_lastPathComponent(const UArray *self); 35 | 36 | // extension 37 | 38 | BASEKIT_API long UArray_findPathExtension(UArray *self); 39 | BASEKIT_API void UArray_removePathExtension(UArray *self); 40 | BASEKIT_API UArray *UArray_pathExtension(UArray *self); 41 | 42 | // fileName 43 | 44 | BASEKIT_API UArray *UArray_fileName(UArray *self); 45 | 46 | // to/from os path - always returns a copy 47 | 48 | BASEKIT_API int UArray_OSPathSeparatorIsUnixSeparator(void); 49 | BASEKIT_API UArray *UArray_asOSPath(UArray *self); 50 | BASEKIT_API UArray *UArray_asUnixPath(UArray *self); 51 | 52 | -------------------------------------------------------------------------------- /basekit/UArray_stream.c: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | #include "UArray.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // read ------------------------------------------------------ 13 | 14 | size_t UArray_fread_(UArray *self, FILE *fp) 15 | { 16 | size_t itemsRead = fread(self->data, self->itemSize, self->size, fp); 17 | UArray_setSize_(self, itemsRead); 18 | return itemsRead; 19 | } 20 | 21 | long UArray_readFromCStream_(UArray *self, FILE *fp) 22 | { 23 | long totalItemsRead = 0; 24 | long itemsPerBuffer = 4096 / self->itemSize; 25 | UArray *buffer = UArray_new(); 26 | UArray_setItemType_(buffer, self->itemType); 27 | UArray_setSize_(buffer, itemsPerBuffer); 28 | 29 | if (!fp) { perror("UArray_readFromCStream_"); return -1; } 30 | 31 | while(!feof(fp) && !ferror(fp)) 32 | { 33 | size_t itemsRead; 34 | UArray_setSize_(buffer, itemsPerBuffer); 35 | itemsRead = UArray_fread_(buffer, fp); 36 | 37 | totalItemsRead += itemsRead; 38 | UArray_append_(self, buffer); 39 | if (itemsRead != itemsPerBuffer) break; 40 | } 41 | 42 | if (ferror(fp)) { perror("UArray_readFromCStream_"); return -1; } 43 | 44 | UArray_free(buffer); 45 | return totalItemsRead; 46 | } 47 | 48 | long UArray_readNumberOfItems_fromCStream_(UArray *self, size_t size, FILE *stream) 49 | { 50 | size_t itemsRead; 51 | UArray *buffer = UArray_new(); 52 | UArray_setItemType_(buffer, self->itemType); 53 | UArray_setSize_(buffer, size); 54 | 55 | itemsRead = UArray_fread_(buffer, stream); 56 | UArray_append_(self, buffer); 57 | 58 | UArray_free(buffer); 59 | return itemsRead; 60 | } 61 | 62 | long UArray_readFromFilePath_(UArray *self, const UArray *path) 63 | { 64 | FILE *stream; 65 | long itemsRead; 66 | UArray *sysPath = (UArray_itemSize(path) == 1) ? (UArray *)path : UArray_asUTF8(path); 67 | const char *p = UArray_asCString(sysPath); 68 | 69 | //printf("UArray_readFromFilePath_(\"%s\")\n", p); 70 | 71 | stream = fopen(p, "rb"); 72 | if (!stream) return -1; 73 | itemsRead = UArray_readFromCStream_(self, stream); 74 | fclose(stream); 75 | 76 | if(sysPath != path) UArray_free(sysPath); 77 | return itemsRead; 78 | } 79 | 80 | 81 | #define CHUNK_SIZE 4096 82 | 83 | int UArray_readLineFromCStream_(UArray *self, FILE *stream) 84 | { 85 | int readSomething = 0; 86 | 87 | if(self->itemSize == 1) 88 | { 89 | char *s = (char *)io_calloc(1, CHUNK_SIZE); 90 | 91 | while (fgets(s, CHUNK_SIZE, stream) != NULL) 92 | { 93 | char *eol1 = strchr(s, '\n'); 94 | char *eol2 = strchr(s, '\r'); 95 | 96 | readSomething = 1; 97 | 98 | if (eol1) { *eol1 = 0; } // remove the \n return character 99 | if (eol2) { *eol2 = 0; } // remove the \r return character 100 | 101 | if (*s) 102 | { 103 | UArray_appendCString_(self, s); 104 | } 105 | 106 | if (eol1 || eol2) 107 | { 108 | break; 109 | } 110 | } 111 | 112 | io_free(s); 113 | } 114 | 115 | return readSomething; 116 | } 117 | 118 | // write ------------------------------------------------------ 119 | 120 | size_t UArray_fwrite_(const UArray *self, size_t size, FILE *fp) 121 | { 122 | return fwrite(self->data, 1, self->itemSize * size, fp); 123 | } 124 | 125 | long UArray_writeToCStream_(const UArray *self, FILE *stream) 126 | { 127 | size_t totalItemsRead = UArray_fwrite_(self, self->size, stream); 128 | if (ferror(stream)) { perror("UArray_readFromCStream_"); return -1; } 129 | return totalItemsRead; 130 | } 131 | 132 | long UArray_writeToFilePath_(const UArray *self, const UArray *path) 133 | { 134 | UArray *sysPath = (UArray_itemSize(path) == 1) ? (UArray *)path : UArray_asUTF8(path); 135 | FILE *fp = fopen(UArray_asCString(sysPath), "w"); 136 | long itemsWritten = -1; 137 | 138 | if (fp) 139 | { 140 | itemsWritten = UArray_writeToCStream_(self, fp); 141 | fclose(fp); 142 | } 143 | 144 | return itemsWritten; 145 | } 146 | 147 | -------------------------------------------------------------------------------- /basekit/UArray_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | // these return item read/written count or -1 on error 7 | 8 | // read 9 | 10 | BASEKIT_API size_t UArray_fread_(UArray *self, FILE *fp); 11 | BASEKIT_API long UArray_readFromCStream_(UArray *self, FILE *stream); 12 | BASEKIT_API long UArray_readFromFilePath_(UArray *self, const UArray *path); 13 | BASEKIT_API long UArray_readNumberOfItems_fromCStream_(UArray *self, size_t size, FILE *stream); 14 | BASEKIT_API int UArray_readLineFromCStream_(UArray *self, FILE *stream); 15 | 16 | // write 17 | 18 | BASEKIT_API size_t UArray_fwrite_(const UArray *self, size_t size, FILE *stream); 19 | BASEKIT_API long UArray_writeToCStream_(const UArray *self, FILE *stream); 20 | BASEKIT_API long UArray_writeToFilePath_(const UArray *self, const UArray *path); 21 | -------------------------------------------------------------------------------- /basekit/UArray_string.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | /* 7 | copyright: Steve Dekorte, 2006. All rights reserved. 8 | license: See _BSDLicense.txt. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | BASEKIT_API void UArray_append_(UArray *self, const UArray *other); 17 | BASEKIT_API void UArray_appendCString_(UArray *self, const char *s); 18 | BASEKIT_API void UArray_prepend_(UArray *self, const UArray *other); 19 | 20 | BASEKIT_API int UArray_equalsAnyCase_(const UArray *self, const UArray *other); 21 | BASEKIT_API void UArray_replace_with_(UArray *self, const UArray *a1, const UArray *a2); 22 | BASEKIT_API void UArray_replaceAnyCase_with_(UArray *self, const UArray *a1, const UArray *a2); 23 | BASEKIT_API void UArray_replaceCString_withCString_(UArray *self, const char *s1, const char *s2); 24 | BASEKIT_API void UArray_remove_(UArray *self, const UArray *a1); 25 | BASEKIT_API void UArray_removeAnyCase_(UArray *self, const UArray *a1); 26 | 27 | // clipping 28 | 29 | BASEKIT_API int UArray_clipBefore_(UArray *self, const UArray *other); 30 | BASEKIT_API int UArray_clipBeforeEndOf_(UArray *self, const UArray *other); 31 | BASEKIT_API int UArray_clipAfter_(UArray *self, const UArray *other); 32 | BASEKIT_API int UArray_clipAfterStartOf_(UArray *self, const UArray *other); 33 | 34 | // strip 35 | 36 | BASEKIT_API void UArray_lstrip_(UArray *self, const UArray *other); 37 | BASEKIT_API void UArray_rstrip_(UArray *self, const UArray *other); 38 | BASEKIT_API void UArray_strip_(UArray *self, const UArray *other); 39 | 40 | // swap 41 | 42 | BASEKIT_API void UArray_swapIndex_withIndex_(UArray *self, size_t i, size_t j); 43 | 44 | // reverse 45 | 46 | BASEKIT_API void UArray_reverse(UArray *self); 47 | 48 | //BASEKIT_API size_t UArray_matchingPrefixSizeWith_(const UArray *self, const UArray *other); 49 | 50 | // split 51 | 52 | BASEKIT_API PtrUArray *UArray_split_(const UArray *self, const PtrUArray *delims); 53 | BASEKIT_API size_t UArray_splitCount_(const UArray *self, const PtrUArray *delims); 54 | 55 | // find 56 | 57 | BASEKIT_API int UArray_beginsWith_(UArray *self, const UArray *other); 58 | BASEKIT_API int UArray_endsWith_(UArray *self, const UArray *other); 59 | 60 | // escape and quote 61 | 62 | BASEKIT_API void UArray_swapWith_(UArray *self, UArray *other); 63 | 64 | BASEKIT_API void UArray_escape(UArray *self); 65 | BASEKIT_API void UArray_unescape(UArray *self); 66 | 67 | BASEKIT_API void UArray_quote(UArray *self); 68 | BASEKIT_API void UArray_unquote(UArray *self); 69 | 70 | BASEKIT_API void UArray_translate(UArray *self, UArray *fromChars, UArray *toChars); 71 | BASEKIT_API size_t UArray_count_(const UArray *self, const UArray *other); 72 | 73 | -------------------------------------------------------------------------------- /basekit/UArray_utf.h: -------------------------------------------------------------------------------- 1 | /* 2 | copyright: Steve Dekorte, 2006. All rights reserved. 3 | license: See _BSDLicense.txt. 4 | */ 5 | 6 | BASEKIT_API int UArray_convertToFixedSizeType(UArray *self); 7 | 8 | BASEKIT_API int UArray_maxCharSize(const UArray *self); 9 | BASEKIT_API int UArray_isMultibyte(const UArray *self); 10 | BASEKIT_API int UArray_isLegalUTF8(const UArray *self); 11 | 12 | BASEKIT_API UArray *UArray_asUTF8(const UArray *self); 13 | BASEKIT_API UArray *UArray_asUTF16(const UArray *self); 14 | BASEKIT_API UArray *UArray_asUTF32(const UArray *self); 15 | 16 | BASEKIT_API void UArray_convertToUTF8(UArray *self); 17 | BASEKIT_API void UArray_convertToUTF16(UArray *self); 18 | BASEKIT_API void UArray_convertToUTF32(UArray *self); 19 | -------------------------------------------------------------------------------- /basekit/simd_cph/LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2004 Patrick Roberts 3 | 4 | This software is provided 'as-is', without any express 5 | or implied warranty. In no event will the authors be held 6 | liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it 10 | and redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; 13 | you must not claim that you wrote the original software. 14 | If you use this software in a product, an acknowledgment in 15 | the product documentation would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, 18 | and must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | 4. THIS LICENSE MAY NOT BE CHANGED, ASSIGNED, OR MIGRATED WITHOUT 23 | THE AUTHOR'S WRITTEN PERMISSION, WITH THE FOLLOWING EXCEPTIONS: 24 | 25 | a. This file may be included with GPL/LGPL licensed 26 | software, but you may not change the license this file 27 | is released under. 28 | */ 29 | -------------------------------------------------------------------------------- /basekit/simd_cph/docs/LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2004 Patrick Roberts 3 | 4 | This software is provided 'as-is', without any express 5 | or implied warranty. In no event will the authors be held 6 | liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it 10 | and redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; 13 | you must not claim that you wrote the original software. 14 | If you use this software in a product, an acknowledgment in 15 | the product documentation would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, 18 | and must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | 4. THIS LICENSE MAY NOT BE CHANGED, ASSIGNED, OR MIGRATED WITHOUT 23 | THE AUTHOR'S WRITTEN PERMISSION, WITH THE FOLLOWING EXCEPTIONS: 24 | 25 | a. This file may be included with GPL/LGPL licensed 26 | software, but you may not change the license this file 27 | is released under. 28 | */ 29 | -------------------------------------------------------------------------------- /basekit/simd_cph/include/simd_cp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2004 Patrick Roberts 3 | 4 | This software is provided 'as-is', without any express 5 | or implied warranty. In no event will the authors be held 6 | liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it 10 | and redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; 13 | you must not claim that you wrote the original software. 14 | If you use this software in a product, an acknowledgment in 15 | the product documentation would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, 18 | and must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | 4. THIS LICENSE MAY NOT BE CHANGED, ASSIGNED, OR MIGRATED WITHOUT 23 | THE AUTHOR'S WRITTEN PERMISSION, WITH THE FOLLOWING EXCEPTIONS: 24 | 25 | a. This file may be included with GPL/LGPL licensed 26 | software, but you may not change the license this file 27 | is released under. 28 | */ 29 | 30 | 31 | /***************************************************** 32 | 33 | Cross-platform SIMD intrinsics header file 34 | 35 | This is the main file and the only one an application should 36 | include. It will find the correct (hopefully) SIMD_CPH 37 | dialect file to include. 38 | 39 | 40 | */ 41 | 42 | #ifndef __SIMD_CPHD_h 43 | 44 | 45 | /* Defines */ 46 | /* Defines */ 47 | /* Defines */ 48 | #define __SIMD_CPHD_h 49 | 50 | 51 | /* Figure out what compiler and CPU we have */ 52 | 53 | #if defined (__SIMD_NO_SIMD__) || defined (__SIMD_EMU__) 54 | #else /* broken pre-processor */ 55 | 56 | #ifdef __GNUC__ /* gcc compiler */ 57 | 58 | /* x86 compiler */ 59 | #ifdef __i386__ 60 | #define __GNUC__X86__ 61 | #define __FOUND 62 | #endif 63 | 64 | /* PowerPC Compiler */ 65 | #ifdef __ALTIVEC__ 66 | #define __GNUC__RS6__ 67 | #define __FOUND 68 | #define __SIMD_NO_SIMD /* No PPC intrinsics file right now */ 69 | #endif 70 | 71 | #ifdef __XSCALE__ 72 | #define __GNUC__ARM_IWMMX__ 73 | #define __FOUND 74 | #endif 75 | 76 | #endif /* __GNUC__ */ 77 | 78 | 79 | 80 | #ifdef _MSC_VER /* Microsoft VC Compiler */ 81 | 82 | #ifdef _M_IX86 /* MSVC for X86 CPU (same as GNUC?)*/ 83 | #define __MSVC__X86__ 84 | #define __FOUND 85 | #endif 86 | 87 | #ifdef _M_ALPHA /* for Compaq Alpha CPU */ 88 | #define __MSVC__AXP__ 89 | #define __FOUND 90 | #define __SIMD_NO_SIMD__ 91 | #endif 92 | 93 | #endif /* _WIN32 */ 94 | 95 | 96 | 97 | #ifndef __FOUND 98 | #define __SIMD_EMU__ 99 | //#warning simd_cp.h does not support or could not figure out your compiler and/or CPU. 100 | #endif 101 | 102 | #endif /* SIMD_NO_SIMD and SIMD_EMU */ 103 | 104 | 105 | /* Include the correct SIMD file */ 106 | 107 | #if defined(__SIMD_NO_SIMD__) || defined(__SIMD_EMU__) 108 | #warning Including Emulated SIMD support... 109 | #define __UNK__EMU__ 110 | #include 111 | #endif 112 | 113 | #if defined( __GNUC__X86__ ) || defined(__MSVC__X86__) 114 | /* gcc x86 compiler or msvc x86 */ 115 | #include 116 | #endif /* __GNUC__X86__ */ 117 | 118 | #ifdef __GNUC__ARM_IWMMX /* gcc ARM compiler with XSCALE SIMD */ 119 | #include 120 | #endif 121 | 122 | 123 | /* Generic Helper commands */ 124 | /* Generic Helper commands */ 125 | /* Generic Helper commands */ 126 | 127 | /* print a simd_m128 variable: l=label to print, a=simd_m128 variable */ 128 | #define simd_print4Floats(l,a) printf("%s: %f %f %f %f\n",l,a.f[0],a.f[1],a.f[2],a.f[3]) 129 | #define simd_print4Ints(l,a) printf("%s: %d %d %d %d\n",l,a.i[0],a.i[1],a.i[2],a.i[3]) 130 | #define simd_print4UInts(l,a) printf("%s: %d %d %d %d\n",l,(unsigned int)a.i[0],(unsigned int)a.i[1],(unsigned int)a.i[2],(unsigned int)a.i[3]) 131 | #define simd_print4Hex(l,a) printf("%s: 0x%08x 0x%08x 0x%08x 0x%08x\n",l,a.i[0],a.i[1],a.i[2],a.i[3]) 132 | 133 | 134 | #endif /* CP_SIMD_h */ 135 | -------------------------------------------------------------------------------- /basekit/simd_cph/simd_cph.readme: -------------------------------------------------------------------------------- 1 | /***************************************************** 2 | 3 | Cross-platform SIMD intrinsics header file 4 | 5 | VERSION: 2004.10.26 (alpha) 6 | 7 | Created by Patrick Roberts 8 | 9 | This is an on-going project. Please add functions and 10 | typedefs as needed, but try to follow the guideline 11 | below: 12 | 13 | The goal of this file is to stay cross-platform. 14 | Only intrinsics or #defines that mimic another system's 15 | SIMD instruction should be included, with the only exception 16 | being instructions that, if non existant, are not 17 | needed (see bottom) 18 | 19 | Currently, the goal is to base support around 128-bit SIMD. 20 | (Only the Gekko and x86-MMX are 64-bit) 21 | 22 | Changelog: 23 | 24 | 2004.05.09 [Patrick Roberts] 25 | *) Created file with some i386, GCC dialect 26 | 2004.10.22 [Patrick Roberts] 27 | *) Created emulated SIMD 28 | 2004.10.25 [Patrick Roberts] 29 | *) Created arm-iwmmx GCC dialect 30 | *) Fixed sqrt bug in emu dialect 31 | *) Organized directories 32 | *) Makefile for test app 33 | 34 | 35 | To Do: 36 | 37 | *( Docs 38 | *( Add new intrinsics to test app 39 | *( MinGW x86 dialect (same as GCC on Linux?) 40 | *( Does 3DNOW buy us anything? 41 | *( Intel ICC x86 dialect 42 | *( MSVC .NET x86 dialect 43 | *( Support for ARM ARM6, VFP and NEON SIMD? What compilers use these? 44 | *( PowerPC AltiVec/Velocity/VMX components 45 | *( MIPS-MMI / PS2-VU components 46 | *( See if SSE2 buys us anything beyond what the compiler does already 47 | *( Compaq Alpha components 48 | 49 | */ 50 | 51 | /*************************************************** 52 | 53 | Platform Notes: 54 | 55 | 56 | General 57 | ------- 58 | 59 | NOTE: Code must be 16-byte aligned. Align to 16 when allocating memory. 60 | 61 | X86/XSCALE (Intel) vs. PowerPC/MIPS 62 | 63 | While the PowerPC and MIPS SIMD instructions take 2 source vectors 64 | and a destination vector, the Intel platforms only take a source and 65 | destination. Example: 66 | 67 | PPC/MIPS can do: 68 | 69 | C = A + B 70 | 71 | X86 can only do: 72 | 73 | A = A + B (or A+=B) 74 | 75 | Code written either way will work on the X86, and still be faster than 76 | 387 math, but preserving the registers takes significant overhead. 77 | (Disassemble the test program for an example. The prints preserve, the 78 | 'disassembly test' does not.) For the fastest code between systems, write 79 | your SIMD math as the X86 expects, manually preserving SIMD variables. 80 | At least GCC for PPC doesn't seem to have any issues figuring out how to 81 | deal with a source and destination memory address being the same. 82 | 83 | 84 | GCC x86 85 | ------- 86 | 87 | You must compile with -msse and -mmmx. I try to avoid mmx as mmx is slower on 88 | the P4 than on the P3 and XP, but sse doesn't have integer math. 89 | 90 | You may want to set -msse2 if you have a P4 CPU (-msse2 is set by default 91 | for x86-64 CPUS), as some of the simd functions not supported on x86 92 | can be sped up by gcc using sse2 commands rather than standard pipeline 93 | commands. 94 | 95 | 96 | GCC PowerPC 97 | ----------- 98 | 99 | You must compile with the switch -maltivec 100 | 101 | 102 | GCC ARM (Xscale only) 103 | ---------------- 104 | 105 | GCC ARM only seems to support Intel Wirekess MMX (XSCALE), not ARMv6, 106 | Neon, or VFP? (Are these all the same beast?) 107 | 108 | You must compile with +iwmmxt 109 | 110 | 111 | */ 112 | -------------------------------------------------------------------------------- /basekit/simd_cph/test/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = gcc 3 | 4 | # X86 5 | #COPTS = -I../include -g -O2 -mmmx -msse 6 | #PLATFORM = X86 7 | DIS = objdump -d -S 8 | 9 | # EMULATED 10 | COPTS = -I../include -D__SIMD_EMU__ -g -O2 11 | PLATFORM = emu 12 | 13 | default: test_simd.c emulated 14 | ${CC} ${COPTS} -o test_simd_${PLATFORM} test_simd.c 15 | 16 | emulated: test_simd.c 17 | ${CC} ${COPTS} -D__SIMD_EMU__ -o test_simd_emu test_simd.c 18 | 19 | xdiff: default emulated 20 | ${DIS} test_simd_${PLATFORM} > test_simd_${PLATFORM}.dis 21 | ${DIS} test_simd_emu > test_simd_emu.dis 22 | xdiff test_simd_emu.dis test_simd_${PLATFORM}.dis 23 | 24 | clean: 25 | rm test_simd_${PLATFORM} test_simd_emu *.dis 26 | -------------------------------------------------------------------------------- /basekit/simd_cph/test/test_simd.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2004 Patrick Roberts 3 | 4 | This software is provided 'as-is', without any express 5 | or implied warranty. In no event will the authors be held 6 | liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any 9 | purpose, including commercial applications, and to alter it 10 | and redistribute it freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; 13 | you must not claim that you wrote the original software. 14 | If you use this software in a product, an acknowledgment in 15 | the product documentation would be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, 18 | and must not be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | 4. THIS LICENSE MAY NOT BE CHANGED, ASSIGNED, OR MIGRATED WITHOUT 23 | THE AUTHOR'S WRITTEN PERMISSION, WITH THE FOLLOWING EXCEPTIONS: 24 | 25 | a. This file may be included with GPL/LGPL licensed 26 | software, but you may not change the license this file 27 | is released under. 28 | */ 29 | 30 | 31 | /* uncomment the line below to force SIMD emulation C code */ 32 | /*#define __SIMD_EMU__ */ 33 | 34 | #include 35 | #include 36 | 37 | int main(void) { 38 | 39 | simd_m128 v0,v1,v2; 40 | 41 | simd_load4Floats(v1,2.0,2.0,2.0,2.0); 42 | simd_load4Floats(v2,10.0,20.0,30.0,40.0); 43 | 44 | printf("\nChecking 4f commands\n"); 45 | 46 | simd_print4Floats("v1 ",v1); 47 | simd_print4Floats("v2 ",v2); 48 | puts(""); 49 | 50 | /* v0 = v1 + v2 */ 51 | simd_4f_add(v1,v2,v0); 52 | simd_print4Floats("4f_add ",v0); 53 | 54 | /* v0 = v1 - v2 */ 55 | simd_4f_sub(v1,v2,v0); 56 | simd_print4Floats("4f_sub ",v0); 57 | 58 | /* v0 = v1 * v2 */ 59 | simd_4f_mult(v1,v2,v0); 60 | simd_print4Floats("4f_mult",v0); 61 | 62 | /* v0 = v1 / v2 */ 63 | simd_4f_div(v1,v2,v0); 64 | simd_print4Floats("4f_div",v0); 65 | 66 | /* 67 | * If you look at the disassembly of this section on an X86 processor, it will be 68 | * very tight, as X86 SSE/MMX only handles 2 regs- i.e. A+=B, instead of C=A+B. 69 | * For the best cross-platform performance, cater to the lowest demoninator and 70 | * write your code like this. 71 | */ 72 | 73 | printf("\ndisassembly test\n"); 74 | simd_4f_add(v1,v2,v1); 75 | simd_4f_mult(v1,v2,v1); 76 | simd_4f_sub(v1,v2,v1); 77 | simd_4f_div(v1,v2,v1); 78 | 79 | 80 | 81 | printf("\nChecking 4i commands\n"); 82 | 83 | simd_load4Ints(v1,20,30,40,50); 84 | simd_load4Ints(v2,2,3,4,5); 85 | 86 | simd_print4Ints("v1 ",v1); 87 | simd_print4Ints("v2 ",v2); 88 | puts(""); 89 | 90 | 91 | /* v0 = v1 + v2 */ 92 | simd_4i_add(v1,v2,v0); 93 | simd_print4Ints("4i_add ",v0); 94 | 95 | /* v0 = v1 - v2 */ 96 | simd_4i_sub(v1,v2,v0); 97 | simd_print4Ints("4i_sub ",v0); 98 | 99 | /* v0 = v1 * v2 */ 100 | simd_4i_mult(v1,v2,v0); 101 | simd_print4Ints("4i_mult",v0); 102 | 103 | /* v0 = v1 / v2 */ 104 | simd_4i_div(v1,v2,v0); 105 | simd_print4Ints("4i_div ",v0); 106 | 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /basekit/simd_cph/test/test_simd_emu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sniperpr/skipdbv2/0406880f08983ad9232be0d3cc0b9f8e2f9d10ef/basekit/simd_cph/test/test_simd_emu -------------------------------------------------------------------------------- /client/skbus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include // fcntl 7 | #include // close 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define MAGIC "magicv1 " 15 | #define MAGIC_LEN 8 16 | #define HEADER_LEN 8 17 | #define HEADER_PREFIX (MAGIC_LEN + HEADER_LEN) 18 | 19 | // TODO 20 | // disconnect and reconnect on each newline 21 | 22 | // Nasty globals for now 23 | // feel free to fork this example and clean it up 24 | EV_P; 25 | ev_io stdin_watcher; 26 | ev_io remote_w; 27 | ev_io send_w; 28 | int remote_fd; 29 | char* line = NULL; 30 | size_t len = 0; 31 | 32 | static void send_cb (EV_P_ ev_io *w, int revents) 33 | { 34 | char *p; 35 | 36 | if (revents & EV_WRITE) 37 | { 38 | puts ("remote ready for writing..."); 39 | 40 | p = malloc(HEADER_PREFIX + len + 1); 41 | sprintf(p, "%s%07d %s", MAGIC, len, line); 42 | puts(p); 43 | if (-1 == send(remote_fd, p, len + HEADER_PREFIX, 0)) { 44 | perror("echo send"); 45 | exit(EXIT_FAILURE); 46 | } 47 | free(p); 48 | 49 | // once the data is sent, stop notifications that 50 | // data can be sent until there is actually more 51 | // data to send 52 | ev_io_stop(EV_A_ &send_w); 53 | ev_io_set(&send_w, remote_fd, EV_READ); 54 | ev_io_start(EV_A_ &send_w); 55 | } 56 | else if (revents & EV_READ) 57 | { 58 | int n; 59 | char str[100] = ".\0"; 60 | 61 | printf("[r,remote]"); 62 | n = recv(remote_fd, str, 100, 0); 63 | if (n <= 0) { 64 | if (0 == n) { 65 | // an orderly disconnect 66 | puts("orderly disconnect"); 67 | ev_io_stop(EV_A_ &send_w); 68 | close(remote_fd); 69 | } else if (EAGAIN == errno) { 70 | puts("should never get in this state with libev"); 71 | } else { 72 | perror("recv"); 73 | } 74 | return; 75 | } 76 | printf("socket client said: %s", str); 77 | 78 | } 79 | } 80 | 81 | static void stdin_cb (EV_P_ ev_io *w, int revents) 82 | { 83 | int len2; // not sure if this is at all useful 84 | 85 | puts ("stdin written to, reading..."); 86 | len2 = getline(&line, &len, stdin); 87 | len = len2; 88 | //fprintf(stderr, "line=%s len2=%d len=%d\n", line, len2, len); 89 | ev_io_stop(EV_A_ &send_w); 90 | ev_io_set (&send_w, remote_fd, EV_READ | EV_WRITE); 91 | ev_io_start(EV_A_ &send_w); 92 | } 93 | 94 | static void remote_cb (EV_P_ ev_io *w, int revents) 95 | { 96 | puts ("connected, now watching stdin"); 97 | // Once the connection is established, listen to stdin 98 | ev_io_start(EV_A_ &stdin_watcher); 99 | // Once we're connected, that's the end of that 100 | ev_io_stop(EV_A_ &remote_w); 101 | } 102 | 103 | 104 | // Simply adds O_NONBLOCK to the file descriptor of choice 105 | int setnonblock(int fd) 106 | { 107 | int flags; 108 | 109 | flags = fcntl(fd, F_GETFL); 110 | flags |= O_NONBLOCK; 111 | return fcntl(fd, F_SETFL, flags); 112 | } 113 | 114 | static void connection_new(EV_P_ char* sock_path) { 115 | int len, opt = 0; 116 | struct sockaddr_un remote; 117 | 118 | if (-1 == (remote_fd = socket(AF_UNIX, SOCK_STREAM, 0))) { 119 | perror("socket"); 120 | exit(1); 121 | } 122 | 123 | //setsockopt(remote_fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); 124 | 125 | // Set it non-blocking 126 | if (-1 == setnonblock(remote_fd)) { 127 | perror("echo client socket nonblock"); 128 | exit(EXIT_FAILURE); 129 | } 130 | 131 | // this should be initialized before the connect() so 132 | // that no packets are dropped when initially sent? 133 | // http://cr.yp.to/docs/connect.html 134 | 135 | // initialize the connect callback so that it starts the stdin asap 136 | ev_io_init (&remote_w, remote_cb, remote_fd, EV_WRITE); 137 | ev_io_start(EV_A_ &remote_w); 138 | // initialize the send callback, but wait to start until there is data to write 139 | ev_io_init(&send_w, send_cb, remote_fd, EV_READ); 140 | ev_io_start(EV_A_ &send_w); 141 | 142 | remote.sun_family = AF_UNIX; 143 | strcpy(remote.sun_path, sock_path); 144 | len = strlen(remote.sun_path) + sizeof(remote.sun_family); 145 | 146 | if (-1 == connect(remote_fd, (struct sockaddr *)&remote, len)) { 147 | perror("connect"); 148 | //exit(1); 149 | } 150 | } 151 | 152 | int main (void) 153 | { 154 | loop = EV_DEFAULT; 155 | // initialise an io watcher, then start it 156 | // this one will watch for stdin to become readable 157 | setnonblock(0); 158 | ev_io_init(&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ); 159 | 160 | connection_new(EV_A_ "/tmp/.skipd_server_sock"); 161 | 162 | // now wait for events to arrive 163 | ev_loop(EV_A_ 0); 164 | 165 | // unloop was called, so exit 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /cross-arm-linux-gnueabihf.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # CMake Toolchain file for crosscompiling on ARM. 3 | # 4 | # This can be used when running cmake in the following way: 5 | # cd build/ 6 | # cmake .. -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake 7 | # 8 | #cmake28 -DCMAKE_TOOLCHAIN_FILE=../cross-arm-linux-gnueabihf.cmake -DLIBEV_LIBRARIES=/projects/arm/lib/libev.a -DLIBEV_INCLUDE_DIRS=/projects/arm/include .. 9 | 10 | set(CROSS_PATH /projects/asuswrt-merlin2/release/src-rt-6.x.4708/toolchains/hndtools-arm-linux-2.6.36-uclibc-4.5.3) 11 | 12 | # Target operating system name. 13 | set(CMAKE_SYSTEM_NAME Linux) 14 | 15 | # Name of C compiler. 16 | set(CMAKE_C_COMPILER "${CROSS_PATH}/bin/arm-brcm-linux-uclibcgnueabi-gcc") 17 | set(CMAKE_CXX_COMPILER "${CROSS_PATH}/bin/arm-brcm-linux-uclibcgnueabi-g++") 18 | 19 | # Where to look for the target environment. (More paths can be added here) 20 | set(CMAKE_FIND_ROOT_PATH "${CROSS_PATH}") 21 | 22 | # Adjust the default behavior of the FIND_XXX() commands: 23 | # search programs in the host environment only. 24 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 25 | 26 | # Search headers and libraries in the target environment only. 27 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 28 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 29 | 30 | -------------------------------------------------------------------------------- /debug.txt: -------------------------------------------------------------------------------- 1 | set args -d ./db/a 2 | b main 3 | -------------------------------------------------------------------------------- /jfile/JFile.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("JFile") 5 | docDescription(""" 6 | JFile - a journaled file 7 | 8 | How it works: 9 | 1. writes are made to a log file (file.log) 10 | 2. when commit is called, a JFILE_COMMITTED value and the length of the log is written to the log header 11 | 2.1 then the log writes are performed on output file 12 | 2.2 then log file header is set to JFILE_UNCOMMITTED 13 | 3. when JFile is opened, if it finds: 14 | 3.1 JFILE_UNCOMMITTED set in the log header 15 | it assumes the log is incomplete and overwrites it 16 | 3.2 JFILE_COMMITTED set in the log header 17 | it goes to step 2.1 18 | 19 | In this way, the output file is assured to be kept in a consistent state. 20 | """) 21 | */ 22 | 23 | #ifndef JFILE_DEFINED 24 | #define JFILE_DEFINED 1 25 | 26 | #include 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /* 34 | // expiremental 35 | #define JFILE_SUPPORTS_MMAP 1 36 | */ 37 | 38 | #define JFILE_UNCOMMITTED 0 39 | #define JFILE_COMMITTED 1 40 | 41 | typedef struct 42 | { 43 | char *path; 44 | FILE *file; 45 | 46 | char *logPath; 47 | FILE *log; 48 | 49 | long pos; 50 | long maxPos; 51 | 52 | unsigned char *buf; 53 | int journalingOn; 54 | int fullSync; 55 | size_t logHighWaterMark; 56 | } JFile; 57 | 58 | JFile *JFile_new(void); 59 | void JFile_free(JFile *self); 60 | 61 | void JFile_setJournalingOn_(JFile *self, int aBool); 62 | 63 | void JFile_setPath_(JFile *self, const char *path); 64 | void JFile_setLogPath_(JFile *self, const char *path); 65 | void JFile_setPath_withExtension_(JFile *self, const char *path, const char *ext); 66 | char *JFile_path(JFile *self); 67 | 68 | void JFile_open(JFile *self); 69 | void JFile_close(JFile *self); 70 | void JFile_delete(JFile *self); 71 | 72 | size_t JFile_fwrite(JFile *self, void *buf, size_t size, size_t nobjs); 73 | size_t JFile_fread(JFile *self, void *buf, size_t size, size_t nobjs); 74 | 75 | int JFile_fputc(JFile *self, int c); 76 | int JFile_fgetc(JFile *self); 77 | 78 | void JFile_writeInt_(JFile *self, int v); 79 | int JFile_readInt(JFile *self); 80 | 81 | void JFile_setPosition_(JFile *self, long pos); 82 | long JFile_setPositionToEnd(JFile *self); 83 | void JFile_fseek(JFile *self, long offset, int whence); 84 | long JFile_position(JFile *self); 85 | 86 | void JFile_begin(JFile *self); 87 | void JFile_commitToLog(JFile *self); // makes sure log is on disk 88 | void JFile_commitToFile(JFile *self); // writes log to file and makes sure changes are on disk 89 | void JFile_remove(JFile *self); 90 | 91 | void JFile_truncate_(JFile *self, off_t size); 92 | 93 | void JFile_setTrueFlush_(JFile *self, int aBool); 94 | size_t JFile_logSize(JFile *self); 95 | int JFile_needsSync(JFile *self); 96 | long JFile_lastCommitPosition(JFile *self); 97 | void JFile_clipLogToLastCompletedTransaction(JFile *self); 98 | void JFile_clipLog(JFile *self); 99 | //int JFile_hasUnfinishedCommits(JFile *self); 100 | int JFile_verifyLog(JFile *self); 101 | 102 | #ifdef __cplusplus 103 | } 104 | #endif 105 | #endif 106 | -------------------------------------------------------------------------------- /mgr/array-heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "array-heap.h" 5 | 6 | int array_init(array* arr, int size) { 7 | arr->data = realloc(NULL, sizeof(void*) * size); 8 | if (0 == (size_t)arr->data) { 9 | return -1; 10 | } 11 | arr->length = size; 12 | arr->index = 0; 13 | return 0; 14 | } 15 | 16 | int array_push(array* arr, void* data) { 17 | ((size_t*)arr->data)[arr->index] = (size_t)data; 18 | arr->index += 1; 19 | if (arr->index >= arr->length) { 20 | if (-1 == array_grow(arr, arr->length * 2)) 21 | { 22 | return -1; 23 | } 24 | } 25 | return arr->index - 1; 26 | } 27 | 28 | int array_grow(array* arr, int size) { 29 | if (size <= arr->length) { 30 | return -1; 31 | } 32 | arr->data = realloc(arr->data, sizeof(void*) * size); 33 | if (-1 == (size_t)arr->data) { 34 | return -1; 35 | } 36 | arr->length = size; 37 | return 0; 38 | } 39 | 40 | void array_free(array* arr, void (*free_element)(void*)) { 41 | int i; 42 | for (i = 0; i < arr->index; i += 1) { 43 | free_element((void*)((size_t*)arr->data)[i]); 44 | } 45 | free(arr->data); 46 | arr->index = -1; 47 | arr->length = 0; 48 | arr->data = NULL; 49 | } 50 | -------------------------------------------------------------------------------- /mgr/array-heap.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARRAY_HEAP_H__ 2 | #define __ARRAY_HEAP_H__ 3 | 4 | typedef struct { 5 | void* data; 6 | int index; 7 | int length; 8 | } array; 9 | 10 | int array_init(array* arr, int size); 11 | int array_push(array* arr, void* data); 12 | int array_grow(array* arr, int size); 13 | void array_free(array* arr, void (*free_element)(void*)); 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /mgr/coroutine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 协程实现,最开始见于putty软件的实现,文件头部有介绍。 3 | * 此版本有修改,不使用动态内存申请,内存由外部函数申请好。 4 | */ 5 | 6 | #ifndef COROUTINE_H 7 | #define COROUTINE_H 8 | 9 | #include 10 | 11 | #define COROUTINE_CONTEXT_LEN 64 12 | 13 | struct ccrContextTag { 14 | int ccrLine; 15 | /* 协程中用于临时内存交换 */ 16 | unsigned char stack_buf[COROUTINE_CONTEXT_LEN]; 17 | }; 18 | 19 | /* assert(sizeof(struct _stack_##__FUNCTION__) < COROUTINE_CONTEXT_LEN) 20 | * 未实现assert函数 */ 21 | #define TOKENPASTE(x, y) x ## y 22 | #define TOKENPASTE2(x, y) TOKENPASTE(x, y) 23 | #define TYPE_UNIQUE TOKENPASTE2(_statck_, __LINE__) 24 | #define ccrBeginContext typedef struct TYPE_UNIQUE { 25 | #define ccrEndContext(x) } TYPE_UNIQUE; TYPE_UNIQUE *CS; do { CS = (TYPE_UNIQUE*)(&((x)->stack_buf[0]));} while(0) 26 | 27 | #define ccrBegin(x) if (x){ \ 28 | switch((x)->ccrLine) { case 0:; 29 | #define ccrFinish(x,z) }} do { (x)->ccrLine = 0; return (z); } while(0) 30 | 31 | #define ccrReturn(x,z) \ 32 | do {\ 33 | (x)->ccrLine=__LINE__;\ 34 | return (z); case __LINE__:;\ 35 | } while (0) 36 | 37 | #define ccrStop(x,z) do{ (x)->ccrLine = 0; return (z); }while(0) 38 | 39 | #endif /* COROUTINE_H */ 40 | -------------------------------------------------------------------------------- /mgr/daemonize.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | void skipd_daemonize(char * path) 20 | { 21 | #ifndef __MINGW32__ 22 | /* Our process ID and Session ID */ 23 | pid_t pid, sid; 24 | 25 | /* Fork off the parent process */ 26 | pid = fork(); 27 | if (pid < 0) { 28 | exit(EXIT_FAILURE); 29 | } 30 | 31 | /* If we got a good PID, then 32 | we can exit the parent process. */ 33 | if (pid > 0) { 34 | FILE *file = fopen(path, "w"); 35 | if (file == NULL) { 36 | fprintf(stderr, "Invalid pid file\n"); 37 | } 38 | 39 | fprintf(file, "%d", pid); 40 | fclose(file); 41 | exit(EXIT_SUCCESS); 42 | } 43 | 44 | 45 | /* Cancel certain signals */ 46 | signal(SIGCHLD, SIG_DFL); /* A child process dies */ 47 | signal(SIGTSTP, SIG_IGN); /* Various TTY signals */ 48 | signal(SIGTTOU, SIG_IGN); 49 | signal(SIGTTIN, SIG_IGN); 50 | signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */ 51 | 52 | /* Change the file mode mask */ 53 | umask(0); 54 | 55 | /* Open any logs here */ 56 | 57 | /* Create a new SID for the child process */ 58 | sid = setsid(); 59 | if (sid < 0) { 60 | /* Log the failure */ 61 | exit(EXIT_FAILURE); 62 | } 63 | 64 | /* Change the current working directory */ 65 | if ((chdir("/")) < 0) { 66 | /* Log the failure */ 67 | exit(EXIT_FAILURE); 68 | } 69 | 70 | /* Redirect standard files to /dev/null */ 71 | if (!freopen("/dev/null", "r", stdin)) { 72 | fprintf(stderr, "unable to freopen() stdin, code %d (%s)", 73 | errno, strerror(errno)); 74 | } 75 | 76 | if (!freopen("/dev/null", "w", stdout)) { 77 | fprintf(stderr, "unable to freopen() stdout, code %d (%s)", 78 | errno, strerror(errno)); 79 | } 80 | 81 | if (!freopen("/dev/null", "w", stderr)) { 82 | fprintf(stderr, "unable to freopen() stderr, code %d (%s)", 83 | errno, strerror(errno)); 84 | } 85 | 86 | /* Close out the standard file descriptors */ 87 | /* close(STDIN_FILENO); 88 | close(STDOUT_FILENO); 89 | close(STDERR_FILENO); */ 90 | #endif 91 | } 92 | -------------------------------------------------------------------------------- /mgr/skipd.h: -------------------------------------------------------------------------------- 1 | #ifndef __SKIPD_H_ 2 | #define __SKIPD_H_ 3 | 4 | #define offsetof2(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 5 | #define container_of(ptr, type, member) ({ \ 6 | const typeof( ((type *)0)->member ) *__mptr = (const typeof( ((type *)0)->member )*)(ptr); \ 7 | (type *)( (char *)__mptr - offsetof2(type,member) );}) 8 | 9 | #define MAGIC "magicv1 " 10 | #define MAGIC_LEN 8 11 | #define HEADER_LEN 8 12 | #define HEADER_PREFIX (MAGIC_LEN + HEADER_LEN) 13 | #define SK_PATH_MAX 128 14 | #define BUF_MAX 2048 15 | #define READ_MAX 65536 16 | 17 | #define DELAY_PREFIX "__delay__" 18 | #define DELAY_PREFIX_LEN 9 19 | #define DELAY_KEY_LEN 128 20 | 21 | #define SKIPD_DEBUG 3 22 | 23 | #define _min(a,b) \ 24 | ({ __typeof__ (a) _a = (a); \ 25 | __typeof__ (b) _b = (b); \ 26 | _a > _b ? _b : _a; }) 27 | 28 | #define _max(a,b) \ 29 | ({ __typeof__ (a) _a = (a); \ 30 | __typeof__ (b) _b = (b); \ 31 | _a > _b ? _a : _b; }) 32 | 33 | typedef enum { 34 | S2ISUCCESS = 0, 35 | S2IOVERFLOW, 36 | S2IUNDERFLOW, 37 | S2IINCONVERTIBLE 38 | } STR2INT_ERROR; 39 | 40 | static STR2INT_ERROR str2int(int *i, char *s, int base) { 41 | char *end; 42 | long l; 43 | errno = 0; 44 | l = strtol(s, &end, base); 45 | 46 | if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) { 47 | return S2IOVERFLOW; 48 | } 49 | if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) { 50 | return S2IUNDERFLOW; 51 | } 52 | if (*s == '\0' || *end != '\0') { 53 | return S2IINCONVERTIBLE; 54 | } 55 | *i = l; 56 | return S2ISUCCESS; 57 | } 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /mgr/unix-echo-client.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include // fcntl 9 | #include // close 10 | 11 | // TODO 12 | // disconnect and reconnect on each newline 13 | 14 | // Nasty globals for now 15 | // feel free to fork this example and clean it up 16 | EV_P; 17 | ev_io stdin_watcher; 18 | ev_io remote_w; 19 | ev_io send_w; 20 | int remote_fd; 21 | char* line = NULL; 22 | size_t len = 0; 23 | 24 | static void send_cb (EV_P_ ev_io *w, int revents) 25 | { 26 | if (revents & EV_WRITE) 27 | { 28 | puts ("remote ready for writing..."); 29 | 30 | if (-1 == send(remote_fd, line, len, 0)) { 31 | perror("echo send"); 32 | exit(EXIT_FAILURE); 33 | } 34 | // once the data is sent, stop notifications that 35 | // data can be sent until there is actually more 36 | // data to send 37 | ev_io_stop(EV_A_ &send_w); 38 | ev_io_set(&send_w, remote_fd, EV_READ); 39 | ev_io_start(EV_A_ &send_w); 40 | } 41 | else if (revents & EV_READ) 42 | { 43 | int n; 44 | char str[100] = ".\0"; 45 | 46 | printf("[r,remote]"); 47 | n = recv(remote_fd, str, 100, 0); 48 | if (n <= 0) { 49 | if (0 == n) { 50 | // an orderly disconnect 51 | puts("orderly disconnect"); 52 | ev_io_stop(EV_A_ &send_w); 53 | close(remote_fd); 54 | } else if (EAGAIN == errno) { 55 | puts("should never get in this state with libev"); 56 | } else { 57 | perror("recv"); 58 | } 59 | return; 60 | } 61 | printf("socket client said: %s", str); 62 | 63 | } 64 | } 65 | 66 | static void stdin_cb (EV_P_ ev_io *w, int revents) 67 | { 68 | int len2; // not sure if this is at all useful 69 | 70 | puts ("stdin written to, reading..."); 71 | len2 = getline(&line, &len, stdin); 72 | ev_io_stop(EV_A_ &send_w); 73 | ev_io_set (&send_w, remote_fd, EV_READ | EV_WRITE); 74 | ev_io_start(EV_A_ &send_w); 75 | } 76 | 77 | static void remote_cb (EV_P_ ev_io *w, int revents) 78 | { 79 | puts ("connected, now watching stdin"); 80 | // Once the connection is established, listen to stdin 81 | ev_io_start(EV_A_ &stdin_watcher); 82 | // Once we're connected, that's the end of that 83 | ev_io_stop(EV_A_ &remote_w); 84 | } 85 | 86 | 87 | // Simply adds O_NONBLOCK to the file descriptor of choice 88 | int setnonblock(int fd) 89 | { 90 | int flags; 91 | 92 | flags = fcntl(fd, F_GETFL); 93 | flags |= O_NONBLOCK; 94 | return fcntl(fd, F_SETFL, flags); 95 | } 96 | 97 | static void connection_new(EV_P_ char* sock_path) { 98 | int len; 99 | struct sockaddr_un remote; 100 | 101 | if (-1 == (remote_fd = socket(AF_UNIX, SOCK_STREAM, 0))) { 102 | perror("socket"); 103 | exit(1); 104 | } 105 | 106 | // Set it non-blocking 107 | if (-1 == setnonblock(remote_fd)) { 108 | perror("echo client socket nonblock"); 109 | exit(EXIT_FAILURE); 110 | } 111 | 112 | // this should be initialized before the connect() so 113 | // that no packets are dropped when initially sent? 114 | // http://cr.yp.to/docs/connect.html 115 | 116 | // initialize the connect callback so that it starts the stdin asap 117 | ev_io_init (&remote_w, remote_cb, remote_fd, EV_WRITE); 118 | ev_io_start(EV_A_ &remote_w); 119 | // initialize the send callback, but wait to start until there is data to write 120 | ev_io_init(&send_w, send_cb, remote_fd, EV_READ); 121 | ev_io_start(EV_A_ &send_w); 122 | 123 | remote.sun_family = AF_UNIX; 124 | strcpy(remote.sun_path, sock_path); 125 | len = strlen(remote.sun_path) + sizeof(remote.sun_family); 126 | 127 | if (-1 == connect(remote_fd, (struct sockaddr *)&remote, len)) { 128 | perror("connect"); 129 | //exit(1); 130 | } 131 | } 132 | 133 | int main (void) 134 | { 135 | loop = EV_DEFAULT; 136 | // initialise an io watcher, then start it 137 | // this one will watch for stdin to become readable 138 | setnonblock(0); 139 | ev_io_init(&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ); 140 | 141 | connection_new(EV_A_ "/tmp/libev-echo.sock"); 142 | 143 | // now wait for events to arrive 144 | ev_loop(EV_A_ 0); 145 | 146 | // unloop was called, so exit 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /mgr/unix-echo-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | //#include 13 | #define g_warning printf 14 | 15 | //#include 16 | #include 17 | 18 | #include "array-heap.h" 19 | 20 | struct sock_ev_serv { 21 | ev_io io; 22 | int fd; 23 | struct sockaddr_un socket; 24 | int socket_len; 25 | array clients; 26 | }; 27 | 28 | struct sock_ev_client { 29 | ev_io io; 30 | int fd; 31 | int index; 32 | struct sock_ev_serv* server; 33 | }; 34 | 35 | int setnonblock(int fd); 36 | static void not_blocked(EV_P_ ev_periodic *w, int revents); 37 | 38 | // This callback is called when client data is available 39 | static void client_cb(EV_P_ ev_io *w, int revents) { 40 | // a client has become readable 41 | 42 | struct sock_ev_client* client = (struct sock_ev_client*) w; 43 | 44 | int n; 45 | char str[100] = ".\0"; 46 | 47 | printf("[r]"); 48 | n = recv(client->fd, str, 100, 0); 49 | if (n <= 0) { 50 | if (0 == n) { 51 | // an orderly disconnect 52 | puts("orderly disconnect"); 53 | ev_io_stop(EV_A_ &client->io); 54 | close(client->fd); 55 | } else if (EAGAIN == errno) { 56 | puts("should never get in this state with libev"); 57 | } else { 58 | perror("recv"); 59 | } 60 | return; 61 | } 62 | printf("socket client said: %s", str); 63 | 64 | // Assuming that whenever a client is readable, it is also writable ? 65 | if (send(client->fd, str, n, 0) < 0) { 66 | perror("send"); 67 | } 68 | } 69 | 70 | inline static struct sock_ev_client* client_new(int fd) { 71 | struct sock_ev_client* client; 72 | 73 | client = realloc(NULL, sizeof(struct sock_ev_client)); 74 | client->fd = fd; 75 | //client->server = server; 76 | setnonblock(client->fd); 77 | ev_io_init(&client->io, client_cb, client->fd, EV_READ); 78 | 79 | return client; 80 | } 81 | 82 | // This callback is called when data is readable on the unix socket. 83 | static void server_cb(EV_P_ ev_io *w, int revents) { 84 | puts("unix stream socket has become readable"); 85 | 86 | int client_fd; 87 | struct sock_ev_client* client; 88 | 89 | // since ev_io is the first member, 90 | // watcher `w` has the address of the 91 | // start of the sock_ev_serv struct 92 | struct sock_ev_serv* server = (struct sock_ev_serv*) w; 93 | 94 | while (1) 95 | { 96 | client_fd = accept(server->fd, NULL, NULL); 97 | if( client_fd == -1 ) 98 | { 99 | if( errno != EAGAIN && errno != EWOULDBLOCK ) 100 | { 101 | g_warning("accept() failed errno=%i (%s)", errno, strerror(errno)); 102 | exit(EXIT_FAILURE); 103 | } 104 | break; 105 | } 106 | puts("accepted a client"); 107 | client = client_new(client_fd); 108 | client->server = server; 109 | client->index = array_push(&server->clients, client); 110 | ev_io_start(EV_A_ &client->io); 111 | } 112 | } 113 | 114 | // Simply adds O_NONBLOCK to the file descriptor of choice 115 | int setnonblock(int fd) 116 | { 117 | int flags; 118 | 119 | flags = fcntl(fd, F_GETFL); 120 | flags |= O_NONBLOCK; 121 | return fcntl(fd, F_SETFL, flags); 122 | } 123 | 124 | int unix_socket_init(struct sockaddr_un* socket_un, char* sock_path, int max_queue) { 125 | int fd; 126 | 127 | unlink(sock_path); 128 | 129 | // Setup a unix socket listener. 130 | fd = socket(AF_UNIX, SOCK_STREAM, 0); 131 | if (-1 == fd) { 132 | perror("echo server socket"); 133 | exit(EXIT_FAILURE); 134 | } 135 | 136 | // Set it non-blocking 137 | if (-1 == setnonblock(fd)) { 138 | perror("echo server socket nonblock"); 139 | exit(EXIT_FAILURE); 140 | } 141 | 142 | // Set it as unix socket 143 | socket_un->sun_family = AF_UNIX; 144 | strcpy(socket_un->sun_path, sock_path); 145 | 146 | return fd; 147 | } 148 | 149 | int server_init(struct sock_ev_serv* server, char* sock_path, int max_queue) { 150 | server->fd = unix_socket_init(&server->socket, sock_path, max_queue); 151 | server->socket_len = sizeof(server->socket.sun_family) + strlen(server->socket.sun_path); 152 | 153 | array_init(&server->clients, 128); 154 | 155 | if (-1 == bind(server->fd, (struct sockaddr*) &server->socket, server->socket_len)) 156 | { 157 | perror("echo server bind"); 158 | exit(EXIT_FAILURE); 159 | } 160 | 161 | if (-1 == listen(server->fd, max_queue)) { 162 | perror("listen"); 163 | exit(EXIT_FAILURE); 164 | } 165 | return 0; 166 | } 167 | 168 | int main(void) { 169 | int max_queue = 128; 170 | struct sock_ev_serv server; 171 | struct ev_periodic every_few_seconds; 172 | // Create our single-loop for this single-thread application 173 | EV_P = ev_default_loop(0); 174 | 175 | // Create unix socket in non-blocking fashion 176 | server_init(&server, "/tmp/libev-echo.sock", max_queue); 177 | 178 | // To be sure that we aren't actually blocking 179 | ev_periodic_init(&every_few_seconds, not_blocked, 0, 5, 0); 180 | ev_periodic_start(EV_A_ &every_few_seconds); 181 | 182 | // Get notified whenever the socket is ready to read 183 | ev_io_init(&server.io, server_cb, server.fd, EV_READ); 184 | ev_io_start(EV_A_ &server.io); 185 | 186 | // Run our loop, ostensibly forever 187 | puts("unix-socket-echo starting...\n"); 188 | ev_loop(EV_A_ 0); 189 | 190 | // This point is only ever reached if the loop is manually exited 191 | close(server.fd); 192 | return EXIT_SUCCESS; 193 | } 194 | 195 | 196 | static void not_blocked(EV_P_ ev_periodic *w, int revents) { 197 | puts("I'm not blocked"); 198 | } 199 | -------------------------------------------------------------------------------- /skipdb/SkipDB.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("SkipDB") 5 | docDescription("A sorted key/value pair database implemented with skip lists on top of UDB.") 6 | */ 7 | 8 | #ifndef SkipDB_DEFINED 9 | #define SkipDB_DEFINED 1 10 | 11 | #if !defined(__MINGW32__) && defined(WIN32) 12 | #if defined(BUILDING_SKIPDB_DLL) || defined(BUILDING_IOVMALL_DLL) 13 | #define SKIPDB_API __declspec(dllexport) 14 | #else 15 | #define SKIPDB_API __declspec(dllimport) 16 | #endif 17 | #else 18 | #define SKIPDB_API 19 | #endif 20 | 21 | 22 | #include "SkipDBRecord.h" 23 | #include "UDB.h" 24 | #include "PHash.h" 25 | #include "RandomGen.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | 31 | // if prob. dist = 0.5, then max level 32 is enough for 2^32 records 32 | 33 | //#define SKIPDB_MAX_LEVEL 32 34 | #define SKIPDB_MAX_LEVEL 16 35 | #define SKIPDB_PROBABILITY_DISTRIBUTION 0.5 36 | 37 | typedef void (SkipDBObjectMarkFunc)(void *); 38 | typedef void (SkipDBFreeObjectFunc)(void *); 39 | 40 | typedef struct 41 | { 42 | UDB *udb; 43 | 44 | void *dbm; 45 | PID_TYPE headerPid; 46 | SkipDBRecord *header; 47 | SkipDBRecord *youngestRecord; // most recently accessed 48 | 49 | SkipDBRecord *update[SKIPDB_MAX_LEVEL]; 50 | float p; 51 | 52 | BStream *stream; 53 | SkipDBObjectMarkFunc *objectMarkFunc; 54 | SkipDBFreeObjectFunc *objectFreeFunc; 55 | List *cursors; 56 | 57 | List *dirtyRecords; 58 | List *pidsToRemove; 59 | 60 | size_t cachedRecordCount; 61 | size_t cacheHighWaterMark; 62 | size_t cacheLowWaterMark; 63 | unsigned char mark; // current record mark identifier 64 | PHash *pidToRecord; 65 | RandomGen *randomGen; 66 | } SkipDB; 67 | 68 | #include "SkipDBCursor.h" 69 | 70 | SKIPDB_API SkipDB *SkipDB_new(void); 71 | SKIPDB_API void SkipDB_setPath_(SkipDB *self, char *path); 72 | SKIPDB_API int SkipDB_open(SkipDB *self); 73 | SKIPDB_API void SkipDB_close(SkipDB *self); 74 | SKIPDB_API void SkipDB_free(SkipDB *self); 75 | 76 | SKIPDB_API void SkipDB_retain(SkipDB *self); 77 | SKIPDB_API void SkipDB_release(SkipDB *self); 78 | 79 | SKIPDB_API BStream *SkipDB_tmpStream(SkipDB *self); 80 | 81 | SKIPDB_API void SkipDB_headerPid_(SkipDB *self, PID_TYPE pid); 82 | SKIPDB_API PID_TYPE SkipDB_headerPid(SkipDB *self); 83 | SKIPDB_API SkipDBRecord *SkipDB_headerRecord(SkipDB *self); 84 | 85 | SKIPDB_API UDB *SkipDB_udb(SkipDB *self); 86 | SKIPDB_API int SkipDB_isOpen(SkipDB *self); 87 | SKIPDB_API void SkipDB_delete(SkipDB *self); 88 | 89 | // notifications 90 | 91 | SKIPDB_API void SkipDB_noteNewRecord_(SkipDB *self, SkipDBRecord *r); 92 | SKIPDB_API void SkipDB_noteAccessedRecord_(SkipDB *self, SkipDBRecord *r); 93 | SKIPDB_API void SkipDB_noteDirtyRecord_(SkipDB *self, SkipDBRecord *r); 94 | SKIPDB_API void SkipDB_noteAssignedPidToRecord_(SkipDB *self, SkipDBRecord *r); 95 | SKIPDB_API void SkipDB_noteWillFreeRecord_(SkipDB *self, SkipDBRecord *r); 96 | 97 | // cache 98 | 99 | SKIPDB_API void SkipDB_setCacheHighWaterMark_(SkipDB *self, size_t recordCount); 100 | SKIPDB_API size_t SkipDB_cacheHighWaterMark(SkipDB *self); 101 | 102 | SKIPDB_API void SkipDB_setCacheLowWaterMark_(SkipDB *self, size_t recordCount); 103 | SKIPDB_API size_t SkipDB_cacheLowWaterMark(SkipDB *self); 104 | 105 | SKIPDB_API void SkipDB_clearCache(SkipDB *self); 106 | SKIPDB_API void SkipDB_freeAllCachedRecords(SkipDB *self); 107 | SKIPDB_API int SkipDB_headerIsEmpty(SkipDB *self); 108 | 109 | // transactions 110 | 111 | SKIPDB_API void SkipDB_beginTransaction(SkipDB *self); 112 | SKIPDB_API void SkipDB_commitTransaction(SkipDB *self); 113 | 114 | SKIPDB_API void SkipDB_sync(SkipDB *self); 115 | SKIPDB_API void SkipDB_removeDirtyRecordsFromSavedRecords(SkipDB *self); 116 | SKIPDB_API void SkipDB_saveDirtyRecords(SkipDB *self); 117 | void SkipDB_deleteRecordsToRemove(SkipDB *self); 118 | 119 | // record api 120 | 121 | SKIPDB_API SkipDBRecord *SkipDB_recordAt_(SkipDB *self, Datum k); 122 | SKIPDB_API SkipDBRecord *SkipDB_recordAt_put_(SkipDB *self, Datum k, Datum v); 123 | SKIPDB_API int SkipDB_replace_put_(SkipDB *self, Datum k, Datum v); 124 | 125 | // bdb style api 126 | 127 | SKIPDB_API int SkipDB_at_put_(SkipDB *self, Datum k, Datum v); 128 | SKIPDB_API Datum SkipDB_at_(SkipDB *self, Datum k); 129 | SKIPDB_API void SkipDB_removeAt_(SkipDB *self, Datum k); 130 | 131 | // compact 132 | 133 | SKIPDB_API int SkipDB_compact(SkipDB *self); 134 | 135 | // debugging 136 | 137 | SKIPDB_API void SkipDB_showUpdate(SkipDB *self); 138 | SKIPDB_API void SkipDB_show(SkipDB *self); 139 | 140 | // private 141 | 142 | SKIPDB_API void SkipDB_updateAt_put_(SkipDB *self, int level, SkipDBRecord *r); 143 | SKIPDB_API SkipDBRecord *SkipDB_recordAtPid_(SkipDB *self, PID_TYPE pid); 144 | 145 | // objects 146 | 147 | SKIPDB_API void SkipDB_objectMarkFunc_(SkipDB *self, SkipDBObjectMarkFunc *func); 148 | SKIPDB_API void SkipDB_freeObjectCallback_(SkipDB *, SkipDBFreeObjectFunc *func); 149 | 150 | // cursor 151 | 152 | SKIPDB_API int SkipDB_count(SkipDB *self); 153 | 154 | SKIPDB_API SkipDBRecord *SkipDB_firstRecord(SkipDB *self); 155 | SKIPDB_API SkipDBRecord *SkipDB_lastRecord(SkipDB *self); 156 | SKIPDB_API SkipDBRecord *SkipDB_goto_(SkipDB *self, Datum key); 157 | 158 | SKIPDB_API SkipDBCursor *SkipDB_createCursor(SkipDB *self); 159 | SKIPDB_API void SkipDB_removeCursor_(SkipDB *self, SkipDBCursor *cursor); 160 | 161 | // moving from in-memory to on-disk 162 | 163 | SKIPDB_API void SkipDB_mergeInto_(SkipDB *self, SkipDB *other); 164 | 165 | SKIPDB_API int SkipDB_exists(SkipDB *self, Datum key); 166 | typedef void (*skipdb_list_callback)(SkipDB* self, SkipDBRecord* rc, void* ctx); 167 | SKIPDB_API void SkipDB_list_prefix(SkipDB* self, Datum k, void* ctx, skipdb_list_callback callback); 168 | 169 | #ifdef __cplusplus 170 | } 171 | #endif 172 | #endif 173 | -------------------------------------------------------------------------------- /skipdb/SkipDBCursor.c: -------------------------------------------------------------------------------- 1 | /*#io 2 | SkipDBCursor ioDoc( 3 | docCopyright("Steve Dekorte", 2004) 4 | docLicense("BSD revised") 5 | docObject("SkipDBCursor") 6 | docDescription("A cursor for a skipdb.") 7 | */ 8 | 9 | #include "SkipDBCursor.h" 10 | 11 | SkipDBCursor *SkipDBCursor_new(void) 12 | { 13 | SkipDBCursor *self = (SkipDBCursor *)calloc(1, sizeof(SkipDBCursor)); 14 | SkipDBCursor_retain(self); 15 | return self; 16 | } 17 | 18 | SkipDBCursor *SkipDBCursor_newWithDB_(SkipDB *sdb) 19 | { 20 | SkipDBCursor *self = SkipDBCursor_new(); 21 | self->sdb = sdb; 22 | return self; 23 | } 24 | 25 | void SkipDBCursor_retain(SkipDBCursor *self) 26 | { 27 | self->refCount ++; 28 | } 29 | 30 | void SkipDBCursor_dealloc(SkipDBCursor *self) 31 | { 32 | if (self->sdb) SkipDB_removeCursor_(self->sdb, self); 33 | free(self); 34 | } 35 | 36 | void SkipDBCursor_release(SkipDBCursor *self) 37 | { 38 | self->refCount --; 39 | 40 | if (self->refCount == 0) 41 | { 42 | SkipDBCursor_dealloc(self); 43 | } 44 | } 45 | 46 | void SkipDBCursor_mark(SkipDBCursor *self) 47 | { 48 | if (self->record) 49 | { 50 | SkipDBRecord_mark(self->record); 51 | } 52 | } 53 | 54 | SkipDBRecord *SkipDBCursor_goto_(SkipDBCursor *self, Datum key) 55 | { 56 | return (self->record = SkipDB_goto_((SkipDB *)(self->sdb), key)); 57 | } 58 | 59 | SkipDBRecord *SkipDBCursor_first(SkipDBCursor *self) 60 | { 61 | return (self->record = SkipDB_firstRecord(self->sdb)); 62 | } 63 | 64 | SkipDBRecord *SkipDBCursor_last(SkipDBCursor *self) 65 | { 66 | return (self->record = SkipDB_lastRecord(self->sdb)); 67 | } 68 | 69 | SkipDBRecord *SkipDBCursor_current(SkipDBCursor *self) 70 | { 71 | return self->record; 72 | } 73 | 74 | SkipDBRecord *SkipDBCursor_previous(SkipDBCursor *self) 75 | { 76 | if (self->record) 77 | { 78 | self->record = SkipDBRecord_previousRecord(self->record); 79 | 80 | if (self->record == SkipDB_headerRecord(self->sdb)) 81 | { 82 | self->record = NULL; 83 | } 84 | } 85 | return self->record; 86 | } 87 | 88 | SkipDBRecord *SkipDBCursor_next(SkipDBCursor *self) 89 | { 90 | if (!self->record) 91 | { 92 | return NULL; 93 | } 94 | 95 | return (self->record = SkipDBRecord_nextRecord(self->record)); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /skipdb/SkipDBCursor.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("SkipDBCursor") 5 | docDescription("A cursor for a skipdb.") 6 | */ 7 | 8 | 9 | #ifndef SkipDBCursor_DEFINED 10 | #define SkipDBCursor_DEFINED 1 11 | 12 | typedef struct SkipDBCursor SkipDBCursor; 13 | 14 | #include "SkipDB.h" 15 | #include 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | struct SkipDBCursor 23 | { 24 | int refCount; 25 | SkipDB *sdb; 26 | SkipDBRecord *record; 27 | }; 28 | 29 | SKIPDB_API SkipDBCursor *SkipDBCursor_new(void); 30 | SKIPDB_API SkipDBCursor *SkipDBCursor_newWithDB_(SkipDB *sdb); 31 | SKIPDB_API void SkipDBCursor_sdb_(SkipDB *sdb); 32 | SKIPDB_API void SkipDBCursor_retain(SkipDBCursor *self); 33 | SKIPDB_API void SkipDBCursor_release(SkipDBCursor *self); 34 | SKIPDB_API void SkipDBCursor_mark(SkipDBCursor *self); 35 | 36 | SKIPDB_API SkipDBRecord *SkipDBCursor_goto_(SkipDBCursor *self, Datum key); 37 | 38 | SKIPDB_API SkipDBRecord *SkipDBCursor_first(SkipDBCursor *self); 39 | SKIPDB_API SkipDBRecord *SkipDBCursor_last(SkipDBCursor *self); 40 | 41 | SKIPDB_API SkipDBRecord *SkipDBCursor_previous(SkipDBCursor *self); 42 | SKIPDB_API SkipDBRecord *SkipDBCursor_current(SkipDBCursor *self); 43 | SKIPDB_API SkipDBRecord *SkipDBCursor_next(SkipDBCursor *self); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | #endif 49 | -------------------------------------------------------------------------------- /skipdb/SkipDBRecord.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("SkipDBRecord") 5 | docDescription("A skip list record.") 6 | */ 7 | 8 | #ifndef SkipDBRecord_DEFINED 9 | #define SkipDBRecord_DEFINED 1 10 | 11 | #include "List.h" 12 | #include "BStream.h" 13 | #include "UDB.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | typedef struct SkipDBRecord SkipDBRecord; 20 | typedef struct SkipDBPointer SkipDBPointer; 21 | 22 | #define SKIPDBRECORD_UNMARKED 0 23 | #define SKIPDBRECORD_MARKED 1 24 | 25 | struct SkipDBPointer 26 | { 27 | PID_TYPE pid; 28 | unsigned char matchingPrefixSize; 29 | SkipDBRecord *record; 30 | }; 31 | 32 | struct SkipDBRecord 33 | { 34 | int level; 35 | SkipDBPointer *pointers; 36 | 37 | PID_TYPE previousPid; 38 | SkipDBRecord *previousRecord; 39 | 40 | UArray *key; 41 | UArray *value; 42 | 43 | void *sdb; 44 | PID_TYPE pid; 45 | void *object; // extra pointer for user to make use of - not stored 46 | int ownsKey; 47 | uint8_t isDirty; 48 | 49 | // cache related 50 | 51 | SkipDBRecord *youngerRecord; // accessed before self 52 | SkipDBRecord *olderRecord; // accessed after self 53 | unsigned char mark; 54 | }; 55 | 56 | SKIPDB_API int SkipDBRecord_pointersAreEmpty(SkipDBRecord *self); 57 | 58 | SKIPDB_API SkipDBRecord *SkipDBRecord_new(void); 59 | SKIPDB_API SkipDBRecord *SkipDBRecord_newWithDB_(void *db); 60 | 61 | SKIPDB_API void SkipDBRecord_setOlderRecord_(SkipDBRecord *self, SkipDBRecord *r); 62 | SKIPDB_API SkipDBRecord *SkipDBRecord_olderRecord(SkipDBRecord *self); 63 | 64 | SKIPDB_API void SkipDBRecord_setYoungerRecord_(SkipDBRecord *self, SkipDBRecord *r); 65 | SKIPDB_API SkipDBRecord *SkipDBRecord_youngerRecord(SkipDBRecord *self); 66 | 67 | SKIPDB_API void SkipDBRecord_removeFromAgeList(SkipDBRecord *self); 68 | 69 | SKIPDB_API void SkipDBRecord_removeReferencesToUnmarked(SkipDBRecord *self); 70 | 71 | SKIPDB_API void SkipDBRecord_dealloc(SkipDBRecord *self); 72 | 73 | SKIPDB_API void SkipDBRecord_db_(SkipDBRecord *self, void *db); 74 | 75 | SKIPDB_API void SkipDBRecord_pid_(SkipDBRecord *self, PID_TYPE pid); 76 | SKIPDB_API PID_TYPE SkipDBRecord_pid(SkipDBRecord *self); 77 | SKIPDB_API PID_TYPE SkipDBRecord_pidAllocIfNeeded(SkipDBRecord *self); 78 | 79 | SKIPDB_API int SkipDBRecord_level(SkipDBRecord *self); 80 | SKIPDB_API void SkipDBRecord_level_(SkipDBRecord *self, int level); 81 | 82 | SKIPDB_API void SkipDBRecord_mark(SkipDBRecord *self); 83 | 84 | SKIPDB_API uint8_t SkipDBRecord_isDirty(SkipDBRecord *self); 85 | SKIPDB_API void SkipDBRecord_markAsDirty(SkipDBRecord *self); 86 | SKIPDB_API void SkipDBRecord_markAsClean(SkipDBRecord *self); 87 | 88 | SKIPDB_API void SkipDBRecord_atLevel_setPid_(SkipDBRecord *self, int level, PID_TYPE pid); 89 | SKIPDB_API PID_TYPE SkipDBRecord_pidAtLevel_(SkipDBRecord *self, int level); 90 | 91 | SKIPDB_API void SkipDBRecord_atLevel_setRecord_(SkipDBRecord *self, int level, SkipDBRecord *r); 92 | SKIPDB_API SkipDBRecord *SkipDBRecord_recordAtLevel_(SkipDBRecord *self, int level); 93 | 94 | SKIPDB_API void SkipDBRecord_copyLevel_from_(SkipDBRecord *self, int level, SkipDBRecord *other); 95 | 96 | //-------------------------------------------- 97 | 98 | SKIPDB_API void SkipDBRecord_keyDatum_(SkipDBRecord *self, Datum k); 99 | SKIPDB_API Datum SkipDBRecord_keyDatum(SkipDBRecord *self); 100 | SKIPDB_API UArray *SkipDBRecord_key(SkipDBRecord *self); 101 | 102 | SKIPDB_API void SkipDBRecord_valueDatum_(SkipDBRecord *self, Datum v); 103 | SKIPDB_API Datum SkipDBRecord_valueDatum(SkipDBRecord *self); 104 | SKIPDB_API UArray *SkipDBRecord_value(SkipDBRecord *self); 105 | 106 | // serialization ----------------------------- 107 | 108 | SKIPDB_API void SkipDBRecord_toStream_(SkipDBRecord *self, BStream *s); 109 | SKIPDB_API void SkipDBRecord_fromStream_(SkipDBRecord *self, BStream *s); 110 | SKIPDB_API void SkipDBRecord_save(SkipDBRecord *self); 111 | 112 | // search ------------------------------------ 113 | 114 | SKIPDB_API SkipDBRecord *SkipDBRecord_find_quick_(SkipDBRecord *self, Datum key, int quick); 115 | SkipDBRecord *SkipDBRecord_findLastRecord(SkipDBRecord *self); 116 | 117 | SKIPDB_API void SkipDBRecord_willRemove_(SkipDBRecord *self, SkipDBRecord *other); 118 | 119 | SKIPDB_API void SkipDBRecord_show(SkipDBRecord *self); 120 | 121 | // object ------------------------------------ 122 | 123 | SKIPDB_API void SkipDBRecord_object_(SkipDBRecord *self, void *object); 124 | SKIPDB_API void *SkipDBRecord_object(SkipDBRecord *self); 125 | 126 | // next ------------------------------------ 127 | 128 | SKIPDB_API SkipDBRecord *SkipDBRecord_nextRecord(SkipDBRecord *self); 129 | 130 | // previous ------------------------------------ 131 | 132 | SKIPDB_API void SkipDBRecord_previousPid_(SkipDBRecord *self, PID_TYPE pid); 133 | SKIPDB_API PID_TYPE SkipDBRecord_previousPid(SkipDBRecord *self); 134 | 135 | SKIPDB_API void SkipDBRecord_previousRecord_(SkipDBRecord *self, SkipDBRecord *r); 136 | SKIPDB_API SkipDBRecord *SkipDBRecord_previousRecord(SkipDBRecord *self); 137 | 138 | #ifdef __cplusplus 139 | } 140 | #endif 141 | #endif 142 | -------------------------------------------------------------------------------- /tests/check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COUNTER=0 4 | V="your are the best" 5 | K="hello" 6 | eval `../build/bin/dbus export hello` 7 | while [ $COUNTER -lt 10000 ]; do 8 | eval "KV=$"$K$COUNTER 9 | if [ "$KV" != "$V$COUNTER" ]; then 10 | echo "$KV $V$COUNTER" 11 | fi 12 | let COUNTER=COUNTER+1 13 | done 14 | -------------------------------------------------------------------------------- /tests/env.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | //TODO for shell env 7 | int main(int argc, char **argv, char * envp[]) 8 | { 9 | char** env; 10 | char* this_env; 11 | char *v; 12 | 13 | for (env = envp; *env != 0; env++) { 14 | this_env = (char*)strdup(*env); 15 | v = strstr(this_env, "="); 16 | if(v != NULL) { 17 | *v = '\0'; 18 | v += 1; 19 | printf("%s=%s\n", this_env, v); 20 | } 21 | if(this_env != NULL) { 22 | free(this_env); 23 | } 24 | } 25 | putenv("SomeVariable=SomeValue"); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/example.c: -------------------------------------------------------------------------------- 1 | #include "SkipDB.h" 2 | 3 | int main(void) 4 | { 5 | Datum key; 6 | Datum value; 7 | Datum key2; 8 | Datum value2; 9 | int count; 10 | 11 | // open 12 | 13 | SkipDB *db = SkipDB_new(); 14 | SkipDB_setPath_(db, "test.skipdb"); 15 | if(0 == SkipDB_open(db)) { 16 | SkipDB_beginTransaction(db); 17 | key = Datum_FromCString_("__inner__"); 18 | value = Datum_FromCString_("__begin__"); 19 | SkipDB_commitTransaction(db); 20 | SkipDB_close(db); 21 | SkipDB_open(db); 22 | } 23 | 24 | // write 25 | 26 | #if 0 27 | SkipDB_beginTransaction(db); 28 | key = Datum_FromCString_("testKey"); 29 | value = Datum_FromCString_("testValue"); 30 | SkipDB_at_put_(db, key, value); 31 | 32 | key2 = Datum_FromCString_("testKey2"); 33 | value2 = Datum_FromCString_("testValue2"); 34 | SkipDB_at_put_(db, key2, value2); 35 | 36 | SkipDB_commitTransaction(db); 37 | #else 38 | key = Datum_FromCString_("testKey"); 39 | key2 = Datum_FromCString_("testKey2"); 40 | //key = Datum_FromCString_("testKey88"); 41 | //key2 = Datum_FromCString_("testKey233"); 42 | #endif 43 | SkipDB_show(db); 44 | 45 | // read 46 | value = SkipDB_at_(db, key); 47 | printf("%s=%s\n", key.data, value.data); 48 | 49 | value2 = SkipDB_at_(db, key2); 50 | printf("%s=%s\n", key2.data, value2.data); 51 | 52 | // count 53 | 54 | count = SkipDB_count(db); 55 | 56 | // remove 57 | 58 | //SkipDB_beginTransaction(db); 59 | //SkipDB_removeAt_(db, key); 60 | //SkipDB_commitTransaction(db); 61 | 62 | // there's also a cursor API 63 | // not shown in this example code 64 | 65 | // close 66 | 67 | SkipDB_close(db); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /tests/jftest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "JFile.h" 4 | #include "List.h" 5 | #include "PortableGettimeofday.h" 6 | #include "Date.h" 7 | 8 | int main(void) 9 | { 10 | int value = 444, nv; 11 | JFile *j = JFile_new(); 12 | JFile_setPath_(j, "test.jfile"); 13 | 14 | #if 0 15 | JFile_remove(j); 16 | JFile_open(j); 17 | 18 | JFile_begin(j); 19 | JFile_setPosition_(j, 0); 20 | JFile_writeInt_(j, value); 21 | JFile_commitToLog(j); 22 | JFile_commitToFile(j); 23 | #else 24 | JFile_open(j); 25 | #endif 26 | 27 | JFile_setPosition_(j, 0); 28 | printf("%d\n", JFile_readInt(j)); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /tests/remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COUNTER=0 4 | 5 | V="your are the best" 6 | K="hello" 7 | while [ $COUNTER -lt 2000 ]; do 8 | ../build/bin/dbus remove $K$COUNTER 9 | let COUNTER=COUNTER+1 10 | done 11 | -------------------------------------------------------------------------------- /tests/skiplist.c: -------------------------------------------------------------------------------- 1 | /* Skip Lists: A Probabilistic Alternative to Balanced Trees */ 2 | 3 | /* 4 | Skip List定义 5 | 一个跳表,应该具有以下特征: 6 | 一个跳表应该有几个层(level)组成; 7 | 跳表的第一层包含所有的元素; 8 | 每一层都是一个有序的链表; 9 | 如果元素x出现在第i层,则所有比i小的层都包含x; 10 | 第i层的元素通过一个down指针指向下一层拥有相同值的元素; 11 | 在每一层中,-1和1两个元素都出现(分别表示INT_MIN和INT_MAX); 12 | Top指针指向最高层的第一个元素。 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define SKIPLIST_MAX_LEVEL 6 20 | 21 | typedef struct snode { 22 | int key; 23 | int value; 24 | struct snode **forward; 25 | } snode; 26 | 27 | typedef struct skiplist { 28 | int level; 29 | int size; 30 | struct snode *header; 31 | } skiplist; 32 | 33 | skiplist *skiplist_init(skiplist *list) 34 | { 35 | int i; 36 | snode *header = (snode *)malloc(sizeof(struct snode)); 37 | list->header = header; 38 | header->key = INT_MAX; 39 | header->forward = (snode **)malloc(sizeof(snode*) * (SKIPLIST_MAX_LEVEL+1)); 40 | for (i = 0; i <= SKIPLIST_MAX_LEVEL; i++) { 41 | header->forward[i] = list->header; 42 | } 43 | 44 | list->level = 1; 45 | list->size = 0; 46 | 47 | return list; 48 | } 49 | 50 | static int rand_level() 51 | { 52 | int level = 1; 53 | while (rand() < RAND_MAX/2 && level < SKIPLIST_MAX_LEVEL) 54 | level++; 55 | return level; 56 | } 57 | 58 | int skiplist_insert(skiplist *list, int key, int value) 59 | { 60 | snode *update[SKIPLIST_MAX_LEVEL+1]; 61 | snode *x = list->header; 62 | int i, level; 63 | for (i = list->level; i >= 1; i--) { 64 | while (x->forward[i]->key < key) 65 | x = x->forward[i]; 66 | update[i] = x; 67 | } 68 | x = x->forward[1]; 69 | 70 | if (key == x->key) { 71 | x->value = value; 72 | return 0; 73 | } else { 74 | level = rand_level(); 75 | if (level > list->level) { 76 | for (i = list->level+1; i <= level; i++) { 77 | update[i] = list->header; 78 | } 79 | list->level = level; 80 | } 81 | 82 | x = (snode *)malloc(sizeof(snode)); 83 | x->key = key; 84 | x->value = value; 85 | x->forward = (snode **)malloc(sizeof(snode*) * (level + 1)); 86 | for (i = 1; i <= level; i++) { 87 | x->forward[i] = update[i]->forward[i]; 88 | update[i]->forward[i] = x; 89 | } 90 | } 91 | return 0; 92 | } 93 | 94 | snode *skiplist_search(skiplist *list, int key) 95 | { 96 | snode *x = list->header; 97 | int i; 98 | for (i = list->level; i >= 1; i--) { 99 | while (x->forward[i]->key < key) 100 | x = x->forward[i]; 101 | } 102 | if (x->forward[1]->key == key) { 103 | return x->forward[1]; 104 | } else { 105 | return NULL; 106 | } 107 | return NULL; 108 | } 109 | 110 | static void skiplist_node_free(snode *x) 111 | { 112 | if (x) { 113 | free(x->forward); 114 | free(x); 115 | } 116 | } 117 | 118 | int skiplist_delete(skiplist *list, int key) 119 | { 120 | int i; 121 | snode *update[SKIPLIST_MAX_LEVEL + 1]; 122 | snode *x = list->header; 123 | for (i = list->level; i >= 1; i--) { 124 | while (x->forward[i]->key < key) 125 | x = x->forward[i]; 126 | update[i] = x; 127 | } 128 | 129 | x = x->forward[1]; 130 | if (x->key == key) { 131 | for (i = 1; i <= list->level; i++) { 132 | if (update[i]->forward[i] != x) 133 | break; 134 | update[i]->forward[1] = x->forward[i]; 135 | } 136 | skiplist_node_free(x); 137 | 138 | while (list->level > 1 && list->header->forward[list->level] == list->header) 139 | list->level--; 140 | return 0; 141 | } 142 | return 1; 143 | } 144 | 145 | static void skiplist_dump(skiplist *list) 146 | { 147 | snode *x = list->header; 148 | while (x && x->forward[1] != list->header) { 149 | printf("%d[%d]->", x->forward[1]->key, x->forward[1]->value); 150 | x = x->forward[1]; 151 | } 152 | printf("NIL\n"); 153 | } 154 | 155 | int main() 156 | { 157 | int arr[] = {3, 6, 9, 2, 11, 1, 4}, i; 158 | skiplist list; 159 | skiplist_init(&list); 160 | 161 | printf("Insert:--------------------\n"); 162 | for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { 163 | skiplist_insert(&list, arr[i], arr[i]); 164 | } 165 | skiplist_dump(&list); 166 | 167 | printf("Search:--------------------\n"); 168 | int keys[] = {3, 4, 7, 10, 111}; 169 | 170 | for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { 171 | snode *x = skiplist_search(&list, keys[i]); 172 | if (x) { 173 | printf("key = %d, value = %d\n", keys[i], x->value); 174 | } else { 175 | printf("key = %d, not fuound\n", keys[i]); 176 | } 177 | } 178 | 179 | printf("Search:--------------------\n"); 180 | skiplist_delete(&list, 3); 181 | skiplist_delete(&list, 9); 182 | skiplist_dump(&list); 183 | 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /tests/test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "SkipDB.h" 3 | #include 4 | #include 5 | #include "Date.h" 6 | 7 | int main(void) 8 | { 9 | Datum k; 10 | int i, max; 11 | time_t t1; 12 | double dt; 13 | char s[100]; 14 | 15 | SkipDB *u = SkipDB_new(); 16 | 17 | printf("SkipDB (ordered key/value database) performance test:\n"); 18 | SkipDB_setPath_(u, "test.skipdb"); 19 | SkipDB_delete(u); 20 | SkipDB_open(u); 21 | 22 | max = 1; 23 | 24 | t1 = Date_SecondsFrom1970ToNow(); 25 | SkipDB_beginTransaction(u); 26 | for (i = 0; i < max; i ++) 27 | { 28 | sprintf(s, "%i", i); 29 | k = Datum_FromCString_(s); 30 | 31 | SkipDB_at_put_(u, k, k); 32 | } 33 | SkipDB_commitTransaction(u); 34 | dt = Date_SecondsFrom1970ToNow()-t1;; 35 | printf(" %i individual sequential transactional writes per second\n", (int)((double)max/dt)); 36 | 37 | SkipDB_close(u); 38 | SkipDB_open(u); 39 | 40 | t1 = Date_SecondsFrom1970ToNow(); 41 | for (i = 0; i < max; i ++) 42 | { 43 | Datum d; 44 | sprintf(s, "%i", i); 45 | k = Datum_FromCString_(s); 46 | 47 | d = SkipDB_at_(u, k); 48 | 49 | if (d.data == NULL || d.size == 0) 50 | { 51 | printf("ERROR: no record at %i\n", i); 52 | exit(-1); 53 | } 54 | else 55 | { 56 | if (strcmp(s, (char *)d.data) != 0) 57 | { 58 | printf("ERROR: bad value at %i\n", i); 59 | exit(-1); 60 | } 61 | } 62 | } 63 | printf("writes verified\n"); 64 | 65 | printf("testing removes\n"); 66 | SkipDB_beginTransaction(u); 67 | for (i = 0; i < max; i ++) 68 | { 69 | sprintf(s, "%i", i); 70 | k = Datum_FromCString_(s); 71 | SkipDB_removeAt_(u, k); 72 | } 73 | //SkipDB_show(u); 74 | SkipDB_commitTransaction(u); 75 | 76 | SkipDB_close(u); 77 | printf("closing after removes\n"); 78 | SkipDB_open(u); 79 | 80 | t1 = Date_SecondsFrom1970ToNow(); 81 | for (i = 0; i < max; i ++) 82 | { 83 | Datum d; 84 | sprintf(s, "%i", i); 85 | k = Datum_FromCString_(s); 86 | 87 | d = SkipDB_at_(u, k); 88 | 89 | if (d.data == NULL || d.size == 0) 90 | { 91 | } 92 | else 93 | { 94 | printf("ERROR: record %i not removed\n", i); 95 | exit(-1); 96 | } 97 | } 98 | printf("removes verified\n"); 99 | 100 | SkipDB_close(u); 101 | SkipDB_delete(u); 102 | SkipDB_open(u); 103 | 104 | max = 1024*64; 105 | 106 | t1 = Date_SecondsFrom1970ToNow(); 107 | SkipDB_beginTransaction(u); 108 | for (i = 0; i < max; i ++) 109 | { 110 | sprintf(s, "%i", i); 111 | k = Datum_FromCString_(s); 112 | 113 | SkipDB_at_put_(u, k, k); 114 | } 115 | SkipDB_commitTransaction(u); 116 | dt = Date_SecondsFrom1970ToNow()-t1;; 117 | printf(" %i group transactional writes per second\n", (int)((double)max/dt)); 118 | 119 | 120 | t1 = Date_SecondsFrom1970ToNow(); 121 | for (i = 0; i < max; i ++) 122 | { 123 | Datum d; 124 | k = Datum_FromCString_(s); 125 | 126 | d = SkipDB_at_(u, k); 127 | 128 | if (d.data == NULL || d.size == 0) 129 | { 130 | printf("ERROR: no record at %i\n", i); 131 | exit(-1); 132 | } 133 | else 134 | { 135 | if (strcmp(s, (char *)d.data) != 0) 136 | { 137 | printf("ERROR: bad value at %i\n", i); 138 | exit(-1); 139 | } 140 | } 141 | } 142 | dt = Date_SecondsFrom1970ToNow()-t1;; 143 | printf(" %i reads per second\n", (int)((float)max/dt)); 144 | 145 | 146 | t1 = Date_SecondsFrom1970ToNow(); 147 | SkipDB_beginTransaction(u); 148 | for (i = 0; i < max; i ++) 149 | { 150 | sprintf(s, "%i", i); 151 | k = Datum_FromCString_(s); 152 | 153 | SkipDB_removeAt_(u, k); 154 | } 155 | SkipDB_commitTransaction(u); 156 | dt = Date_SecondsFrom1970ToNow()-t1;; 157 | printf(" %i group transactional removes per second\n", (int)((float)max/dt)); 158 | 159 | SkipDB_delete(u); 160 | SkipDB_free(u); 161 | return 0; 162 | } 163 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COUNTER=0 4 | 5 | V="your are the best" 6 | K="hello" 7 | while [ $COUNTER -lt 10000 ]; do 8 | #echo The counter is $V$COUNTER 9 | #../build/bin/dbus set $K$COUNTER=$V$COUNTER 10 | #../build/bin/dbus get $K$COUNTER 11 | export $K$COUNTER="$V$COUNTER" 12 | let COUNTER=COUNTER+1 13 | done 14 | ../build/bin/dbus save $K 15 | -------------------------------------------------------------------------------- /tests/test2.c: -------------------------------------------------------------------------------- 1 | #include "SkipDB.h" 2 | #include 3 | #include 4 | #include "Date.h" 5 | 6 | void skipdb_list(SkipDB* self, SkipDBRecord* rc, void* ctx) 7 | { 8 | Datum k = SkipDBRecord_keyDatum(rc); 9 | Datum v = SkipDBRecord_valueDatum(rc); 10 | printf("%s=%s\n", k.data, v.data); 11 | } 12 | 13 | void SkipDB_show_by_prefix(SkipDB *u, Datum k) 14 | { 15 | Datum t; 16 | SkipDBCursor* cursor = SkipDBCursor_newWithDB_(u); 17 | SkipDBRecord* rc = SkipDBCursor_goto_(cursor, k); 18 | if(NULL == rc) { 19 | printf("hear\n"); 20 | return; 21 | } 22 | 23 | t = SkipDBRecord_valueDatum(rc); 24 | //printf("k.size=%d t.size=%d k=%s t=%s\n", k.size, t.size, k.data, t.data); 25 | if((k.size <= t.size) && (0 == strncmp((char*)t.data, (char*)k.data, k.size-1))) { 26 | printf("%s\n", t.data); 27 | } 28 | 29 | rc = SkipDBCursor_next(cursor); 30 | while(NULL != rc) { 31 | t = SkipDBRecord_valueDatum(rc); 32 | if((k.size <= t.size) && (0 == strncmp((char*)t.data, (char*)k.data, k.size-1))) { 33 | printf("%s\n", t.data); 34 | rc = SkipDBCursor_next(cursor); 35 | } else { 36 | break; 37 | } 38 | } 39 | 40 | SkipDBCursor_release(cursor); 41 | } 42 | 43 | int main(void) 44 | { 45 | Datum k, t; 46 | int i, max; 47 | time_t t1; 48 | double dt; 49 | char s[100]; 50 | 51 | SkipDB *u = SkipDB_new(); 52 | 53 | printf("SkipDB (ordered key/value database) performance test:\n"); 54 | SkipDB_setPath_(u, "test.skipdb"); 55 | SkipDB_delete(u); 56 | SkipDB_open(u); 57 | 58 | max = 3000; 59 | 60 | t1 = Date_SecondsFrom1970ToNow(); 61 | SkipDB_beginTransaction(u); 62 | for (i = 0; i < max; i ++) 63 | { 64 | sprintf(s, "test%i", i); 65 | k = Datum_FromCString_(s); 66 | 67 | SkipDB_at_put_(u, k, k); 68 | } 69 | 70 | SkipDB_commitTransaction(u); 71 | dt = Date_SecondsFrom1970ToNow()-t1;; 72 | printf(" %i individual sequential transactional writes per second\n", (int)((double)max/dt)); 73 | 74 | SkipDB_close(u); 75 | SkipDB_open(u); 76 | 77 | //SkipDB_show(u); 78 | 79 | sprintf(s, "test%d", 33); 80 | t = Datum_FromCString_(s); 81 | SkipDB_list_prefix(u, t, NULL, skipdb_list); 82 | #if 0 83 | t1 = Date_SecondsFrom1970ToNow(); 84 | for (i = 0; i < max; i ++) 85 | { 86 | Datum d; 87 | sprintf(s, "test%i", i); 88 | k = Datum_FromCString_(s); 89 | 90 | d = SkipDB_at_(u, k); 91 | 92 | if (d.data == NULL || d.size == 0) 93 | { 94 | printf("ERROR: no record at %i\n", i); 95 | exit(-1); 96 | } 97 | else 98 | { 99 | if (strcmp(s, (char *)d.data) != 0) 100 | { 101 | printf("ERROR: bad value at %i\n", i); 102 | exit(-1); 103 | } 104 | } 105 | } 106 | 107 | for (i = 0; i < max; i ++) 108 | { 109 | Datum d; 110 | sprintf(s, "test%i", i); 111 | k = Datum_FromCString_(s); 112 | 113 | d = SkipDB_at_(u, k); 114 | 115 | if (d.data == NULL || d.size == 0) 116 | { 117 | printf("ERROR: no record at %i\n", i); 118 | exit(-1); 119 | } 120 | else 121 | { 122 | if (strcmp(s, (char *)d.data) != 0) 123 | { 124 | printf("ERROR: bad value at %i\n", i); 125 | exit(-1); 126 | } 127 | } 128 | } 129 | printf("writes verified\n"); 130 | 131 | SkipDB_show(u); 132 | 133 | printf("testing removes\n"); 134 | SkipDB_beginTransaction(u); 135 | for (i = 0; i < max; i ++) 136 | { 137 | sprintf(s, "test%i", i); 138 | k = Datum_FromCString_(s); 139 | SkipDB_removeAt_(u, k); 140 | } 141 | //SkipDB_show(u); 142 | SkipDB_commitTransaction(u); 143 | 144 | SkipDB_close(u); 145 | printf("closing after removes\n"); 146 | SkipDB_open(u); 147 | 148 | SkipDB_show(u); 149 | 150 | t1 = Date_SecondsFrom1970ToNow(); 151 | for (i = 0; i < max; i ++) 152 | { 153 | Datum d; 154 | sprintf(s, "test%i", i); 155 | k = Datum_FromCString_(s); 156 | 157 | d = SkipDB_at_(u, k); 158 | 159 | if (d.data == NULL || d.size == 0) 160 | { 161 | } 162 | else 163 | { 164 | printf("ERROR: record %i not removed\n", i); 165 | exit(-1); 166 | } 167 | } 168 | printf("removes verified\n"); 169 | #endif 170 | 171 | SkipDB_delete(u); 172 | SkipDB_free(u); 173 | return 0; 174 | } 175 | -------------------------------------------------------------------------------- /tests/udbtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "UDB.h" 4 | #include "Date.h" 5 | 6 | int main(void) 7 | { 8 | int max, i, v; 9 | PID_TYPE pid; 10 | Datum d; 11 | UDB *u = UDB_new(); 12 | UDB_setPath_(u, "test.skipdb"); 13 | //UDB_delete(u); 14 | UDB_open(u); 15 | 16 | max = 30; 17 | 18 | #if 0 19 | for (i = 0; i < max; i++) { 20 | UDB_beginTransaction(u); 21 | d.size = sizeof(int); 22 | v = i; 23 | d.data = (void *)&v; 24 | 25 | pid = UDB_allocPid(u); 26 | fprintf(stderr, "pid=%d\n", pid); 27 | UDB_at_put_(u, pid, d); 28 | UDB_commitTransaction(u); 29 | } 30 | #endif 31 | 32 | #if 0 33 | for (i = 0; i < max; i++) { 34 | pid = i+1; 35 | d = UDB_at_(u, pid); 36 | 37 | if (d.data == NULL || d.size == 0) { 38 | printf("ERROR: no record at %i\n", pid); 39 | } else { 40 | if(d.size != 4) { 41 | printf("ERROR: wrong size %i at pid %i\n", d.size, pid); 42 | } else { 43 | memcpy(&v, d.data, sizeof(int)); 44 | if(v != i) { 45 | printf("ERROR: wrong value %i at pid %i\n", v, i); 46 | } 47 | } 48 | } 49 | } 50 | #endif 51 | 52 | pid = 1; 53 | d = UDB_at_(u, pid); 54 | printf("size:%d %s\n", d.size, d.data); 55 | 56 | pid = 2; 57 | d = UDB_at_(u, pid); 58 | printf("size:%d %s\n", d.size, d.data); 59 | 60 | pid = 3; 61 | d = UDB_at_(u, pid); 62 | printf("size:%d %s\n", d.size, d.data); 63 | 64 | return 0; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /udb/UDB.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("UDB") 5 | docDescription("An unordered value database. (sort of like malloc for disk space) 6 | It compacts the data like a single space copying garbage collector.") 7 | */ 8 | 9 | #ifndef UDB_DEFINED 10 | #define UDB_DEFINED 1 11 | 12 | #if !defined(__MINGW32__) && defined(WIN32) 13 | #if defined(BUILDING_SKIPDB_DLL) || defined(BUILDING_IOVMALL_DLL) 14 | #define UDB_API __declspec(dllexport) 15 | #else 16 | #define UDB_API __declspec(dllimport) 17 | #endif 18 | #else 19 | #define UDB_API 20 | #endif 21 | 22 | 23 | #include "List.h" 24 | #include "UDBRecord.h" 25 | #include "UDBIndex.h" 26 | #include "UDBRecords.h" 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | typedef struct 33 | { 34 | char *path; 35 | UDBIndex *index; 36 | UDBRecords *records; 37 | int withinTransaction; 38 | int isOpen; 39 | FILE *committedFile; 40 | char *committedPath; 41 | } UDB; 42 | 43 | UDB_API UDB *UDB_new(void); 44 | UDB_API void UDB_free(UDB *self); 45 | 46 | UDB_API void UDB_setPath_(UDB *self, const char *s); 47 | UDB_API void UDB_setLogPath_(UDB *self, const char *s); 48 | UDB_API char *UDB_path(UDB *self); 49 | 50 | UDB_API void UDB_delete(UDB *self); 51 | UDB_API void UDB_open(UDB *self); 52 | UDB_API int UDB_isOpen(UDB *self); 53 | UDB_API void UDB_close(UDB *self); 54 | 55 | // transactions --------------------------------------------------- 56 | 57 | UDB_API void UDB_beginTransaction(UDB *self); 58 | UDB_API void UDB_commitTransaction(UDB *self); 59 | 60 | // ops -------------------------------------------------- 61 | 62 | UDB_API PID_TYPE UDB_nextPid(UDB *self); 63 | UDB_API PID_TYPE UDB_allocPid(UDB *self); 64 | 65 | UDB_API PID_TYPE UDB_put_(UDB *self, Datum d); 66 | UDB_API void UDB_at_put_(UDB *self, PID_TYPE pid, Datum d); 67 | UDB_API Datum UDB_at_(UDB *self, PID_TYPE pid); 68 | UDB_API void UDB_removeAt_(UDB *self, PID_TYPE id); 69 | 70 | UDB_API int UDB_compact(UDB *self); 71 | UDB_API int UDB_compactStep(UDB *self); 72 | UDB_API int UDB_compactStepFor_(UDB *self, double maxSeconds); 73 | 74 | UDB_API void UDB_show(UDB *self); 75 | UDB_API void UDB_showIndex(UDB *self); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | #endif 81 | -------------------------------------------------------------------------------- /udb/UDBIndex.c: -------------------------------------------------------------------------------- 1 | /*#io 2 | UDBIndex ioDoc( 3 | docCopyright("Steve Dekorte", 2004) 4 | docLicense("BSD revised") 5 | docObject("UDBIndex") 6 | docDescription("") 7 | */ 8 | 9 | #include "UDBIndex.h" 10 | #include 11 | #include 12 | #include 13 | 14 | UDBIndex *UDBIndex_new(void) 15 | { 16 | UDBIndex *self = (UDBIndex *)calloc(1, sizeof(UDBIndex)); 17 | self->file = JFile_new(); 18 | UDBIndex_setPath_(self, "default"); 19 | self->holes = List_new(); 20 | return self; 21 | } 22 | 23 | void UDBIndex_free(UDBIndex *self) 24 | { 25 | UDBIndex_close(self); 26 | JFile_free(self->file); 27 | List_free(self->holes); 28 | free(self); 29 | } 30 | 31 | JFile *UDBIndex_jfile(UDBIndex *self) 32 | { 33 | return self->file; 34 | } 35 | 36 | void UDBIndex_delete(UDBIndex *self) 37 | { 38 | JFile_close(self->file); 39 | JFile_delete(self->file); 40 | } 41 | 42 | void UDBIndex_setPath_(UDBIndex *self, const char *path) 43 | { 44 | JFile_setPath_withExtension_(self->file, path, "udbIndex"); 45 | } 46 | 47 | void UDBIndex_setLogPath_(UDBIndex *self, const char *s) 48 | { 49 | JFile_setLogPath_(self->file, s); 50 | } 51 | 52 | char *UDBIndex_path(UDBIndex *self) 53 | { 54 | return JFile_path(self->file); 55 | } 56 | 57 | void UDBIndex_open(UDBIndex *self) 58 | { 59 | JFile_open(self->file); 60 | // need to also call UDBIndex_finishOpening 61 | UDBIndex_finishOpening(self); 62 | self->maxPid = 0; 63 | } 64 | 65 | void UDBIndex_finishOpening(UDBIndex *self) 66 | { 67 | JFile_begin(self->file); 68 | UDBIndex_setPos_forPid_(self, 0, 0); 69 | UDBIndex_preCommit(self); 70 | UDBIndex_findHoles(self); 71 | } 72 | 73 | void UDBIndex_close(UDBIndex *self) 74 | { 75 | JFile_close(self->file); 76 | } 77 | 78 | void UDBIndex_begin(UDBIndex *self) 79 | { 80 | JFile_begin(self->file); 81 | } 82 | 83 | void UDBIndex_preCommit(UDBIndex *self) 84 | { 85 | JFile_commitToLog(self->file); 86 | } 87 | 88 | void UDBIndex_commit(UDBIndex *self) 89 | { 90 | JFile_commitToFile(self->file); 91 | } 92 | 93 | // holes ------------------------------------------- 94 | 95 | void UDBIndex_findHoles(UDBIndex *self) 96 | { 97 | PID_TYPE pid = UDBIndex_pidCount(self); 98 | 99 | List_removeAll(self->holes); 100 | 101 | while (pid --) 102 | { 103 | if (!UDBIndex_posForPid_(self, pid)) 104 | { 105 | List_push_(self->holes, (void *)pid); 106 | } 107 | } 108 | } 109 | 110 | // pid ops ------------------------------------------- 111 | 112 | PID_TYPE UDBIndex_nextPid(UDBIndex *self) 113 | { 114 | PID_TYPE hole = (PID_TYPE)List_top(self->holes); 115 | 116 | if (hole) 117 | { 118 | return hole; 119 | } 120 | 121 | return JFile_setPositionToEnd(self->file) / sizeof(UDBIndexEntry); 122 | } 123 | 124 | PID_TYPE UDBIndex_allocPid(UDBIndex *self) 125 | { 126 | PID_TYPE hole = (PID_TYPE)List_pop(self->holes); 127 | 128 | if (hole) 129 | { 130 | return hole; 131 | } 132 | else 133 | { 134 | PID_TYPE max = JFile_setPositionToEnd(self->file) / sizeof(UDBIndexEntry); 135 | 136 | if (max > self->maxPid) 137 | { 138 | self->maxPid = max; 139 | } 140 | else 141 | { 142 | self->maxPid ++; 143 | } 144 | 145 | return self->maxPid; 146 | } 147 | } 148 | 149 | PID_TYPE UDBIndex_posForPid_(UDBIndex *self, PID_TYPE pid) 150 | { 151 | UDBIndexEntry entry; 152 | 153 | JFile_setPosition_(self->file, pid * sizeof(UDBIndexEntry)); 154 | 155 | //#ifdef JFILE_SUPPORTS_MMAP 156 | //JFile_mmapfread(self->file, (unsigned char *)(&pos), sizeof(UDBIndexEntry), 1); 157 | //#else 158 | JFile_fread(self->file, (unsigned char *)(&entry), sizeof(UDBIndexEntry), 1); 159 | //#endif 160 | 161 | return entry.pos; 162 | } 163 | 164 | void UDBIndex_setPos_forPid_(UDBIndex *self, PID_TYPE pos, PID_TYPE pid) 165 | { 166 | UDBIndexEntry entry; 167 | entry.pos = pos; 168 | //entry.size = 0; 169 | 170 | JFile_setPosition_(self->file, pid * sizeof(UDBIndexEntry)); 171 | JFile_fwrite(self->file, (unsigned char *)(&entry), sizeof(UDBIndexEntry), 1); 172 | 173 | if (pos == 0) 174 | { 175 | List_push_(self->holes, (void *)pid); 176 | } 177 | } 178 | 179 | long UDBIndex_pidCount(UDBIndex *self) 180 | { 181 | return JFile_setPositionToEnd(self->file) / sizeof(UDBIndexEntry); 182 | } 183 | 184 | void UDBIndex_show(UDBIndex *self) 185 | { 186 | PID_TYPE pid, maxPid = UDBIndex_pidCount(self); 187 | 188 | printf("UDBIndex: (pid/pos)\n\n"); 189 | 190 | for (pid = 0; pid < maxPid; pid ++) 191 | { 192 | PID_TYPE pos = UDBIndex_posForPid_(self, pid); 193 | printf(" %i -> %i\n", (int)pid, (int)pos); 194 | } 195 | 196 | printf("\n"); 197 | } 198 | 199 | -------------------------------------------------------------------------------- /udb/UDBIndex.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("UDBIndex") 5 | docDescription("An on-disk array of indexes into the data file.") 6 | */ 7 | 8 | #ifndef UDBIndex_DEFINED 9 | #define UDBIndex_DEFINED 1 10 | 11 | #include "List.h" 12 | #include "UDBRecord.h" 13 | #include "JFile.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | typedef struct 20 | { 21 | //unsigned char sizeLog2; // size = 2^sizeLog2 22 | PID_TYPE pos; 23 | } UDBIndexEntry; 24 | 25 | typedef struct 26 | { 27 | JFile *file; 28 | List *holes; 29 | PID_TYPE maxPid; 30 | } UDBIndex; 31 | 32 | UDBIndex *UDBIndex_new(void); 33 | void UDBIndex_free(UDBIndex *self); 34 | 35 | JFile *UDBIndex_jfile(UDBIndex *self); 36 | 37 | void UDBIndex_setPath_(UDBIndex *self, const char *s); 38 | void UDBIndex_setLogPath_(UDBIndex *self, const char *s); 39 | char *UDBIndex_path(UDBIndex *self); 40 | 41 | void UDBIndex_delete(UDBIndex *self); 42 | void UDBIndex_open(UDBIndex *self); 43 | void UDBIndex_finishOpening(UDBIndex *self); 44 | void UDBIndex_close(UDBIndex *self); 45 | 46 | void UDBIndex_begin(UDBIndex *self); 47 | void UDBIndex_preCommit(UDBIndex *self); 48 | void UDBIndex_commit(UDBIndex *self); 49 | 50 | // holes ------------------------------------------- 51 | 52 | void UDBIndex_findHoles(UDBIndex *self); 53 | 54 | // pid ops ------------------------------------------- 55 | 56 | PID_TYPE UDBIndex_nextPid(UDBIndex *self); 57 | PID_TYPE UDBIndex_allocPid(UDBIndex *self); 58 | PID_TYPE UDBIndex_posForPid_(UDBIndex *self, PID_TYPE pid); 59 | void UDBIndex_setPos_forPid_(UDBIndex *self, PID_TYPE pos, PID_TYPE pid); 60 | long UDBIndex_pidCount(UDBIndex *self); 61 | void UDBIndex_show(UDBIndex *self); 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | #endif 67 | -------------------------------------------------------------------------------- /udb/UDBRecord.c: -------------------------------------------------------------------------------- 1 | /*#io 2 | UDBRecord ioDoc( 3 | docCopyright("Steve Dekorte", 2004) 4 | docLicense("BSD revised") 5 | docObject("UDBRecord") 6 | docDescription("") 7 | */ 8 | 9 | #include "UDB.h" 10 | #include 11 | #include 12 | #include 13 | 14 | UDBRecord *UDBRecord_new(void) 15 | { 16 | UDBRecord *self = (UDBRecord *)calloc(1, sizeof(UDBRecord)); 17 | return self; 18 | } 19 | 20 | UDBRecord *UDBRecord_clone(UDBRecord *self) 21 | { 22 | UDBRecord *clone = (UDBRecord *)cpalloc(self, sizeof(UDBRecord)); 23 | return clone; 24 | } 25 | 26 | void UDBRecord_free(UDBRecord *self) 27 | { 28 | if (self->data) UArray_free(self->data); 29 | free(self); 30 | } 31 | 32 | UArray *UDBRecord_data(UDBRecord *self) 33 | { 34 | if (!self->data) self->data = UArray_new(); 35 | return self->data; 36 | } 37 | 38 | void UDBRecord_setJFile_(UDBRecord *self, JFile *file) 39 | { 40 | self->file = file; 41 | } 42 | 43 | void UDBRecord_setPos_(UDBRecord *self, PID_TYPE pos) 44 | { 45 | self->pos = pos; 46 | } 47 | 48 | PID_TYPE UDBRecord_pos(UDBRecord *self) 49 | { 50 | return self->pos; 51 | } 52 | 53 | void UDBRecord_setPosToEnd(UDBRecord *self) 54 | { 55 | self->pos = JFile_setPositionToEnd(self->file); 56 | } 57 | 58 | void UDBRecord_pid_(UDBRecord *self, PID_TYPE pid) 59 | { 60 | self->header.pid = pid; 61 | } 62 | 63 | PID_TYPE UDBRecord_pid(UDBRecord *self) 64 | { 65 | return self->header.pid; 66 | } 67 | 68 | void UDBRecord_size_(UDBRecord *self, PID_TYPE size) 69 | { 70 | self->header.size = size; 71 | } 72 | 73 | PID_TYPE UDBRecord_size(UDBRecord *self) 74 | { 75 | return self->header.size; 76 | } 77 | 78 | void UDBRecord_remove(UDBRecord *self) 79 | { 80 | self->header.tag = RECORD_TAG_EMPTY; 81 | UDBRecord_saveHeader(self); 82 | } 83 | 84 | int UDBRecord_isEmpty(UDBRecord *self) 85 | { 86 | return (self->header.tag == RECORD_TAG_EMPTY); 87 | } 88 | 89 | 90 | // save ----------------------------------------- 91 | 92 | void UDBRecord_saveHeader(UDBRecord *self) 93 | { 94 | if (self->pos) JFile_setPosition_(self->file, self->pos); 95 | JFile_fwrite(self->file, (unsigned char *)(&(self->header)), sizeof(UDBRecordHeader), 1); 96 | } 97 | 98 | void UDBRecord_saveWithDatum_(UDBRecord *self, Datum d) 99 | { 100 | self->header.size = d.size; 101 | UDBRecord_saveHeader(self); 102 | JFile_fwrite(self->file, d.data, d.size, 1); 103 | } 104 | 105 | // read ----------------------------------------- 106 | 107 | int UDBRecord_readHeader(UDBRecord *self) 108 | { 109 | int objectsRead; 110 | 111 | JFile_setPosition_(self->file, self->pos); 112 | objectsRead = JFile_fread(self->file, (unsigned char *)(&(self->header)), sizeof(UDBRecordHeader), 1); 113 | 114 | if (objectsRead != 1) 115 | { 116 | self->header.pid = 0; 117 | self->header.size = 0; 118 | return 0; 119 | } 120 | 121 | return 1; 122 | } 123 | 124 | Datum UDBRecord_readDatum(UDBRecord *self) 125 | { 126 | UArray *ba = UDBRecord_data(self); 127 | Datum d; 128 | PID_TYPE size = self->header.size; 129 | 130 | JFile_fseek(self->file, self->pos + sizeof(UDBRecordHeader), SEEK_SET); 131 | 132 | UArray_setSize_(ba, size); 133 | JFile_fread(self->file, UArray_bytes(ba), size, 1); 134 | d.size = size; 135 | d.data = UArray_bytes(ba); 136 | return d; 137 | } 138 | 139 | // compact ----------------------------------------- 140 | 141 | void UDBRecord_moveToPos_(UDBRecord *self, PID_TYPE newPos) 142 | { 143 | PID_TYPE totalSize = UDBRecord_totalSize(self); 144 | unsigned char *data; 145 | UArray *ba = UDBRecord_data(self); 146 | UArray_setSize_(ba, totalSize); 147 | data = UArray_bytes(ba); 148 | 149 | JFile_fseek(self->file, self->pos, SEEK_SET); 150 | JFile_fread(self->file, data, totalSize, 1); 151 | 152 | JFile_fseek(self->file, newPos, SEEK_SET); 153 | JFile_fwrite(self->file, data, totalSize, 1); 154 | } 155 | 156 | PID_TYPE UDBRecord_totalSize(UDBRecord *self) 157 | { 158 | return sizeof(UDBRecordHeader) + self->header.size; 159 | } 160 | 161 | void UDBRecord_show(UDBRecord *self) 162 | { 163 | printf("Record pos: %" PID_FORMAT "\n", self->pos); 164 | printf(" pid: %" PID_FORMAT "\n", self->header.pid); 165 | printf(" size: %" PID_FORMAT "\n", self->header.size); 166 | printf("\n"); 167 | } 168 | 169 | 170 | -------------------------------------------------------------------------------- /udb/UDBRecord.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("UDBRecord") 5 | docDescription("An individual UDB Record.") 6 | */ 7 | 8 | #ifndef UDBRecord_DEFINED 9 | #define UDBRecord_DEFINED 1 10 | 11 | #include 12 | #include "JFile.h" 13 | #include "Datum.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define RECORD_TAG_NORMAL 0 20 | #define RECORD_TAG_EMPTY 1 21 | 22 | typedef struct 23 | { 24 | //unsigned char recordSizeLog2; 25 | unsigned char tag; 26 | PID_TYPE pid; 27 | PID_TYPE size; // the actual size of the datum 28 | } UDBRecordHeader; 29 | 30 | typedef struct 31 | { 32 | JFile *file; 33 | PID_TYPE pos; 34 | UDBRecordHeader header; 35 | UArray *data; 36 | } UDBRecord; 37 | 38 | UDBRecord *UDBRecord_new(void); 39 | UDBRecord *UDBRecord_clone(UDBRecord *self); 40 | void UDBRecord_free(UDBRecord *self); 41 | 42 | void UDBRecord_setJFile_(UDBRecord *self, JFile *file); 43 | 44 | void UDBRecord_setPos_(UDBRecord *self, PID_TYPE pos); 45 | void UDBRecord_setPosToEnd(UDBRecord *self); 46 | PID_TYPE UDBRecord_pos(UDBRecord *self); 47 | 48 | void UDBRecord_pid_(UDBRecord *self, PID_TYPE pid); 49 | PID_TYPE UDBRecord_pid(UDBRecord *self); 50 | 51 | void UDBRecord_size_(UDBRecord *self, PID_TYPE size); 52 | PID_TYPE UDBRecord_size(UDBRecord *self); 53 | 54 | void UDBRecord_remove(UDBRecord *self); 55 | 56 | void UDBRecord_saveHeader(UDBRecord *self); 57 | void UDBRecord_saveWithDatum_(UDBRecord *self, Datum d); 58 | 59 | int UDBRecord_readHeader(UDBRecord *self); 60 | Datum UDBRecord_readDatum(UDBRecord *self); 61 | 62 | int UDBRecord_isEmpty(UDBRecord *self); 63 | //int UDBRecord_readNextHeader(UDBRecord *self); 64 | void UDBRecord_moveToPos_(UDBRecord *self, PID_TYPE newPos); 65 | 66 | PID_TYPE UDBRecord_totalSize(UDBRecord *self); 67 | void UDBRecord_show(UDBRecord *self); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | #endif 73 | -------------------------------------------------------------------------------- /udb/UDBRecords.c: -------------------------------------------------------------------------------- 1 | /*#io 2 | UDBRecords ioDoc( 3 | docCopyright("Steve Dekorte", 2004) 4 | docLicense("BSD revised") 5 | docObject("UDBRecords") 6 | docDescription("") 7 | */ 8 | 9 | #include "UDB.h" 10 | #include 11 | #include 12 | #include 13 | 14 | UDBRecords *UDBRecords_new(void) 15 | { 16 | UDBRecords *self = (UDBRecords *)calloc(1, sizeof(UDB)); 17 | self->file = JFile_new(); 18 | self->record = UDBRecord_new(); 19 | self->firstEmptyRecord = UDBRecord_new(); 20 | UDBRecords_setPath_(self, "default"); 21 | return self; 22 | } 23 | 24 | void UDBRecords_free(UDBRecords *self) 25 | { 26 | UDBRecords_close(self); 27 | JFile_free(self->file); 28 | UDBRecord_free(self->record); 29 | UDBRecord_free(self->firstEmptyRecord); 30 | free(self); 31 | } 32 | 33 | JFile *UDBRecords_jfile(UDBIndex *self) 34 | { 35 | return self->file; 36 | } 37 | 38 | void UDBRecords_delete(UDBRecords *self) 39 | { 40 | JFile_delete(self->file); 41 | } 42 | 43 | void UDBRecords_setPath_(UDBRecords *self, const char *path) 44 | { 45 | JFile_setPath_withExtension_(self->file, path, "udbData"); 46 | } 47 | 48 | void UDBRecords_setLogPath_(UDBRecords *self, const char *path) 49 | { 50 | JFile_setLogPath_(self->file, path); 51 | } 52 | 53 | char *UDBRecords_path(UDBRecords *self) 54 | { 55 | return JFile_path(self->file); 56 | } 57 | 58 | void UDBRecords_open(UDBRecords *self) 59 | { 60 | JFile_open(self->file); 61 | 62 | if (JFile_setPositionToEnd(self->file) == 0) 63 | { 64 | // position 0-4 holds the pos of the first empty record 65 | JFile_begin(self->file); 66 | UDBRecords_firstEmptyRecordPos_(self, 0); 67 | //UDBRecords_setEndPos_(self, 0); 68 | JFile_commitToLog(self->file); 69 | } 70 | 71 | UDBRecord_setJFile_(self->record, self->file); 72 | UDBRecord_setJFile_(self->firstEmptyRecord, self->file); 73 | self->firstEmptyPos = UDBRecords_firstEmptyRecordPos(self); 74 | } 75 | 76 | void UDBRecords_close(UDBRecords *self) 77 | { 78 | JFile_close(self->file); 79 | } 80 | 81 | void UDBRecords_begin(UDBRecords *self) 82 | { 83 | JFile_begin(self->file); 84 | } 85 | 86 | void UDBRecords_preCommit(UDBRecords *self) 87 | { 88 | JFile_commitToLog(self->file); 89 | } 90 | 91 | void UDBRecords_commit(UDBRecords *self) 92 | { 93 | JFile_commitToFile(self->file); 94 | } 95 | 96 | // ops -------------------------------------------------- 97 | 98 | UDBRecord *UDBRecords_firstRecord(UDBRecords *self) 99 | { 100 | return UDBRecords_recordAtPos_(self, 1); 101 | } 102 | 103 | UDBRecord *UDBRecords_newRecord(UDBRecords *self) 104 | { 105 | UDBRecord_setPosToEnd(self->record); 106 | return self->record; 107 | } 108 | 109 | UDBRecord *UDBRecords_nextRecord(UDBRecords *self) 110 | { 111 | PID_TYPE nextPos = self->record->pos + UDBRecord_totalSize(self->record); 112 | //printf("rec %i totalSize: %i\n", 113 | // self->record->header.pid, UDBRecord_totalSize(self->record)); 114 | return UDBRecords_recordAtPos_(self, nextPos); 115 | } 116 | 117 | UDBRecord *UDBRecords_recordAfter_(UDBRecords *self, UDBRecord *record) 118 | { 119 | PID_TYPE nextPos = record->pos + UDBRecord_totalSize(record); 120 | return UDBRecords_recordAtPos_(self, nextPos); 121 | } 122 | 123 | 124 | UDBRecord *UDBRecords_recordAtPos_(UDBRecords *self, PID_TYPE pos) 125 | { 126 | UDBRecord_setPos_(self->record, pos); 127 | 128 | if (UDBRecord_readHeader(self->record)) 129 | { 130 | return self->record; 131 | } 132 | 133 | return NULL; 134 | } 135 | 136 | void UDBRecords_removeRecord_(UDBRecords *self, UDBRecord *record) 137 | { 138 | PID_TYPE pos = UDBRecord_pos(record); 139 | 140 | if ((!self->firstEmptyPos) || 141 | (pos && pos < self->firstEmptyPos)) 142 | { 143 | UDBRecords_firstEmptyRecordPos_(self, pos); 144 | } 145 | 146 | UDBRecord_remove(record); 147 | } 148 | 149 | /* 150 | void UDBRecords_moveRecord_toPos_(UDBRecords *self, UDBRecord *record, PID_TYPE emptyPos) 151 | { 152 | UDBRecord_moveToPos_(record, emptyPos); 153 | } 154 | */ 155 | 156 | void UDBRecords_show(UDBRecords *self) 157 | { 158 | UDBRecord *record = UDBRecords_firstRecord(self); 159 | printf("UDB Records:\n"); 160 | if (record) 161 | { 162 | for (;;) 163 | { 164 | UDBRecord_show(record); 165 | if (!UDBRecords_nextRecord(self)) break; 166 | } 167 | } 168 | } 169 | 170 | // first empty record ------------------------------------ 171 | 172 | UDBRecord *UDBRecords_findFirstEmptyRecord(UDBRecords *self) 173 | { 174 | UDBRecord *record = UDBRecords_firstRecord(self); 175 | 176 | while (record) 177 | { 178 | if (UDBRecord_isEmpty(record)) return record; 179 | record = UDBRecords_nextRecord(self); 180 | } 181 | 182 | return NULL; 183 | } 184 | 185 | /* 186 | UDBRecord *UDBRecords_nextEmptyRecordAfter_(UDBRecords *self, UDBRecord *record) 187 | { 188 | UDBRecord *record; 189 | 190 | while (record = UDBRecords_nextRecord(self)) 191 | { 192 | if (UDBRecord_isEmpty(record)) return record; 193 | } 194 | 195 | return NULL; 196 | } 197 | */ 198 | 199 | PID_TYPE UDBRecords_firstEmptyRecordPos(UDBRecords *self) 200 | { 201 | JFile_fseek(self->file, 0, SEEK_SET); 202 | JFile_fread(self->file, (unsigned char *)(&(self->firstEmptyPos)), sizeof(PID_TYPE), 1); 203 | return self->firstEmptyPos; 204 | } 205 | 206 | void UDBRecords_firstEmptyRecordPos_(UDBRecords *self, PID_TYPE pos) 207 | { 208 | self->firstEmptyPos = pos; 209 | JFile_fseek(self->file, 0, SEEK_SET); 210 | JFile_fwrite(self->file, (unsigned char *)(&(self->firstEmptyPos)), sizeof(PID_TYPE), 1); 211 | } 212 | 213 | UDBRecord *UDBRecords_firstEmptyRecord(UDBRecords *self) 214 | { 215 | // store the position of the first empty record 216 | 217 | //printf("self->firstEmptyPos = %i\n", (int)self->firstEmptyPos); 218 | if (self->firstEmptyPos) 219 | { 220 | UDBRecord_setPos_(self->firstEmptyRecord, self->firstEmptyPos); 221 | 222 | if (UDBRecord_readHeader(self->firstEmptyRecord)) 223 | { 224 | return self->firstEmptyRecord; 225 | } 226 | } 227 | 228 | return NULL; 229 | } 230 | 231 | void UDBRecords_truncate_(UDBRecords *self, off_t size) 232 | { 233 | JFile_truncate_(self->file, size); 234 | } 235 | -------------------------------------------------------------------------------- /udb/UDBRecords.h: -------------------------------------------------------------------------------- 1 | /*#io 2 | docCopyright("Steve Dekorte", 2004) 3 | docLicense("BSD revised") 4 | docObject("UDBRecords") 5 | docDescription("An object for storing and fetching UDB records from the records file.") 6 | */ 7 | 8 | #ifndef UDBRecords_DEFINED 9 | #define UDBRecords_DEFINED 1 10 | 11 | #include "List.h" 12 | #include "UDBRecord.h" 13 | #include "UDBIndex.h" 14 | #include "JFile.h" 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | typedef struct 21 | { 22 | JFile *file; 23 | UDBRecord *record; 24 | UDBRecord *firstEmptyRecord; 25 | PID_TYPE firstEmptyPos; 26 | } UDBRecords; 27 | 28 | UDBRecords *UDBRecords_new(void); 29 | void UDBRecords_free(UDBRecords *self); 30 | 31 | JFile *UDBRecords_jfile(UDBIndex *self); 32 | 33 | void UDBRecords_setPath_(UDBRecords *self, const char *s); 34 | void UDBRecords_setLogPath_(UDBRecords *self, const char *s); 35 | char *UDBRecords_path(UDBRecords *self); 36 | 37 | void UDBRecords_delete(UDBRecords *self); 38 | void UDBRecords_open(UDBRecords *self); 39 | void UDBRecords_close(UDBRecords *self); 40 | 41 | void UDBRecords_begin(UDBRecords *self); 42 | void UDBRecords_preCommit(UDBRecords *self); 43 | void UDBRecords_commit(UDBRecords *self); 44 | int UDBRecords_isUncommitted(UDBRecords *self); 45 | 46 | // ops -------------------------------------------------- 47 | 48 | UDBRecord *UDBRecords_firstRecord(UDBRecords *self); 49 | UDBRecord *UDBRecords_newRecord(UDBRecords *self); 50 | UDBRecord *UDBRecords_nextRecord(UDBRecords *self); 51 | UDBRecord *UDBRecords_recordAfter_(UDBRecords *self, UDBRecord *record); 52 | UDBRecord *UDBRecords_recordAtPos_(UDBRecords *self, PID_TYPE pos); 53 | void UDBRecords_removeRecord_(UDBRecords *self, UDBRecord *record); 54 | void UDBRecords_moveRecord_toPos_(UDBRecords *self, UDBRecord *record, PID_TYPE pos); 55 | 56 | void UDBRecords_truncate_(UDBRecords *self, off_t size); 57 | 58 | // first empty record ------------------------------------ 59 | 60 | UDBRecord *UDBRecords_findFirstEmptyRecord(UDBRecords *self); 61 | //UDBRecord *UDBRecords_nextEmptyRecordAfter_(UDBRecords *self, UDBRecord *record); 62 | PID_TYPE UDBRecords_firstEmptyRecordPos(UDBRecords *self); 63 | void UDBRecords_firstEmptyRecordPos_(UDBRecords *self, PID_TYPE firstEmptyPos); 64 | UDBRecord *UDBRecords_firstEmptyRecord(UDBRecords *self); 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | #endif 70 | --------------------------------------------------------------------------------