Initial commit
This commit is contained in:
72
.gitignore
vendored
Executable file
72
.gitignore
vendored
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
# CMake
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Linker output
|
||||||
|
*.ilk
|
||||||
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Build directories
|
||||||
|
[Bb]uild/
|
||||||
|
[Dd]ebug/
|
||||||
|
[Rr]elease/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Doxygen
|
||||||
|
[Dd]ocs/[Hh]tml
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
[Cc]overage
|
||||||
100
CMakeLists.txt
Normal file
100
CMakeLists.txt
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Project and C standard configuration
|
||||||
|
project(bhlib LANGUAGES C)
|
||||||
|
set(CMAKE_C_STANDARD 90)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Project includes
|
||||||
|
include(CheckIPOSupported)
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
|
||||||
|
# Check for IPO/LTO
|
||||||
|
check_ipo_supported(RESULT supported)
|
||||||
|
|
||||||
|
# Unit testing and coverage configuration
|
||||||
|
set(TESTING ON CACHE BOOL "Enable unit-testing")
|
||||||
|
set(COVERAGE OFF CACHE BOOL "Enable coverage")
|
||||||
|
|
||||||
|
if(supported)
|
||||||
|
message(STATUS "IPO/LTO enabled")
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TESTING)
|
||||||
|
# Enable testing
|
||||||
|
include(CTest)
|
||||||
|
enable_testing()
|
||||||
|
endif(TESTING)
|
||||||
|
|
||||||
|
# Set library code
|
||||||
|
set(BH_SOURCE
|
||||||
|
src/algo.c
|
||||||
|
src/hashmap.c
|
||||||
|
src/io.c
|
||||||
|
src/math.c
|
||||||
|
src/queue.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set(BH_HEADER
|
||||||
|
include/bh/common.h
|
||||||
|
include/bh/algo.h
|
||||||
|
include/bh/hashmap.h
|
||||||
|
include/bh/io.h
|
||||||
|
include/bh/math.h
|
||||||
|
include/bh/queue.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(BH_INCLUDE_DIRS
|
||||||
|
include
|
||||||
|
${PROJECT_BINARY_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Determine platform
|
||||||
|
if(WIN32)
|
||||||
|
message(STATUS "Platform - Win32")
|
||||||
|
|
||||||
|
# Add platform dependent files
|
||||||
|
list(APPEND BH_SOURCE
|
||||||
|
src/win32/file.c
|
||||||
|
)
|
||||||
|
elseif(UNIX)
|
||||||
|
message(STATUS "Platform: Unix (Linux/BSD/MacOS X)")
|
||||||
|
|
||||||
|
# Add platform dependent files
|
||||||
|
list(APPEND BH_SOURCE
|
||||||
|
src/posix/file.c
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(STATUS "Platform: Unknown")
|
||||||
|
|
||||||
|
# Add platform dependent files
|
||||||
|
list(APPEND BH_SOURCE
|
||||||
|
src/dummy/file.c
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Library
|
||||||
|
add_library(bhlib STATIC ${BH_SOURCE} ${BH_HEADER})
|
||||||
|
target_include_directories(bhlib PUBLIC ${BH_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(bhlib PUBLIC m)
|
||||||
|
|
||||||
|
# Enable all compiler warnings
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(bhlib PRIVATE /W4 /WX)
|
||||||
|
else()
|
||||||
|
target_compile_options(bhlib PRIVATE -Wall -Wextra -Wpedantic -Werror)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
if(COVERAGE)
|
||||||
|
target_compile_options(bhlib PRIVATE -coverage)
|
||||||
|
target_link_options(bhlib PRIVATE -coverage)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
if(TESTING)
|
||||||
|
add_subdirectory(unit)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
18
cmake/toolchain/i686-w64-mingw32.cmake
Normal file
18
cmake/toolchain/i686-w64-mingw32.cmake
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# the name of the target operating system
|
||||||
|
SET(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
SET(CMAKE_SYSTEM_PROCESSOR i686)
|
||||||
|
|
||||||
|
# which compilers to use for C and C++ and ASM-ATT
|
||||||
|
SET(CMAKE_C_COMPILER /usr/bin/i686-w64-mingw32-gcc)
|
||||||
|
SET(CMAKE_CXX_COMPILER /usr/bin/i686-w64-mingw32-g++)
|
||||||
|
SET(CMAKE_ASM-ATT_COMPILER /usr/bin/i686-w64-mingw32-as)
|
||||||
|
|
||||||
|
# here is the target environment located
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
|
||||||
|
|
||||||
|
# adjust the default behaviour of the FIND_XXX() commands:
|
||||||
|
# search headers and libraries in the target environment, search
|
||||||
|
# programs in the host environment
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
18
cmake/toolchain/x86_64-w64-mingw32.cmake
Normal file
18
cmake/toolchain/x86_64-w64-mingw32.cmake
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# the name of the target operating system
|
||||||
|
SET(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
SET(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||||
|
|
||||||
|
# which compilers to use for C and C++ and ASM-ATT
|
||||||
|
SET(CMAKE_C_COMPILER /usr/bin/x86_64-w64-mingw32-gcc)
|
||||||
|
SET(CMAKE_CXX_COMPILER /usr/bin/x86_64-w64-mingw32-g++)
|
||||||
|
SET(CMAKE_ASM-ATT_COMPILER /usr/bin/x86_64-w64-mingw32-as)
|
||||||
|
|
||||||
|
# here is the target environment located
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
|
||||||
|
|
||||||
|
# adjust the default behaviour of the FIND_XXX() commands:
|
||||||
|
# search headers and libraries in the target environment, search
|
||||||
|
# programs in the host environment
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
126
include/bh/algo.h
Executable file
126
include/bh/algo.h
Executable file
@@ -0,0 +1,126 @@
|
|||||||
|
#ifndef BH_ALGO_H
|
||||||
|
#define BH_ALGO_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchanges the values of two elements.
|
||||||
|
*
|
||||||
|
* \param dest Pointer to the element
|
||||||
|
* \param src Pointer to the element
|
||||||
|
* \param size Element size in bytes
|
||||||
|
*/
|
||||||
|
void bh_swap(void *dest,
|
||||||
|
void *src,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partitions the array relative to the specified pivot element.
|
||||||
|
*
|
||||||
|
* The pivot element can be part of the partitioned array.
|
||||||
|
*
|
||||||
|
* \param pivot Pointer to the pivot element
|
||||||
|
* \param array Pointer to the array
|
||||||
|
* \param size Array size
|
||||||
|
* \param element Element size in bytes
|
||||||
|
* \param equal Comparision function
|
||||||
|
*
|
||||||
|
* \return Pointer to the first element of the second partition.
|
||||||
|
*/
|
||||||
|
void *bh_partition(void *pivot,
|
||||||
|
void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts the array.
|
||||||
|
*
|
||||||
|
* \param array Pointer to the array
|
||||||
|
* \param size Array size
|
||||||
|
* \param element Element size in bytes
|
||||||
|
* \param equal Comparision function
|
||||||
|
*/
|
||||||
|
void bh_sort(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes heap in an array from the array.
|
||||||
|
*
|
||||||
|
* \param array Pointer to the array
|
||||||
|
* \param size Array size
|
||||||
|
* \param element Element size in bytes
|
||||||
|
* \param equal Comparision function
|
||||||
|
*/
|
||||||
|
void bh_heap_make(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes top/first element from a heap in an array.
|
||||||
|
*
|
||||||
|
* \param array Pointer to the array
|
||||||
|
* \param size Array size
|
||||||
|
* \param element Element size in bytes
|
||||||
|
* \param equal Comparasion function
|
||||||
|
*/
|
||||||
|
void bh_heap_remove(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts new element into heap in an array.
|
||||||
|
*
|
||||||
|
* If the pointer to value is NULL, this function assumes that the new value
|
||||||
|
* is at the end of the array.
|
||||||
|
*
|
||||||
|
* \param value Pointer to the value
|
||||||
|
* \param array Pointer to the array
|
||||||
|
* \param size Array size
|
||||||
|
* \param element Element size in bytes
|
||||||
|
* \param equal Comparasion function
|
||||||
|
*/
|
||||||
|
void bh_heap_insert(void *value,
|
||||||
|
void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes top/first element and inserts new element into heap in an array.
|
||||||
|
*
|
||||||
|
* If the pointer to value is NULL, this function assumes that the new value
|
||||||
|
* is at the end of the array.
|
||||||
|
*
|
||||||
|
* This function is roughly equivalent to the following code:
|
||||||
|
* \code
|
||||||
|
* bh_heap_remove(array, size, element, equal);
|
||||||
|
* bh_heap_insert(value, array, size - 1, element, equal);
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \param value Pointer to the value
|
||||||
|
* \param array Pointer to the array
|
||||||
|
* \param size Array size
|
||||||
|
* \param element Element size in bytes
|
||||||
|
* \param equal Comparasion function
|
||||||
|
*/
|
||||||
|
void bh_heap_replace(void *value,
|
||||||
|
void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_ALGO_H */
|
||||||
24
include/bh/common.h
Normal file
24
include/bh/common.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef BH_COMMON_H
|
||||||
|
#define BH_COMMON_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define BH_OK 0x0000
|
||||||
|
#define BH_ERROR 0x0001
|
||||||
|
#define BH_NOIMPL 0x0002
|
||||||
|
#define BH_OOM 0x0003
|
||||||
|
#define BH_INVALID 0x0004
|
||||||
|
#define BH_FOUND 0x0005
|
||||||
|
#define BH_NOTFOUND 0x0006
|
||||||
|
#define BH_TIMEOUT 0x0007
|
||||||
|
|
||||||
|
#define BH_UNUSED(x) (void)(x)
|
||||||
|
#define BH_PTR2INT(x) ((intptr_t)(x))
|
||||||
|
#define BH_INT2PTR(x) ((void*)(x))
|
||||||
|
|
||||||
|
typedef int (*bh_equal_cb_t)(const void *, const void *);
|
||||||
|
typedef size_t (*bh_hash_cb_t)(const void *);
|
||||||
|
|
||||||
|
#endif /* BH_COMMON_H */
|
||||||
|
|
||||||
223
include/bh/hashmap.h
Executable file
223
include/bh/hashmap.h
Executable file
@@ -0,0 +1,223 @@
|
|||||||
|
#ifndef BH_HASHMAP_H
|
||||||
|
#define BH_HASHMAP_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_hashmap_s bh_hashmap_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the new hashmap handle.
|
||||||
|
*
|
||||||
|
* \param equal Comparision function
|
||||||
|
* \param hash Key hash function
|
||||||
|
*
|
||||||
|
* \return On success, returns hashmap handle.
|
||||||
|
* \return On failure, returns a null pointer.
|
||||||
|
*/
|
||||||
|
bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
|
||||||
|
bh_hash_cb_t hash);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
*/
|
||||||
|
void bh_hashmap_free(bh_hashmap_t *hashmap);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
*/
|
||||||
|
void bh_hashmap_clear(bh_hashmap_t *hashmap);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserves space in the hashmap.
|
||||||
|
*
|
||||||
|
* This function can both expand and shrink the available space in hashmap.
|
||||||
|
* This function takes into account current hashmap load factor.
|
||||||
|
*
|
||||||
|
* \param hashmap Hahsmap handle
|
||||||
|
* \param size Capacity
|
||||||
|
*
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
* \note Actual hashmap capacity can be bigger then requested.
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the pair of key-value into the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param key Key
|
||||||
|
* \param value Value
|
||||||
|
*
|
||||||
|
* \note This function allows duplicates to be inserted.
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_hashmap_insert(bh_hashmap_t *hashmap,
|
||||||
|
void *key,
|
||||||
|
void *value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes value from the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param key Key
|
||||||
|
*
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
* \note If hashmap contains several elements with the same key, this function
|
||||||
|
* will remove only one key-value pair.
|
||||||
|
*/
|
||||||
|
void bh_hashmap_remove(bh_hashmap_t *hashmap,
|
||||||
|
void *key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns value from the hashmap by key.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param key Key
|
||||||
|
* \param value Value (optional)
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_hashmap_at(bh_hashmap_t *hashmap,
|
||||||
|
void *key,
|
||||||
|
void **value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the hashmap is empty.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
*
|
||||||
|
* \return If hashmap is empty, returns non-zero value
|
||||||
|
* \return If hashmap is not empty, returns zero value
|
||||||
|
*/
|
||||||
|
int bh_hashmap_empty(bh_hashmap_t *hashmap);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
*
|
||||||
|
* \return Returns the size of the hashmap.
|
||||||
|
*/
|
||||||
|
size_t bh_hashmap_size(bh_hashmap_t *hashmap);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the capacity of the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
*
|
||||||
|
* \return Returns the capacity of the hashmap.
|
||||||
|
*/
|
||||||
|
size_t bh_hashmap_capacity(bh_hashmap_t *hashmap);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the load factor of the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
*
|
||||||
|
* \return Returns the load factor of the hashmap.
|
||||||
|
*/
|
||||||
|
float bh_hashmap_factor(bh_hashmap_t *hashmap);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the load factor of the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param factor Load factor
|
||||||
|
*
|
||||||
|
* \note New load factor will be applied on the next reserve/insert operation.
|
||||||
|
*/
|
||||||
|
void bh_hashmap_set_factor(bh_hashmap_t *hashmap,
|
||||||
|
float factor);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the iterator to the element in the hashmap with specified key.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param iter Iterator
|
||||||
|
*
|
||||||
|
* \return On success, returns iterator value.
|
||||||
|
* \return On failure, returns NULL pointer.
|
||||||
|
*
|
||||||
|
* \note If hashmap contains several elements with the same key, this function
|
||||||
|
* will return iterator to one of them
|
||||||
|
*/
|
||||||
|
void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
|
||||||
|
void *key);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the iterator to the next element in the hashmap.
|
||||||
|
*
|
||||||
|
* If the iterator is NULL pointer, this function will return iterator to the
|
||||||
|
* first element of the hashmap.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param iter Iterator
|
||||||
|
*
|
||||||
|
* \return On success, returns new iterator value for the next element.
|
||||||
|
* \return On failure, returns NULL pointer.
|
||||||
|
*/
|
||||||
|
void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
|
||||||
|
void *iter);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes value from the hashmap pointed by by iterator.
|
||||||
|
*
|
||||||
|
* \param hashmap Hashmap handle
|
||||||
|
* \param iter Iterator
|
||||||
|
*
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
*/
|
||||||
|
void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
|
||||||
|
void *iter);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns key, pointed by the iterator.
|
||||||
|
*
|
||||||
|
* \param iter Iterator
|
||||||
|
*
|
||||||
|
* \return Returns key.
|
||||||
|
*/
|
||||||
|
void *bh_hashmap_iter_key(void *iter);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns value, pointed by the iterator.
|
||||||
|
*
|
||||||
|
* \param iter Iterator
|
||||||
|
*
|
||||||
|
* \return Returns value.
|
||||||
|
*/
|
||||||
|
void *bh_hashmap_iter_value(void *iter);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_HASHMAP_H */
|
||||||
251
include/bh/io.h
Normal file
251
include/bh/io.h
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
#ifndef BH_IO_H
|
||||||
|
#define BH_IO_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_IO_INFO_CB 0x0000
|
||||||
|
#define BH_IO_INIT_CB 0x0001
|
||||||
|
#define BH_IO_DESTROY_CB 0x0002
|
||||||
|
#define BH_IO_OPEN_CB 0x0003
|
||||||
|
#define BH_IO_CLOSE_CB 0x0004
|
||||||
|
#define BH_IO_READ_CB 0x0005
|
||||||
|
#define BH_IO_WRITE_CB 0x0006
|
||||||
|
#define BH_IO_PEEK_CB 0x0007
|
||||||
|
#define BH_IO_TELL_CB 0x0008
|
||||||
|
#define BH_IO_SEEK_CB 0x0009
|
||||||
|
#define BH_IO_FLUSH_CB 0x000A
|
||||||
|
#define BH_IO_SIZE_CB 0x000B
|
||||||
|
#define BH_IO_FLAGS_CB 0x000C
|
||||||
|
#define BH_IO_CLEAR_CB 0x000D
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_IO_READ 0x0001
|
||||||
|
#define BH_IO_WRITE 0x0002
|
||||||
|
#define BH_IO_READWRITE 0x0003
|
||||||
|
#define BH_IO_APPEND 0x0010
|
||||||
|
#define BH_IO_TRUNCATE 0x0020
|
||||||
|
#define BH_IO_CREATE 0x0040
|
||||||
|
#define BH_IO_EXIST 0x0080
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_IO_SEEK_SET 0x0000
|
||||||
|
#define BH_IO_SEEK_CUR 0x0001
|
||||||
|
#define BH_IO_SEEK_END 0x0002
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_IO_FLAG_OK 0x0000
|
||||||
|
#define BH_IO_FLAG_ERROR 0x0001
|
||||||
|
#define BH_IO_FLAG_EOF 0x0002
|
||||||
|
#define BH_IO_FLAG_OPEN 0x0004
|
||||||
|
|
||||||
|
#define BH_FILE_CLASSNAME "bh_file"
|
||||||
|
|
||||||
|
typedef struct bh_io_s bh_io_t;
|
||||||
|
typedef int (*bh_io_func_t)(void *, int, void *, void *);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the IO handle that represents file.
|
||||||
|
*
|
||||||
|
* \param path Path to the file
|
||||||
|
*
|
||||||
|
* \return On success, returns IO handle.
|
||||||
|
* \return On failure, returns NULL pointer.
|
||||||
|
*/
|
||||||
|
bh_io_t *bh_file_new(const char *path);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the IO handle that represents buffered IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*
|
||||||
|
* \return On success, returns IO handle.
|
||||||
|
* \return On failure, returns NULL pointer.
|
||||||
|
*/
|
||||||
|
bh_io_t *bh_buffer_new(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the IO handle with specified handler and context.
|
||||||
|
*
|
||||||
|
* \param func IO actions handler
|
||||||
|
* \param data Initialization data
|
||||||
|
*
|
||||||
|
* \return On success, returns IO handle.
|
||||||
|
* \return On failure, returns NULL pointer.
|
||||||
|
*/
|
||||||
|
bh_io_t *bh_io_new(bh_io_func_t func,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*/
|
||||||
|
void bh_io_free(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the IO instance classname.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*
|
||||||
|
* \return On success, returns pointer to constant string.
|
||||||
|
* \return On failure, returns NULL pointer
|
||||||
|
*/
|
||||||
|
const char *bh_io_classname(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the IO in specified mode of operation.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param mode Mode of operation
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_open(bh_io_t *io,
|
||||||
|
int mode);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_close(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads up to specified amount of bytes from the IO into memory buffer.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param buffer Pointer to the buffer
|
||||||
|
* \param size Bytes to read
|
||||||
|
* \param actual Bytes read
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_read(bh_io_t *io,
|
||||||
|
char *buffer,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes up to specified amount of bytes into the IO from the memory buffer.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param buffer Pointer to the buffer
|
||||||
|
* \param size Bytes to write
|
||||||
|
* \param actual Bytes written
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_write(bh_io_t *io,
|
||||||
|
const char *buffer,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peeks up to specified amount of bytes from the IO handle.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param buffer Pointer to the buffer
|
||||||
|
* \param size Bytes to peek
|
||||||
|
* \param actial Bytes peeked
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_peek(bh_io_t *io,
|
||||||
|
char *buffer,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells current offset in the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param position Offset
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_tell(bh_io_t *io,
|
||||||
|
int64_t *position);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seeks to specified offset in the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param position Offset
|
||||||
|
* \param direction Direction
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_seek(bh_io_t *io,
|
||||||
|
int64_t position,
|
||||||
|
int direction);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes the internal buffers of the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_flush(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the IO (either total or available size).
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
* \param size Available/total size
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_size(bh_io_t *io,
|
||||||
|
int64_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns flags of the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*
|
||||||
|
* \return Flags of the IO
|
||||||
|
*/
|
||||||
|
int bh_io_flags(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears errors of the IO.
|
||||||
|
*
|
||||||
|
* \param io IO handle
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_io_clear(bh_io_t *io);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_IO_H */
|
||||||
715
include/bh/math.h
Normal file
715
include/bh/math.h
Normal file
@@ -0,0 +1,715 @@
|
|||||||
|
#ifndef BH_MATH_H
|
||||||
|
#define BH_MATH_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_point2f_s
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} bh_point2f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_point3f_s
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
} bh_point3f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_point4f_s
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float w;
|
||||||
|
} bh_point4f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_point2i_s
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} bh_point2i_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_point3i_s
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int z;
|
||||||
|
} bh_point3i_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_point4i_s
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int z;
|
||||||
|
int w;
|
||||||
|
} bh_point4i_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_matrix3f_s
|
||||||
|
{
|
||||||
|
bh_point3f_t x;
|
||||||
|
bh_point3f_t y;
|
||||||
|
bh_point3f_t z;
|
||||||
|
} bh_matrix3f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_matrix4f_s
|
||||||
|
{
|
||||||
|
bh_point4f_t x;
|
||||||
|
bh_point4f_t y;
|
||||||
|
bh_point4f_t z;
|
||||||
|
bh_point4f_t w;
|
||||||
|
} bh_matrix4f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_line2f_s
|
||||||
|
{
|
||||||
|
bh_point2f_t normal;
|
||||||
|
float distance;
|
||||||
|
} bh_line2f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_plane3f_s
|
||||||
|
{
|
||||||
|
bh_point3f_t normal;
|
||||||
|
float distance;
|
||||||
|
} bh_plane3f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_ray2f_s
|
||||||
|
{
|
||||||
|
bh_point2f_t origin;
|
||||||
|
bh_point2f_t normal;
|
||||||
|
} bh_ray2f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_ray3f_s
|
||||||
|
{
|
||||||
|
bh_point3f_t origin;
|
||||||
|
bh_point3f_t normal;
|
||||||
|
} bh_ray3f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_aabb2f_s
|
||||||
|
{
|
||||||
|
bh_point2f_t origin;
|
||||||
|
bh_point2f_t size;
|
||||||
|
} bh_aabb2f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_aabb3f_s
|
||||||
|
{
|
||||||
|
bh_point3f_t origin;
|
||||||
|
bh_point3f_t size;
|
||||||
|
} bh_aabb3f_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_aabb2i_s
|
||||||
|
{
|
||||||
|
bh_point2i_t origin;
|
||||||
|
bh_point2i_t size;
|
||||||
|
} bh_aabb2i_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_aabb3i_s
|
||||||
|
{
|
||||||
|
bh_point3i_t origin;
|
||||||
|
bh_point3i_t size;
|
||||||
|
} bh_aabb3i_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef bh_point4f_t bh_quat_t;
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_add(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_sub(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_mul(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_scale(const bh_point4f_t *a,
|
||||||
|
float b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_madd(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
const bh_point4f_t *c,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_negate(const bh_point4f_t *in,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point4f_dot(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point4f_dot3(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_cross(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point4f_length(const bh_point4f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_normal(const bh_point4f_t *in,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_min(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_max(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_lerp(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_point4f_slerp(const bh_point4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_add(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_sub(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_mul(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_scale(const bh_point3f_t *a,
|
||||||
|
float b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_madd(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
const bh_point3f_t *c,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_negate(const bh_point3f_t *in,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point3f_dot(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_cross(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point3f_length(const bh_point3f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_normal(const bh_point3f_t *in,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_min(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_max(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_lerp(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_point3f_slerp(const bh_point3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_add(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_sub(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_mul(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_scale(const bh_point2f_t *a,
|
||||||
|
float b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_madd(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
const bh_point2f_t *c,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_negate(const bh_point2f_t *in,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point2f_dot(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point2f_cross(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_point2f_length(const bh_point2f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_normal(const bh_point2f_t *in,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_min(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_max(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_lerp(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_point2f_slerp(const bh_point2f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_add(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_sub(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_mul(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_scale(const bh_point4i_t *a,
|
||||||
|
int b,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_madd(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
const bh_point4i_t *c,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_negate(const bh_point4i_t *in,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_min(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_max(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4i_t *bh_point4i_lerp(const bh_point4i_t *a,
|
||||||
|
const bh_point4i_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point4i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_add(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_sub(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_mul(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_scale(const bh_point3i_t *a,
|
||||||
|
int b,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_madd(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
const bh_point3i_t *c,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_negate(const bh_point3i_t *in,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_min(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_max(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3i_t *bh_point3i_lerp(const bh_point3i_t *a,
|
||||||
|
const bh_point3i_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point3i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_add(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_sub(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_mul(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_scale(const bh_point2i_t *a,
|
||||||
|
int b,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_madd(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
const bh_point2i_t *c,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_negate(const bh_point2i_t *in,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_min(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_max(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2i_t *bh_point2i_lerp(const bh_point2i_t *a,
|
||||||
|
const bh_point2i_t *b,
|
||||||
|
float t,
|
||||||
|
bh_point2i_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_add bh_point4f_add
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_sub bh_point4f_sub
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_scale bh_point4f_scale
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_negate bh_point4f_negate
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_length bh_point4f_length
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_normal bh_point4f_normal
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_dot bh_point4f_dot
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_lerp bh_point4f_lerp
|
||||||
|
|
||||||
|
|
||||||
|
#define bh_quat_slerp bh_point4f_slerp
|
||||||
|
|
||||||
|
|
||||||
|
bh_quat_t *bh_quat_identity(bh_quat_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_quat_t *bh_quat_conjugate(const bh_quat_t *in,
|
||||||
|
bh_quat_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_quat_t *bh_quat_inverse(const bh_quat_t *in,
|
||||||
|
bh_quat_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_quat_t *bh_quat_mul(const bh_quat_t *a,
|
||||||
|
const bh_quat_t *b,
|
||||||
|
bh_quat_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_quat_t *bh_quat_set_euler(float roll,
|
||||||
|
float pitch,
|
||||||
|
float yaw,
|
||||||
|
bh_quat_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_quat_t *bh_quat_set_rotation(const bh_point3f_t *axis,
|
||||||
|
float angle,
|
||||||
|
bh_quat_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
void bh_quat_euler(const bh_quat_t *in,
|
||||||
|
float *roll,
|
||||||
|
float *pitch,
|
||||||
|
float *yaw);
|
||||||
|
|
||||||
|
|
||||||
|
void bh_quat_rotation(const bh_quat_t *in,
|
||||||
|
bh_point3f_t *axis,
|
||||||
|
float *angle);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_quat_matrix(const bh_quat_t *in,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_identity(bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_add(const bh_matrix4f_t *a,
|
||||||
|
const bh_matrix4f_t *b,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_sub(const bh_matrix4f_t *a,
|
||||||
|
const bh_matrix4f_t *b,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_mul(const bh_matrix4f_t *a,
|
||||||
|
const bh_matrix4f_t *b,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_scale(const bh_matrix4f_t *a,
|
||||||
|
float b,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_transpose(const bh_matrix4f_t *in,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_matrix4f_trace(const bh_matrix4f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_matrix4f_determinant(const bh_matrix4f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_inverse(const bh_matrix4f_t *in,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_scaling(float x,
|
||||||
|
float y,
|
||||||
|
float z,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_translation(float x,
|
||||||
|
float y,
|
||||||
|
float z,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_rotation_x(float angle,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_rotation_y(float angle,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_rotation_z(float angle,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_rotation(const bh_point3f_t *axis,
|
||||||
|
float angle,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_rotation_euler(float roll,
|
||||||
|
float pitch,
|
||||||
|
float yaw,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_rotation_quat(bh_quat_t *rotation,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_ortho(float x_min,
|
||||||
|
float x_max,
|
||||||
|
float y_min,
|
||||||
|
float y_max,
|
||||||
|
float z_min,
|
||||||
|
float z_max,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_perspective(float fov,
|
||||||
|
float aspect,
|
||||||
|
float z_min,
|
||||||
|
float z_max,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix4f_t *bh_matrix4f_lookat(const bh_point3f_t *camera,
|
||||||
|
const bh_point3f_t *at,
|
||||||
|
const bh_point3f_t *up,
|
||||||
|
bh_matrix4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_matrix4f_transform_point3f(const bh_matrix4f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point4f_t *bh_matrix4f_transform_point4f(const bh_matrix4f_t *a,
|
||||||
|
const bh_point4f_t *b,
|
||||||
|
bh_point4f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_identity(bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_add(const bh_matrix3f_t *a,
|
||||||
|
const bh_matrix3f_t *b,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_sub(const bh_matrix3f_t *a,
|
||||||
|
const bh_matrix3f_t *b,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_mul(const bh_matrix3f_t *a,
|
||||||
|
const bh_matrix3f_t *b,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_scale(const bh_matrix3f_t *a,
|
||||||
|
float b,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_transpose(const bh_matrix3f_t *in,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_matrix3f_trace(const bh_matrix3f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
float bh_matrix3f_determinant(const bh_matrix3f_t *in);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_inverse(const bh_matrix3f_t *in,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_scaling(float x,
|
||||||
|
float y,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_translation(float x,
|
||||||
|
float y,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_matrix3f_t *bh_matrix3f_rotation(float angle,
|
||||||
|
bh_matrix3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point2f_t *bh_matrix3f_transform_point2f(const bh_matrix3f_t *a,
|
||||||
|
const bh_point2f_t *b,
|
||||||
|
bh_point2f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
bh_point3f_t *bh_matrix3f_transform_point3f(const bh_matrix3f_t *a,
|
||||||
|
const bh_point3f_t *b,
|
||||||
|
bh_point3f_t *result);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_MATH_H */
|
||||||
149
include/bh/queue.h
Executable file
149
include/bh/queue.h
Executable file
@@ -0,0 +1,149 @@
|
|||||||
|
#ifndef BH_QUEUE_H
|
||||||
|
#define BH_QUEUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_queue_s bh_queue_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the new queue object.
|
||||||
|
*
|
||||||
|
* \return On success, returns the pointer to the new queue object.
|
||||||
|
* \return On failure, returns a null pointer.
|
||||||
|
*/
|
||||||
|
bh_queue_t *bh_queue_new(void);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the \a queue object.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object to be freed
|
||||||
|
*/
|
||||||
|
void bh_queue_free(bh_queue_t *queue);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the \a queue object.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object to be cleared
|
||||||
|
*/
|
||||||
|
void bh_queue_clear(bh_queue_t *queue);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserves the space for \a size elements in the \a queue.
|
||||||
|
*
|
||||||
|
* This function can both expand and shrink the available space in \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object to be resized in terms of capacity
|
||||||
|
* \param size New capacity of the queue
|
||||||
|
*
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
* \note Actual hashmap capacity can be bigger then requested.
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_queue_reserve(bh_queue_t *queue,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the \a value into the \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
* \param value Value to be inserted
|
||||||
|
*
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int bh_queue_insert(bh_queue_t *queue,
|
||||||
|
void *value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes front value from the \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
*
|
||||||
|
* \note Calling this function will invalidate iterators.
|
||||||
|
*/
|
||||||
|
void bh_queue_remove(bh_queue_t *queue);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns front value from the \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
*
|
||||||
|
* \return On success, returns front value from the queue.
|
||||||
|
* \return On failure, returns null pointer.
|
||||||
|
*/
|
||||||
|
int bh_queue_front(bh_queue_t *queue,
|
||||||
|
void **value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the \a queue is empty.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
*
|
||||||
|
* \return If queue is empty, returns non-zero value
|
||||||
|
* \return If queue is not empty, returns zero value
|
||||||
|
*/
|
||||||
|
int bh_queue_empty(bh_queue_t *queue);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
*
|
||||||
|
* \return Returns the size of the queue.
|
||||||
|
*/
|
||||||
|
size_t bh_queue_size(bh_queue_t *queue);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the capacity of the \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
*
|
||||||
|
* \return Returns the capacity of the queue.
|
||||||
|
*/
|
||||||
|
size_t bh_queue_capacity(bh_queue_t *queue);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the iterator to the next element in the \a queue.
|
||||||
|
*
|
||||||
|
* \param queue Pointer to the queue object
|
||||||
|
* \param iter Opaque iterator value
|
||||||
|
*
|
||||||
|
* \return If the \a iter doesn't point to the last element of the queue,
|
||||||
|
* returns next iterator value.
|
||||||
|
* \return If the \a iter point to the last element of the queue, returns
|
||||||
|
* null pointer.
|
||||||
|
* \return If the \a iter is the null pointer, returns iterator to the
|
||||||
|
* first element of the queue.
|
||||||
|
*/
|
||||||
|
void *bh_queue_iter_next(bh_queue_t *queue,
|
||||||
|
void *iter);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value, pointed by the queue iterator \a iter.
|
||||||
|
*
|
||||||
|
* \param iter Opaque iterator value
|
||||||
|
*
|
||||||
|
* \return Returns value, pointed by iterator.
|
||||||
|
*/
|
||||||
|
void *bh_queue_iter_value(void *iter);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_QUEUE_H */
|
||||||
10
main.c
Normal file
10
main.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <bh/io.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
bh_io_t *io = bh_file_new("hello.txt");
|
||||||
|
bh_io_open(io, BH_IO_WRITE);
|
||||||
|
bh_io_write(io, "Hello, world!", 13, NULL);
|
||||||
|
bh_io_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
411
src/algo.c
Executable file
411
src/algo.c
Executable file
@@ -0,0 +1,411 @@
|
|||||||
|
#include <bh/algo.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
void bh_swap(void *dest,
|
||||||
|
void *src,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
/* Swap bytes in int-sized chunks */
|
||||||
|
while (size >= sizeof(tmp))
|
||||||
|
{
|
||||||
|
memmove(&tmp, dest, sizeof(tmp));
|
||||||
|
memmove(dest, src, sizeof(tmp));
|
||||||
|
memmove(src, &tmp, sizeof(tmp));
|
||||||
|
|
||||||
|
dest = (char *)dest + sizeof(tmp);
|
||||||
|
src = (char *)src + sizeof(tmp);
|
||||||
|
size -= sizeof(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap the remaining size */
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
memmove(&tmp, dest, size);
|
||||||
|
memmove(dest, src, size);
|
||||||
|
memmove(src, &tmp, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_partition(void *pivot,
|
||||||
|
void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
char *start, *end, *i, *j;
|
||||||
|
|
||||||
|
/* Calculate start, end and item pointers */
|
||||||
|
start = (char *)array;
|
||||||
|
end = start + size * element;
|
||||||
|
i = start;
|
||||||
|
j = start + (size - 1) * element;
|
||||||
|
|
||||||
|
/* Iterate over array */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* Find first element from the left that are bigger then pivot */
|
||||||
|
while (i < end && equal(i, pivot) < 0)
|
||||||
|
i += element;
|
||||||
|
|
||||||
|
/* Find first element from the right that are less then pivot*/
|
||||||
|
while (j >= start && equal(j, pivot) >= 0)
|
||||||
|
j -= element;
|
||||||
|
|
||||||
|
/* If item elemetns passed each other - we are done */
|
||||||
|
if (i >= j)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Special case when pivot is actually part of the array */
|
||||||
|
if (pivot == i)
|
||||||
|
pivot = j;
|
||||||
|
else if (pivot == j)
|
||||||
|
pivot = i;
|
||||||
|
|
||||||
|
/* Swap elements and continue */
|
||||||
|
bh_swap(i, j, element);
|
||||||
|
i += element;
|
||||||
|
j -= element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return pointer to the middle of the partition */
|
||||||
|
return j + element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void bh_sort_insert(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
/* Standard insert sort */
|
||||||
|
for (i = 1; i < size; i++)
|
||||||
|
{
|
||||||
|
for (j = i; j >= 1; j -= 1)
|
||||||
|
{
|
||||||
|
char *lhs, *rhs;
|
||||||
|
|
||||||
|
lhs = (char *)array + j * element;
|
||||||
|
rhs = (char *)array + (j - 1) * element;
|
||||||
|
|
||||||
|
if (equal(lhs, rhs) < 0)
|
||||||
|
bh_swap(lhs, rhs, element);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_sort_shell(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
static const size_t gaps[10] = {1750, 701, 301, 132, 57, 23, 10, 4, 1, 0};
|
||||||
|
const size_t *gap;
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
/* Shell sort with A102549 sequence */
|
||||||
|
for (gap = gaps; *gap; ++gap)
|
||||||
|
{
|
||||||
|
for (i = *gap; i < size; i++)
|
||||||
|
{
|
||||||
|
for (j = i; j >= *gap; j -= *gap)
|
||||||
|
{
|
||||||
|
char *lhs, *rhs;
|
||||||
|
|
||||||
|
lhs = (char *)array + j * element;
|
||||||
|
rhs = (char *)array + (j - *gap) * element;
|
||||||
|
|
||||||
|
if (equal(lhs, rhs) < 0)
|
||||||
|
bh_swap(lhs, rhs, element);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_sort_heap(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
bh_heap_make(array, size, element, equal);
|
||||||
|
for (i = size; i > 0; i--)
|
||||||
|
bh_heap_remove(array, i, element, equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_sort_intro_r(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal,
|
||||||
|
size_t depth)
|
||||||
|
{
|
||||||
|
/* Introsort (with manual tail call optimization) */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
char *start, *middle, *end, *pivot;
|
||||||
|
|
||||||
|
if (size < 16)
|
||||||
|
{
|
||||||
|
/* There are less then 16 elements left - use Shell/Insert sort */
|
||||||
|
bh_sort_shell(array, size, element, equal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!depth)
|
||||||
|
{
|
||||||
|
/* Max depth reached - use heap sort */
|
||||||
|
bh_sort_heap(array, size, element, equal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate start, middle and end pointers */
|
||||||
|
start = (char *)array;
|
||||||
|
middle = start + (size / 2) * element;
|
||||||
|
end = start + (size - 1) * element;
|
||||||
|
|
||||||
|
/* Select middle element */
|
||||||
|
if (equal(start, middle) > 0)
|
||||||
|
{
|
||||||
|
if (equal(middle, end) > 0)
|
||||||
|
pivot = middle;
|
||||||
|
else if (equal(start, end) > 0)
|
||||||
|
pivot = end;
|
||||||
|
else
|
||||||
|
pivot = start;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (equal(start, end) > 0)
|
||||||
|
pivot = start;
|
||||||
|
else if (equal(middle, end) > 0)
|
||||||
|
pivot = end;
|
||||||
|
else
|
||||||
|
pivot = middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Partition the array */
|
||||||
|
middle = bh_partition(pivot, array, size, element, equal);
|
||||||
|
|
||||||
|
/* Recursive call into first half */
|
||||||
|
bh_sort_intro_r(array, (middle - start) / element, element, equal, depth - 1);
|
||||||
|
|
||||||
|
/* Setup array and size for the second half */
|
||||||
|
array = middle;
|
||||||
|
size = size - (middle - start) / element;
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_sort(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
size_t depth, depth_log;
|
||||||
|
|
||||||
|
/* Calculate max depth */
|
||||||
|
depth = 0;
|
||||||
|
depth_log = 1;
|
||||||
|
while (depth_log < size)
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
depth_log <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call main sorting function */
|
||||||
|
bh_sort_intro_r(array, size, element, equal, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_heap_make(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
char *start, *end;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Calculate start and end pointers of the array */
|
||||||
|
start = (char *)array;
|
||||||
|
end = start + size * element;
|
||||||
|
|
||||||
|
/* Bottom up heapify algorithm */
|
||||||
|
for (i = size / 2 + 1; i; --i)
|
||||||
|
{
|
||||||
|
char *current, *left, *right;
|
||||||
|
|
||||||
|
/* Calculate current and children pointers */
|
||||||
|
current = start + (i - 1) * element;
|
||||||
|
left = start + (current - start) * 2 + element;
|
||||||
|
right = left + element;
|
||||||
|
|
||||||
|
while (left < end)
|
||||||
|
{
|
||||||
|
char *biggest;
|
||||||
|
|
||||||
|
/* Determine biggest child */
|
||||||
|
biggest = left;
|
||||||
|
if (right < end && equal(left, right) < 0)
|
||||||
|
biggest = right;
|
||||||
|
|
||||||
|
/* Compare biggest child with current */
|
||||||
|
if (equal(current, biggest) < 0)
|
||||||
|
{
|
||||||
|
/* Swap content and recalculate children pointers */
|
||||||
|
bh_swap(current, biggest, element);
|
||||||
|
current = biggest;
|
||||||
|
left = start + (current - start) * 2 + element;
|
||||||
|
right = left + element;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_heap_remove(void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
char *start, *end, *current, *left, *right;
|
||||||
|
|
||||||
|
if (size <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Calculate start, end and children pointers */
|
||||||
|
start = (char *)array;
|
||||||
|
end = start + (size - 1) * element;
|
||||||
|
current = start;
|
||||||
|
left = start + (current - start) * 2 + element;
|
||||||
|
right = left + element;
|
||||||
|
|
||||||
|
/* Swap first and last element */
|
||||||
|
bh_swap(current, end, element);
|
||||||
|
|
||||||
|
/* Iterate until we reach the end */
|
||||||
|
while (left < end)
|
||||||
|
{
|
||||||
|
char *biggest;
|
||||||
|
|
||||||
|
/* Determine biggest child */
|
||||||
|
biggest = left;
|
||||||
|
if (right < end && equal(left, right) < 0)
|
||||||
|
biggest = right;
|
||||||
|
|
||||||
|
/* Compare biggest child with current */
|
||||||
|
if (equal(current, biggest) < 0)
|
||||||
|
{
|
||||||
|
/* Swap content and recalculate children pointers */
|
||||||
|
bh_swap(current, biggest, element);
|
||||||
|
current = biggest;
|
||||||
|
left = start + (current - start) * 2 + element;
|
||||||
|
right = left + element;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_heap_insert(void *value,
|
||||||
|
void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
char *start, *end, *current;
|
||||||
|
|
||||||
|
/* Calculate begin and end pointers */
|
||||||
|
start = (char *)array;
|
||||||
|
end = start + size * element;
|
||||||
|
current = end;
|
||||||
|
|
||||||
|
/* Copy value into array */
|
||||||
|
if (value)
|
||||||
|
memmove(current, value, element);
|
||||||
|
|
||||||
|
while (current > start)
|
||||||
|
{
|
||||||
|
char *parent;
|
||||||
|
|
||||||
|
/* Calculate parent pointer */
|
||||||
|
parent = start + (((current - start) / element - 1) / 2) * element;
|
||||||
|
|
||||||
|
/* Compare current and parent */
|
||||||
|
if (equal(parent, current) < 0)
|
||||||
|
{
|
||||||
|
/* Swap current and parent */
|
||||||
|
bh_swap(parent, current, element);
|
||||||
|
current = parent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_heap_replace(void *value,
|
||||||
|
void *array,
|
||||||
|
size_t size,
|
||||||
|
size_t element,
|
||||||
|
bh_equal_cb_t equal)
|
||||||
|
{
|
||||||
|
char *start, *end, *current, *left, *right;
|
||||||
|
|
||||||
|
if (size < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Calculate start, end and children pointers */
|
||||||
|
start = (char *)array;
|
||||||
|
end = start + size * element;
|
||||||
|
current = start;
|
||||||
|
left = start + (current - start) * 2 + element;
|
||||||
|
right = left + element;
|
||||||
|
|
||||||
|
/* Copy supplied element to the first (top) position */
|
||||||
|
if (value)
|
||||||
|
memmove(current, value, element);
|
||||||
|
else
|
||||||
|
memmove(current, start + size * element, element);
|
||||||
|
|
||||||
|
/* Iterate until we reach the end */
|
||||||
|
while (left < end)
|
||||||
|
{
|
||||||
|
char *biggest;
|
||||||
|
|
||||||
|
/* Determine biggest child */
|
||||||
|
biggest = left;
|
||||||
|
if (right < end && equal(left, right) < 0)
|
||||||
|
biggest = right;
|
||||||
|
|
||||||
|
/* Compare biggest child with current */
|
||||||
|
if (equal(current, biggest) < 0)
|
||||||
|
{
|
||||||
|
/* Swap content and recalculate children pointers */
|
||||||
|
bh_swap(current, biggest, element);
|
||||||
|
current = biggest;
|
||||||
|
left = start + (current - start) * 2 + element;
|
||||||
|
right = left + element;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
170
src/dummy/file.c
Normal file
170
src/dummy/file.c
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
#include <bh/io.h>
|
||||||
|
|
||||||
|
typedef struct bh_file_s
|
||||||
|
{
|
||||||
|
int implement;
|
||||||
|
int me;
|
||||||
|
} bh_file_t;
|
||||||
|
|
||||||
|
static int file_info(bh_file_t *file,
|
||||||
|
size_t *size,
|
||||||
|
const char **name);
|
||||||
|
|
||||||
|
static int file_init(bh_file_t *file,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
|
static int file_destroy(bh_file_t *file);
|
||||||
|
|
||||||
|
static int file_open(bh_file_t *file,
|
||||||
|
int *mode);
|
||||||
|
|
||||||
|
static int file_close(bh_file_t *file);
|
||||||
|
|
||||||
|
static int file_read(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
static int file_write(bh_file_t *file,
|
||||||
|
const char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
static int file_peek(bh_file_t* file,
|
||||||
|
char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
static int file_flush(bh_file_t *file);
|
||||||
|
|
||||||
|
static int file_seek(bh_file_t *file,
|
||||||
|
int64_t *pos,
|
||||||
|
int *dir);
|
||||||
|
|
||||||
|
static int file_tell(bh_file_t *file,
|
||||||
|
int64_t *pos);
|
||||||
|
|
||||||
|
static int file_size(bh_file_t *file,
|
||||||
|
int64_t *size);
|
||||||
|
|
||||||
|
static int file_flags(bh_file_t *file);
|
||||||
|
|
||||||
|
static int file_clear(bh_file_t *file);
|
||||||
|
|
||||||
|
static int file_info(bh_file_t *file,
|
||||||
|
size_t *size,
|
||||||
|
const char **name)
|
||||||
|
{
|
||||||
|
static const char classname[] = BH_FILE_CLASSNAME;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = sizeof(*file);
|
||||||
|
if (name)
|
||||||
|
*name = classname;
|
||||||
|
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_init(bh_file_t *file,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_destroy(bh_file_t *file)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_open(bh_file_t *file,
|
||||||
|
int *mode)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_close(bh_file_t *file)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_read(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_write(bh_file_t *file,
|
||||||
|
const char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_peek(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_flush(bh_file_t *file)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_seek(bh_file_t *file,
|
||||||
|
int64_t *pos,
|
||||||
|
int *dir)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_tell(bh_file_t *file,
|
||||||
|
int64_t *pos)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_size(bh_file_t *file,
|
||||||
|
int64_t *size)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_flags(bh_file_t *file)
|
||||||
|
{
|
||||||
|
return BH_IO_FLAG_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_clear(bh_file_t *file)
|
||||||
|
{
|
||||||
|
return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_proc(bh_file_t *file,
|
||||||
|
int type,
|
||||||
|
void *arg1,
|
||||||
|
void *arg2)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case BH_IO_INFO_CB: return file_info(file, (size_t *)arg1, (const char **)arg2);
|
||||||
|
case BH_IO_INIT_CB: return file_init(file, (const char *)arg1);
|
||||||
|
case BH_IO_DESTROY_CB: return file_destroy(file);
|
||||||
|
case BH_IO_OPEN_CB: return file_open(file, (int *)arg1);
|
||||||
|
case BH_IO_CLOSE_CB: return file_close(file);
|
||||||
|
case BH_IO_READ_CB: return file_read(file, (char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_WRITE_CB: return file_write(file, (const char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_PEEK_CB: return file_peek(file, (char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_FLUSH_CB: return file_flush(file);
|
||||||
|
case BH_IO_SEEK_CB: return file_seek(file, (int64_t *)arg1, (int *)arg2);
|
||||||
|
case BH_IO_TELL_CB: return file_tell(file, (int64_t *)arg1);
|
||||||
|
case BH_IO_SIZE_CB: return file_size(file, (int64_t *)arg1);
|
||||||
|
case BH_IO_FLAGS_CB: return file_flags(file);
|
||||||
|
case BH_IO_CLEAR_CB: return file_clear(file);
|
||||||
|
default: return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bh_io_t *bh_file_new(const char *path)
|
||||||
|
{
|
||||||
|
return bh_io_new((bh_io_func_t)file_proc, (void *)path);
|
||||||
|
}
|
||||||
390
src/hashmap.c
Executable file
390
src/hashmap.c
Executable file
@@ -0,0 +1,390 @@
|
|||||||
|
#include <bh/hashmap.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_hashmap_node_s
|
||||||
|
{
|
||||||
|
void *key;
|
||||||
|
void *value;
|
||||||
|
} bh_hashmap_node_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct bh_hashmap_s
|
||||||
|
{
|
||||||
|
bh_hashmap_node_t *data;
|
||||||
|
size_t *psls;
|
||||||
|
size_t size;
|
||||||
|
size_t capacity;
|
||||||
|
size_t threshold;
|
||||||
|
bh_equal_cb_t equal;
|
||||||
|
bh_hash_cb_t hash;
|
||||||
|
float factor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_hashmap_init(bh_hashmap_t *hashmap,
|
||||||
|
bh_equal_cb_t equal,
|
||||||
|
bh_hash_cb_t hash)
|
||||||
|
{
|
||||||
|
memset(hashmap, 0, sizeof(*hashmap));
|
||||||
|
hashmap->factor = 0.75f;
|
||||||
|
hashmap->equal = equal;
|
||||||
|
hashmap->hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_hashmap_destroy(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
if (hashmap->capacity)
|
||||||
|
{
|
||||||
|
free(hashmap->data);
|
||||||
|
free(hashmap->psls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int calc_capacity(size_t size,
|
||||||
|
float factor,
|
||||||
|
size_t *capacity,
|
||||||
|
size_t *threshold)
|
||||||
|
{
|
||||||
|
/* Check if we need any capacity at all */
|
||||||
|
if (!size)
|
||||||
|
{
|
||||||
|
*capacity = 0;
|
||||||
|
*threshold = 0;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate nearest power of 2 capacity */
|
||||||
|
*capacity = 16;
|
||||||
|
*threshold = *capacity * factor;
|
||||||
|
while (size > *threshold)
|
||||||
|
{
|
||||||
|
*capacity *= 2;
|
||||||
|
*threshold = *capacity * factor;
|
||||||
|
|
||||||
|
/* Catch capacity overflow */
|
||||||
|
if (*capacity < 16)
|
||||||
|
return BH_OOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Catch malloc overflow */
|
||||||
|
if (*capacity >= ((size_t)-1) / sizeof(bh_hashmap_node_t))
|
||||||
|
return BH_OOM;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void copy_hashmap(bh_hashmap_t *dest,
|
||||||
|
bh_hashmap_t *src)
|
||||||
|
{
|
||||||
|
void *iter;
|
||||||
|
|
||||||
|
/* Iterate and insert data into hashmap */
|
||||||
|
iter = bh_hashmap_iter_next(src, NULL);
|
||||||
|
while (iter)
|
||||||
|
{
|
||||||
|
void *key, *value;
|
||||||
|
|
||||||
|
key = bh_hashmap_iter_key(iter);
|
||||||
|
value = bh_hashmap_iter_value(iter);
|
||||||
|
bh_hashmap_insert(dest, key, value);
|
||||||
|
|
||||||
|
iter = bh_hashmap_iter_next(src, iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
|
||||||
|
bh_hash_cb_t hash)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *result;
|
||||||
|
|
||||||
|
result = malloc(sizeof(*result));
|
||||||
|
if (result)
|
||||||
|
bh_hashmap_init(result, equal, hash);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_hashmap_free(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
bh_hashmap_destroy(hashmap);
|
||||||
|
free(hashmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_hashmap_clear(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
if (hashmap->capacity)
|
||||||
|
memset(hashmap->psls, 0, hashmap->capacity * sizeof(size_t));
|
||||||
|
hashmap->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
bh_hashmap_t other;
|
||||||
|
size_t capacity, threshold;
|
||||||
|
|
||||||
|
/* New capacity can't be smaller then current hashmap size */
|
||||||
|
if (size < hashmap->size)
|
||||||
|
size = hashmap->size;
|
||||||
|
|
||||||
|
/* Calculate new capacity */
|
||||||
|
if (calc_capacity(size, hashmap->factor, &capacity, &threshold))
|
||||||
|
return BH_OOM;
|
||||||
|
|
||||||
|
/* Prevent same size reallocation */
|
||||||
|
if (capacity == hashmap->capacity)
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
/* Initialize new hashmap */
|
||||||
|
bh_hashmap_init(&other, hashmap->equal, hashmap->hash);
|
||||||
|
other.factor = hashmap->factor;
|
||||||
|
|
||||||
|
if (capacity)
|
||||||
|
{
|
||||||
|
/* Allocate new memory for the hashmap */
|
||||||
|
other.data = malloc(sizeof(*other.data) * capacity);
|
||||||
|
other.psls = malloc(sizeof(size_t) * capacity);
|
||||||
|
other.threshold = threshold;
|
||||||
|
other.capacity = capacity;
|
||||||
|
|
||||||
|
/* Check for allocations failure */
|
||||||
|
if (!other.data || !other.psls)
|
||||||
|
{
|
||||||
|
if (other.data)
|
||||||
|
free(other.data);
|
||||||
|
if (other.psls)
|
||||||
|
free(other.psls);
|
||||||
|
return BH_OOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset probe sequence lengths */
|
||||||
|
memset(other.psls, 0, sizeof(size_t) * other.capacity);
|
||||||
|
|
||||||
|
/* Copy data from old hashmap to the new hashmap */
|
||||||
|
copy_hashmap(&other, hashmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Swap hashmaps */
|
||||||
|
bh_hashmap_destroy(hashmap);
|
||||||
|
*hashmap = other;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_hashmap_insert(bh_hashmap_t *hashmap,
|
||||||
|
void *key,
|
||||||
|
void *value)
|
||||||
|
{
|
||||||
|
size_t bucket, psl, tmp_psl;
|
||||||
|
bh_hashmap_node_t item, tmp;
|
||||||
|
|
||||||
|
/* Try to stay below hashmap threshold */
|
||||||
|
if (hashmap->size + 1 > hashmap->threshold)
|
||||||
|
if (bh_hashmap_reserve(hashmap, hashmap->size + 1))
|
||||||
|
if (hashmap->size >= hashmap->capacity)
|
||||||
|
return BH_OOM;
|
||||||
|
|
||||||
|
/* Prepare inserted data and set PSL to 1 */
|
||||||
|
item.key = key;
|
||||||
|
item.value = value;
|
||||||
|
psl = 1;
|
||||||
|
|
||||||
|
/* Calculate prefered bucket index */
|
||||||
|
bucket = hashmap->hash(key) & (hashmap->capacity - 1);
|
||||||
|
|
||||||
|
/* Find empty bucket */
|
||||||
|
while (hashmap->psls[bucket])
|
||||||
|
{
|
||||||
|
/* Current bucket is richer then us - swap elements */
|
||||||
|
if (psl > hashmap->psls[bucket])
|
||||||
|
{
|
||||||
|
tmp = hashmap->data[bucket];
|
||||||
|
tmp_psl = hashmap->psls[bucket];
|
||||||
|
hashmap->data[bucket] = item;
|
||||||
|
hashmap->psls[bucket] = psl;
|
||||||
|
item = tmp;
|
||||||
|
psl = tmp_psl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket = (bucket + 1) & (hashmap->capacity - 1);
|
||||||
|
psl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Found empty bucket - place item here */
|
||||||
|
hashmap->data[bucket] = item;
|
||||||
|
hashmap->psls[bucket] = psl;
|
||||||
|
hashmap->size++;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_hashmap_remove(bh_hashmap_t *hashmap,
|
||||||
|
void *key)
|
||||||
|
{
|
||||||
|
void *iter;
|
||||||
|
|
||||||
|
iter = bh_hashmap_iter_at(hashmap, key);
|
||||||
|
if (iter)
|
||||||
|
bh_hashmap_iter_remove(hashmap, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_hashmap_at(bh_hashmap_t *hashmap,
|
||||||
|
void *key,
|
||||||
|
void **value)
|
||||||
|
{
|
||||||
|
void *iter;
|
||||||
|
iter = bh_hashmap_iter_at(hashmap, key);
|
||||||
|
|
||||||
|
if (!iter)
|
||||||
|
return BH_NOTFOUND;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
*value = bh_hashmap_iter_value(iter);
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_hashmap_empty(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
return !hashmap->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t bh_hashmap_size(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
return hashmap->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t bh_hashmap_capacity(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
return hashmap->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float bh_hashmap_factor(bh_hashmap_t *hashmap)
|
||||||
|
{
|
||||||
|
return hashmap->factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_hashmap_set_factor(bh_hashmap_t *hashmap,
|
||||||
|
float factor)
|
||||||
|
{
|
||||||
|
/* Limit the factor value to [0.15, 1.0] */
|
||||||
|
factor = (factor > 1.0f) ? (1.0f) : (factor);
|
||||||
|
factor = (factor < 0.15f) ? (0.15f) : (factor);
|
||||||
|
|
||||||
|
/* Calculate new threshold value */
|
||||||
|
hashmap->factor = factor;
|
||||||
|
hashmap->threshold = hashmap->capacity * factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
|
||||||
|
void *key)
|
||||||
|
{
|
||||||
|
size_t bucket, psl;
|
||||||
|
|
||||||
|
/* Nothing can be in empty map */
|
||||||
|
if (!hashmap->size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Calculate prefered bucket index and set PSL to 1 */
|
||||||
|
bucket = hashmap->hash(key) & (hashmap->capacity - 1);
|
||||||
|
psl = 1;
|
||||||
|
|
||||||
|
/* Iterate hashmap until we find element or find richer bucket */
|
||||||
|
while (hashmap->psls[bucket] >= psl && hashmap->equal(hashmap->data[bucket].key, key))
|
||||||
|
{
|
||||||
|
bucket = (bucket + 1) & (hashmap->capacity - 1);
|
||||||
|
psl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If bucket is poorer or equal to us - we found our element */
|
||||||
|
if (hashmap->psls[bucket] >= psl)
|
||||||
|
return hashmap->data + bucket;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
|
||||||
|
void *iter)
|
||||||
|
{
|
||||||
|
bh_hashmap_node_t *item;
|
||||||
|
|
||||||
|
item = (bh_hashmap_node_t *)iter;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* Advance or set iterator to the first element */
|
||||||
|
if (item)
|
||||||
|
item++;
|
||||||
|
else
|
||||||
|
item = hashmap->data;
|
||||||
|
|
||||||
|
/* Check iterator for validity */
|
||||||
|
if (item >= hashmap->data + hashmap->capacity)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Check iterator's item PSL */
|
||||||
|
if (hashmap->psls[item - hashmap->data])
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
|
||||||
|
void *iter)
|
||||||
|
{
|
||||||
|
size_t bucket, next_bucket;
|
||||||
|
|
||||||
|
/* Check if hashmap is empty or we are given NULL iterator */
|
||||||
|
if (!iter || !hashmap->size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Adjust hashmap size, calculate current and next bucket index */
|
||||||
|
hashmap->size--;
|
||||||
|
bucket = (bh_hashmap_node_t *)iter - hashmap->data;
|
||||||
|
next_bucket = (bucket + 1) & (hashmap->capacity - 1);
|
||||||
|
|
||||||
|
/* Shift all elements toward their preffered place */
|
||||||
|
while (hashmap->psls[next_bucket] > 1)
|
||||||
|
{
|
||||||
|
/* Copy item and adjust PSL */
|
||||||
|
hashmap->data[bucket] = hashmap->data[next_bucket];
|
||||||
|
hashmap->psls[bucket] = hashmap->psls[next_bucket] - 1;
|
||||||
|
|
||||||
|
/* Calculate next bucket index */
|
||||||
|
bucket = next_bucket;
|
||||||
|
next_bucket = (bucket + 1) & (hashmap->capacity - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset bucket's PSL (mark empty) */
|
||||||
|
hashmap->psls[bucket] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_hashmap_iter_key(void *iter)
|
||||||
|
{
|
||||||
|
return ((bh_hashmap_node_t *)iter)->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_hashmap_iter_value(void *iter)
|
||||||
|
{
|
||||||
|
return ((bh_hashmap_node_t *)iter)->value;
|
||||||
|
}
|
||||||
|
|
||||||
224
src/io.c
Normal file
224
src/io.c
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
#include <bh/io.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define BUFFER_SIZE (sizeof(char *))
|
||||||
|
|
||||||
|
|
||||||
|
struct bh_io_s
|
||||||
|
{
|
||||||
|
bh_io_func_t func;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bh_io_t *bh_io_new(bh_io_func_t func,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
size_t requested;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Get information about IO device size */
|
||||||
|
if (func(NULL, BH_IO_INFO_CB, &requested, NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate space for the IO device */
|
||||||
|
io = malloc(sizeof(*io) + requested);
|
||||||
|
if (!io)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Initialize IO device */
|
||||||
|
io->func = func;
|
||||||
|
if (func(io + 1, BH_IO_INIT_CB, data, NULL))
|
||||||
|
{
|
||||||
|
free(io);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return io;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_io_free(bh_io_t *io)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Call the IO device destruction handler */
|
||||||
|
io->func(io + 1, BH_IO_DESTROY_CB, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *bh_io_classname(bh_io_t *io)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!io)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (io->func(io + 1, BH_IO_INFO_CB, NULL, &name) != BH_OK)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return name;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_open(bh_io_t *io,
|
||||||
|
int mode)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device open handler with specified mode */
|
||||||
|
return io->func(io + 1, BH_IO_OPEN_CB, &mode, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_close(bh_io_t *io)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device close handler */
|
||||||
|
return io->func(io + 1, BH_IO_CLOSE_CB, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_read(bh_io_t *io,
|
||||||
|
char *buffer,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual)
|
||||||
|
{
|
||||||
|
int code;
|
||||||
|
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device read handler */
|
||||||
|
code = io->func(io + 1, BH_IO_READ_CB, buffer, &size);
|
||||||
|
|
||||||
|
/* If caller wants to know actual read size - report it back */
|
||||||
|
if (actual)
|
||||||
|
*actual = size;
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_write(bh_io_t *io,
|
||||||
|
const char *buffer,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual)
|
||||||
|
{
|
||||||
|
int code;
|
||||||
|
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device write handler */
|
||||||
|
code = io->func(io + 1, BH_IO_WRITE_CB, (void *)buffer, &size);
|
||||||
|
|
||||||
|
/* If caller wants to know actual written size - report it back */
|
||||||
|
if (actual)
|
||||||
|
*actual = size;
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bh_io_peek(bh_io_t *io,
|
||||||
|
char *buffer,
|
||||||
|
size_t size,
|
||||||
|
size_t *actual)
|
||||||
|
{
|
||||||
|
int code;
|
||||||
|
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device peek handler */
|
||||||
|
code = io->func(io + 1, BH_IO_PEEK_CB, (void *)buffer, &size);
|
||||||
|
|
||||||
|
/* If caller wants to know actual written size - report it back */
|
||||||
|
if (actual)
|
||||||
|
*actual = size;
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_tell(bh_io_t *io,
|
||||||
|
int64_t *position)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device tell handler */
|
||||||
|
return io->func(io + 1, BH_IO_TELL_CB, position, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_seek(bh_io_t *io,
|
||||||
|
int64_t position,
|
||||||
|
int direction)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device seek handler */
|
||||||
|
return io->func(io + 1, BH_IO_SEEK_CB, &position, &direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_flush(bh_io_t *io)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device flush handler */
|
||||||
|
return io->func(io + 1, BH_IO_FLUSH_CB, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_size(bh_io_t *io,
|
||||||
|
int64_t *size)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device size handler */
|
||||||
|
return io->func(io + 1, BH_IO_SIZE_CB, size, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_flags(bh_io_t *io)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_IO_FLAG_ERROR;
|
||||||
|
|
||||||
|
/* Call the IO device flags handler */
|
||||||
|
return io->func(io + 1, BH_IO_FLAGS_CB, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_io_clear(bh_io_t *io)
|
||||||
|
{
|
||||||
|
/* Prevent working with NULL io */
|
||||||
|
if (!io)
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
/* Call the IO device clear error handler */
|
||||||
|
return io->func(io + 1, BH_IO_CLEAR_CB, NULL, NULL);
|
||||||
|
}
|
||||||
1778
src/math.c
Normal file
1778
src/math.c
Normal file
File diff suppressed because it is too large
Load Diff
405
src/posix/file.c
Normal file
405
src/posix/file.c
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
#include <bh/io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_file_s
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int mode;
|
||||||
|
int flags;
|
||||||
|
int handle;
|
||||||
|
} bh_file_t;
|
||||||
|
|
||||||
|
|
||||||
|
static int file_info(bh_file_t *file,
|
||||||
|
size_t *size,
|
||||||
|
const char **ident);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_init(bh_file_t *file,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_destroy(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_open(bh_file_t *file,
|
||||||
|
int *mode);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_close(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_read(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_write(bh_file_t *file,
|
||||||
|
const char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_peek(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flush(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_seek(bh_file_t *file,
|
||||||
|
int64_t *pos,
|
||||||
|
int *dir);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_tell(bh_file_t *file,
|
||||||
|
int64_t *pos);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_size(bh_file_t *file,
|
||||||
|
int64_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flags(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_clear(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_info(bh_file_t *file,
|
||||||
|
size_t *size,
|
||||||
|
const char **name)
|
||||||
|
{
|
||||||
|
static const char classname[] = BH_FILE_CLASSNAME;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = sizeof(*file);
|
||||||
|
if (name)
|
||||||
|
*name = classname;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_init(bh_file_t *file,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
/* Check if path is valid */
|
||||||
|
if (!path)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Duplicate path string and initialize the file struct */
|
||||||
|
file->path = strdup(path);
|
||||||
|
file->mode = 0;
|
||||||
|
file->handle = -1;
|
||||||
|
file->flags = 0;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_destroy(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* Close the file handle on destruction */
|
||||||
|
if (file->handle != -1)
|
||||||
|
file_close(file);
|
||||||
|
|
||||||
|
/* Free path string */
|
||||||
|
free(file->path);
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_openflags(int mode)
|
||||||
|
{
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
/* Determine read/write flags */
|
||||||
|
if ((mode & BH_IO_READWRITE) == BH_IO_READWRITE)
|
||||||
|
flags |= O_RDWR;
|
||||||
|
else if (mode & BH_IO_WRITE)
|
||||||
|
flags |= O_WRONLY;
|
||||||
|
else if (mode & BH_IO_READ)
|
||||||
|
flags |= O_RDONLY;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Check if existing file should be opened */
|
||||||
|
if (!(mode & BH_IO_EXIST))
|
||||||
|
{
|
||||||
|
flags |= O_CREAT;
|
||||||
|
|
||||||
|
/* Check if file should be created */
|
||||||
|
if (mode & BH_IO_CREATE)
|
||||||
|
flags |= O_EXCL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if file should be opened in append mode */
|
||||||
|
if (mode & BH_IO_APPEND)
|
||||||
|
flags |= O_APPEND;
|
||||||
|
|
||||||
|
/* Check if file should be truncated */
|
||||||
|
if (mode & BH_IO_TRUNCATE)
|
||||||
|
flags |= O_TRUNC;
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_open(bh_file_t *file,
|
||||||
|
int *mode)
|
||||||
|
{
|
||||||
|
static const mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
/* If file is already opened - report error */
|
||||||
|
if (file->handle != -1)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Determine file open flags */
|
||||||
|
flags = file_openflags(*mode);
|
||||||
|
if (flags == -1)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Open the file */
|
||||||
|
file->handle = open(file->path, flags, open_mode);
|
||||||
|
if (file->handle == -1)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_close(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* If file is closed - report error */
|
||||||
|
if (file->handle == -1)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Close and reset the file handle */
|
||||||
|
close(file->handle);
|
||||||
|
file->handle = -1;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_read(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
ssize_t readed;
|
||||||
|
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Read data from the file */
|
||||||
|
readed = read(file->handle, data, *size);
|
||||||
|
if (readed < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Check for EOF condition */
|
||||||
|
if (readed > 0)
|
||||||
|
file->flags &= ~BH_IO_FLAG_EOF;
|
||||||
|
else
|
||||||
|
file->flags |= BH_IO_FLAG_EOF;
|
||||||
|
|
||||||
|
*size = readed;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_write(bh_file_t *file,
|
||||||
|
const char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
ssize_t written;
|
||||||
|
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Write data to the file */
|
||||||
|
written = write(file->handle, data, *size);
|
||||||
|
if (written < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Check for EOF condition */
|
||||||
|
if (!written)
|
||||||
|
file->flags |= BH_IO_FLAG_EOF;
|
||||||
|
else
|
||||||
|
file->flags &= ~BH_IO_FLAG_EOF;
|
||||||
|
|
||||||
|
*size = written;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_peek(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
int64_t position;
|
||||||
|
int direction;
|
||||||
|
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Read data from the file */
|
||||||
|
if (file_read(file, data, size))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Backtrack by the read amount */
|
||||||
|
position = -((int64_t)*size);
|
||||||
|
direction = BH_IO_SEEK_CUR;
|
||||||
|
if (file_seek(file, &position, &direction))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flush(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
{
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush the buffers */
|
||||||
|
fsync(file->handle);
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_seek(bh_file_t *file,
|
||||||
|
int64_t *pos,
|
||||||
|
int *dir)
|
||||||
|
{
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Seek to the specified position */
|
||||||
|
if (lseek(file->handle, *pos, *dir) == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_tell(bh_file_t *file,
|
||||||
|
int64_t *pos)
|
||||||
|
{
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get current offset in the file */
|
||||||
|
if ((*pos = lseek(file->handle, 0, SEEK_CUR)) == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_size(bh_file_t *file,
|
||||||
|
int64_t *size)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
/* Check if file is open */
|
||||||
|
if (file->handle == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get file size from the OS */
|
||||||
|
if (fstat(file->handle, &sb))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
*size = sb.st_size;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flags(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* If file handle is valid - append IO_OPEN flag */
|
||||||
|
if (file->handle != -1)
|
||||||
|
return file->flags | BH_IO_FLAG_OPEN;
|
||||||
|
|
||||||
|
return file->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_clear(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* Clear IO_ERROR flag */
|
||||||
|
file->flags &= ~BH_IO_FLAG_ERROR;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_proc(bh_file_t *file,
|
||||||
|
int type,
|
||||||
|
void *arg1,
|
||||||
|
void *arg2)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case BH_IO_INFO_CB: return file_info(file, (size_t *)arg1, (const char **)arg2);
|
||||||
|
case BH_IO_INIT_CB: return file_init(file, (const char *)arg1);
|
||||||
|
case BH_IO_DESTROY_CB: return file_destroy(file);
|
||||||
|
case BH_IO_OPEN_CB: return file_open(file, (int *)arg1);
|
||||||
|
case BH_IO_CLOSE_CB: return file_close(file);
|
||||||
|
case BH_IO_READ_CB: return file_read(file, (char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_WRITE_CB: return file_write(file, (const char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_PEEK_CB: return file_peek(file, (char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_FLUSH_CB: return file_flush(file);
|
||||||
|
case BH_IO_SEEK_CB: return file_seek(file, (int64_t *)arg1, (int *)arg2);
|
||||||
|
case BH_IO_TELL_CB: return file_tell(file, (int64_t *)arg1);
|
||||||
|
case BH_IO_SIZE_CB: return file_size(file, (int64_t *)arg1);
|
||||||
|
case BH_IO_FLAGS_CB: return file_flags(file);
|
||||||
|
case BH_IO_CLEAR_CB: return file_clear(file);
|
||||||
|
default: return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bh_io_t *bh_file_new(const char *path)
|
||||||
|
{
|
||||||
|
return bh_io_new((bh_io_func_t)file_proc, (void *)path);
|
||||||
|
}
|
||||||
209
src/queue.c
Executable file
209
src/queue.c
Executable file
@@ -0,0 +1,209 @@
|
|||||||
|
#include <bh/queue.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct bh_queue_s
|
||||||
|
{
|
||||||
|
void **data;
|
||||||
|
size_t size;
|
||||||
|
size_t head;
|
||||||
|
size_t tail;
|
||||||
|
size_t capacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_queue_init(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
memset(queue, 0, sizeof(*queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void bh_queue_destroy(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
if (queue->capacity)
|
||||||
|
free(queue->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void queue_copy(bh_queue_t *dest,
|
||||||
|
bh_queue_t *src)
|
||||||
|
{
|
||||||
|
void *iter;
|
||||||
|
|
||||||
|
/* Iterate over old queue and insert data into new queue */
|
||||||
|
iter = bh_queue_iter_next(src, NULL);
|
||||||
|
while (iter)
|
||||||
|
{
|
||||||
|
bh_queue_insert(dest, bh_queue_iter_value(iter));
|
||||||
|
iter = bh_queue_iter_next(src, iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bh_queue_t *bh_queue_new(void)
|
||||||
|
{
|
||||||
|
bh_queue_t *result;
|
||||||
|
|
||||||
|
result = malloc(sizeof(*result));
|
||||||
|
if (result)
|
||||||
|
bh_queue_init(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_queue_free(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
bh_queue_destroy(queue);
|
||||||
|
free(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_queue_clear(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
queue->head = 0;
|
||||||
|
queue->tail = 0;
|
||||||
|
queue->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_queue_reserve(bh_queue_t *queue,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
bh_queue_t other;
|
||||||
|
|
||||||
|
/* New capacity should be great or equal to current size */
|
||||||
|
if (size < queue->size)
|
||||||
|
size = queue->size;
|
||||||
|
|
||||||
|
/* Catch malloc overflow */
|
||||||
|
if (size >= ((size_t)-1) / sizeof(void *))
|
||||||
|
return BH_OOM;
|
||||||
|
|
||||||
|
/* Prevent same size memory reallocation */
|
||||||
|
if (size == queue->capacity)
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
/* Prepare new empty queue */
|
||||||
|
bh_queue_init(&other);
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
/* Allocate new capacity for the queue */
|
||||||
|
other.data = malloc(size * sizeof(void *));
|
||||||
|
other.capacity = size;
|
||||||
|
if (!other.data)
|
||||||
|
return BH_OOM;
|
||||||
|
|
||||||
|
/* Iterate over old queue and insert data into new queue */
|
||||||
|
queue_copy(&other, queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If old queue had allocated data - free it */
|
||||||
|
if (queue->capacity)
|
||||||
|
free(queue->data);
|
||||||
|
|
||||||
|
/* Copy queue information */
|
||||||
|
*queue = other;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_queue_insert(bh_queue_t *queue,
|
||||||
|
void *value)
|
||||||
|
{
|
||||||
|
/* Check if queue can contain new element */
|
||||||
|
if (queue->size + 1 > queue->capacity)
|
||||||
|
{
|
||||||
|
size_t capacity;
|
||||||
|
|
||||||
|
/* Check for capacity overflow and reserve capacity */
|
||||||
|
capacity = (queue->capacity) ? (queue->capacity * 2) : (16);
|
||||||
|
if (capacity < queue->capacity || bh_queue_reserve(queue, capacity))
|
||||||
|
return BH_OOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase queue size and advance tail index */
|
||||||
|
queue->data[queue->tail] = value;
|
||||||
|
queue->size++;
|
||||||
|
if (++queue->tail >= queue->capacity)
|
||||||
|
queue->tail = 0;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bh_queue_remove(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
/* Do nothing if queue is empty */
|
||||||
|
if (!queue->size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Decrease queue size and advance head index */
|
||||||
|
queue->size--;
|
||||||
|
if (++queue->head >= queue->capacity)
|
||||||
|
queue->head = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_queue_front(bh_queue_t *queue, void **value)
|
||||||
|
{
|
||||||
|
/* Do nothing if queue is empty */
|
||||||
|
if (!queue->size)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Return front element */
|
||||||
|
*value = queue->data[queue->head];
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int bh_queue_empty(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
return !queue->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t bh_queue_size(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
return queue->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t bh_queue_capacity(bh_queue_t *queue)
|
||||||
|
{
|
||||||
|
return queue->capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_queue_iter_next(bh_queue_t *queue,
|
||||||
|
void *iter)
|
||||||
|
{
|
||||||
|
void **element = (void **)iter;
|
||||||
|
|
||||||
|
/* Do nothing if queue is empty */
|
||||||
|
if (!queue->size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Advance or set iterator */
|
||||||
|
if (element)
|
||||||
|
{
|
||||||
|
element++;
|
||||||
|
if (element == queue->data + queue->capacity)
|
||||||
|
element = queue->data;
|
||||||
|
|
||||||
|
/* Check if we reached the end */
|
||||||
|
if (element == queue->data + queue->tail)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
element = queue->data + queue->head;
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *bh_queue_iter_value(void *iter)
|
||||||
|
{
|
||||||
|
return *(void **)iter;
|
||||||
|
}
|
||||||
405
src/win32/file.c
Normal file
405
src/win32/file.c
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
#include <bh/io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bh_file_s
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int mode;
|
||||||
|
int flags;
|
||||||
|
HANDLE handle;
|
||||||
|
} bh_file_t;
|
||||||
|
|
||||||
|
|
||||||
|
static int file_info(bh_file_t *file,
|
||||||
|
size_t *size,
|
||||||
|
const char **name);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_init(bh_file_t *file,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_destroy(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_open(bh_file_t *file,
|
||||||
|
int *mode);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_close(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_read(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_write(bh_file_t *file,
|
||||||
|
const char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_peek(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flush(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_seek(bh_file_t *file,
|
||||||
|
int64_t *pos,
|
||||||
|
int *dir);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_tell(bh_file_t *file,
|
||||||
|
int64_t *pos);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_size(bh_file_t *file,
|
||||||
|
int64_t *size);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flags(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_clear(bh_file_t *file);
|
||||||
|
|
||||||
|
|
||||||
|
static int file_info(bh_file_t *file,
|
||||||
|
size_t *size,
|
||||||
|
const char **name)
|
||||||
|
{
|
||||||
|
static const char classname[] = BH_FILE_CLASSNAME;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = sizeof(*file);
|
||||||
|
if (name)
|
||||||
|
*name = classname;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_init(bh_file_t *file,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
/* Check if path is valid */
|
||||||
|
if (!path)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Duplicate path string and initialize the file struct */
|
||||||
|
file->path = strdup(path);
|
||||||
|
file->mode = 0;
|
||||||
|
file->handle = INVALID_HANDLE_VALUE;
|
||||||
|
file->flags = 0;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_destroy(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* Close the file handle on destruction */
|
||||||
|
if (file->handle != INVALID_HANDLE_VALUE)
|
||||||
|
file_close(file);
|
||||||
|
|
||||||
|
/* Free path string */
|
||||||
|
free(file->path);
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_open(bh_file_t *file,
|
||||||
|
int *mode)
|
||||||
|
{
|
||||||
|
DWORD access = 0, how = 0;
|
||||||
|
|
||||||
|
/* Check if file is already openned */
|
||||||
|
if (file->handle != INVALID_HANDLE_VALUE)
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
/* Determine read/write access flags */
|
||||||
|
if (*mode & BH_IO_READ)
|
||||||
|
access |= GENERIC_READ;
|
||||||
|
if (*mode & BH_IO_WRITE)
|
||||||
|
access |= GENERIC_WRITE;
|
||||||
|
|
||||||
|
if (!access)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Determine open mode flags */
|
||||||
|
if (*mode & BH_IO_TRUNCATE)
|
||||||
|
{
|
||||||
|
switch (*mode & (BH_IO_CREATE | BH_IO_EXIST))
|
||||||
|
{
|
||||||
|
case 0: how = CREATE_ALWAYS; break;
|
||||||
|
case BH_IO_CREATE: how = CREATE_NEW; break;
|
||||||
|
case BH_IO_EXIST: how = TRUNCATE_EXISTING; break;
|
||||||
|
default: return BH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (*mode & (BH_IO_CREATE | BH_IO_EXIST))
|
||||||
|
{
|
||||||
|
case 0: how = OPEN_ALWAYS; break;
|
||||||
|
case BH_IO_CREATE: how = CREATE_NEW; break;
|
||||||
|
case BH_IO_EXIST: how = OPEN_EXISTING; break;
|
||||||
|
default: return BH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save mode that we are in and open file */
|
||||||
|
file->mode = *mode;
|
||||||
|
file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Truncate file if needed */
|
||||||
|
if (*mode & BH_IO_TRUNCATE)
|
||||||
|
SetEndOfFile(file->handle);
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_close(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* If file is opened - close it */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Reset handle and mode values */
|
||||||
|
CloseHandle(file->handle);
|
||||||
|
file->handle = INVALID_HANDLE_VALUE;
|
||||||
|
file->mode = 0;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_read(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
DWORD readed;
|
||||||
|
|
||||||
|
/* Check if file is opened */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Read data from the file */
|
||||||
|
if (!ReadFile(file->handle, data, (DWORD)*size, &readed, NULL))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Check if we reached end of file */
|
||||||
|
if (!readed)
|
||||||
|
file->flags |= BH_IO_FLAG_EOF;
|
||||||
|
else
|
||||||
|
file->flags &= ~BH_IO_FLAG_EOF;
|
||||||
|
|
||||||
|
*size = readed;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_write(bh_file_t *file,
|
||||||
|
const char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
DWORD written;
|
||||||
|
|
||||||
|
/* Check if file is opened */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Adjust current position in the file to the end */
|
||||||
|
if (file->mode & BH_IO_APPEND)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER position;
|
||||||
|
|
||||||
|
position.QuadPart = 0;
|
||||||
|
if (!SetFilePointerEx(file->handle, position, NULL, FILE_END))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write data to the file */
|
||||||
|
if (!WriteFile(file->handle, data, (DWORD)*size, &written, NULL))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Check for end of file */
|
||||||
|
if (!written)
|
||||||
|
file->flags |= BH_IO_FLAG_EOF;
|
||||||
|
else
|
||||||
|
file->flags &= ~BH_IO_FLAG_EOF;
|
||||||
|
|
||||||
|
*size = written;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_peek(bh_file_t *file,
|
||||||
|
char *data,
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
int64_t position;
|
||||||
|
int direction;
|
||||||
|
|
||||||
|
/* Read data from the file */
|
||||||
|
if (file_read(file, data, size))
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Backtrack by the read amount */
|
||||||
|
position = -((int64_t)*size);
|
||||||
|
direction = BH_IO_SEEK_CUR;
|
||||||
|
if (file_seek(file, &position, &direction))
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flush(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* Check if file is opened */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Flush OS buffers */
|
||||||
|
FlushFileBuffers(file->handle);
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_seek(bh_file_t *file,
|
||||||
|
int64_t *pos,
|
||||||
|
int *dir)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER position;
|
||||||
|
|
||||||
|
/* Check if file is opened */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Set read/write position in the file */
|
||||||
|
position.QuadPart = *pos;
|
||||||
|
if (!SetFilePointerEx(file->handle, position, NULL, *dir))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_tell(bh_file_t *file,
|
||||||
|
int64_t *pos)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER dummy, position;
|
||||||
|
|
||||||
|
/* Check if file is opened */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Readback current position in the file */
|
||||||
|
dummy.QuadPart = 0;
|
||||||
|
if (!SetFilePointerEx(file->handle, dummy, &position, BH_IO_SEEK_CUR))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
*pos = position.QuadPart;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_size(bh_file_t *file,
|
||||||
|
int64_t *size)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER dummy;
|
||||||
|
|
||||||
|
/* Check if file is opened */
|
||||||
|
if (file->handle == INVALID_HANDLE_VALUE)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get current file size */
|
||||||
|
if (!GetFileSizeEx(file->handle, &dummy))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
*size = dummy.QuadPart;
|
||||||
|
return BH_OK;
|
||||||
|
|
||||||
|
error:
|
||||||
|
file->flags |= BH_IO_FLAG_ERROR;
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_flags(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* If file handle is valid - append IO_OPEN flag */
|
||||||
|
if (file->handle != INVALID_HANDLE_VALUE)
|
||||||
|
return file->flags | BH_IO_FLAG_OPEN;
|
||||||
|
return file->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_clear(bh_file_t *file)
|
||||||
|
{
|
||||||
|
/* Clear IO_ERROR flag */
|
||||||
|
file->flags &= ~BH_IO_FLAG_ERROR;
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int file_proc(bh_file_t *file,
|
||||||
|
int type,
|
||||||
|
void *arg1,
|
||||||
|
void *arg2)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case BH_IO_INFO_CB: return file_info(file, (size_t *)arg1, (const char **)arg2);
|
||||||
|
case BH_IO_INIT_CB: return file_init(file, (const char *)arg1);
|
||||||
|
case BH_IO_DESTROY_CB: return file_destroy(file);
|
||||||
|
case BH_IO_OPEN_CB: return file_open(file, (int *)arg1);
|
||||||
|
case BH_IO_CLOSE_CB: return file_close(file);
|
||||||
|
case BH_IO_READ_CB: return file_read(file, (char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_WRITE_CB: return file_write(file, (const char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_PEEK_CB: return file_peek(file, (char *)arg1, (size_t *)arg2);
|
||||||
|
case BH_IO_FLUSH_CB: return file_flush(file);
|
||||||
|
case BH_IO_SEEK_CB: return file_seek(file, (int64_t *)arg1, (int *)arg2);
|
||||||
|
case BH_IO_TELL_CB: return file_tell(file, (int64_t *)arg1);
|
||||||
|
case BH_IO_SIZE_CB: return file_size(file, (int64_t *)arg1);
|
||||||
|
case BH_IO_FLAGS_CB: return file_flags(file);
|
||||||
|
case BH_IO_CLEAR_CB: return file_clear(file);
|
||||||
|
default: return BH_NOIMPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bh_io_t *bh_file_new(const char *path)
|
||||||
|
{
|
||||||
|
return bh_io_new((bh_io_func_t)file_proc, (void *)path);
|
||||||
|
}
|
||||||
24
test/CMakeLists.txt
Executable file
24
test/CMakeLists.txt
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
set(CMAKE_C_STANDARD 90)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# Enable warnings and pedantics
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic")
|
||||||
|
|
||||||
|
# Enable testing
|
||||||
|
include(CTest)
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
# Search files
|
||||||
|
file(GLOB TEST_FILES "src/*.c")
|
||||||
|
|
||||||
|
foreach(TEST_FILENAME ${TEST_FILES})
|
||||||
|
get_filename_component(TEST_NAME ${TEST_FILENAME} NAME_WE)
|
||||||
|
add_executable("${TEST_NAME}" ${TEST_FILENAME})
|
||||||
|
target_link_libraries("${TEST_NAME}" bhlib bhunit)
|
||||||
|
add_test(NAME "${TEST_NAME}" COMMAND "${TEST_NAME}")
|
||||||
|
if(COVERAGE)
|
||||||
|
target_compile_options("${TEST_NAME}" PRIVATE -coverage)
|
||||||
|
target_link_options("${TEST_NAME}" PRIVATE -coverage)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
483
test/src/testalgo.c
Normal file
483
test/src/testalgo.c
Normal file
@@ -0,0 +1,483 @@
|
|||||||
|
#include <bh/algo.h>
|
||||||
|
#include <bh/unit.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int int_equal(const void *lhs,
|
||||||
|
const void *rhs)
|
||||||
|
{
|
||||||
|
return *(const int*)lhs - *(const int*)rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int verify_partition(size_t index,
|
||||||
|
int pivot,
|
||||||
|
int *array,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < index; i++)
|
||||||
|
if (array[i] >= pivot)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = index; i < size; i++)
|
||||||
|
if (array[i] < pivot)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int verify_heap(int *array,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
size_t i, left, right;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
left = i * 2 + 1;
|
||||||
|
right = i * 2 + 2;
|
||||||
|
|
||||||
|
if (left < size && array[i] < array[left])
|
||||||
|
return -1;
|
||||||
|
if (right < size && array[i] < array[right])
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int reference_rand(void)
|
||||||
|
{
|
||||||
|
static uint32_t next = 2025;
|
||||||
|
next = next * 1103515245 + 12345;
|
||||||
|
return (next / 65536) % 32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void reference_sort(int *array, size_t size)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
/* Reference sort is... buble sort! */
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
for (j = 1; j < size; j++)
|
||||||
|
{
|
||||||
|
if (array[j - 1] > array[j])
|
||||||
|
{
|
||||||
|
tmp = array[j - 1];
|
||||||
|
array[j - 1] = array[j];
|
||||||
|
array[j] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void fill_arrays(int *array,
|
||||||
|
int *reference,
|
||||||
|
size_t size,
|
||||||
|
int mask)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
int negate;
|
||||||
|
|
||||||
|
/* Check if mask needs to be negated */
|
||||||
|
negate = mask < 0;
|
||||||
|
if (negate)
|
||||||
|
mask = -mask;
|
||||||
|
|
||||||
|
/* Fill the array */
|
||||||
|
for (i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
array[i] = reference_rand();
|
||||||
|
|
||||||
|
if (mask > 1)
|
||||||
|
array[i] = array[i] % mask;
|
||||||
|
|
||||||
|
if (negate)
|
||||||
|
array[i] = -array[i];
|
||||||
|
|
||||||
|
if (reference)
|
||||||
|
reference[i] = array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_sort(void)
|
||||||
|
{
|
||||||
|
size_t sizes[] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0}, *size;
|
||||||
|
int reference[317], data[317];
|
||||||
|
|
||||||
|
/* Test empty array and one element arrays */
|
||||||
|
data[0] = 1; data[1] = 2; data[2] = 3;
|
||||||
|
bh_sort(data, 0, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(data[0] == 1);
|
||||||
|
BH_VERIFY(data[1] == 2);
|
||||||
|
BH_VERIFY(data[2] == 3);
|
||||||
|
|
||||||
|
bh_sort(data, 1, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(data[0] == 1);
|
||||||
|
BH_VERIFY(data[1] == 2);
|
||||||
|
BH_VERIFY(data[2] == 3);
|
||||||
|
|
||||||
|
/* Test array against different sizes */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
bh_sort(data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(memcmp(reference, data, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against negative values */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, -1);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
bh_sort(data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(memcmp(reference, data, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against duplicates */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 4);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
bh_sort(data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(memcmp(reference, data, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_partition(void)
|
||||||
|
{
|
||||||
|
size_t sizes[] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0}, *size;
|
||||||
|
int reference[317], data[317], value, *pivot;
|
||||||
|
|
||||||
|
/* Test empty array and one element array */
|
||||||
|
data[0] = 1; data[1] = 2; data[2] = 3;
|
||||||
|
value = 0;
|
||||||
|
pivot = bh_partition(&value, data, 0, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(pivot != NULL);
|
||||||
|
BH_VERIFY(data[0] == 1);
|
||||||
|
BH_VERIFY(data[1] == 2);
|
||||||
|
BH_VERIFY(data[2] == 3);
|
||||||
|
|
||||||
|
pivot = bh_partition(&value, data, 1, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(pivot == data);
|
||||||
|
BH_VERIFY(data[0] == 1);
|
||||||
|
BH_VERIFY(data[1] == 2);
|
||||||
|
BH_VERIFY(data[2] == 3);
|
||||||
|
|
||||||
|
/* Test array against different sizes */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
value = 16384;
|
||||||
|
pivot = bh_partition(&value, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against negative values */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, -1);
|
||||||
|
value = -16384;
|
||||||
|
pivot = bh_partition(&value, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against duplicates */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 4);
|
||||||
|
value = 2;
|
||||||
|
pivot = bh_partition(&value, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test array against small pivots */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
value = -100;
|
||||||
|
pivot = bh_partition(&value, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test array against large pivots */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
value = 65536;
|
||||||
|
pivot = bh_partition(&value, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test array against different sizes (pivot inside the array) */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
value = data[0];
|
||||||
|
pivot = bh_partition(data, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against negative values (pivot inside the array) */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, -1);
|
||||||
|
value = data[0];
|
||||||
|
pivot = bh_partition(data, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against duplicates (pivot inside the array) */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, reference, *size, 4);
|
||||||
|
value = data[0];
|
||||||
|
pivot = bh_partition(data, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Same data test */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
memset(data, 0, sizeof(int) * *size);
|
||||||
|
memset(reference, 0, sizeof(int) * *size);
|
||||||
|
value = data[*size - 1];
|
||||||
|
pivot = bh_partition(data + *size - 1, data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_partition(pivot - data, value, data, *size) == 0);
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size * sizeof(int)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_heap_make(void)
|
||||||
|
{
|
||||||
|
size_t sizes[] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0}, *size;
|
||||||
|
int data[317];
|
||||||
|
|
||||||
|
/* Test empty array */
|
||||||
|
data[0] = 1; data[1] = 2; data[2] = 3;
|
||||||
|
bh_heap_make(data, 0, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(data[0] == 1);
|
||||||
|
BH_VERIFY(data[1] == 2);
|
||||||
|
BH_VERIFY(data[2] == 3);
|
||||||
|
|
||||||
|
/* Test array against different sizes */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, NULL, *size, 0);
|
||||||
|
bh_heap_make(data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, *size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test array against negative values */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, NULL, *size, -1);
|
||||||
|
bh_heap_make(data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, *size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test against duplicates */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
fill_arrays(data, NULL, *size, 4);
|
||||||
|
bh_heap_make(data, *size, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, *size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_heap_insert(void)
|
||||||
|
{
|
||||||
|
size_t sizes[] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0}, *size;
|
||||||
|
int data[317], reference[317];
|
||||||
|
|
||||||
|
/* Test array against different sizes */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
for (i = 0; i < *size; ++i)
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
|
||||||
|
value = data[i];
|
||||||
|
bh_heap_insert(&value, data, i, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, i + 1) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test array against different sizes (inplace)*/
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
for (i = 0; i < *size; ++i)
|
||||||
|
{
|
||||||
|
bh_heap_insert(NULL, data, i, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, i + 1) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_heap_remove(void)
|
||||||
|
{
|
||||||
|
size_t sizes[] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0}, *size;
|
||||||
|
int data[317], reference[317];
|
||||||
|
|
||||||
|
/* Test array against different sizes */
|
||||||
|
for (size = sizes; *size; ++size)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
fill_arrays(data, reference, *size, 0);
|
||||||
|
bh_heap_make(data, *size, sizeof(int), int_equal);
|
||||||
|
|
||||||
|
for (i = *size; i > 0; i--)
|
||||||
|
{
|
||||||
|
BH_VERIFY(verify_heap(data, i) == 0);
|
||||||
|
bh_heap_remove(data, i, sizeof(int), int_equal);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference_sort(data, *size);
|
||||||
|
reference_sort(reference, *size);
|
||||||
|
BH_VERIFY(memcmp(data, reference, *size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int check_heap_replace(void)
|
||||||
|
{
|
||||||
|
int data[11] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0};
|
||||||
|
int reference[11] = {1, 2, 3, 5, 11, 23, 41, 79, 163, 317, 0};
|
||||||
|
int value;
|
||||||
|
|
||||||
|
/* Prepare test arrays */
|
||||||
|
bh_heap_make(data, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_make(reference, 10, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, 10) == 0);
|
||||||
|
BH_VERIFY(verify_heap(reference, 10) == 0);
|
||||||
|
|
||||||
|
/* Verfify heap replace */
|
||||||
|
value = 20;
|
||||||
|
bh_heap_replace(&value, data, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_remove(reference, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_insert(&value, reference, 9, sizeof(int), int_equal);
|
||||||
|
|
||||||
|
BH_VERIFY(verify_heap(data, 10) == 0);
|
||||||
|
BH_VERIFY(verify_heap(reference, 10) == 0);
|
||||||
|
bh_sort(data, 10, sizeof(int), int_equal);
|
||||||
|
bh_sort(reference, 10, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(memcmp(data, reference, 10 * sizeof(int)) == 0);
|
||||||
|
|
||||||
|
/* Verify heap replace on single element array */
|
||||||
|
value = 400;
|
||||||
|
bh_heap_replace(&value, data, 1, sizeof(int), int_equal);
|
||||||
|
bh_heap_remove(reference, 1, sizeof(int), int_equal);
|
||||||
|
bh_heap_insert(&value, reference, 0, sizeof(int), int_equal);
|
||||||
|
|
||||||
|
BH_VERIFY(verify_heap(data, 1) == 0);
|
||||||
|
BH_VERIFY(verify_heap(reference, 1) == 0);
|
||||||
|
BH_VERIFY(memcmp(data, reference, 1 * sizeof(int)) == 0);
|
||||||
|
|
||||||
|
/* Prepare test arrays */
|
||||||
|
bh_sort(data, 10, sizeof(int), int_equal);
|
||||||
|
bh_sort(reference, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_make(data, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_make(reference, 10, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, 10) == 0);
|
||||||
|
BH_VERIFY(verify_heap(reference, 10) == 0);
|
||||||
|
|
||||||
|
data[10] = 1000;
|
||||||
|
value = 1000;
|
||||||
|
bh_heap_replace(NULL, data, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_remove(reference, 10, sizeof(int), int_equal);
|
||||||
|
bh_heap_insert(&value, reference, 9, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(verify_heap(data, 10) == 0);
|
||||||
|
BH_VERIFY(verify_heap(reference, 10) == 0);
|
||||||
|
bh_sort(data, 10, sizeof(int), int_equal);
|
||||||
|
bh_sort(reference, 10, sizeof(int), int_equal);
|
||||||
|
BH_VERIFY(memcmp(data, reference, 10 * sizeof(int)) == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
BH_UNUSED(argc);
|
||||||
|
BH_UNUSED(argv);
|
||||||
|
|
||||||
|
bh_unit_add("sort", check_sort);
|
||||||
|
bh_unit_add("partition", check_partition);
|
||||||
|
bh_unit_add("heap_make", check_heap_make);
|
||||||
|
bh_unit_add("heap_insert", check_heap_insert);
|
||||||
|
bh_unit_add("heap_remove", check_heap_remove);
|
||||||
|
bh_unit_add("heap_replace", check_heap_replace);
|
||||||
|
|
||||||
|
return bh_unit_run();
|
||||||
|
}
|
||||||
630
test/src/testfile.c
Normal file
630
test/src/testfile.c
Normal file
@@ -0,0 +1,630 @@
|
|||||||
|
#include <bh/unit.h>
|
||||||
|
#include <bh/io.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define FILENAME1 "bhfile1.dat"
|
||||||
|
#define FILENAME2 "bhfile2.dat"
|
||||||
|
#define FILENAME3 "bhfile3.dat"
|
||||||
|
#define FILENAME4 "bhfile4.dat"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup any files, that could be left from previous test runs.
|
||||||
|
*/
|
||||||
|
static void cleanup(void)
|
||||||
|
{
|
||||||
|
remove(FILENAME1);
|
||||||
|
remove(FILENAME2);
|
||||||
|
remove(FILENAME3);
|
||||||
|
remove(FILENAME4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for invalid arguments.
|
||||||
|
*/
|
||||||
|
static int check_null(void)
|
||||||
|
{
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Check against NULL pointers */
|
||||||
|
BH_VERIFY(bh_file_new(NULL) == NULL);
|
||||||
|
BH_VERIFY(bh_io_classname(NULL) == NULL);
|
||||||
|
BH_VERIFY(bh_io_open(NULL, 0) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_close(NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(NULL, NULL, 0, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_write(NULL, NULL, 0, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_peek(NULL, NULL, 0, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(NULL, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(NULL, 0, 0) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flush(NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_size(NULL, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(NULL) == BH_IO_FLAG_ERROR);
|
||||||
|
BH_VERIFY(bh_io_clear(NULL) == BH_OK);
|
||||||
|
bh_io_free(NULL);
|
||||||
|
|
||||||
|
/* Check against NULL pointers and valid IO object */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, 0) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_close(io) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, NULL, 0, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_write(io, NULL, 0, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_peek(io, NULL, 0, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, 0) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flush(io) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_size(io, NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) == BH_IO_FLAG_ERROR);
|
||||||
|
BH_VERIFY(bh_io_clear(io) == BH_OK);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for normal mode.
|
||||||
|
*/
|
||||||
|
static int check_normal(void)
|
||||||
|
{
|
||||||
|
int64_t position;
|
||||||
|
char buffer[128];
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Check operations for write only access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ) != BH_OK);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 10, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 1, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_END) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, &position) == BH_OK);
|
||||||
|
BH_VERIFY(position == 20);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read only access */
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, sizeof(buffer), &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890abcde67890", 20) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, -5, BH_IO_SEEK_CUR) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "67890", 5) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read and write access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890abcde67890", 20, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 35, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 35);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
bh_io_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for truncate mode.
|
||||||
|
*/
|
||||||
|
static int check_truncate(void)
|
||||||
|
{
|
||||||
|
int64_t position;
|
||||||
|
char buffer[128];
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Check operations for write only access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 10, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 1, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_END) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, &position) == BH_OK);
|
||||||
|
BH_VERIFY(position == 20);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read only access without truncate */
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, sizeof(buffer), &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890abcde67890", 20) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, -5, BH_IO_SEEK_CUR) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "67890", 5) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read only access */
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, sizeof(buffer), &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read and write access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890abcde67890", 20, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 35, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 35);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
bh_io_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for exist mode.
|
||||||
|
*/
|
||||||
|
static int check_exist(void)
|
||||||
|
{
|
||||||
|
int64_t position;
|
||||||
|
char buffer[128];
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Check operations for write only access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_EXIST) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 10, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 1, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_END) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, &position) == BH_OK);
|
||||||
|
BH_VERIFY(position == 20);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read only access */
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ | BH_IO_EXIST) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, sizeof(buffer), &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890abcde67890", 20) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, -5, BH_IO_SEEK_CUR) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "67890", 5) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read and write access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ | BH_IO_EXIST) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890abcde67890", 20, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 35, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 35);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde12345678901234567890abcde67890", 35) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
/* Check against non existing files */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME2)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_EXIST) != BH_OK);
|
||||||
|
BH_VERIFY((bh_io_flags(io) & BH_IO_FLAG_OPEN) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ | BH_IO_EXIST) != BH_OK);
|
||||||
|
BH_VERIFY((bh_io_flags(io) & BH_IO_FLAG_OPEN) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ | BH_IO_EXIST) != BH_OK);
|
||||||
|
BH_VERIFY((bh_io_flags(io) & BH_IO_FLAG_OPEN) == 0);
|
||||||
|
bh_io_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check in append mode.
|
||||||
|
*/
|
||||||
|
static int check_append(void)
|
||||||
|
{
|
||||||
|
int64_t position;
|
||||||
|
char buffer[128];
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Explicitly call cleanup */
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
/* Check operations for write only access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_APPEND) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 10, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 1, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_END) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, &position) == BH_OK);
|
||||||
|
BH_VERIFY(position == 25);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read only access */
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ | BH_IO_APPEND) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
BH_VERIFY(memcmp(buffer, "1234567890", 10) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_seek(io, -5, BH_IO_SEEK_CUR) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
BH_VERIFY(memcmp(buffer, "abcde", 5) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
/* Check operations for read and write access */
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ | BH_IO_APPEND) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "abcde", 5, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 5);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 40, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 40);
|
||||||
|
BH_VERIFY(memcmp(buffer, "12345678901234567890abcdeabcde1234567890", 40) == 0);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
bh_io_close(io);
|
||||||
|
|
||||||
|
bh_io_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for create mode.
|
||||||
|
*/
|
||||||
|
static int check_create(void)
|
||||||
|
{
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
/* Check for already existing file */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_CREATE) != BH_OK);
|
||||||
|
BH_VERIFY((bh_io_flags(io) & BH_IO_FLAG_OPEN) == 0);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
/* Check for new file with write access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME2)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_CREATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
/* Check for new file with read access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME3)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ | BH_IO_CREATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
/* Check for new file with read/write access */
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME4)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ | BH_IO_CREATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for EOF flags.
|
||||||
|
*/
|
||||||
|
static int check_eof(void)
|
||||||
|
{
|
||||||
|
char buffer[128];
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_read(io, buffer, 128, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 0);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_EOF);
|
||||||
|
|
||||||
|
bh_io_close(io);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for error flags.
|
||||||
|
*/
|
||||||
|
static int check_error(void)
|
||||||
|
{
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "12345", 5, &actual) != BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_ERROR);
|
||||||
|
BH_VERIFY(bh_io_clear(io) == BH_OK);
|
||||||
|
BH_VERIFY((bh_io_flags(io) & BH_IO_FLAG_ERROR) == 0);
|
||||||
|
|
||||||
|
bh_io_close(io);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check peek operation.
|
||||||
|
*/
|
||||||
|
static int check_peek(void)
|
||||||
|
{
|
||||||
|
int64_t previous, current;
|
||||||
|
char buffer[128];
|
||||||
|
size_t actual;
|
||||||
|
bh_io_t *io;
|
||||||
|
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_WRITE | BH_IO_READ | BH_IO_TRUNCATE) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_flags(io) & BH_IO_FLAG_OPEN);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_write(io, "1234567890", 10, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 10);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, &previous) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_peek(io, buffer, 128, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, ¤t) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
BH_VERIFY(memcmp(buffer, "12345678901234567890", 20) == 0);
|
||||||
|
BH_VERIFY(previous == current);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_seek(io, 0, BH_IO_SEEK_SET) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, &previous) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_peek(io, buffer, 128, &actual) == BH_OK);
|
||||||
|
BH_VERIFY(bh_io_tell(io, ¤t) == BH_OK);
|
||||||
|
BH_VERIFY(actual == 20);
|
||||||
|
BH_VERIFY(memcmp(buffer, "12345678901234567890", 20) == 0);
|
||||||
|
BH_VERIFY(previous == current);
|
||||||
|
|
||||||
|
bh_io_close(io);
|
||||||
|
bh_io_free(io);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check file size operation.
|
||||||
|
*/
|
||||||
|
static int check_size(void)
|
||||||
|
{
|
||||||
|
bh_io_t *io;
|
||||||
|
int64_t size;
|
||||||
|
|
||||||
|
BH_VERIFY((io = bh_file_new(FILENAME1)) != NULL);
|
||||||
|
BH_VERIFY(strcmp(bh_io_classname(io), BH_FILE_CLASSNAME) == 0);
|
||||||
|
BH_VERIFY(bh_io_open(io, BH_IO_READ) == BH_OK);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_io_size(io, &size) == BH_OK);
|
||||||
|
BH_VERIFY(size == 20);
|
||||||
|
|
||||||
|
bh_io_close(io);
|
||||||
|
bh_io_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
BH_UNUSED(argc);
|
||||||
|
BH_UNUSED(argv);
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
bh_unit_add("null", check_null);
|
||||||
|
bh_unit_add("normal", check_normal);
|
||||||
|
bh_unit_add("truncate", check_truncate);
|
||||||
|
bh_unit_add("exist", check_exist);
|
||||||
|
bh_unit_add("append", check_append);
|
||||||
|
bh_unit_add("create", check_create);
|
||||||
|
bh_unit_add("eof", check_eof);
|
||||||
|
bh_unit_add("error", check_error);
|
||||||
|
bh_unit_add("peek", check_peek);
|
||||||
|
bh_unit_add("size", check_size);
|
||||||
|
|
||||||
|
return bh_unit_run();
|
||||||
|
}
|
||||||
234
test/src/testhashmap.c
Normal file
234
test/src/testhashmap.c
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
#include <bh/hashmap.h>
|
||||||
|
#include <bh/unit.h>
|
||||||
|
|
||||||
|
|
||||||
|
static size_t direct_hash(const void *ptr)
|
||||||
|
{
|
||||||
|
return BH_PTR2INT(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int direct_equal(const void *lhs, const void *rhs)
|
||||||
|
{
|
||||||
|
return BH_PTR2INT(lhs) - BH_PTR2INT(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int new_free(void)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *hashmap;
|
||||||
|
|
||||||
|
hashmap = bh_hashmap_new(direct_equal, direct_hash);
|
||||||
|
BH_VERIFY(hashmap != NULL);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) != 0);
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_factor(hashmap) >= 0.15f);
|
||||||
|
BH_VERIFY(bh_hashmap_factor(hashmap) <= 1.0f);
|
||||||
|
|
||||||
|
bh_hashmap_free(hashmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int grow_shrink(void)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *hashmap;
|
||||||
|
void *iter;
|
||||||
|
|
||||||
|
hashmap = bh_hashmap_new(direct_equal, direct_hash);
|
||||||
|
BH_VERIFY(hashmap != NULL);
|
||||||
|
|
||||||
|
/* Allocate space for 1024 entries and insert 1 element */
|
||||||
|
BH_VERIFY(bh_hashmap_reserve(hashmap, 1024) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_insert(hashmap, BH_INT2PTR(1337), BH_INT2PTR(80085)) == 0);
|
||||||
|
|
||||||
|
/* Check hashmap contents */
|
||||||
|
iter = bh_hashmap_iter_next(hashmap, NULL);
|
||||||
|
BH_VERIFY(iter != NULL);
|
||||||
|
BH_VERIFY(BH_PTR2INT(bh_hashmap_iter_key(iter)) == 1337);
|
||||||
|
BH_VERIFY(BH_PTR2INT(bh_hashmap_iter_value(iter)) == 80085);
|
||||||
|
BH_VERIFY(bh_hashmap_iter_next(hashmap, iter) == NULL);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 1);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) >= 1024);
|
||||||
|
|
||||||
|
/* Change factor and grow */
|
||||||
|
bh_hashmap_set_factor(hashmap, 0.35f);
|
||||||
|
|
||||||
|
/* Check hashmap contents */
|
||||||
|
iter = bh_hashmap_iter_next(hashmap, NULL);
|
||||||
|
BH_VERIFY(iter != NULL);
|
||||||
|
BH_VERIFY(BH_PTR2INT(bh_hashmap_iter_key(iter)) == 1337);
|
||||||
|
BH_VERIFY(BH_PTR2INT(bh_hashmap_iter_value(iter)) == 80085);
|
||||||
|
BH_VERIFY(bh_hashmap_iter_next(hashmap, iter) == NULL);
|
||||||
|
BH_VERIFY(bh_hashmap_reserve(hashmap, 8192) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 1);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) >= 8192);
|
||||||
|
BH_VERIFY(bh_hashmap_factor(hashmap) == 0.35f);
|
||||||
|
|
||||||
|
/* Shrink */
|
||||||
|
BH_VERIFY(bh_hashmap_reserve(hashmap, 0) == 0);
|
||||||
|
|
||||||
|
/* Check hashmap contents */
|
||||||
|
iter = bh_hashmap_iter_next(hashmap, NULL);
|
||||||
|
BH_VERIFY(iter != NULL);
|
||||||
|
BH_VERIFY(BH_PTR2INT(bh_hashmap_iter_key(iter)) == 1337);
|
||||||
|
BH_VERIFY(BH_PTR2INT(bh_hashmap_iter_value(iter)) == 80085);
|
||||||
|
BH_VERIFY(bh_hashmap_iter_next(hashmap, iter) == NULL);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 1);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) >= 1);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) < 8192);
|
||||||
|
BH_VERIFY(bh_hashmap_factor(hashmap) == 0.35f);
|
||||||
|
|
||||||
|
/* Shrink to 0 (deallocate) */
|
||||||
|
bh_hashmap_clear(hashmap);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) != 0);
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) > 0);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_hashmap_reserve(hashmap, 0) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) != 0);
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 0);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) == 0);
|
||||||
|
|
||||||
|
/* Check hashmap contents */
|
||||||
|
iter = bh_hashmap_iter_next(hashmap, NULL);
|
||||||
|
BH_VERIFY(iter == NULL);
|
||||||
|
|
||||||
|
bh_hashmap_free(hashmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int insert_remove(void)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *hashmap;
|
||||||
|
size_t i, added, removed;
|
||||||
|
void *iter;
|
||||||
|
|
||||||
|
hashmap = bh_hashmap_new(direct_equal, direct_hash);
|
||||||
|
BH_VERIFY(hashmap != NULL);
|
||||||
|
bh_hashmap_set_factor(hashmap, 1.0f);
|
||||||
|
|
||||||
|
/* Insert elements into hashmap */
|
||||||
|
added = 0;
|
||||||
|
for (i = 1024; i > 0; i--)
|
||||||
|
{
|
||||||
|
added += (i - 1) / 4;
|
||||||
|
BH_VERIFY(bh_hashmap_insert(hashmap, BH_INT2PTR((i - 1) / 4), BH_INT2PTR(i)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove elements */
|
||||||
|
iter = bh_hashmap_iter_next(hashmap, NULL);
|
||||||
|
removed = 0;
|
||||||
|
while (iter)
|
||||||
|
{
|
||||||
|
removed += BH_PTR2INT(bh_hashmap_iter_key(iter));
|
||||||
|
bh_hashmap_iter_remove(hashmap, iter);
|
||||||
|
|
||||||
|
iter = bh_hashmap_iter_next(hashmap, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check inserted elements are equal to removed */
|
||||||
|
BH_VERIFY(added == removed);
|
||||||
|
|
||||||
|
bh_hashmap_free(hashmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lookup(void)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *hashmap;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
hashmap = bh_hashmap_new(direct_equal, direct_hash);
|
||||||
|
BH_VERIFY(hashmap != NULL);
|
||||||
|
|
||||||
|
/* Insert elements into hashmap */
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
BH_VERIFY(bh_hashmap_insert(hashmap, BH_INT2PTR(i * 4), BH_INT2PTR(i)) == 0);
|
||||||
|
|
||||||
|
/* Lookup inserted elements */
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
void *value;
|
||||||
|
|
||||||
|
BH_VERIFY(bh_hashmap_at(hashmap, BH_INT2PTR(i * 4), NULL) == BH_OK);
|
||||||
|
BH_VERIFY(bh_hashmap_at(hashmap, BH_INT2PTR(i * 4), &value) == BH_OK);
|
||||||
|
BH_VERIFY(BH_PTR2INT(value) == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup non-existing elements */
|
||||||
|
for (i = 256; i < 512; i++)
|
||||||
|
{
|
||||||
|
void *value;
|
||||||
|
|
||||||
|
BH_VERIFY(bh_hashmap_at(hashmap, BH_INT2PTR(i * 4), NULL) != BH_OK);
|
||||||
|
BH_VERIFY(bh_hashmap_at(hashmap, BH_INT2PTR(i * 4), &value) != BH_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
bh_hashmap_free(hashmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clear(void)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *hashmap;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
hashmap = bh_hashmap_new(direct_equal, direct_hash);
|
||||||
|
BH_VERIFY(hashmap != NULL);
|
||||||
|
|
||||||
|
/* Insert elements into hashmap */
|
||||||
|
for (i = 0; i < 128; i++)
|
||||||
|
BH_VERIFY(bh_hashmap_insert(hashmap, BH_INT2PTR(i), 0) == 0);
|
||||||
|
|
||||||
|
bh_hashmap_clear(hashmap);
|
||||||
|
|
||||||
|
/* Remove non-existing elements */
|
||||||
|
for (i = 0; i < 128; i++)
|
||||||
|
bh_hashmap_remove(hashmap, BH_INT2PTR(i));
|
||||||
|
|
||||||
|
bh_hashmap_free(hashmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fields(void)
|
||||||
|
{
|
||||||
|
bh_hashmap_t *hashmap;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
hashmap = bh_hashmap_new(direct_equal, direct_hash);
|
||||||
|
BH_VERIFY(hashmap != NULL);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) == 1);
|
||||||
|
|
||||||
|
/* Insert elements into hashmap */
|
||||||
|
for (i = 0; i < 14; i++)
|
||||||
|
BH_VERIFY(bh_hashmap_insert(hashmap, BH_INT2PTR(i), NULL) == 0);
|
||||||
|
|
||||||
|
/* Check hashmap fields correspond to getter functions */
|
||||||
|
BH_VERIFY(bh_hashmap_size(hashmap) == 14);
|
||||||
|
BH_VERIFY(bh_hashmap_capacity(hashmap) >= 14);
|
||||||
|
BH_VERIFY(bh_hashmap_empty(hashmap) == 0);
|
||||||
|
|
||||||
|
bh_hashmap_free(hashmap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
/* Add unit tests */
|
||||||
|
bh_unit_add("new_free", new_free);
|
||||||
|
bh_unit_add("grow_shrink", grow_shrink);
|
||||||
|
bh_unit_add("insert_remove", insert_remove);
|
||||||
|
bh_unit_add("lookup", lookup);
|
||||||
|
bh_unit_add("clear", clear);
|
||||||
|
bh_unit_add("fields", fields);
|
||||||
|
|
||||||
|
return bh_unit_run();
|
||||||
|
}
|
||||||
171
test/src/testqueue.c
Normal file
171
test/src/testqueue.c
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
#include <bh/queue.h>
|
||||||
|
#include <bh/unit.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int new_free(void)
|
||||||
|
{
|
||||||
|
bh_queue_t *queue;
|
||||||
|
|
||||||
|
queue = bh_queue_new();
|
||||||
|
BH_VERIFY(queue != NULL);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 0);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) == 0);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) != 0);
|
||||||
|
|
||||||
|
bh_queue_free(queue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int grow_shrink(void)
|
||||||
|
{
|
||||||
|
bh_queue_t *queue;
|
||||||
|
void *value;
|
||||||
|
|
||||||
|
queue = bh_queue_new();
|
||||||
|
BH_VERIFY(queue != NULL);
|
||||||
|
|
||||||
|
/* Reserve 1024 elements and insert item into queue */
|
||||||
|
BH_VERIFY(bh_queue_reserve(queue, 1024) == BH_OK);
|
||||||
|
BH_VERIFY(bh_queue_insert(queue, BH_INT2PTR(1337)) == BH_OK);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) >= 1024);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 1);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) == 0);
|
||||||
|
|
||||||
|
/* Check queue content */
|
||||||
|
BH_VERIFY(bh_queue_front(queue, &value) == BH_OK);
|
||||||
|
BH_VERIFY(BH_PTR2INT(value) == 1337);
|
||||||
|
|
||||||
|
/* Grow queue */
|
||||||
|
BH_VERIFY(bh_queue_reserve(queue, 8192) == BH_OK);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) >= 8192);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 1);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) == 0);
|
||||||
|
|
||||||
|
/* Check queue content */
|
||||||
|
BH_VERIFY(bh_queue_front(queue, &value) == BH_OK);
|
||||||
|
BH_VERIFY(BH_PTR2INT(value) == 1337);
|
||||||
|
|
||||||
|
/* Shrink the queue */
|
||||||
|
BH_VERIFY(bh_queue_reserve(queue, 0) == BH_OK);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) >= 1);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) < 8192);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 1);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) == 0);
|
||||||
|
|
||||||
|
/* Check queue content */
|
||||||
|
BH_VERIFY(bh_queue_front(queue, &value) == BH_OK);
|
||||||
|
BH_VERIFY(BH_PTR2INT(value) == 1337);
|
||||||
|
|
||||||
|
/* Shrink to 0 (deallocate) */
|
||||||
|
bh_queue_clear(queue);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 0);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) != 0);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) >= 1);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_queue_reserve(queue, 0) == BH_OK);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 0);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) != 0);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) == 0);
|
||||||
|
|
||||||
|
bh_queue_free(queue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int insert_remove(void)
|
||||||
|
{
|
||||||
|
bh_queue_t *queue;
|
||||||
|
size_t i, added, removed;
|
||||||
|
void *iter;
|
||||||
|
|
||||||
|
queue = bh_queue_new();
|
||||||
|
BH_VERIFY(queue != NULL);
|
||||||
|
|
||||||
|
added = 0;
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
added += i * 2;
|
||||||
|
BH_VERIFY(bh_queue_insert(queue, BH_INT2PTR(i * 2)) == BH_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
removed = 0;
|
||||||
|
iter = bh_queue_iter_next(queue, NULL);
|
||||||
|
while (iter)
|
||||||
|
{
|
||||||
|
void *value;
|
||||||
|
|
||||||
|
BH_VERIFY(bh_queue_front(queue, &value) == BH_OK);
|
||||||
|
removed += BH_PTR2INT(value);
|
||||||
|
|
||||||
|
bh_queue_remove(queue);
|
||||||
|
iter = bh_queue_iter_next(queue, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
BH_VERIFY(added == removed);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) != 0);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 0);
|
||||||
|
|
||||||
|
bh_queue_free(queue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int rollover(void)
|
||||||
|
{
|
||||||
|
bh_queue_t *queue;
|
||||||
|
size_t i, j, capacity;
|
||||||
|
|
||||||
|
queue = bh_queue_new();
|
||||||
|
BH_VERIFY(queue != NULL);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_queue_reserve(queue, 128) == 0);
|
||||||
|
capacity = bh_queue_capacity(queue);
|
||||||
|
|
||||||
|
for (i = 0; i < 128; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
bh_queue_remove(queue);
|
||||||
|
|
||||||
|
for (j = 0; j < 4 && bh_queue_size(queue) < 128; j++)
|
||||||
|
BH_VERIFY(bh_queue_insert(queue, BH_INT2PTR(i * 4 + j)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 128);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) == capacity);
|
||||||
|
|
||||||
|
bh_queue_free(queue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int fields(void)
|
||||||
|
{
|
||||||
|
bh_queue_t *queue;
|
||||||
|
|
||||||
|
queue = bh_queue_new();
|
||||||
|
BH_VERIFY(queue != NULL);
|
||||||
|
|
||||||
|
BH_VERIFY(bh_queue_insert(queue, BH_INT2PTR(1337)) == 0);
|
||||||
|
BH_VERIFY(bh_queue_size(queue) == 1);
|
||||||
|
BH_VERIFY(bh_queue_empty(queue) == 0);
|
||||||
|
BH_VERIFY(bh_queue_capacity(queue) >= 1);
|
||||||
|
|
||||||
|
bh_queue_free(queue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
bh_unit_add("new_free", new_free);
|
||||||
|
bh_unit_add("grow_shrink", grow_shrink);
|
||||||
|
bh_unit_add("insert_remove", insert_remove);
|
||||||
|
bh_unit_add("rollover", rollover);
|
||||||
|
bh_unit_add("fields", fields);
|
||||||
|
|
||||||
|
return bh_unit_run();
|
||||||
|
}
|
||||||
29
unit/CMakeLists.txt
Executable file
29
unit/CMakeLists.txt
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Project and C standard configuration
|
||||||
|
project(bhunit LANGUAGES C)
|
||||||
|
set(CMAKE_C_STANDARD 90)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Disable extensions
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# Library code
|
||||||
|
set(BHUNIT_SOURCE
|
||||||
|
src/unit.c
|
||||||
|
)
|
||||||
|
|
||||||
|
set(BHUNIT_HEADER
|
||||||
|
include/bh/unit.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# Library
|
||||||
|
add_library(bhunit STATIC ${BHUNIT_SOURCE} ${BHUNIT_HEADER})
|
||||||
|
target_include_directories(bhunit PUBLIC include)
|
||||||
|
|
||||||
|
# Enable all compiler warnings
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(bhunit PRIVATE /W4 /WX)
|
||||||
|
else()
|
||||||
|
target_compile_options(bhunit PRIVATE -Wall -Wextra -Wpedantic -Werror)
|
||||||
|
endif()
|
||||||
29
unit/include/bh/unit.h
Executable file
29
unit/include/bh/unit.h
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef BH_UNIT_H
|
||||||
|
#define BH_UNIT_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef int (*bh_unit_cb_t)(void);
|
||||||
|
|
||||||
|
#define BH_VERIFY(e) \
|
||||||
|
do { if (!(e)) { \
|
||||||
|
printf("%s:%d\t%s\n", __FILE__, __LINE__, #e); \
|
||||||
|
return -1; \
|
||||||
|
} } while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_FAIL(msg) \
|
||||||
|
do { printf("%s:%d\t%s\n", __FILE__, __LINE__, msg); \
|
||||||
|
return -1; } while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_VERIFY_DELTA(x, y, e) \
|
||||||
|
do { if ((((x)>(y))?((x)-(y)):((y)-(x)))>(e)) { \
|
||||||
|
printf("%s:%d\t%s\n", __FILE__, __LINE__, #x " == " #y); \
|
||||||
|
return -1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
void bh_unit_add(const char *name, bh_unit_cb_t func);
|
||||||
|
int bh_unit_run(void);
|
||||||
|
|
||||||
|
#endif /* BH_UNIT_H */
|
||||||
56
unit/src/unit.c
Executable file
56
unit/src/unit.c
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#include <bh/unit.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef struct bh_unit_s
|
||||||
|
{
|
||||||
|
struct bh_unit_s *next;
|
||||||
|
const char *name;
|
||||||
|
bh_unit_cb_t func;
|
||||||
|
} bh_unit_t;
|
||||||
|
|
||||||
|
static bh_unit_t *root = NULL;
|
||||||
|
|
||||||
|
void bh_unit_add(const char *name, bh_unit_cb_t func)
|
||||||
|
{
|
||||||
|
bh_unit_t *unit, *current;
|
||||||
|
|
||||||
|
unit = malloc(sizeof(*unit));
|
||||||
|
if (!unit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unit->name = name;
|
||||||
|
unit->func = func;
|
||||||
|
unit->next = NULL;
|
||||||
|
|
||||||
|
current = root;
|
||||||
|
while (current && current->next)
|
||||||
|
current = current->next;
|
||||||
|
|
||||||
|
if (current)
|
||||||
|
current->next = unit;
|
||||||
|
else
|
||||||
|
root = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bh_unit_run(void)
|
||||||
|
{
|
||||||
|
bh_unit_t *current;
|
||||||
|
printf("Running tests...\n");
|
||||||
|
|
||||||
|
current = root;
|
||||||
|
while (current)
|
||||||
|
{
|
||||||
|
printf("%s\n", current->name);
|
||||||
|
if (current->func())
|
||||||
|
{
|
||||||
|
printf("\tFAIL\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
printf("\tPASS\n");
|
||||||
|
fflush(stdout);
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
2
util/trim-whitespace.sh
Executable file
2
util/trim-whitespace.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
find . \( -iname "*.h" -o -iname "*.c" \) -exec sed -i "s/[ \t]*$//" {} \;
|
||||||
Reference in New Issue
Block a user