Add documentation, expand error handling, implement file and buffer io
This commit is contained in:
@@ -23,8 +23,9 @@ include(CTest)
|
||||
enable_testing()
|
||||
|
||||
# Set library code
|
||||
set(BHLIB_SOURCE
|
||||
set(BH_SOURCE
|
||||
src/algo.c
|
||||
src/buffer.c
|
||||
src/hashmap.c
|
||||
src/queue.c
|
||||
src/thread.c
|
||||
@@ -32,9 +33,10 @@ set(BHLIB_SOURCE
|
||||
src/deflate.c
|
||||
)
|
||||
|
||||
set(BHLIB_HEADER
|
||||
set(BH_HEADER
|
||||
include/bh/bh.h
|
||||
include/bh/platform.h
|
||||
include/bh/buffer.h
|
||||
include/bh/algo.h
|
||||
include/bh/hashmap.h
|
||||
include/bh/queue.h
|
||||
@@ -43,7 +45,7 @@ set(BHLIB_HEADER
|
||||
include/bh/deflate.h
|
||||
)
|
||||
|
||||
set(BHLIB_INCLUDE_DIRS
|
||||
set(BH_INCLUDE_DIRS
|
||||
include
|
||||
${PROJECT_BINARY_DIR}/include
|
||||
)
|
||||
@@ -52,45 +54,58 @@ set(BHLIB_INCLUDE_DIRS
|
||||
# Determine platform
|
||||
if(WIN32)
|
||||
message(STATUS "Platform - Win32")
|
||||
set(BH_PLATFORM_WIN TRUE)
|
||||
|
||||
# Add platform dependent files
|
||||
list(APPEND BH_SOURCE
|
||||
src/file_win.c
|
||||
)
|
||||
|
||||
# Check multithreading support
|
||||
check_symbol_exists(_beginthread process.h BHLIB_USE_WINTHREAD)
|
||||
if(BHLIB_USE_WINTHREAD)
|
||||
check_symbol_exists(_beginthread process.h BH_USE_WINTHREAD)
|
||||
if(BH_USE_WINTHREAD)
|
||||
message(STATUS "Multithreading enabled")
|
||||
list(APPEND BHLIB_SOURCE
|
||||
list(APPEND BH_SOURCE
|
||||
src/thread_win.c
|
||||
)
|
||||
else()
|
||||
message(STATUS "Multithreading disabled")
|
||||
list(APPEND BHLIB_SOURCE
|
||||
list(APPEND BH_SOURCE
|
||||
src/thread_null.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BHLIB_NO_WINXP)
|
||||
if(BH_NO_WINXP)
|
||||
add_definitions(-D_WIN32_WINNT=_WIN32_WINNT_VISTA -DWINVER=_WIN32_WINNT_VISTA)
|
||||
endif()
|
||||
elseif(UNIX)
|
||||
message(STATUS "Platform: Unix (Linux/BSD/MacOS X)")
|
||||
set(BH_PLATFORM_POSIX TRUE)
|
||||
|
||||
# Add platform dependent files
|
||||
list(APPEND BH_SOURCE
|
||||
src/file_posix.c
|
||||
)
|
||||
|
||||
# Check multithreading support
|
||||
check_include_file(pthread.h BHLIB_USE_PTHREAD)
|
||||
if(BHLIB_USE_PTHREAD)
|
||||
check_include_file(pthread.h BH_USE_PTHREAD)
|
||||
if(BH_USE_PTHREAD)
|
||||
message(STATUS "Multithreading enabled")
|
||||
list(APPEND BHLIB_SOURCE
|
||||
list(APPEND BH_SOURCE
|
||||
src/thread_posix.c
|
||||
)
|
||||
else()
|
||||
message(STATUS "Multithreading disabled")
|
||||
list(APPEND BHLIB_SOURCE
|
||||
list(APPEND BH_SOURCE
|
||||
src/thread_null.c
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Platform: Unknown")
|
||||
message(STATUS "Multithreading disabled")
|
||||
list(APPEND BHLIB_SOURCE
|
||||
list(APPEND BH_SOURCE
|
||||
src/thread_null.c
|
||||
src/file_null.c
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -98,8 +113,8 @@ endif()
|
||||
configure_file(include/bh/config.in include/bh/config.h)
|
||||
|
||||
# Library
|
||||
add_library(bhlib STATIC ${BHLIB_SOURCE} ${BHLIB_HEADER})
|
||||
target_include_directories(bhlib PUBLIC ${BHLIB_INCLUDE_DIRS})
|
||||
add_library(bhlib STATIC ${BH_SOURCE} ${BH_HEADER})
|
||||
target_include_directories(bhlib PUBLIC ${BH_INCLUDE_DIRS})
|
||||
|
||||
# Runtime definition
|
||||
add_executable(main
|
||||
|
||||
2737
docs/Doxyfile
Normal file
2737
docs/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,154 +1,63 @@
|
||||
#ifndef BHLIB_ALGO_H
|
||||
#define BHLIB_ALGO_H
|
||||
#ifndef BH_ALGO_H
|
||||
#define BH_ALGO_H
|
||||
|
||||
#include "bh.h"
|
||||
|
||||
/**
|
||||
* @brief Swap two elements.
|
||||
*
|
||||
* @param lhs Pointer to the first element
|
||||
* @param rhs Pointer to the second element
|
||||
* @param size Element size
|
||||
*/
|
||||
void bh_swap(void *lhs,
|
||||
void *rhs,
|
||||
void bh_swap(void *dest,
|
||||
void *src,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Partition the array.
|
||||
*
|
||||
* @param pivot Pointer to the pivot element
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*
|
||||
* @return The return value is the pointer to the first element of the second
|
||||
* partition.
|
||||
*
|
||||
* @warning Pivot element can be a part of the partitioned array.
|
||||
*/
|
||||
void *bh_partition(void *pivot,
|
||||
void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Sort the array.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*/
|
||||
void bh_sort(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Sort the array using insert sort.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*/
|
||||
void bh_sort_insert(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Sort the array using shell sort.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*/
|
||||
void bh_sort_shell(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Sort the array using intro sort.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*/
|
||||
void bh_sort_intro(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Sort the array using heap sort.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*/
|
||||
void bh_sort_heap(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Make heap from the array.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*
|
||||
* @sa bh_heap_remove, bh_heap_insert
|
||||
*/
|
||||
void bh_heap_make(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Remove element from the heap.
|
||||
*
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*
|
||||
* @warning Removed element is placed at the end of the array
|
||||
*
|
||||
* @sa bh_heap_make, bh_heap_remove
|
||||
*/
|
||||
void bh_heap_remove(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
/**
|
||||
* @brief Insert element to the heap.
|
||||
*
|
||||
* @param value Pointer to the inserted value (optional)
|
||||
* @param array Pointer to the array
|
||||
* @param size Array size
|
||||
* @param element Element size
|
||||
* @param equal Equal/compare function
|
||||
*
|
||||
* @warning If value is not passed, function assumes inserted element
|
||||
* is already placed at the end of the array.
|
||||
*
|
||||
* @sa bh_heap_make, bh_heap_remove
|
||||
*/
|
||||
void bh_heap_insert(void *value,
|
||||
void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
#endif /* BHLIB_ALGO_H */
|
||||
void bh_heap_replace(void *value,
|
||||
void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
bh_equal_cb_t equal);
|
||||
|
||||
#endif /* BH_ALGO_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BHLIB_H
|
||||
#define BHLIB_H
|
||||
#ifndef BH_H
|
||||
#define BH_H
|
||||
|
||||
#include <bh/config.h>
|
||||
#include <stddef.h>
|
||||
@@ -18,8 +18,17 @@
|
||||
#define BH_PTR_TO_UINT(x) \
|
||||
((bh_uintptr_t)(x))
|
||||
|
||||
#define BH_OK 0x0000
|
||||
#define BH_ERROR 0x0001
|
||||
#define BH_OOM 0x0002
|
||||
#define BH_INVALID 0x0003
|
||||
#define BH_NO_IMPL 0x0004
|
||||
#define BH_FOUND 0x0005
|
||||
#define BH_NOT_FOUND 0x0006
|
||||
#define BH_TIMEOUT 0x0007
|
||||
|
||||
typedef int (*bh_equal_cb_t)(const void *, const void *);
|
||||
typedef size_t (*bh_hash_cb_t)(const void *);
|
||||
|
||||
#endif /* BHLIB_H */
|
||||
#endif /* BH_H */
|
||||
|
||||
|
||||
91
include/bh/buffer.h
Normal file
91
include/bh/buffer.h
Normal file
@@ -0,0 +1,91 @@
|
||||
#ifndef BH_BUFFER_H
|
||||
#define BH_BUFFER_H
|
||||
|
||||
#include "io.h"
|
||||
|
||||
typedef struct bh_buffer_s bh_buffer_t;
|
||||
|
||||
bh_buffer_t *bh_buffer_new(void);
|
||||
|
||||
void bh_buffer_free(bh_buffer_t *buffer);
|
||||
|
||||
const char *bh_buffer_data(bh_buffer_t *buffer);
|
||||
|
||||
void bh_buffer_set_data(bh_buffer_t *buffer,
|
||||
const char *data,
|
||||
size_t size);
|
||||
|
||||
size_t bh_buffer_capacity(bh_buffer_t *buffer);
|
||||
|
||||
int bh_buffer_reserve(bh_buffer_t *buffer,
|
||||
size_t size);
|
||||
|
||||
int bh_buffer_open_base(bh_buffer_t *buffer,
|
||||
int mode);
|
||||
|
||||
void bh_buffer_close_base(bh_buffer_t *buffer);
|
||||
|
||||
int bh_buffer_is_open_base(bh_buffer_t *buffer);
|
||||
|
||||
size_t bh_buffer_read_base(bh_buffer_t *buffer,
|
||||
char *data,
|
||||
size_t size);
|
||||
|
||||
size_t bh_buffer_write_base(bh_buffer_t *buffer,
|
||||
const char *data,
|
||||
size_t size);
|
||||
|
||||
void bh_buffer_flush_base(bh_buffer_t *buffer);
|
||||
|
||||
int bh_buffer_seek_base(bh_buffer_t *buffer,
|
||||
bh_off_t pos,
|
||||
int dir);
|
||||
|
||||
bh_off_t bh_buffer_size_base(bh_buffer_t *buffer);
|
||||
|
||||
bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer);
|
||||
|
||||
bh_off_t bh_buffer_available_base(bh_buffer_t *buffer);
|
||||
|
||||
void bh_buffer_clear_base(bh_buffer_t *buffer);
|
||||
|
||||
#define bh_buffer_open(buffer, mode) \
|
||||
bh_io_open((bh_io_t *)(buffer), (mode))
|
||||
|
||||
#define bh_buffer_close(buffer) \
|
||||
bh_io_close((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_is_open(buffer) \
|
||||
bh_io_is_open((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_read(buffer, data, size) \
|
||||
bh_io_read((bh_io_t *)(buffer), (data), (size))
|
||||
|
||||
#define bh_buffer_write(buffer, data, size) \
|
||||
bh_io_write((bh_io_t *)(buffer), (data), (size))
|
||||
|
||||
#define bh_buffer_flush(buffer) \
|
||||
bh_io_flush((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_seek(buffer, pos, dir) \
|
||||
bh_io_seek((bh_io_t *)(buffer), (pos), (dir))
|
||||
|
||||
#define bh_buffer_size(buffer) \
|
||||
bh_io_size((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_tell(buffer) \
|
||||
bh_io_tell((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_available(buffer) \
|
||||
bh_io_available((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_clear(buffer) \
|
||||
bh_io_clear((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_error(buffer) \
|
||||
bh_io_error((bh_io_t *)(buffer))
|
||||
|
||||
#define bh_buffer_eof(buffer) \
|
||||
bh_io_eof((bh_io_t *)(buffer))
|
||||
|
||||
#endif /* BH_BUFFER_H */
|
||||
@@ -1,8 +1,10 @@
|
||||
#ifndef BHLIB_CONFIG_H
|
||||
#define BHLIB_CONFIG_H
|
||||
#ifndef BH_CONFIG_H
|
||||
#define BH_CONFIG_H
|
||||
|
||||
#cmakedefine BHLIB_USE_WINTHREAD
|
||||
#cmakedefine BHLIB_USE_PTHREAD
|
||||
#cmakedefine BHLIB_NO_WINXP
|
||||
#cmakedefine BH_USE_WINTHREAD
|
||||
#cmakedefine BH_USE_PTHREAD
|
||||
#cmakedefine BH_NO_WINXP
|
||||
#cmakedefine BH_PLATFORM_POSIX
|
||||
#cmakedefine BH_PLATFORM_WIN
|
||||
|
||||
#endif /* BHLIB_CONFIG_H */
|
||||
#endif /* BH_CONFIG_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BHLIB_DEFLATE_H
|
||||
#define BHLIB_DEFLATE_H
|
||||
#ifndef BH_DEFLATE_H
|
||||
#define BH_DEFLATE_H
|
||||
|
||||
|
||||
#endif /* BHLIB_DEFLATE_H */
|
||||
#endif /* BH_DEFLATE_H */
|
||||
|
||||
@@ -1,37 +1,80 @@
|
||||
#ifndef BHLIB_FILE_H
|
||||
#define BHLIB_FILE_H
|
||||
#ifndef BH_FILE_H
|
||||
#define BH_FILE_H
|
||||
|
||||
#include "io.h"
|
||||
|
||||
typedef struct bh_file_s bh_file_t;
|
||||
|
||||
bh_file_t *bh_file_new(const char *path,
|
||||
const char *mode);
|
||||
bh_file_t *bh_file_new(const char *path);
|
||||
|
||||
void bh_file_free(bh_file_t *file);
|
||||
|
||||
size_t bh_file_read(bh_file_t *file,
|
||||
char *buffer,
|
||||
int bh_file_open_base(bh_file_t *file,
|
||||
int mode);
|
||||
|
||||
void bh_file_close_base(bh_file_t *file);
|
||||
|
||||
int bh_file_is_open_base(bh_file_t *file);
|
||||
|
||||
size_t bh_file_read_base(bh_file_t *file,
|
||||
char *data,
|
||||
size_t size);
|
||||
|
||||
size_t bh_file_write(bh_file_t *file,
|
||||
const char *buffer,
|
||||
size_t bh_file_write_base(bh_file_t *file,
|
||||
const char *data,
|
||||
size_t size);
|
||||
|
||||
void bh_file_flush(bh_file_t *file);
|
||||
void bh_file_flush_base(bh_file_t *file);
|
||||
|
||||
void bh_file_seek(bh_file_t *file,
|
||||
int bh_file_seek_base(bh_file_t *file,
|
||||
bh_off_t pos,
|
||||
int dir);
|
||||
|
||||
bh_off_t bh_file_tell(bh_file_t *file);
|
||||
bh_off_t bh_file_size_base(bh_file_t *file);
|
||||
|
||||
bh_off_t bh_file_available(bh_file_t *file);
|
||||
bh_off_t bh_file_tell_base(bh_file_t *file);
|
||||
|
||||
int bh_file_error(bh_file_t *file);
|
||||
bh_off_t bh_file_available_base(bh_file_t *file);
|
||||
|
||||
int bh_file_eof(bh_file_t *file);
|
||||
void bh_file_clear_base(bh_file_t *file);
|
||||
|
||||
void bh_file_clear(bh_file_t *file);
|
||||
#define bh_file_open(file, mode) \
|
||||
bh_io_open((bh_io_t *)(file), (mode))
|
||||
|
||||
#endif /* BHLIB_FILE_H */
|
||||
#define bh_file_close(file) \
|
||||
bh_io_close((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_is_open(file) \
|
||||
bh_io_is_open((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_read(file, data, size) \
|
||||
bh_io_read((bh_io_t *)(file), (data), (size))
|
||||
|
||||
#define bh_file_write(file, data, size) \
|
||||
bh_io_write((bh_io_t *)(file), (data), (size))
|
||||
|
||||
#define bh_file_flush(file) \
|
||||
bh_io_flush((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_seek(file, pos, dir) \
|
||||
bh_io_seek((bh_io_t *)(file), (pos), (dir))
|
||||
|
||||
#define bh_file_size(file) \
|
||||
bh_io_size((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_tell(file) \
|
||||
bh_io_tell((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_available(file) \
|
||||
bh_io_available((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_clear(file) \
|
||||
bh_io_clear((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_error(file) \
|
||||
bh_io_error((bh_io_t *)(file))
|
||||
|
||||
#define bh_file_eof(file) \
|
||||
bh_io_eof((bh_io_t *)(file))
|
||||
|
||||
#endif /* BH_FILE_H */
|
||||
|
||||
@@ -1,231 +1,53 @@
|
||||
#ifndef BHLIB_HASHMAP_H
|
||||
#define BHLIB_HASHMAP_H
|
||||
#ifndef BH_HASHMAP_H
|
||||
#define BH_HASHMAP_H
|
||||
|
||||
#include "bh.h"
|
||||
|
||||
typedef struct bh_hashmap_s bh_hashmap_t;
|
||||
|
||||
/**
|
||||
* @brief Create new hashmap object.
|
||||
*
|
||||
* @param equal Function used for comparing keys
|
||||
* @param hash Function used to calculate hash value of the key
|
||||
*
|
||||
* @return If the function succeeds, the return value is a pointer to the new
|
||||
* hashmap object.
|
||||
* @return If the function fails, the return value is NULL.
|
||||
*
|
||||
* @sa bh_hashmap_free, bh_hashmap_reserve, bh_hashmap_insert
|
||||
*/
|
||||
bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
|
||||
bh_hash_cb_t hash);
|
||||
|
||||
/**
|
||||
* @brief Free hashmap object.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
*
|
||||
* @sa bh_hashmap_clear
|
||||
*/
|
||||
void bh_hashmap_free(bh_hashmap_t *hashmap);
|
||||
|
||||
/**
|
||||
* @brief Clear the hashmap.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_hashmap_remove
|
||||
*/
|
||||
void bh_hashmap_clear(bh_hashmap_t *hashmap);
|
||||
|
||||
/**
|
||||
* @brief Reserve space for the specified amount of elements.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param size The amount of elements.
|
||||
*
|
||||
* @return If the function succeeds, the return value is zero.
|
||||
* @return If the function fails, the return value is non-zero.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_hashmap_capacity, bh_hashmap_insert
|
||||
*/
|
||||
int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Insert key/value into the hashmap.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param key Key
|
||||
* @param value Value
|
||||
*
|
||||
* @return If the function succeeds, the return value is zero.
|
||||
* @return If the function fails, the return value is non-zero.
|
||||
*
|
||||
* @warning Inserted element is owned by the caller of the function.
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_hashmap_remove, bh_hashmap_at
|
||||
*/
|
||||
int bh_hashmap_insert(bh_hashmap_t *hashmap,
|
||||
void *key,
|
||||
void *value);
|
||||
|
||||
/**
|
||||
* @brief Remove element from the hashmap.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param key Key.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_hashmap_insert, bh_hashmap_at
|
||||
*/
|
||||
void bh_hashmap_remove(bh_hashmap_t *hashmap,
|
||||
void *key);
|
||||
|
||||
/**
|
||||
* @brief Return element value by the key from the hashmap.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap.
|
||||
* @param key Key.
|
||||
* @param exists Optional pointer to the exists flag.
|
||||
*
|
||||
* @return If the function succeeds, the return value is a valid pointer to
|
||||
* the element value.
|
||||
* @return If the function fails, the return value is NULL.
|
||||
*
|
||||
* @sa bh_hashmap_empty, bh_hashmap_insert
|
||||
*/
|
||||
void *bh_hashmap_at(bh_hashmap_t *hashmap,
|
||||
void *key,
|
||||
int *exists);
|
||||
|
||||
/**
|
||||
* @brief Check if the hashmap is empty.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
*
|
||||
* @return The return value is non-zero if the hashmap is empty, otherwise
|
||||
* zero.
|
||||
*
|
||||
* @sa bh_hashmap_size
|
||||
*/
|
||||
int bh_hashmap_empty(bh_hashmap_t *hashmap);
|
||||
|
||||
/**
|
||||
* @brief Return hashmap size.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
*
|
||||
* @return The return value is current hashmap size.
|
||||
*
|
||||
* @sa bh_hashmap_empty, bh_hashmap_capacity
|
||||
*/
|
||||
size_t bh_hashmap_size(bh_hashmap_t *hashmap);
|
||||
|
||||
/**
|
||||
* @brief Return hashmap capacity.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
*
|
||||
* @return The return value is current hashmap capacity.
|
||||
*
|
||||
* @sa bh_hashmap_reserve, bh_hashmap_size
|
||||
*/
|
||||
size_t bh_hashmap_capacity(bh_hashmap_t *hashmap);
|
||||
|
||||
/**
|
||||
* @brief Return hashmap load factor.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
*
|
||||
* @return The return value is current hashmap load factor.
|
||||
*
|
||||
* @sa bh_hashmap_set_factor, bh_hashmap_capacity
|
||||
*/
|
||||
float bh_hashmap_factor(bh_hashmap_t *hashmap);
|
||||
|
||||
/**
|
||||
* @brief Set hashmap load factor.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param factor Load factor.
|
||||
*
|
||||
* @sa bh_hashmap_factor
|
||||
*/
|
||||
void bh_hashmap_set_factor(bh_hashmap_t *hashmap,
|
||||
float factor);
|
||||
|
||||
/**
|
||||
* @brief Return iterator for the element by the key.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param key Key
|
||||
*
|
||||
* @return The return value is the valid iterator for the element in the
|
||||
* hashmap.
|
||||
* @return The return value is the NULL iterator if there is no element with
|
||||
* specified key.
|
||||
*
|
||||
* @sa bh_hashmap_iter_key, bh_hashmap_iter_value
|
||||
*/
|
||||
void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
|
||||
void *key);
|
||||
|
||||
/**
|
||||
* @brief Return iterator for the next element in the hashmap.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param iter Valid or NULL iterator.
|
||||
*
|
||||
* @return The return value is the valid iterator for the next element in the
|
||||
* hashmap.
|
||||
* @return The return value is the NULL iterator if there is no more elements
|
||||
* in the hashmap.
|
||||
*
|
||||
* @sa bh_hashmap_iter_key, bh_hashmap_iter_value
|
||||
*/
|
||||
void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
|
||||
void *iter);
|
||||
|
||||
/**
|
||||
* @brief Remove element from the hashmap by the iterator.
|
||||
*
|
||||
* @param hashmap Valid pointer to the hashmap object.
|
||||
* @param key Valid iterator.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_hashmap_insert, bh_hashmap_at
|
||||
*/
|
||||
void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
|
||||
void *iter);
|
||||
|
||||
/**
|
||||
* @brief Return pointer to the element's key.
|
||||
*
|
||||
* @param iter Valid iterator.
|
||||
*
|
||||
* @return The return value is the stored element key.
|
||||
*
|
||||
* @sa bh_hashmap_iter_value, bh_hashmap_iter_next
|
||||
*/
|
||||
void *bh_hashmap_iter_key(void *iter);
|
||||
|
||||
/**
|
||||
* @brief Return pointer to the element's value.
|
||||
*
|
||||
* @param iter Valid iterator.
|
||||
*
|
||||
* @return The return value is the stored element value.
|
||||
*
|
||||
* @sa bh_hashmap_iter_key, bh_hashmap_iter_next
|
||||
*/
|
||||
void *bh_hashmap_iter_value(void *iter);
|
||||
|
||||
#endif /* BHLIB_HASHMAP_H */
|
||||
#endif /* BH_HASHMAP_H */
|
||||
|
||||
20
include/bh/internal/buffer.h
Normal file
20
include/bh/internal/buffer.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef BH_INTERNAL_BUFFER_H
|
||||
#define BH_INTERNAL_BUFFER_H
|
||||
|
||||
#include <bh/buffer.h>
|
||||
|
||||
struct bh_buffer_s
|
||||
{
|
||||
bh_io_t base;
|
||||
char *data;
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
size_t at;
|
||||
int mode;
|
||||
};
|
||||
|
||||
int bh_buffer_init(bh_buffer_t *buffer);
|
||||
|
||||
void bh_buffer_destroy(bh_buffer_t *buffer);
|
||||
|
||||
#endif /* BH_INTERNAL_BUFFER_H */
|
||||
20
include/bh/internal/file.h
Normal file
20
include/bh/internal/file.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef BH_INTERNAL_FILE_H
|
||||
#define BH_INTERNAL_FILE_H
|
||||
|
||||
#include "io.h"
|
||||
#include <bh/file.h>
|
||||
|
||||
#if defined(BH_PLATFORM_POSIX)
|
||||
#include "file_posix.h"
|
||||
#elif defined(BH_PLATFORM_WIN)
|
||||
#include "file_win.h"
|
||||
#else
|
||||
#include "file_null.h"
|
||||
#endif
|
||||
|
||||
int bh_file_init(bh_file_t *file,
|
||||
const char *path);
|
||||
|
||||
void bh_file_destroy(bh_file_t *file);
|
||||
|
||||
#endif /* BH_INTERNAL_FILE_H */
|
||||
4
include/bh/internal/file_null.h
Normal file
4
include/bh/internal/file_null.h
Normal file
@@ -0,0 +1,4 @@
|
||||
struct bh_file_s
|
||||
{
|
||||
bh_io_t base;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
struct bh_file_s
|
||||
{
|
||||
bh_io_t base;
|
||||
char *path;
|
||||
int mode;
|
||||
int handle;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <windows.h>
|
||||
|
||||
struct bh_file_s
|
||||
{
|
||||
bh_io_t base;
|
||||
char *path;
|
||||
int mode;
|
||||
HANDLE handle;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BHLIB_INTERNAL_HASHMAP_H
|
||||
#define BHLIB_INTERNAL_HASHMAP_H
|
||||
#ifndef BH_INTERNAL_HASHMAP_H
|
||||
#define BH_INTERNAL_HASHMAP_H
|
||||
|
||||
#include <bh/hashmap.h>
|
||||
|
||||
@@ -27,4 +27,4 @@ void bh_hashmap_init(bh_hashmap_t *hashmap,
|
||||
|
||||
void bh_hashmap_destroy(bh_hashmap_t *hashmap);
|
||||
|
||||
#endif /* BHLIB_INTERNAL_HASHMAP_H */
|
||||
#endif /* BH_INTERNAL_HASHMAP_H */
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef BHLIB_INTERNAL_IO_H
|
||||
#define BHLIB_INTERNAL_IO_H
|
||||
#ifndef BH_INTERNAL_IO_H
|
||||
#define BH_INTERNAL_IO_H
|
||||
|
||||
#include <bh/io.h>
|
||||
|
||||
void bh_io_init(bh_io_t *io,
|
||||
bh_io_table_t *table);
|
||||
const bh_io_table_t *table);
|
||||
|
||||
void bh_io_destroy(bh_io_t *io);
|
||||
|
||||
#endif /* BHLIB_INTERNAL_IO_H */
|
||||
#endif /* BH_INTERNAL_IO_H */
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BHLIB_INTERNAL_QUEUE_H
|
||||
#define BHLIB_INTERNAL_QUEUE_H
|
||||
#ifndef BH_INTERNAL_QUEUE_H
|
||||
#define BH_INTERNAL_QUEUE_H
|
||||
|
||||
#include <bh/queue.h>
|
||||
|
||||
@@ -12,24 +12,8 @@ struct bh_queue_s
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Initialize embedded queue object.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @sa bh_queue_destroy
|
||||
*/
|
||||
void bh_queue_init(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Destroy embedded queue object.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @sa bh_queue_init
|
||||
*/
|
||||
void bh_queue_destroy(bh_queue_t *queue);
|
||||
|
||||
#endif /* BHLIB_INTERNAL_QUEUE_H */
|
||||
#endif /* BH_INTERNAL_QUEUE_H */
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#ifndef BHLIB_INTERNAL_THREAD_H
|
||||
#define BHLIB_INTERNAL_THREAD_H
|
||||
#ifndef BH_INTERNAL_THREAD_H
|
||||
#define BH_INTERNAL_THREAD_H
|
||||
|
||||
#include <bh/thread.h>
|
||||
#include "queue.h"
|
||||
|
||||
#define BH_THREAD_DONE (1 << 8)
|
||||
#define BH_THREAD_DONE 0x0100
|
||||
|
||||
#if defined(BHLIB_USE_PTHREAD)
|
||||
#if defined(BH_USE_PTHREAD)
|
||||
#include "thread_posix.h"
|
||||
#elif defined(BHLIB_USE_WINTHREAD)
|
||||
#elif defined(BH_USE_WINTHREAD)
|
||||
#include "thread_win.h"
|
||||
#else
|
||||
#include "thread_null.h"
|
||||
@@ -42,4 +42,4 @@ void bh_task_destroy(bh_task_t *task);
|
||||
|
||||
void bh_thread_pool_worker(void *arg);
|
||||
|
||||
#endif /* BHLIB_INTERNAL_THREAD_H */
|
||||
#endif /* BH_INTERNAL_THREAD_H */
|
||||
|
||||
159
include/bh/io.h
159
include/bh/io.h
@@ -1,10 +1,24 @@
|
||||
#ifndef BHLIB_IO_H
|
||||
#define BHLIB_IO_H
|
||||
#ifndef BH_IO_H
|
||||
#define BH_IO_H
|
||||
|
||||
#include "bh.h"
|
||||
|
||||
#define BH_IO_ERROR (1 << 0)
|
||||
#define BH_IO_EOF (1 << 1)
|
||||
#define BH_IO_ERROR 0x0001
|
||||
#define BH_IO_EOF 0x0002
|
||||
|
||||
#define BH_IO_READ 0x0001
|
||||
#define BH_IO_WRITE 0x0002
|
||||
#define BH_IO_READ_WRITE (BH_IO_READ | BH_IO_WRITE)
|
||||
#define BH_IO_OPEN 0x0000
|
||||
#define BH_IO_CREATE 0x0100
|
||||
#define BH_IO_APPEND 0x0200
|
||||
#define BH_IO_TRUNCATE 0x0300
|
||||
#define BH_IO_MASK 0xFF00
|
||||
|
||||
|
||||
#define BH_IO_SET 0x0000
|
||||
#define BH_IO_CURRENT 0x0001
|
||||
#define BH_IO_END 0x0002
|
||||
|
||||
#define BH_IO_CAST(x) \
|
||||
((bh_io_t *)(x))
|
||||
@@ -13,6 +27,13 @@ struct bh_io_s;
|
||||
|
||||
typedef struct bh_io_table_s
|
||||
{
|
||||
int (*open)(struct bh_io_s *io,
|
||||
int mode);
|
||||
|
||||
void (*close)(struct bh_io_s *io);
|
||||
|
||||
int (*is_open)(struct bh_io_s *io);
|
||||
|
||||
size_t (*read)(struct bh_io_s *io,
|
||||
char *data,
|
||||
size_t size);
|
||||
@@ -23,10 +44,12 @@ typedef struct bh_io_table_s
|
||||
|
||||
void (*flush)(struct bh_io_s *io);
|
||||
|
||||
void (*seek)(struct bh_io_s *io,
|
||||
int (*seek)(struct bh_io_s *io,
|
||||
bh_off_t offset,
|
||||
int dir);
|
||||
|
||||
bh_off_t (*size)(struct bh_io_s *io);
|
||||
|
||||
bh_off_t (*tell)(struct bh_io_s *io);
|
||||
|
||||
bh_off_t (*available)(struct bh_io_s *io);
|
||||
@@ -38,145 +61,49 @@ typedef struct bh_io_table_s
|
||||
|
||||
typedef struct bh_io_s
|
||||
{
|
||||
bh_io_table_t *table;
|
||||
const bh_io_table_t *table;
|
||||
int flags;
|
||||
} bh_io_t;
|
||||
|
||||
/**
|
||||
* @brief Create new IO object.
|
||||
*
|
||||
* @param table Valid pointer to the IO table.
|
||||
* @param size Size of the IO object.
|
||||
*
|
||||
* @return If the function succeeds, the return value is a pointer to the
|
||||
* new, semi-initalized, IO object.
|
||||
* @return If the function fails, the return value is NULL.
|
||||
*
|
||||
* @warning This function should be used in context of implementing child
|
||||
* IO objects (files, sockets, streaming compression, etc).
|
||||
*
|
||||
* @sa bh_io_free
|
||||
*/
|
||||
bh_io_t *bh_io_new(bh_io_table_t *table,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free IO object.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*/
|
||||
void bh_io_free(bh_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Read data from IO.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
* @param data Valid pointer to the buffer.
|
||||
* @param size Size of the buffer.
|
||||
*
|
||||
* @return If the function succeeds, the return value is the amount
|
||||
* of bytes read from the IO object.
|
||||
* @return If the function fails, the return value is zero and error
|
||||
* flag is set.
|
||||
*
|
||||
* @sa bh_io_write, bh_io_eof, bh_io_error
|
||||
*/
|
||||
int bh_io_open(bh_io_t *io,
|
||||
int mode);
|
||||
|
||||
void bh_io_close(bh_io_t *io);
|
||||
|
||||
int bh_io_is_open(bh_io_t *io);
|
||||
|
||||
size_t bh_io_read(bh_io_t *io,
|
||||
char *data,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Write data to IO.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
* @param data Valid pointer to the buffer.
|
||||
* @param size Size of the buffer.
|
||||
*
|
||||
* @return If the function succeeds, the return value is the amount
|
||||
* of bytes written to the IO object.
|
||||
* @return If the function fails, the return value is zero and error
|
||||
* flag is set.
|
||||
*
|
||||
* @sa bh_io_read, bh_io_error, bh_io_flush
|
||||
*/
|
||||
|
||||
size_t bh_io_write(bh_io_t *io,
|
||||
const char* data,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Writes any uncommited changes (if possible).
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*/
|
||||
void bh_io_flush(bh_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Seeks IO object to the specified position (if possible).
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
* @param offset Position
|
||||
* @param dir Direction
|
||||
*
|
||||
* @sa bh_io_tell
|
||||
*/
|
||||
void bh_io_seek(bh_io_t *io,
|
||||
|
||||
int bh_io_seek(bh_io_t *io,
|
||||
bh_off_t offset,
|
||||
int dir);
|
||||
|
||||
/**
|
||||
* @brief Return current position in IO.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*
|
||||
* @return If the function succeeds, the return value is current
|
||||
* position in the IO.
|
||||
* @return If the function fails, the return value is -1.
|
||||
*
|
||||
* @sa bh_io_seek
|
||||
*/
|
||||
bh_off_t bh_io_size(bh_io_t *io);
|
||||
|
||||
bh_off_t bh_io_tell(bh_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Return available bytes in the IO.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*
|
||||
* @return If the function succeeds, the return value is the amount
|
||||
* of the available bytes for reading.
|
||||
* @return If the function fails, the return value is zero.
|
||||
*/
|
||||
|
||||
bh_off_t bh_io_available(bh_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Return error flag of the IO.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*
|
||||
* @return The return value is error flag.
|
||||
*
|
||||
* @sa bh_io_eof, bh_io_clear
|
||||
*/
|
||||
int bh_io_error(bh_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Return end-of-file flag of the IO.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*
|
||||
* @return The return value is end-of-file flag.
|
||||
*
|
||||
* @sa bh_io_error, bh_io_clear
|
||||
*/
|
||||
int bh_io_eof(bh_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Crear IO object state.
|
||||
*
|
||||
* @param io Valid pointer to the IO object.
|
||||
*
|
||||
* @sa bh_io_error, bh_io_eof
|
||||
*/
|
||||
void bh_io_clear(bh_io_t *io);
|
||||
|
||||
|
||||
#endif /* BHLIB_IO_H */
|
||||
#endif /* BH_IO_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BHLIB_PLATFORM_H
|
||||
#define BHLIB_PLATFORM_H
|
||||
#ifndef BH_PLATFORM_H
|
||||
#define BH_PLATFORM_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -43,4 +43,4 @@ typedef unsigned __int32 bh_uintptr_t;
|
||||
|
||||
typedef bh_int64_t bh_off_t;
|
||||
|
||||
#endif /* BHLIB_PLATFORM_H */
|
||||
#endif /* BH_PLATFORM_H */
|
||||
|
||||
@@ -5,152 +5,31 @@
|
||||
|
||||
typedef struct bh_queue_s bh_queue_t;
|
||||
|
||||
/**
|
||||
* @brief Create new queue object.
|
||||
*
|
||||
* @return If the function succeeds, the return value is a pointer to the new
|
||||
* queue object.
|
||||
* @return If the function fails, the return value is NULL.
|
||||
*
|
||||
* @sa bh_queue_free, bh_queue_reserve, bh_queue_insert
|
||||
*/
|
||||
bh_queue_t *bh_queue_new(void);
|
||||
|
||||
/**
|
||||
* @brief Free queue object.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @sa bh_queue_clear
|
||||
*/
|
||||
void bh_queue_free(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Clear the queue.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_queue_remove
|
||||
*/
|
||||
void bh_queue_clear(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Reserve space for the specified amount of elements.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
* @param size The amount of elements.
|
||||
*
|
||||
* @return If the function succeeds, the return value is zero.
|
||||
* @return If the function fails, the return value is non-zero.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_queue_capacity, bh_queue_insert
|
||||
*/
|
||||
int bh_queue_reserve(bh_queue_t *queue,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @brief Insert element at the end of the queue.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
* @param value Element.
|
||||
*
|
||||
* @return If the function succeeds, the return value is zero.
|
||||
* @return If the function fails, the return value is non-zero.
|
||||
*
|
||||
* @warning Inserted element is owned by the caller of the function.
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_queue_remove, bh_queue_front
|
||||
*/
|
||||
int bh_queue_insert(bh_queue_t *queue,
|
||||
void *value);
|
||||
|
||||
/**
|
||||
* @brief Remove element from the front of the queue.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @warning Calling this function will invalidate iterators.
|
||||
*
|
||||
* @sa bh_queue_insert, bh_queue_front
|
||||
*/
|
||||
void bh_queue_remove(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Return element from the front of the queue.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @return If the function succeeds, the return value is a valid pointer to
|
||||
* the element.
|
||||
* @return If the function fails, the return value is NULL.
|
||||
*
|
||||
* @sa bh_queue_empty, bh_queue_insert
|
||||
*/
|
||||
void *bh_queue_front(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Check if the queue is empty.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @return The return value is non-zero if the queue is empty, otherwise zero.
|
||||
*
|
||||
* @sa bh_queue_size
|
||||
*/
|
||||
int bh_queue_empty(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Return queue size.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @return The return value is current queue size.
|
||||
*
|
||||
* @sa bh_queue_empty, bh_queue_capacity
|
||||
*/
|
||||
size_t bh_queue_size(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Return queue capacity.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
*
|
||||
* @return The return value is current queue capacity.
|
||||
*
|
||||
* @sa bh_queue_reserve, bh_queue_size
|
||||
*/
|
||||
size_t bh_queue_capacity(bh_queue_t *queue);
|
||||
|
||||
/**
|
||||
* @brief Return iterator for the next element in the queue.
|
||||
*
|
||||
* @param queue Valid pointer to the queue object.
|
||||
* @param iter Valid or NULL iterator.
|
||||
*
|
||||
* @return The return value is the valid iterator for the next element in the
|
||||
* queue.
|
||||
* @return The return value is the NULL iterator if there is no more elements
|
||||
* in the queue.
|
||||
*
|
||||
* @sa bh_queue_iter_value
|
||||
*/
|
||||
void *bh_queue_iter_next(bh_queue_t *queue,
|
||||
void *iter);
|
||||
|
||||
/**
|
||||
* @brief Return pointer to the element's value.
|
||||
*
|
||||
* @param iter Valid iterator.
|
||||
*
|
||||
* @return The return value is the stored element.
|
||||
*
|
||||
* @sa bh_queue_iter_next
|
||||
*/
|
||||
void *bh_queue_iter_value(void *iter);
|
||||
|
||||
#endif /* BH_QUEUE_H */
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef BHLIB_THREAD_H
|
||||
#define BHLIB_THREAD_H
|
||||
#ifndef BH_THREAD_H
|
||||
#define BH_THREAD_H
|
||||
|
||||
#include "bh.h"
|
||||
|
||||
#define BH_THREAD_CLEANUP (1 << 0)
|
||||
#define BH_THREAD_CLEANUP 0x0001
|
||||
|
||||
typedef void (*bh_thread_cb_t)(void *);
|
||||
typedef struct bh_thread_s bh_thread_t;
|
||||
@@ -13,12 +13,12 @@ typedef struct bh_cond_s bh_cond_t;
|
||||
typedef struct bh_task_s bh_task_t;
|
||||
typedef struct bh_thread_pool_s bh_thread_pool_t;
|
||||
|
||||
#if defined(BHLIB_USE_PTHREAD)
|
||||
#if defined(BH_USE_PTHREAD)
|
||||
bh_thread_t *bh_thread_new(bh_task_t *task);
|
||||
|
||||
bh_thread_pool_t *bh_thread_pool_new(size_t size);
|
||||
|
||||
#elif defined(BHLIB_USE_WINTHREAD)
|
||||
#elif defined(BH_USE_WINTHREAD)
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
|
||||
@@ -47,250 +47,65 @@ bh_thread_pool_t *bh_thread_pool_new_base(size_t size,
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Create new task
|
||||
*
|
||||
* @param func Function
|
||||
* @param data Function data
|
||||
* @param flags Task flags
|
||||
*
|
||||
* @return Pointer to the new task
|
||||
*
|
||||
* @sa bh_task_free, bh_task_reuse, bh_task_done
|
||||
*/
|
||||
bh_task_t *bh_task_new(void (*func)(void *),
|
||||
void *data,
|
||||
int flags);
|
||||
|
||||
/**
|
||||
* @brief Free the task.
|
||||
*
|
||||
* @param task Pointer to the task
|
||||
*/
|
||||
void bh_task_free(bh_task_t *task);
|
||||
|
||||
/**
|
||||
* @brief Reuse task.
|
||||
*
|
||||
* @param task Pointer to the task
|
||||
* @param func Function
|
||||
* @param data Data
|
||||
*
|
||||
* @sa bh_task_free, bh_task_done
|
||||
*/
|
||||
void bh_task_reuse(bh_task_t *task,
|
||||
void (*func)(void *),
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* @brief Check if task is done.
|
||||
*
|
||||
* @param task Pointer to the task
|
||||
*
|
||||
* @return The return value is boolean flag, indicating if the task is done.
|
||||
*/
|
||||
int bh_task_done(bh_task_t *task);
|
||||
|
||||
/**
|
||||
* @function bh_thread_new
|
||||
*
|
||||
* @brief Create new thread.
|
||||
*
|
||||
* @param task Thread task
|
||||
*
|
||||
* @return Pointer to thread
|
||||
*
|
||||
* @sa bh_thread_join, bh_thread_detach
|
||||
*/
|
||||
|
||||
/**
|
||||
* @function bh_thread_pool_new
|
||||
* @brief Create new thread pool.
|
||||
*
|
||||
* @param pool Pointer to the thread pool
|
||||
* @param size Amount of threads
|
||||
*
|
||||
* @return Pointer to thread pool
|
||||
*
|
||||
* @sa bh_thread_pool_add, bh_thread_pool_join, bh_thread_pool_free
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Join thread.
|
||||
*
|
||||
* @param thread Pointer to the thread
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_thread_detach
|
||||
*/
|
||||
int bh_thread_join(bh_thread_t *thread);
|
||||
|
||||
/**
|
||||
* @brief Detach thread.
|
||||
*
|
||||
* @param thread Pointer to the thread
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_thread_join
|
||||
*/
|
||||
int bh_thread_detach(bh_thread_t *thread);
|
||||
|
||||
/**
|
||||
* @brief Create mutex.
|
||||
*
|
||||
* @return Pointer to the mutex
|
||||
*
|
||||
* @sa bh_mutex_lock, bh_mutex_try_lock, bh_mutex_destroy
|
||||
*/
|
||||
bh_mutex_t *bh_mutex_new(void);
|
||||
|
||||
/**
|
||||
* @brief Free mutex.
|
||||
*
|
||||
* @param mutex Pointer ot the mutex
|
||||
*/
|
||||
void bh_mutex_free(bh_mutex_t *mutex);
|
||||
|
||||
/**
|
||||
* @brief Lock mutex.
|
||||
*
|
||||
* @param mutex Pointer to the mutex
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @note Locking already locked mutex will block thread until mutex is
|
||||
* released
|
||||
*
|
||||
* @sa bh_mutex_try_lock, bh_mutex_unlock
|
||||
*/
|
||||
int bh_mutex_lock(bh_mutex_t *mutex);
|
||||
|
||||
/**
|
||||
* @brief Try to lock mutex.
|
||||
*
|
||||
* @param mutex Pointer to the mutex
|
||||
*
|
||||
* @return 0 on success, positive value if mutex is locked, negative value on
|
||||
* error
|
||||
*
|
||||
* @sa bh_mutex_lock, bh_mutex_unlock
|
||||
*/
|
||||
int bh_mutex_try_lock(bh_mutex_t *mutex);
|
||||
|
||||
/**
|
||||
* @brief Unlock mutex.
|
||||
*
|
||||
* @param mutex Pointer to the mutex
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_mutex_lock, bh_mutex_try_lock
|
||||
*/
|
||||
int bh_mutex_unlock(bh_mutex_t *mutex);
|
||||
|
||||
bh_semaphore_t *bh_semaphore_new(int count);
|
||||
|
||||
void bh_semaphore_free(bh_semaphore_t *semaphore);
|
||||
|
||||
int bh_semaphore_post(bh_semaphore_t *semaphore);
|
||||
|
||||
int bh_semaphore_wait(bh_semaphore_t *semaphore);
|
||||
|
||||
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
|
||||
unsigned long timeout);
|
||||
|
||||
int bh_semaphore_try_wait(bh_semaphore_t *semaphore);
|
||||
|
||||
/**
|
||||
* @brief Create condition variable.
|
||||
*
|
||||
* @return Pointer to the condition variable
|
||||
*/
|
||||
bh_cond_t *bh_cond_new(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy condition variable.
|
||||
*
|
||||
* @param cond Pointer to the conditional variable
|
||||
*/
|
||||
void bh_cond_free(bh_cond_t *cond);
|
||||
|
||||
/**
|
||||
* @brief Block on conditional variable.
|
||||
*
|
||||
* @param cond Pointer to the condition variable
|
||||
* @param mutex Pointer to the mutex
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_cond_wait_for, bh_cond_signal, bh_cond_broadcast
|
||||
*/
|
||||
int bh_cond_wait(bh_cond_t *cond,
|
||||
bh_mutex_t *mutex);
|
||||
|
||||
/**
|
||||
* @brief Block on conditional variable for a period of the time.
|
||||
*
|
||||
* @param cond Pointer to the conditional variable
|
||||
* @param mutex Pointer to the mutex
|
||||
* @param timeout Timeout in miliseconds
|
||||
*
|
||||
* @return 0 on success, positive value on timeout, negative on error
|
||||
*
|
||||
* @sa bh_cond_wait, bh_cond_signal, bh_cond_broadcast
|
||||
*/
|
||||
int bh_cond_wait_for(bh_cond_t *cond,
|
||||
bh_mutex_t *mutex,
|
||||
unsigned long timeout);
|
||||
|
||||
/**
|
||||
* @brief Unblock (notify) thread.
|
||||
*
|
||||
* @param cond Pointer to the condition variable
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_cond_broadcast, bh_cond_wait, bh_cond_wait_for
|
||||
*/
|
||||
int bh_cond_signal(bh_cond_t *cond);
|
||||
|
||||
/**
|
||||
* @brief Unblock all threads.
|
||||
*
|
||||
* @param cond Pointer to the conditional variable
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_cond_signal, bh_cond_wait, bh_cond_wait_for
|
||||
*/
|
||||
int bh_cond_broadcast(bh_cond_t *cond);
|
||||
|
||||
/**
|
||||
* @brief Submit task to the thread pool.
|
||||
*
|
||||
* @param pool Pointer to the thread pool
|
||||
* @param func Task function
|
||||
* @param data Task data
|
||||
*
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_thread_pool_join
|
||||
*/
|
||||
int bh_thread_pool_add(bh_thread_pool_t *pool,
|
||||
bh_task_t *task);
|
||||
|
||||
/**
|
||||
* @brief Wait until all tasks are finished.
|
||||
*
|
||||
* @param pool Pointer to the thread pool
|
||||
* @return 0 on success, non-zero otherwise
|
||||
*
|
||||
* @sa bh_thread_pool_add
|
||||
*/
|
||||
int bh_thread_pool_wait(bh_thread_pool_t *pool);
|
||||
|
||||
/**
|
||||
* @brief Destroy thread pool.
|
||||
*
|
||||
* @param pool Pointer to the thread pool
|
||||
*/
|
||||
void bh_thread_pool_free(bh_thread_pool_t *pool);
|
||||
|
||||
#endif /* BHLIB_THREAD_H */
|
||||
#endif /* BH_THREAD_H */
|
||||
|
||||
149
main.c
149
main.c
@@ -1,6 +1,8 @@
|
||||
#include <bh/queue.h>
|
||||
#include <bh/hashmap.h>
|
||||
#include <bh/thread.h>
|
||||
#include <bh/file.h>
|
||||
#include <bh/buffer.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -98,13 +100,160 @@ void bar()
|
||||
//system("pause");
|
||||
}
|
||||
|
||||
int fib(int x)
|
||||
{
|
||||
static int memory[128] = {0};
|
||||
int result;
|
||||
|
||||
if (x < 128 && memory[x] != 0)
|
||||
return memory[x];
|
||||
|
||||
if (x <= 1)
|
||||
return 1;
|
||||
|
||||
|
||||
result = fib(x - 1) + fib(x - 2);
|
||||
|
||||
if (x < 128)
|
||||
memory[x] = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char* itoa (unsigned long long value, char str[], int radix)
|
||||
{
|
||||
char buf [66];
|
||||
char* dest = buf + sizeof(buf);
|
||||
int sign = 0;
|
||||
|
||||
if (value == 0) {
|
||||
memcpy (str, "0", 2);
|
||||
return str;
|
||||
}
|
||||
|
||||
if (radix < 0) {
|
||||
radix = -radix;
|
||||
if ( (long long) value < 0) {
|
||||
value = -value;
|
||||
sign = 1;
|
||||
}
|
||||
}
|
||||
|
||||
*--dest = '\0';
|
||||
|
||||
switch (radix)
|
||||
{
|
||||
case 16:
|
||||
while (value) {
|
||||
* --dest = '0' + (value & 0xF);
|
||||
if (*dest > '9') *dest += 'A' - '9' - 1;
|
||||
value >>= 4;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
while (value) {
|
||||
*--dest = '0' + (value % 10);
|
||||
value /= 10;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
while (value) {
|
||||
*--dest = '0' + (value & 7);
|
||||
value >>= 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
while (value) {
|
||||
*--dest = '0' + (value & 1);
|
||||
value >>= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // The slow version, but universal
|
||||
while (value) {
|
||||
*--dest = '0' + (value % radix);
|
||||
if (*dest > '9') *dest += 'A' - '9' - 1;
|
||||
value /= radix;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (sign) *--dest = '-';
|
||||
|
||||
memcpy (str, dest, buf +sizeof(buf) - dest);
|
||||
return str;
|
||||
}
|
||||
|
||||
void test_api(bh_io_t *io)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
char str[65];
|
||||
|
||||
itoa(i, str, 10);
|
||||
bh_io_write(io, str, strlen(str));
|
||||
bh_io_write(io, " ", 1);
|
||||
itoa(fib(i), str, 10);
|
||||
bh_io_write(io, str, strlen(str));
|
||||
bh_io_write(io, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
void test(void)
|
||||
{
|
||||
bh_file_t *file = bh_file_new("log.txt");
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
if (bh_file_open(file, BH_IO_APPEND | BH_IO_WRITE))
|
||||
{
|
||||
printf("File not opened?");
|
||||
bh_file_free(file);
|
||||
return;
|
||||
}
|
||||
|
||||
bh_file_write(file, "Hello, world!\n", 14);
|
||||
test_api((bh_io_t *)file);
|
||||
bh_file_free(file);
|
||||
}
|
||||
|
||||
void ddump()
|
||||
{
|
||||
bh_buffer_t *buffer;
|
||||
bh_file_t *file;
|
||||
|
||||
buffer = bh_buffer_new();
|
||||
bh_buffer_open(buffer, BH_IO_WRITE);
|
||||
|
||||
bh_buffer_write(buffer, "Hello, world!", 13);
|
||||
bh_buffer_close(buffer);
|
||||
|
||||
file = bh_file_new("debug.txt");
|
||||
bh_file_open(file, BH_IO_WRITE | BH_IO_TRUNCATE);
|
||||
bh_file_write(file, bh_buffer_data(buffer), bh_buffer_size(buffer));
|
||||
|
||||
bh_file_free(file);
|
||||
bh_buffer_free(buffer);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bh_queue_t *queue;
|
||||
void *iter;
|
||||
size_t i, j;
|
||||
|
||||
ddump();
|
||||
return 0;
|
||||
|
||||
//foo();
|
||||
test();
|
||||
|
||||
printf("Thread?\n");
|
||||
fflush(stdout);
|
||||
|
||||
230
src/algo.c
230
src/algo.c
@@ -1,34 +1,72 @@
|
||||
#include <bh/algo.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void bh_swap(void *lhs,
|
||||
void *rhs,
|
||||
/**
|
||||
* \defgroup algo Algorithms
|
||||
*
|
||||
* Common algorithms (search, swap, heap, etc)
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Swaps \a size bytes between the object pointed to by \a src and object
|
||||
* pointed to by \a dest.
|
||||
*
|
||||
* If the objects overlap, the behavior is undefined.
|
||||
*
|
||||
* If either \a src or \a dest is an invalid or null pointer, the behavior is
|
||||
* undefined.
|
||||
*
|
||||
* \param dest Pointer to the memory location to swap to
|
||||
* \param src Pointer to the memory location to swap from
|
||||
* \param size Number of bytes to swap
|
||||
*/
|
||||
void bh_swap(void *dest,
|
||||
void *src,
|
||||
size_t size)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
/* Swap values in int sized chunks */
|
||||
/* Swap bytes in int-sized chunks */
|
||||
while (size >= sizeof(tmp))
|
||||
{
|
||||
memmove(&tmp, lhs, sizeof(tmp));
|
||||
memmove(lhs, rhs, sizeof(tmp));
|
||||
memmove(rhs, &tmp, sizeof(tmp));
|
||||
memmove(&tmp, dest, sizeof(tmp));
|
||||
memmove(dest, src, sizeof(tmp));
|
||||
memmove(src, &tmp, sizeof(tmp));
|
||||
|
||||
lhs = (char *)lhs + sizeof(tmp);
|
||||
rhs = (char *)rhs + sizeof(tmp);
|
||||
dest = (char *)dest + sizeof(tmp);
|
||||
src = (char *)src + sizeof(tmp);
|
||||
size -= sizeof(tmp);
|
||||
}
|
||||
|
||||
/* Swap the rest */
|
||||
/* Swap the remaining size */
|
||||
if (size)
|
||||
{
|
||||
memmove(&tmp, lhs, size);
|
||||
memmove(lhs, rhs, size);
|
||||
memmove(rhs, &tmp, size);
|
||||
memmove(&tmp, dest, size);
|
||||
memmove(dest, src, size);
|
||||
memmove(src, &tmp, size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Partitions the \a array of \a size elements of \a element bytes, relative to
|
||||
* the specified \a pivot element. Function pointed by \a equal is used for
|
||||
* comparison.
|
||||
*
|
||||
* If the \a pivot element is part of the partitioned \a array, function will
|
||||
* behaive the same way, as if \a pivot element wasn't part of the array.
|
||||
*
|
||||
* If \a equal indicates two elements as equivalent, their order in the
|
||||
* resulting partitioned array is unspecified.
|
||||
*
|
||||
* \param pivot Pointer to the pivot element
|
||||
* \param array Pointer to the array to partition
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array 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,
|
||||
@@ -74,6 +112,17 @@ void *bh_partition(void *pivot,
|
||||
return j + element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the \a array of \a size elements of \a element bytes. Function pointed
|
||||
* by \a equal is used for comparision.
|
||||
*
|
||||
* This sorting does not make any gurantees about time or space complexity.
|
||||
*
|
||||
* \param array Pointer to the array to sort
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparision function
|
||||
*/
|
||||
void bh_sort(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -83,6 +132,23 @@ void bh_sort(void *array,
|
||||
bh_sort_intro(array, size, element, equal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sorts the \a array of \a size elements of \a element bytes with insertion
|
||||
* sort. Function pointed by \a equal is used for comparision.
|
||||
*
|
||||
* This sorting has following time complexity:
|
||||
* - best case O(n)
|
||||
* - average case O(n^2)
|
||||
* - worst case O(n^2)
|
||||
*
|
||||
* This sorting has O(1) space complexity.
|
||||
*
|
||||
* \param array Pointer to the array to sort
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparision function
|
||||
*/
|
||||
void bh_sort_insert(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -109,6 +175,20 @@ void bh_sort_insert(void *array,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the \a array of \a size elements of \a element bytes with shell sort.
|
||||
* Function pointed by \a equal is used for comparision.
|
||||
*
|
||||
* This sorting has the O(n log n) best cast time complexity. Average and worst
|
||||
* cases are implementation dependant.
|
||||
*
|
||||
* This sorting has O(1) space complexity.
|
||||
*
|
||||
* \param array Pointer to the array to sort
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparision function
|
||||
*/
|
||||
void bh_sort_shell(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -118,7 +198,7 @@ void bh_sort_shell(void *array,
|
||||
const size_t *gap;
|
||||
size_t i, j;
|
||||
|
||||
/* Shell sort with A102549 sequence*/
|
||||
/* Shell sort with A102549 sequence */
|
||||
for (gap = gaps; gap < gaps + sizeof(gaps) / sizeof(*gaps); gap++)
|
||||
{
|
||||
for (i = *gap; i < size; i++)
|
||||
@@ -201,6 +281,22 @@ static void bh_sort_intro_r(void *array,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the \a array of \a size elements of \a element bytes with insertion
|
||||
* sort. Function pointed by \a equal is used for comparision.
|
||||
*
|
||||
* This sorting has following time complexity:
|
||||
* - best case O(n log n)
|
||||
* - average case O(n log n)
|
||||
* - worst case O(n log n)
|
||||
*
|
||||
* This sorting has O(log n) space complexity.
|
||||
*
|
||||
* \param array Pointer to the array to sort
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparision function
|
||||
*/
|
||||
void bh_sort_intro(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -221,6 +317,22 @@ void bh_sort_intro(void *array,
|
||||
bh_sort_intro_r(array, size, element, equal, depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the \a array of \a size elements of \a element bytes with insertion
|
||||
* sort. Function pointed by \a equal is used for comparision.
|
||||
*
|
||||
* This sorting has following time complexity:
|
||||
* - best case O(n)
|
||||
* - average case O(n log n)
|
||||
* - worst case O(n log n)
|
||||
*
|
||||
* This sorting has O(1) space complexity.
|
||||
*
|
||||
* \param array Pointer to the array to sort
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparision function
|
||||
*/
|
||||
void bh_sort_heap(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -232,7 +344,15 @@ void bh_sort_heap(void *array,
|
||||
bh_heap_remove(array, size--, element, equal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Heapifes the \a array of \a size elements of \a element bytes. Function
|
||||
* pointed by \a equal is used for comparision.
|
||||
*
|
||||
* \param array Pointer to the array to heapify
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparision function
|
||||
*/
|
||||
void bh_heap_make(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -279,6 +399,15 @@ void bh_heap_make(void *array,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes top element from heapified \a array of \a size elements of \a
|
||||
* elements bytes. Function pointed by \a equal is used for comparasion.
|
||||
*
|
||||
* \param array Pointer to the array to remove element from
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparasion function
|
||||
*/
|
||||
void bh_heap_remove(void *array,
|
||||
size_t size,
|
||||
size_t element,
|
||||
@@ -323,6 +452,16 @@ void bh_heap_remove(void *array,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new element into heapified \a array of \a size elements of \a
|
||||
* elements bytes. Function pointed by \a equal is used for comparasion.
|
||||
*
|
||||
* \param value Pointer to the value to be inserted
|
||||
* \param array Pointer to the array to remove element from
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array in bytes
|
||||
* \param equal Comparasion function
|
||||
*/
|
||||
void bh_heap_insert(void *value,
|
||||
void *array,
|
||||
size_t size,
|
||||
@@ -358,3 +497,64 @@ void bh_heap_insert(void *value,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces top element of the heapified \a array of \a size elements of \a
|
||||
* elements bytes. Function pointed by \a equal is used for comparasion.
|
||||
*
|
||||
* This function is equal to two consecutive operations of remove and insert.
|
||||
*
|
||||
* \param value Pointer to the value to be inserted
|
||||
* \param array Pointer to the array to remove element from
|
||||
* \param size Number of elements in the array
|
||||
* \param element Size of each element in the array 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)
|
||||
{
|
||||
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 */
|
||||
memmove(current, value, 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
278
src/buffer.c
Normal file
278
src/buffer.c
Normal file
@@ -0,0 +1,278 @@
|
||||
#include <bh/internal/buffer.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const bh_io_table_t bh_buffer_table = {
|
||||
(int (*)(struct bh_io_s *, int)) bh_buffer_open_base,
|
||||
(void (*)(struct bh_io_s *)) bh_buffer_close_base,
|
||||
(int (*)(struct bh_io_s *)) bh_buffer_is_open_base,
|
||||
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_buffer_read_base,
|
||||
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_buffer_write_base,
|
||||
(void (*)(struct bh_io_s *)) bh_buffer_flush_base,
|
||||
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_buffer_seek_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_size_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_tell_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_buffer_available_base,
|
||||
(void (*)(struct bh_io_s *)) bh_buffer_clear_base,
|
||||
(void (*)(struct bh_io_s *)) bh_buffer_destroy
|
||||
};
|
||||
|
||||
bh_buffer_t *bh_buffer_new(void)
|
||||
{
|
||||
bh_buffer_t *result;
|
||||
|
||||
/* Allocate and initialize buffer structure */
|
||||
result = malloc(sizeof(*result));
|
||||
if (result && bh_buffer_init(result))
|
||||
{
|
||||
/* Something went wrong - free allocated memory */
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bh_buffer_free(bh_buffer_t *buffer)
|
||||
{
|
||||
bh_buffer_destroy(buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
int bh_buffer_init(bh_buffer_t *buffer)
|
||||
{
|
||||
bh_io_init(&buffer->base, &bh_buffer_table);
|
||||
|
||||
buffer->data = NULL;
|
||||
buffer->capacity = 0;
|
||||
buffer->size = 0;
|
||||
buffer->at = 0;
|
||||
buffer->mode = 0;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_buffer_destroy(bh_buffer_t *buffer)
|
||||
{
|
||||
bh_buffer_close(buffer);
|
||||
if (buffer->data)
|
||||
free(buffer->data);
|
||||
}
|
||||
|
||||
const char *bh_buffer_data(bh_buffer_t *buffer)
|
||||
{
|
||||
return buffer->data;
|
||||
}
|
||||
|
||||
void bh_buffer_set_data(bh_buffer_t *buffer,
|
||||
const char *data,
|
||||
size_t size)
|
||||
{
|
||||
buffer->size = 0;
|
||||
bh_buffer_write_base(buffer, data, size);
|
||||
}
|
||||
|
||||
size_t bh_buffer_capacity(bh_buffer_t *buffer)
|
||||
{
|
||||
return buffer->capacity;
|
||||
}
|
||||
|
||||
int bh_buffer_reserve(bh_buffer_t *buffer,
|
||||
size_t size)
|
||||
{
|
||||
char *data = NULL;
|
||||
|
||||
/* New capacity can't be less then current buffer size */
|
||||
if (size < buffer->size)
|
||||
size = buffer->size;
|
||||
|
||||
/* Prevent same size reallocation */
|
||||
if (buffer->capacity == size)
|
||||
return BH_OK;
|
||||
|
||||
/* Allocate new memory for the buffer */
|
||||
if (size)
|
||||
{
|
||||
data = malloc(size);
|
||||
if (!data)
|
||||
return BH_OOM;
|
||||
|
||||
/* Copy data */
|
||||
if (buffer->size)
|
||||
memmove(data, buffer->data, buffer->size);
|
||||
}
|
||||
|
||||
/* Free previosly allocated memory */
|
||||
if (buffer->data)
|
||||
free(buffer->data);
|
||||
|
||||
/* Update buffer fields */
|
||||
buffer->data = data;
|
||||
buffer->capacity = size;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_buffer_open_base(bh_buffer_t *buffer,
|
||||
int mode)
|
||||
{
|
||||
/* Check if buffer is already open */
|
||||
if (buffer->mode != 0)
|
||||
return BH_OK;
|
||||
|
||||
/* Update buffer mode field */
|
||||
buffer->mode = mode;
|
||||
|
||||
/* Determine open mode */
|
||||
switch (mode & BH_IO_MASK)
|
||||
{
|
||||
case BH_IO_OPEN:
|
||||
case BH_IO_CREATE:
|
||||
case BH_IO_APPEND:
|
||||
break;
|
||||
|
||||
case BH_IO_TRUNCATE:
|
||||
buffer->size = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_buffer_close_base(bh_buffer_t *buffer)
|
||||
{
|
||||
buffer->mode = 0;
|
||||
}
|
||||
|
||||
int bh_buffer_is_open_base(bh_buffer_t *buffer)
|
||||
{
|
||||
return buffer->mode != 0;
|
||||
}
|
||||
|
||||
size_t bh_buffer_read_base(bh_buffer_t *buffer,
|
||||
char *data,
|
||||
size_t size)
|
||||
{
|
||||
/* Check if buffer openned in read mode */
|
||||
if (!(buffer->mode & BH_IO_READ))
|
||||
{
|
||||
buffer->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate maximum available size for reading */
|
||||
if (size > buffer->size - buffer->at)
|
||||
size = buffer->size - buffer->at;
|
||||
|
||||
/* Perform reading */
|
||||
if (size)
|
||||
{
|
||||
memmove(data, buffer->data + buffer->at, size);
|
||||
buffer->at += size;
|
||||
}
|
||||
|
||||
/* Check for end of file */
|
||||
if (!size)
|
||||
buffer->base.flags |= BH_IO_EOF;
|
||||
else
|
||||
buffer->base.flags &= ~BH_IO_EOF;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t bh_buffer_write_base(bh_buffer_t *buffer,
|
||||
const char *data,
|
||||
size_t size)
|
||||
{
|
||||
size_t capacity = 0;
|
||||
|
||||
/* Check if buffer is openned in write mode */
|
||||
if (!(buffer->mode & BH_IO_WRITE))
|
||||
{
|
||||
buffer->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adjust at position */
|
||||
if ((buffer->mode & BH_IO_MASK) == BH_IO_APPEND)
|
||||
buffer->at = buffer->size;
|
||||
|
||||
/* Calculate required capacity and check for overflow */
|
||||
capacity = buffer->at + size;
|
||||
if (capacity < size)
|
||||
{
|
||||
buffer->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to grow buffer */
|
||||
if (buffer->capacity < capacity)
|
||||
bh_buffer_reserve(buffer, capacity);
|
||||
|
||||
/* Calculate maximum write size */
|
||||
if (size > buffer->capacity - buffer->at)
|
||||
size = buffer->capacity - buffer->at;
|
||||
|
||||
/* Perform writing */
|
||||
if (size)
|
||||
{
|
||||
memmove(buffer->data + buffer->at, data, size);
|
||||
buffer->at += size;
|
||||
buffer->size += size;
|
||||
}
|
||||
|
||||
/* Check for end of file */
|
||||
if (!size)
|
||||
buffer->base.flags |= BH_IO_EOF;
|
||||
else
|
||||
buffer->base.flags &= ~BH_IO_EOF;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void bh_buffer_flush_base(bh_buffer_t *buffer)
|
||||
{
|
||||
(void)buffer;
|
||||
}
|
||||
|
||||
int bh_buffer_seek_base(bh_buffer_t *buffer,
|
||||
bh_off_t pos,
|
||||
int dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case BH_IO_SET: buffer->at = pos; break;
|
||||
case BH_IO_CURRENT: buffer->at += pos; break;
|
||||
case BH_IO_END: buffer->at = buffer->size - pos; break;
|
||||
default: return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
if (buffer->at > buffer->size)
|
||||
buffer->at = buffer->size;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
bh_off_t bh_buffer_size_base(bh_buffer_t *buffer)
|
||||
{
|
||||
return buffer->size;
|
||||
}
|
||||
|
||||
bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer)
|
||||
{
|
||||
return buffer->at;
|
||||
}
|
||||
|
||||
bh_off_t bh_buffer_available_base(bh_buffer_t *buffer)
|
||||
{
|
||||
return buffer->size - buffer->at;
|
||||
}
|
||||
|
||||
void bh_buffer_clear_base(bh_buffer_t *buffer)
|
||||
{
|
||||
buffer->base.flags &= ~BH_IO_ERROR;
|
||||
}
|
||||
|
||||
275
src/file_null.c
Normal file
275
src/file_null.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include <bh/internal/file.h>
|
||||
|
||||
/**
|
||||
* \defgroup file File IO
|
||||
*
|
||||
* File input/output API
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates new file object with specified \a path to file.
|
||||
*
|
||||
* \param path Path to the file
|
||||
*
|
||||
* \return On success, returns new file object.
|
||||
* \return On failure, returns null pointer.
|
||||
*/
|
||||
bh_file_t *bh_file_new(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a file object.
|
||||
*
|
||||
* Before freeing the file object, this function ensures that underlying file
|
||||
* was closed.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*/
|
||||
void bh_file_free(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a file object with specified \a path to file.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
* \param path Path to the file
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_file_init(bh_file_t *file,
|
||||
const char *path)
|
||||
{
|
||||
(void)file;
|
||||
(void)path;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroyes the \a file object.
|
||||
*
|
||||
* Before destroying the file object, this function ensures that underlying
|
||||
* file was closed.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*/
|
||||
void bh_file_destroy(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the \a file object for specified \a mode of operation.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
* \param mode Bitmask determining access mode
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
int bh_file_open_base(bh_file_t *file,
|
||||
int mode)
|
||||
{
|
||||
(void)file;
|
||||
(void)mode;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the \a file object.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
void bh_file_close_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the \a file is open.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*
|
||||
* \return If file object is open - returns non-zero.
|
||||
* \return If file object is closed - returns zero.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
int bh_file_is_open_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to \a size amount of bytes from the \a file object into memory
|
||||
* buffer pointed by \a data pointer.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
* \param data Pointer to the memory buffer
|
||||
* \param size Maximum number of bytes to be read
|
||||
*
|
||||
* \return On success, returns number of bytes successfuly read.
|
||||
* \return On failure, returns zero.
|
||||
*
|
||||
* \note To check for end-of-file or error see bh_io_eof and bh_io_error.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
size_t bh_file_read_base(bh_file_t *file,
|
||||
char *data,
|
||||
size_t size)
|
||||
{
|
||||
(void)file;
|
||||
(void)data;
|
||||
(void)size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes up to \a size amount of bytes to the \a file object from memory
|
||||
* buffer pointed by \a data pointer.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
* \param data Pointer to the memory buffer
|
||||
* \param size Maximum number of bytes to be read
|
||||
*
|
||||
* \return On success, returns number of bytes successfuly written.
|
||||
* \return On failure, returns zero.
|
||||
*
|
||||
* \note To check for error see bh_io_error.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
size_t bh_file_write_base(bh_file_t *file,
|
||||
const char *data,
|
||||
size_t size)
|
||||
{
|
||||
(void)file;
|
||||
(void)data;
|
||||
(void)size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the \a file object (if possible).
|
||||
*
|
||||
* In most cases, this function causes any unwritten/buffered data to be
|
||||
* written.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
void bh_file_flush_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks the \a file object in the specified direction \a dir and \a offset
|
||||
* (if possible).
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
* \param offset Number of bytes to seek in specified direciton
|
||||
* \param dir Seeking direction
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
int bh_file_seek_base(bh_file_t *file,
|
||||
bh_off_t off,
|
||||
int dir)
|
||||
{
|
||||
(void)file;
|
||||
(void)off;
|
||||
(void)dir;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total size of the \a file object (if possible)
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*
|
||||
* \return On success, returns total size of the file object.
|
||||
* \return On failure, returns -1.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
bh_off_t bh_file_size_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current position in the \a file object (if possible).
|
||||
*
|
||||
* \param file Pointer to the io object
|
||||
*
|
||||
* \return On success, returns current position in the file object.
|
||||
* \return On failure, returns -1.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
bh_off_t bh_file_tell_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available number of bytes to be read from the \a file object.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*
|
||||
* \return On success, returns number of available bytes to be read.
|
||||
* \return On failure, returns zero.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
bh_off_t bh_file_available_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears error of the \a file object.
|
||||
*
|
||||
* \param file Pointer to the file object
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
void bh_file_clear_base(bh_file_t *file)
|
||||
{
|
||||
(void)file;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
253
src/file_posix.c
253
src/file_posix.c
@@ -0,0 +1,253 @@
|
||||
#include <bh/internal/file.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
static const bh_io_table_t bh_file_table = {
|
||||
(int (*)(struct bh_io_s *, int)) bh_file_open_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_close_base,
|
||||
(int (*)(struct bh_io_s *)) bh_file_is_open_base,
|
||||
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base,
|
||||
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_flush_base,
|
||||
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_file_size_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_clear_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_destroy
|
||||
};
|
||||
|
||||
bh_file_t *bh_file_new(const char *path)
|
||||
{
|
||||
bh_file_t *result;
|
||||
|
||||
/* Allocate and initialize file structure */
|
||||
result = malloc(sizeof(*result));
|
||||
if (result && bh_file_init(result, path))
|
||||
{
|
||||
/* Something went wrong - free allocated memory */
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bh_file_free(bh_file_t *file)
|
||||
{
|
||||
bh_file_destroy(file);
|
||||
free(file);
|
||||
}
|
||||
|
||||
int bh_file_init(bh_file_t *file,
|
||||
const char *path)
|
||||
{
|
||||
/* Ensure that path is not empty */
|
||||
if (!path)
|
||||
return BH_INVALID;
|
||||
|
||||
/* Initialize base io object */
|
||||
bh_io_init(&file->base, &bh_file_table);
|
||||
|
||||
/* Initialize file io object */
|
||||
file->handle = -1;
|
||||
file->mode = 0;
|
||||
file->path = strdup(path);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_file_destroy(bh_file_t *file)
|
||||
{
|
||||
/* Close the file */
|
||||
bh_file_close(file);
|
||||
free(file->path);
|
||||
}
|
||||
|
||||
int bh_file_open_base(bh_file_t *file,
|
||||
int mode)
|
||||
{
|
||||
/* Set open mode for 0666 permisions */
|
||||
mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
int open_flags = 0;
|
||||
|
||||
/* Check if file is already opened */
|
||||
if (file->handle != -1)
|
||||
return BH_OK;
|
||||
|
||||
/* Determine read/write flags */
|
||||
if (mode & BH_IO_READ_WRITE)
|
||||
open_flags |= O_RDWR;
|
||||
else if (mode & BH_IO_READ)
|
||||
open_flags |= O_RDONLY;
|
||||
else if (mode & BH_IO_WRITE)
|
||||
open_flags |= O_WRONLY;
|
||||
else
|
||||
return BH_INVALID;
|
||||
|
||||
/* Determine open mode */
|
||||
switch (mode & BH_IO_MASK)
|
||||
{
|
||||
case BH_IO_OPEN: break;
|
||||
case BH_IO_CREATE: open_flags |= O_CREAT | O_EXCL; break;
|
||||
case BH_IO_APPEND: open_flags |= O_CREAT | O_APPEND; break;
|
||||
case BH_IO_TRUNCATE: open_flags |= O_CREAT | O_TRUNC; break;
|
||||
|
||||
default:
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/* Open file */
|
||||
file->handle = open(file->path, open_flags, open_mode);
|
||||
|
||||
/* Check for errors */
|
||||
if (file->handle == -1)
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_file_close_base(bh_file_t *file)
|
||||
{
|
||||
/* Close file if it's open */
|
||||
if (file->handle != -1)
|
||||
close(file->handle);
|
||||
|
||||
/* Set handle to invalid value */
|
||||
file->handle = -1;
|
||||
}
|
||||
|
||||
int bh_file_is_open_base(bh_file_t *file)
|
||||
{
|
||||
/* If handle is not -1 - then file is open */
|
||||
return file->handle != -1;
|
||||
}
|
||||
|
||||
size_t bh_file_read_base(bh_file_t *file,
|
||||
char *data,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t readed;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
{
|
||||
/* Error occured - set error bit */
|
||||
file->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read data from file */
|
||||
readed = read(file->handle, data, size);
|
||||
if (readed < 0)
|
||||
{
|
||||
/* Error occured - set error bit */
|
||||
file->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for end of file */
|
||||
if (!readed)
|
||||
file->base.flags |= BH_IO_EOF;
|
||||
else
|
||||
file->base.flags &= ~BH_IO_EOF;
|
||||
|
||||
/* Return number of readed bytes */
|
||||
return readed;
|
||||
}
|
||||
|
||||
size_t bh_file_write_base(bh_file_t *file,
|
||||
const char *data,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t written;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
{
|
||||
/* Error occured - set error bit */
|
||||
file->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write data to file */
|
||||
written = write(file->handle, data, size);
|
||||
if (written < 0)
|
||||
{
|
||||
/* Error occured - set error bit */
|
||||
file->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for end of file */
|
||||
if (!written)
|
||||
file->base.flags |= BH_IO_EOF;
|
||||
else
|
||||
file->base.flags &= ~BH_IO_EOF;
|
||||
|
||||
/* Return number of written bytes */
|
||||
return written;
|
||||
}
|
||||
|
||||
void bh_file_flush_base(bh_file_t *file)
|
||||
{
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
return;
|
||||
|
||||
/* Signal OS to flush data from the internal buffers */
|
||||
fsync(file->handle);
|
||||
}
|
||||
|
||||
int bh_file_seek_base(bh_file_t *file,
|
||||
bh_off_t pos,
|
||||
int dir)
|
||||
{
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
return BH_ERROR;
|
||||
|
||||
/* Seek to desired location */
|
||||
if (lseek(file->handle, pos, dir) == -1);
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
bh_off_t bh_file_size_base(bh_file_t *file)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
return -1;
|
||||
|
||||
/* Get file size from the OS */
|
||||
if (fstat(file->handle, &sb))
|
||||
return -1;
|
||||
|
||||
return sb.st_size;
|
||||
}
|
||||
|
||||
bh_off_t bh_file_tell_base(bh_file_t *file)
|
||||
{
|
||||
/* Check if file is open */
|
||||
if (file->handle == -1)
|
||||
return -1;
|
||||
|
||||
/* Get current file position */
|
||||
return lseek(file->handle, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
bh_off_t bh_file_available_base(bh_file_t *file)
|
||||
{
|
||||
/* Get available bytes for reading */
|
||||
return bh_file_size_base(file) - bh_file_tell_base(file);
|
||||
}
|
||||
|
||||
void bh_file_clear_base(bh_file_t *file)
|
||||
{
|
||||
file->base.flags &= ~BH_IO_ERROR;
|
||||
}
|
||||
|
||||
195
src/file_win.c
195
src/file_win.c
@@ -0,0 +1,195 @@
|
||||
#include <bh/internal/file.h>
|
||||
|
||||
static const bh_io_table_t bh_file_table = {
|
||||
(int (*)(struct bh_io_s *, int)) bh_file_open_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_close_base,
|
||||
(int (*)(struct bh_io_s *)) bh_file_is_open_base,
|
||||
(size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base,
|
||||
(size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_flush_base,
|
||||
(int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_file_size_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base,
|
||||
(bh_off_t (*)(struct bh_io_s *)) bh_file_available_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_clear_base,
|
||||
(void (*)(struct bh_io_s *)) bh_file_destroy
|
||||
};
|
||||
|
||||
bh_file_t *bh_file_new(const char *path)
|
||||
{
|
||||
bh_file_t *result;
|
||||
|
||||
result = malloc(sizeof(*result));
|
||||
if (result && bh_file_init(result, path))
|
||||
{
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bh_file_free(bh_file_t *file)
|
||||
{
|
||||
bh_file_destroy(file);
|
||||
free(file);
|
||||
}
|
||||
|
||||
int bh_file_init(bh_file_t *file,
|
||||
const char *path)
|
||||
{
|
||||
if (!path)
|
||||
return BH_INVALID;
|
||||
|
||||
file->handle = INVALID_HANDLE_VALUE;
|
||||
file->mode = 0;
|
||||
file->path = strdup(path);
|
||||
file->base.table = &bh_file_table;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_file_open_base(bh_file_t *file,
|
||||
int mode)
|
||||
{
|
||||
DWORD access = 0, how = 0;
|
||||
|
||||
if (mode & BH_IO_READ)
|
||||
access |= GENERIC_READ;
|
||||
if (mode & BH_IO_WRITE)
|
||||
access |= GENERIC_WRITE;
|
||||
|
||||
switch (mode & BH_IO_MASK)
|
||||
{
|
||||
case BH_IO_OPEN: how = OPEN_EXISTING; break;
|
||||
case BH_IO_CREATE: how = CREATE_ALWAYS; break;
|
||||
case BH_IO_APPEND: how = OPEN_ALWAYS; break;
|
||||
|
||||
default:
|
||||
case BH_IO_TRUNCATE:
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
file->mode = mode;
|
||||
file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (file->handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* Error handling */
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_FILE_EXISTS: return BH_FOUND;
|
||||
case ERROR_FILE_NOT_FOUND: return BH_NOT_FOUND;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_file_close_base(bh_file_t *file)
|
||||
{
|
||||
if (file->handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(file->handle);
|
||||
|
||||
file->handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
int bh_file_is_open_base(bh_file_t *file)
|
||||
{
|
||||
return file->handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
void bh_file_destroy(bh_file_t *file)
|
||||
{
|
||||
bh_file_close(file);
|
||||
free(file->path);
|
||||
}
|
||||
|
||||
size_t bh_file_read_base(bh_file_t *file,
|
||||
char *data,
|
||||
size_t size)
|
||||
{
|
||||
DWORD readed;
|
||||
|
||||
if (!ReadFile(file->handle, data, (DWORD)size, &readed, NULL))
|
||||
{
|
||||
file->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!readed)
|
||||
file->base.flags |= BH_IO_EOF;
|
||||
else
|
||||
file->base.flags &= ~BH_IO_EOF;
|
||||
|
||||
return readed;
|
||||
}
|
||||
|
||||
size_t bh_file_write_base(bh_file_t *file,
|
||||
const char *data,
|
||||
size_t size)
|
||||
{
|
||||
DWORD written;
|
||||
|
||||
if ((file->mode & BH_IO_MASK) == BH_IO_APPEND)
|
||||
bh_file_seek(file, 0, BH_IO_END);
|
||||
|
||||
if (!WriteFile(file->handle, data, (DWORD)size, &written, NULL))
|
||||
{
|
||||
file->base.flags |= BH_IO_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!written)
|
||||
file->base.flags |= BH_IO_EOF;
|
||||
else
|
||||
file->base.flags &= ~BH_IO_EOF;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
void bh_file_flush_base(bh_file_t *file)
|
||||
{
|
||||
FlushFileBuffers(file->handle);
|
||||
}
|
||||
|
||||
int bh_file_seek_base(bh_file_t *file,
|
||||
bh_off_t pos,
|
||||
int dir)
|
||||
{
|
||||
LARGE_INTEGER position;
|
||||
|
||||
position.QuadPart = pos;
|
||||
if (SetFilePointerEx(file->handle, position, NULL, dir))
|
||||
return BH_OK;
|
||||
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
bh_off_t bh_file_size_base(bh_file_t *file)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
bh_off_t bh_file_tell_base(bh_file_t *file)
|
||||
{
|
||||
LARGE_INTEGER dummy, position;
|
||||
|
||||
dummy.QuadPart = 0;
|
||||
|
||||
if (SetFilePointerEx(file->handle, dummy, &position, BH_IO_CURRENT))
|
||||
return position.QuadPart;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bh_off_t bh_file_available_base(bh_file_t *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bh_file_clear_base(bh_file_t *file)
|
||||
{
|
||||
file->base.flags &= ~BH_IO_ERROR;
|
||||
}
|
||||
|
||||
197
src/hashmap.c
197
src/hashmap.c
@@ -2,6 +2,22 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \defgroup hashmap Hashmap
|
||||
*
|
||||
* Data stucture for storing pointers in the hashmap.
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates the new hashmap object.
|
||||
*
|
||||
* \param equal Comparision function
|
||||
* \param hash Key hash function
|
||||
*
|
||||
* \return On success, returns the pointer to the new hashmap object.
|
||||
* \return On failure, returns a null pointer.
|
||||
*/
|
||||
bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
|
||||
bh_hash_cb_t hash)
|
||||
{
|
||||
@@ -14,12 +30,26 @@ bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a hashmap object.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object to be freed
|
||||
*/
|
||||
void bh_hashmap_free(bh_hashmap_t *hashmap)
|
||||
{
|
||||
bh_hashmap_destroy(hashmap);
|
||||
free(hashmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a hashmap object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object to be initialized
|
||||
* \param equal Comparision function
|
||||
* \param hash Key hash function
|
||||
*/
|
||||
void bh_hashmap_init(bh_hashmap_t *hashmap,
|
||||
bh_equal_cb_t equal,
|
||||
bh_hash_cb_t hash)
|
||||
@@ -30,6 +60,13 @@ void bh_hashmap_init(bh_hashmap_t *hashmap,
|
||||
hashmap->hash = hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the \a hashmap object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object to be destroied
|
||||
*/
|
||||
void bh_hashmap_destroy(bh_hashmap_t *hashmap)
|
||||
{
|
||||
if (hashmap->capacity)
|
||||
@@ -39,6 +76,11 @@ void bh_hashmap_destroy(bh_hashmap_t *hashmap)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the \a hashmap object.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object to be cleared
|
||||
*/
|
||||
void bh_hashmap_clear(bh_hashmap_t *hashmap)
|
||||
{
|
||||
if (hashmap->capacity)
|
||||
@@ -46,6 +88,22 @@ void bh_hashmap_clear(bh_hashmap_t *hashmap)
|
||||
hashmap->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves the space for \a size elements in the \a hashmap.
|
||||
*
|
||||
* This function can both expand and shrink the available space in \a hashmap.
|
||||
* This function takes into account current hashmap load factor.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object to be resized in terms of
|
||||
* capacity
|
||||
* \param size New capacity of the hashmap
|
||||
*
|
||||
* \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)
|
||||
{
|
||||
@@ -78,7 +136,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||
|
||||
/* Capacity can't be bigger than max capacity and overflow */
|
||||
if (capacity > max_capacity || capacity < 16)
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -93,7 +151,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||
|
||||
/* Prevent same size reallocation */
|
||||
if (capacity == hashmap->capacity)
|
||||
return 0;
|
||||
return BH_OK;
|
||||
|
||||
/* Initialize new hashmap */
|
||||
bh_hashmap_init(&other, hashmap->equal, hashmap->hash);
|
||||
@@ -105,7 +163,6 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||
|
||||
/* 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;
|
||||
@@ -117,7 +174,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||
free(other.data);
|
||||
if (other.psls)
|
||||
free(other.psls);
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
}
|
||||
|
||||
/* Reset probe sequence lengths */
|
||||
@@ -140,9 +197,22 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap,
|
||||
/* Swap hashmaps */
|
||||
bh_hashmap_destroy(hashmap);
|
||||
*hashmap = other;
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the pair of \a key and \a value into the \a hashmap. This function
|
||||
* allows duplicates to be inserted.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param key Key to be inserted
|
||||
* \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_hashmap_insert(bh_hashmap_t *hashmap,
|
||||
void *key,
|
||||
void *value)
|
||||
@@ -154,7 +224,7 @@ int bh_hashmap_insert(bh_hashmap_t *hashmap,
|
||||
if (hashmap->size + 1 > hashmap->threshold)
|
||||
if (bh_hashmap_reserve(hashmap, hashmap->size + 1))
|
||||
if (hashmap->size >= hashmap->capacity)
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
|
||||
/* Prepare inserted data and set PSL to 1 */
|
||||
item.key = key;
|
||||
@@ -187,9 +257,19 @@ int bh_hashmap_insert(bh_hashmap_t *hashmap,
|
||||
hashmap->psls[bucket] = psl;
|
||||
hashmap->size++;
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes value from the \a hashmap by \a key.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param key Key value
|
||||
*
|
||||
* \note Calling this function will invalidate iterators.
|
||||
* \note If hashmap contains several key-value pairs with the same key, only
|
||||
* one pair will be removed.
|
||||
*/
|
||||
void bh_hashmap_remove(bh_hashmap_t *hashmap,
|
||||
void *key)
|
||||
{
|
||||
@@ -200,6 +280,19 @@ void bh_hashmap_remove(bh_hashmap_t *hashmap,
|
||||
bh_hashmap_iter_remove(hashmap, iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value from the \a hashmap by the specified \a key.
|
||||
*
|
||||
* If the \a exists is not null pointer, the value will be stored to indicated,
|
||||
* whether the \a key exists in the hashmap or not.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param key Key value
|
||||
* \param exists Pointer to the exists flag variable (optional)
|
||||
*
|
||||
* \return On success, returns value.
|
||||
* \return On failure, return null pointer.
|
||||
*/
|
||||
void *bh_hashmap_at(bh_hashmap_t *hashmap,
|
||||
void *key,
|
||||
int *exists)
|
||||
@@ -221,36 +314,87 @@ void *bh_hashmap_at(bh_hashmap_t *hashmap,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the \a hashmap is empty.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
*
|
||||
* \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)
|
||||
{
|
||||
return !hashmap->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the \a hashmap.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
*
|
||||
* \return Returns the size of the hashmap.
|
||||
*/
|
||||
size_t bh_hashmap_size(bh_hashmap_t *hashmap)
|
||||
{
|
||||
return hashmap->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capacity of the \a hashmap.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
*
|
||||
* \return Returns the capacity of the hashmap.
|
||||
*/
|
||||
size_t bh_hashmap_capacity(bh_hashmap_t *hashmap)
|
||||
{
|
||||
return hashmap->capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the load factor of the \a hashmap.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
*
|
||||
* \return Returns the load factor of the hashmap.
|
||||
*/
|
||||
float bh_hashmap_factor(bh_hashmap_t *hashmap)
|
||||
{
|
||||
return hashmap->factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the load \a factor of the \a hashmap.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param factor Load factor value
|
||||
*
|
||||
* \note New load factor will be applied on the next reserve/insert operation.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iterator to the element in the \a hashmap with specified \a key.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param iter Opaque iterator value
|
||||
*
|
||||
* \return On success, returns iterator value.
|
||||
* \return On failure, returns null pointer.
|
||||
*
|
||||
* \note If hashmap contains several key-value pairs with the same key, only
|
||||
* iterator to the one of the pairs will returned.
|
||||
*/
|
||||
void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
|
||||
void *key)
|
||||
{
|
||||
@@ -278,6 +422,19 @@ void *bh_hashmap_iter_at(bh_hashmap_t *hashmap,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iterator to the next element in the \a hashmap.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param iter Opaque iterator value
|
||||
*
|
||||
* \return If the \a iter doesn't point to the last element of the hashmap,
|
||||
* returns next iterator value.
|
||||
* \return If the \a iter point to the last element of the hashmap, returns
|
||||
* null pointer.
|
||||
* \return If the \a iter is the null pointer, returns iterator to the
|
||||
* first element of the hashmap.
|
||||
*/
|
||||
void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
|
||||
void *iter)
|
||||
{
|
||||
@@ -302,6 +459,14 @@ void *bh_hashmap_iter_next(bh_hashmap_t *hashmap,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes value from the \a hashmap by iterator \a iter.
|
||||
*
|
||||
* \param hashmap Pointer to the hashmap object
|
||||
* \param iter Iterator value
|
||||
*
|
||||
* \note Calling this function will invalidate iterators.
|
||||
*/
|
||||
void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
|
||||
void *iter)
|
||||
{
|
||||
@@ -332,12 +497,30 @@ void bh_hashmap_iter_remove(bh_hashmap_t *hashmap,
|
||||
hashmap->psls[bucket] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key, pointed by the hashmap iterator \a iter.
|
||||
*
|
||||
* \param iter Opaque iterator value
|
||||
*
|
||||
* \return Returns key, pointed by iterator.
|
||||
*/
|
||||
void *bh_hashmap_iter_key(void *iter)
|
||||
{
|
||||
return ((bh_hashmap_node_t *)iter)->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value, pointed by the hashmap iterator \a iter.
|
||||
*
|
||||
* \param iter Opaque iterator value
|
||||
*
|
||||
* \return Returns value, pointed by iterator.
|
||||
*/
|
||||
void *bh_hashmap_iter_value(void *iter)
|
||||
{
|
||||
return ((bh_hashmap_node_t *)iter)->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
182
src/io.c
182
src/io.c
@@ -1,6 +1,25 @@
|
||||
#include <bh/internal/io.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* \defgroup io Input/Output
|
||||
*
|
||||
* Input/output device abstraction layer.
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates the new io object with specified \a table and \a size.
|
||||
*
|
||||
* \param table Pointer to the io table
|
||||
* \param size Size of the io object
|
||||
*
|
||||
* \return On success, returns new semi-initialized io object.
|
||||
* \return On failure, returns null pointer.
|
||||
*
|
||||
* \warning This function should be used in context of implementing child
|
||||
* io objects (files, sockets, streaming compression, etc).
|
||||
*/
|
||||
bh_io_t *bh_io_new(bh_io_table_t *table,
|
||||
size_t size)
|
||||
{
|
||||
@@ -13,24 +32,91 @@ bh_io_t *bh_io_new(bh_io_table_t *table,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object to be freed
|
||||
*/
|
||||
void bh_io_free(bh_io_t *io)
|
||||
{
|
||||
bh_io_destroy(io);
|
||||
free(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a io object with specified \a table.
|
||||
*
|
||||
* \param io Pointer to the io object to be initialized
|
||||
* \param table Pointer to the io table
|
||||
*/
|
||||
void bh_io_init(bh_io_t *io,
|
||||
bh_io_table_t *table)
|
||||
const bh_io_table_t *table)
|
||||
{
|
||||
io->table = table;
|
||||
io->flags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object to be destroyed
|
||||
*/
|
||||
void bh_io_destroy(bh_io_t *io)
|
||||
{
|
||||
io->table->destroy(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the \a io object for specified \a mode of operation.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
* \param mode Bitmask determining access mode
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_io_open(bh_io_t *io,
|
||||
int mode)
|
||||
{
|
||||
return io->table->open(io, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*/
|
||||
void bh_io_close(bh_io_t *io)
|
||||
{
|
||||
io->table->close(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the \a io is open.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*
|
||||
* \return If io object is open - returns non-zero.
|
||||
* \return If io object is closed - returns zero.
|
||||
*/
|
||||
int bh_io_is_open(bh_io_t *io)
|
||||
{
|
||||
return io->table->is_open(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to \a size amount of bytes from the \a io object into memory buffer
|
||||
* pointed by \a data pointer.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
* \param data Pointer to the memory buffer
|
||||
* \param size Maximum number of bytes to be read
|
||||
*
|
||||
* \return On success, returns number of bytes successfuly read.
|
||||
* \return On failure, returns zero.
|
||||
*
|
||||
* \note To check for end-of-file or error see bh_io_eof and bh_io_error.
|
||||
*/
|
||||
size_t bh_io_read(bh_io_t *io,
|
||||
char *data,
|
||||
size_t size)
|
||||
@@ -38,6 +124,19 @@ size_t bh_io_read(bh_io_t *io,
|
||||
return io->table->read(io, data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes up to \a size amount of bytes to the \a io object from memory buffer
|
||||
* pointed by \a data pointer.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
* \param data Pointer to the memory buffer
|
||||
* \param size Maximum number of bytes to be read
|
||||
*
|
||||
* \return On success, returns number of bytes successfuly written.
|
||||
* \return On failure, returns zero.
|
||||
*
|
||||
* \note To check for error see bh_io_error.
|
||||
*/
|
||||
size_t bh_io_write(bh_io_t *io,
|
||||
const char* data,
|
||||
size_t size)
|
||||
@@ -45,39 +144,112 @@ size_t bh_io_write(bh_io_t *io,
|
||||
return io->table->write(io, data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the \a io object (if possible).
|
||||
*
|
||||
* In most cases, this function causes any unwritten/buffered data to be
|
||||
* written.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*/
|
||||
void bh_io_flush(bh_io_t *io)
|
||||
{
|
||||
io->table->flush(io);
|
||||
}
|
||||
|
||||
void bh_io_seek(bh_io_t *io,
|
||||
/**
|
||||
* Seeks the \a io object in the specified direction \a dir and \a offset (if
|
||||
* possible).
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
* \param offset Number of bytes to seek in specified direciton
|
||||
* \param dir Seeking direction
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_io_seek(bh_io_t *io,
|
||||
bh_off_t offset,
|
||||
int dir)
|
||||
{
|
||||
io->table->seek(io, offset, dir);
|
||||
return io->table->seek(io, offset, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total size of the \a io object (if possible)
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*
|
||||
* \return On success, returns total size of the io object.
|
||||
* \return On failure, returns -1.
|
||||
*/
|
||||
bh_off_t bh_io_size(bh_io_t *io)
|
||||
{
|
||||
return io->table->size(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current position in the \a io object (if possible).
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*
|
||||
* \return On success, returns current position in the io object.
|
||||
* \return On failure, returns -1.
|
||||
*/
|
||||
bh_off_t bh_io_tell(bh_io_t *io)
|
||||
{
|
||||
return io->table->tell(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available number of bytes to be read from the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*
|
||||
* \return On success, returns number of available bytes to be read.
|
||||
* \return On failure, returns zero.
|
||||
*/
|
||||
bh_off_t bh_io_available(bh_io_t *io)
|
||||
{
|
||||
return io->table->available(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks error flag of the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*
|
||||
* \return If error flag is set, returns non-zero.
|
||||
* \return If error flag is not set, returns zero.
|
||||
*/
|
||||
int bh_io_error(bh_io_t *io)
|
||||
{
|
||||
return (io->flags & BH_IO_ERROR) > 0;
|
||||
return (io->flags & BH_IO_ERROR) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks end-of-file flag of the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*
|
||||
* \return If end-of-file flag is set, returns non-zero.
|
||||
* \return If end-of-file flag is not set, returns zero.
|
||||
*/
|
||||
int bh_io_eof(bh_io_t *io)
|
||||
{
|
||||
return (io->flags & BH_IO_EOF) > 0;
|
||||
return (io->flags & BH_IO_EOF) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears error of the \a io object.
|
||||
*
|
||||
* \param io Pointer to the io object
|
||||
*/
|
||||
void bh_io_clear(bh_io_t *io)
|
||||
{
|
||||
io->table->clear(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
135
src/queue.c
135
src/queue.c
@@ -2,6 +2,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \defgroup queue Queue
|
||||
*
|
||||
* Data stucture for storing pointers in queue.
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
bh_queue_t *result;
|
||||
@@ -13,23 +26,47 @@ bh_queue_t *bh_queue_new(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a queue object.
|
||||
*
|
||||
* \param queue Pointer to the queue object to be freed
|
||||
*/
|
||||
void bh_queue_free(bh_queue_t *queue)
|
||||
{
|
||||
bh_queue_destroy(queue);
|
||||
free(queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a queue object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param queue Pointer to the queue object to be initialized
|
||||
*/
|
||||
void bh_queue_init(bh_queue_t *queue)
|
||||
{
|
||||
memset(queue, 0, sizeof(*queue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the \a queue object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param queue Pointer to the queue object to be destroyed
|
||||
*/
|
||||
void bh_queue_destroy(bh_queue_t *queue)
|
||||
{
|
||||
if (queue->capacity)
|
||||
free(queue->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the \a queue object.
|
||||
*
|
||||
* \param queue Pointer to the queue object to be cleared
|
||||
*/
|
||||
void bh_queue_clear(bh_queue_t *queue)
|
||||
{
|
||||
queue->head = 0;
|
||||
@@ -37,6 +74,20 @@ void bh_queue_clear(bh_queue_t *queue)
|
||||
queue->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@@ -48,11 +99,11 @@ int bh_queue_reserve(bh_queue_t *queue,
|
||||
|
||||
/* New capacity should not exceed maximum capacity */
|
||||
if (size > ((size_t)-1) / sizeof(void *))
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
|
||||
/* Prevent same size memory reallocation */
|
||||
if (size == queue->capacity)
|
||||
return 0;
|
||||
return BH_OK;
|
||||
|
||||
/* Prepare new empty queue */
|
||||
bh_queue_init(&other);
|
||||
@@ -64,7 +115,7 @@ int bh_queue_reserve(bh_queue_t *queue,
|
||||
other.data = malloc(size * sizeof(void *));
|
||||
other.capacity = size;
|
||||
if (!other.data)
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
|
||||
/* Iterate over old queue and insert data into new queue */
|
||||
iter = bh_queue_iter_next(queue, NULL);
|
||||
@@ -81,9 +132,20 @@ int bh_queue_reserve(bh_queue_t *queue,
|
||||
|
||||
/* Copy queue information */
|
||||
*queue = other;
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@@ -95,7 +157,7 @@ int bh_queue_insert(bh_queue_t *queue,
|
||||
/* Check potential size overflow and reserve capacity */
|
||||
capacity = (queue->capacity) ? (queue->capacity * 2) : (16);
|
||||
if (capacity < queue->capacity || bh_queue_reserve(queue, capacity))
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
}
|
||||
|
||||
/* Increase queue size and advance tail index */
|
||||
@@ -104,9 +166,16 @@ int bh_queue_insert(bh_queue_t *queue,
|
||||
if (++queue->tail >= queue->capacity)
|
||||
queue->tail = 0;
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
/* Do nothing if queue is empty */
|
||||
@@ -119,6 +188,14 @@ void bh_queue_remove(bh_queue_t *queue)
|
||||
queue->head = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void *bh_queue_front(bh_queue_t *queue)
|
||||
{
|
||||
/* Do nothing if queue is empty */
|
||||
@@ -129,21 +206,56 @@ void *bh_queue_front(bh_queue_t *queue)
|
||||
return queue->data[queue->head];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return !queue->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return queue->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return queue->capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@@ -170,7 +282,18 @@ void *bh_queue_iter_next(bh_queue_t *queue,
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return *(void **)iter;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
||||
148
src/thread.c
148
src/thread.c
@@ -1,6 +1,27 @@
|
||||
#include <bh/internal/thread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* \defgroup thread Multithreading
|
||||
*
|
||||
* Multithreading API
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates new task object with specified function \a func, \a data and \a
|
||||
* flags.
|
||||
*
|
||||
* If the \a flags contain BH_THREAD_CLEANUP, upon successful completion task
|
||||
* will be automaticly destroyed.
|
||||
*
|
||||
* \param func Task's function
|
||||
* \param data Task's data
|
||||
* \param flags Task's flags
|
||||
*
|
||||
* \return On success, returns new task object.
|
||||
* \return On failure, returns null pointer.
|
||||
*/
|
||||
bh_task_t *bh_task_new(void (*func)(void *),
|
||||
void *data,
|
||||
int flags)
|
||||
@@ -14,12 +35,31 @@ bh_task_t *bh_task_new(void (*func)(void *),
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a task object.
|
||||
*
|
||||
* \param task Pointer to the task object.
|
||||
*/
|
||||
void bh_task_free(bh_task_t *task)
|
||||
{
|
||||
bh_task_destroy(task);
|
||||
free(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a task object with specified function \a func, \a data and
|
||||
* \a flags.
|
||||
*
|
||||
* If the \a flags contain BH_THREAD_CLEANUP, upon successful completion task
|
||||
* will be automaticly destroyed.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param task Pointer to the task object
|
||||
* \param func Task's function
|
||||
* \param data Task's data
|
||||
* \param flags Task's flags
|
||||
*/
|
||||
void bh_task_init(bh_task_t *task,
|
||||
void (*func)(void *),
|
||||
void *data,
|
||||
@@ -30,24 +70,53 @@ void bh_task_init(bh_task_t *task,
|
||||
task->flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroyes the \a task object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param task Pointer to the task object
|
||||
*/
|
||||
void bh_task_destroy(bh_task_t *task)
|
||||
{
|
||||
(void)task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reuses the \a task object for different purpose.
|
||||
*
|
||||
* \param task Pointer to the task object
|
||||
* \param func New task's function
|
||||
* \param data New task's data
|
||||
*/
|
||||
void bh_task_reuse(bh_task_t *task,
|
||||
void (*func)(void *),
|
||||
void *data)
|
||||
{
|
||||
/* If the task is done - reinitilize it with new data */
|
||||
if (task->flags & BH_THREAD_DONE)
|
||||
bh_task_init(task, func, data, task->flags & ~(BH_THREAD_DONE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the \a task is done.
|
||||
*
|
||||
* \param task Pointer to the task object
|
||||
*
|
||||
* \return If the task is done, returns non-zero.
|
||||
* \return If the task is not done, returns zero.
|
||||
*/
|
||||
int bh_task_done(bh_task_t *task)
|
||||
{
|
||||
return (task->flags & BH_THREAD_DONE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the mutex object.
|
||||
*
|
||||
* \return On success, returns new mutex object.
|
||||
* \return On failure, returns null pointer.
|
||||
*/
|
||||
bh_mutex_t *bh_mutex_new(void)
|
||||
{
|
||||
bh_mutex_t *result;
|
||||
@@ -62,12 +131,27 @@ bh_mutex_t *bh_mutex_new(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a mutex object.
|
||||
*
|
||||
* \param mutex Pointer to the mutex object
|
||||
*/
|
||||
void bh_mutex_free(bh_mutex_t *mutex)
|
||||
{
|
||||
bh_mutex_destroy(mutex);
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the semaphore object with initial \a count value.
|
||||
*
|
||||
* \param count Initial semaphore value
|
||||
*
|
||||
* \return On success, returns new semaphore object.
|
||||
* \return On failure, returns null pointer.
|
||||
*
|
||||
* \note Guranteed maximum \a count value is 32767.
|
||||
*/
|
||||
bh_semaphore_t *bh_semaphore_new(int count)
|
||||
{
|
||||
bh_semaphore_t *result;
|
||||
@@ -82,12 +166,23 @@ bh_semaphore_t *bh_semaphore_new(int count)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the \a semaphore object.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
*/
|
||||
void bh_semaphore_free(bh_semaphore_t *semaphore)
|
||||
{
|
||||
bh_semaphore_destroy(semaphore);
|
||||
free(semaphore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the condition variable object.
|
||||
*
|
||||
* \return On success, returns new condition variable object.
|
||||
* \return On failure, returns null pointer.
|
||||
*/
|
||||
bh_cond_t *bh_cond_new(void)
|
||||
{
|
||||
bh_cond_t *result;
|
||||
@@ -102,12 +197,26 @@ bh_cond_t *bh_cond_new(void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the condition variable object \a cond.
|
||||
*
|
||||
* \param cond Pointer to the condition variable object
|
||||
*/
|
||||
void bh_cond_free(bh_cond_t *cond)
|
||||
{
|
||||
bh_cond_destroy(cond);
|
||||
free(cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds \a task to the thread \a pool.
|
||||
*
|
||||
* \param pool Pointer to the thread pool object
|
||||
* \param task Pointer to the task object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_thread_pool_add(bh_thread_pool_t *pool,
|
||||
bh_task_t *task)
|
||||
{
|
||||
@@ -119,16 +228,24 @@ int bh_thread_pool_add(bh_thread_pool_t *pool,
|
||||
if (bh_queue_insert(&pool->tasks, task))
|
||||
{
|
||||
bh_mutex_unlock(&pool->lock);
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
/* Signal new job */
|
||||
bh_mutex_unlock(&pool->lock);
|
||||
bh_cond_signal(&pool->new_task);
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits unitl all task in thread \a pool are complete.
|
||||
*
|
||||
* \param pool Pointer to the thread pool.
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_thread_pool_wait(bh_thread_pool_t *pool)
|
||||
{
|
||||
/* Lock and check if there is jobs in the queue */
|
||||
@@ -160,9 +277,16 @@ int bh_thread_pool_wait(bh_thread_pool_t *pool)
|
||||
/* Unlock */
|
||||
bh_mutex_unlock(&pool->lock);
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroyes the thread \a pool object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param pool Pointer to the thread pool object
|
||||
*/
|
||||
void bh_thread_pool_destroy(bh_thread_pool_t *pool)
|
||||
{
|
||||
size_t i;
|
||||
@@ -195,12 +319,21 @@ void bh_thread_pool_destroy(bh_thread_pool_t *pool)
|
||||
bh_mutex_destroy(&pool->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the thread \a pool object.
|
||||
*
|
||||
* \param pool Pointer to the thread pool object
|
||||
*/
|
||||
void bh_thread_pool_free(bh_thread_pool_t *pool)
|
||||
{
|
||||
bh_thread_pool_destroy(pool);
|
||||
free(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* \warning This is an internal function.
|
||||
* \warning Do not use this function directly!
|
||||
*/
|
||||
void bh_thread_pool_worker(void *arg)
|
||||
{
|
||||
bh_thread_pool_t *pool;
|
||||
@@ -210,26 +343,31 @@ void bh_thread_pool_worker(void *arg)
|
||||
{
|
||||
bh_task_t *task;
|
||||
|
||||
/* Wait unitl there is a task or shutdown signal */
|
||||
bh_mutex_lock(&pool->lock);
|
||||
while (!pool->shutdown && bh_queue_empty(&pool->tasks))
|
||||
bh_cond_wait(&pool->new_task, &pool->lock);
|
||||
|
||||
/* If its shutdown signal - exit the loop */
|
||||
if (pool->shutdown)
|
||||
{
|
||||
bh_mutex_unlock(&pool->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fetch task from the front of the queue, increase active counter */
|
||||
task = bh_queue_front(&pool->tasks);
|
||||
bh_queue_remove(&pool->tasks);
|
||||
pool->active++;
|
||||
bh_mutex_unlock(&pool->lock);
|
||||
|
||||
/* Do the task, mark as done, and if required - free it */
|
||||
task->func(task->data);
|
||||
task->flags |= BH_THREAD_DONE;
|
||||
if (task->flags & BH_THREAD_CLEANUP)
|
||||
bh_task_free(task);
|
||||
|
||||
/* Decrease active counter and broadcast that we are done */
|
||||
bh_mutex_lock(&pool->lock);
|
||||
pool->active--;
|
||||
|
||||
@@ -237,3 +375,7 @@ void bh_thread_pool_worker(void *arg)
|
||||
bh_cond_broadcast(&pool->done_task);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
@@ -1,116 +1,300 @@
|
||||
#include <bh/internal/thread.h>
|
||||
|
||||
int bh_thread_init(bh_thread_t *thread,
|
||||
bh_task_t *task)
|
||||
{
|
||||
(void)thread;
|
||||
(void)task;
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* \ingroup thread
|
||||
* \{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates the thread object with the given \a task.
|
||||
*
|
||||
* \warning This function can be implemented either as a macro or as a function.
|
||||
*
|
||||
* \param task Pointer to the task object
|
||||
*
|
||||
* \return On success, returns the pointer to the new queue object.
|
||||
* \return On failure, returns a null pointer.
|
||||
*/
|
||||
bh_thread_t *bh_thread_new(bh_task_t *task)
|
||||
{
|
||||
(void)task;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a thread object with the given \a task.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
* \warning This function can be implemented either as a macro or as a function.
|
||||
*
|
||||
* \param thread Pointer to the thread object
|
||||
* \param task Pointer to the task object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_thread_init(bh_thread_t *thread,
|
||||
bh_task_t *task)
|
||||
{
|
||||
(void)thread;
|
||||
(void)task;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the \a thread.
|
||||
*
|
||||
* If thread was created with bh_thread_new, this function also frees the \a
|
||||
* thread object.
|
||||
*
|
||||
* \param thread Pointer to the thread object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_thread_join(bh_thread_t *thread)
|
||||
{
|
||||
(void)thread;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches the \a thread.
|
||||
*
|
||||
* If thread was created with bh_thread_new, this function also frees the \a
|
||||
* thread object.
|
||||
*
|
||||
* \param thread Pointer to the thread object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_thread_detach(bh_thread_t *thread)
|
||||
{
|
||||
(void)thread;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the \a mutex object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param mutex Pointer to the mutex object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_mutex_init(bh_mutex_t *mutex)
|
||||
{
|
||||
(void)mutex;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroyes the \a mutex object.
|
||||
*
|
||||
* \param mutex Pointer to the mutex object
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*/
|
||||
void bh_mutex_destroy(bh_mutex_t *mutex)
|
||||
{
|
||||
(void)mutex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the \a mutex object.
|
||||
*
|
||||
* \param mutex Pointer to the mutex object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_mutex_lock(bh_mutex_t *mutex)
|
||||
{
|
||||
(void)mutex;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to lock the \a mutex object.
|
||||
*
|
||||
* \param mutex Pointer to the mutex object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_mutex_try_lock(bh_mutex_t *mutex)
|
||||
{
|
||||
(void)mutex;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the \a mutex object.
|
||||
*
|
||||
* \param mutex Pointer to the mutex object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_mutex_unlock(bh_mutex_t *mutex)
|
||||
{
|
||||
(void)mutex;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initilizes the \a semaphore object with specified \a count value.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
* \param count Initial semaphore value
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*
|
||||
* \note Guranteed maximum \a count value is 32767.
|
||||
*/
|
||||
int bh_semaphore_init(bh_semaphore_t *semaphore, int count)
|
||||
{
|
||||
(void)semaphore;
|
||||
(void)count;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroyes the \a semaphore object.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
*/
|
||||
void bh_semaphore_destroy(bh_semaphore_t *semaphore)
|
||||
{
|
||||
(void)semaphore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts (increases value of) the \a semaphore.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_semaphore_post(bh_semaphore_t *semaphore)
|
||||
{
|
||||
(void)semaphore;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits (decreases value of) the \a semaphore.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_semaphore_wait(bh_semaphore_t *semaphore)
|
||||
{
|
||||
(void)semaphore;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits (decreases value of) the \a semaphore for the specified \a timeout
|
||||
* amount of milliseconds.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
* \param timeout Number of milliseconds to wait for
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure or timeout, returns error code.
|
||||
*/
|
||||
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
|
||||
unsigned long timeout)
|
||||
{
|
||||
(void)semaphore;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to waits (decrease value of) the \a semaphore.
|
||||
*
|
||||
* \param semaphore Pointer to the semaphore object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_semaphore_try_wait(bh_semaphore_t *semaphore)
|
||||
{
|
||||
(void)semaphore;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the condition variable object \a cond.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param cond Pointer to the condition variable
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_cond_init(bh_cond_t *cond)
|
||||
{
|
||||
(void)cond;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroyes the condition variable object \a cond.
|
||||
*
|
||||
* \param cond Pointer to the condition variable object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*/
|
||||
void bh_cond_destroy(bh_cond_t *cond)
|
||||
{
|
||||
(void)cond;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on the condition variable \a cond with specified \a mutex.
|
||||
*
|
||||
* \param cond Pointer to the condition variable object
|
||||
* \param mutex Pointer to the mutex object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return ON failure, returns error code.
|
||||
*/
|
||||
int bh_cond_wait(bh_cond_t *cond,
|
||||
bh_mutex_t *mutex)
|
||||
{
|
||||
(void)cond;
|
||||
(void)mutex;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on the condition variable \a cond with specified \a mutex for the
|
||||
* specified \a timeout amount of milliseconds.
|
||||
*
|
||||
* \param cond Pointer to the condition variable object
|
||||
* \param mutex Pointer to the mutex object
|
||||
* \param timeout Number of milliseconds to wait for
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure or timeout, returns error code.
|
||||
*/
|
||||
int bh_cond_wait_for(bh_cond_t *cond,
|
||||
bh_mutex_t *mutex,
|
||||
unsigned long timeout)
|
||||
@@ -118,33 +302,71 @@ int bh_cond_wait_for(bh_cond_t *cond,
|
||||
(void)cond;
|
||||
(void)mutex;
|
||||
(void)timeout;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals (notifies) one waiting thread on the condition variable \a cond.
|
||||
*
|
||||
* \param cond Pointer to the condition variable object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_cond_signal(bh_cond_t *cond)
|
||||
{
|
||||
(void)cond;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals (notifies) all waiting threads on the condition variable \a cond.
|
||||
*
|
||||
* \param cond Pointer to the condition variable object
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_cond_broadcast(bh_cond_t *cond)
|
||||
{
|
||||
(void)cond;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bh_thread_pool_init(bh_thread_pool_t *pool,
|
||||
size_t size)
|
||||
{
|
||||
(void)pool;
|
||||
(void)size;
|
||||
return -1;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the thread pool object with specified \a size amount of threads.
|
||||
*
|
||||
* \param size Number of threads in the thread pool
|
||||
*
|
||||
* \return On success, returns pointer to the new thread pool object.
|
||||
* \return On failure, returns null pointer.
|
||||
*/
|
||||
bh_thread_pool_t *bh_thread_pool_new(size_t size)
|
||||
{
|
||||
(void)size;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initilizes the thread \a pool object with specified \a size amount of
|
||||
* threads.
|
||||
*
|
||||
* \warning This is an internal function.
|
||||
*
|
||||
* \param pool Pointer to the thread pool object
|
||||
* \param size Number of threads in the thread pool
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int bh_thread_pool_init(bh_thread_pool_t *pool,
|
||||
size_t size)
|
||||
{
|
||||
(void)pool;
|
||||
(void)size;
|
||||
return BH_NO_IMPL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
@@ -5,9 +5,9 @@
|
||||
static void *bh_thread_run(void *arg)
|
||||
{
|
||||
bh_task_t *task;
|
||||
|
||||
task = (bh_task_t *)arg;
|
||||
|
||||
/* Do the task, mark as done, and if required free it */
|
||||
task->func(task->data);
|
||||
task->flags |= BH_THREAD_DONE;
|
||||
|
||||
@@ -21,21 +21,25 @@ int bh_thread_init(bh_thread_t *thread,
|
||||
bh_task_t *task)
|
||||
{
|
||||
thread->allocated = 0;
|
||||
return pthread_create(&thread->handle, NULL, bh_thread_run, task);
|
||||
if (pthread_create(&thread->handle, NULL, bh_thread_run, task))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
bh_thread_t *bh_thread_new(bh_task_t *task)
|
||||
{
|
||||
bh_thread_t *result;
|
||||
|
||||
/* Allocate thread object */
|
||||
result = malloc(sizeof(*result));
|
||||
|
||||
if (result && bh_thread_init(result, task))
|
||||
{
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
/* Mark thread as allocated for deallocation in join/detach */
|
||||
if (result)
|
||||
result->allocated = 1;
|
||||
|
||||
@@ -44,27 +48,35 @@ bh_thread_t *bh_thread_new(bh_task_t *task)
|
||||
|
||||
int bh_thread_join(bh_thread_t *thread)
|
||||
{
|
||||
int result = pthread_join(thread->handle, NULL);
|
||||
/* Join the thread */
|
||||
if (pthread_join(thread->handle, NULL))
|
||||
return BH_ERROR;
|
||||
|
||||
/* If thread is allocated, deallocate it */
|
||||
if (thread->allocated)
|
||||
free(thread);
|
||||
|
||||
return result;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_thread_detach(bh_thread_t *thread)
|
||||
{
|
||||
int result = pthread_detach(thread->handle);
|
||||
/* Detach the thread */
|
||||
if (pthread_detach(thread->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
/* If thread is allocated, deallocate it */
|
||||
if (thread->allocated)
|
||||
free(thread);
|
||||
|
||||
return result;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_mutex_init(bh_mutex_t *mutex)
|
||||
{
|
||||
return pthread_mutex_init(&mutex->handle, NULL);
|
||||
if (pthread_mutex_init(&mutex->handle, NULL))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_mutex_destroy(bh_mutex_t *mutex)
|
||||
@@ -74,22 +86,30 @@ void bh_mutex_destroy(bh_mutex_t *mutex)
|
||||
|
||||
int bh_mutex_lock(bh_mutex_t *mutex)
|
||||
{
|
||||
return pthread_mutex_lock(&mutex->handle);
|
||||
if (pthread_mutex_lock(&mutex->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_mutex_try_lock(bh_mutex_t *mutex)
|
||||
{
|
||||
return pthread_mutex_trylock(&mutex->handle);
|
||||
if (pthread_mutex_trylock(&mutex->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_mutex_unlock(bh_mutex_t *mutex)
|
||||
{
|
||||
return pthread_mutex_unlock(&mutex->handle);
|
||||
if (pthread_mutex_unlock(&mutex->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_init(bh_semaphore_t *semaphore, int count)
|
||||
{
|
||||
return sem_init(&semaphore->handle, 0, count);
|
||||
if (sem_init(&semaphore->handle, 0, count))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_semaphore_destroy(bh_semaphore_t *semaphore)
|
||||
@@ -99,12 +119,16 @@ void bh_semaphore_destroy(bh_semaphore_t *semaphore)
|
||||
|
||||
int bh_semaphore_post(bh_semaphore_t *semaphore)
|
||||
{
|
||||
return sem_post(&semaphore->handle);
|
||||
if (sem_post(&semaphore->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_wait(bh_semaphore_t *semaphore)
|
||||
{
|
||||
return sem_wait(&semaphore->handle);
|
||||
if (sem_wait(&semaphore->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
|
||||
@@ -115,17 +139,23 @@ int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000;
|
||||
|
||||
return sem_timedwait(&semaphore->handle, &ts);
|
||||
if (sem_timedwait(&semaphore->handle, &ts))
|
||||
return BH_TIMEOUT;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_try_wait(bh_semaphore_t *semaphore)
|
||||
{
|
||||
return sem_trywait(&semaphore->handle);
|
||||
if (sem_trywait(&semaphore->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_init(bh_cond_t *cond)
|
||||
{
|
||||
return pthread_cond_init(&cond->handle, NULL);
|
||||
if (pthread_cond_init(&cond->handle, NULL))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_cond_destroy(bh_cond_t *cond)
|
||||
@@ -136,7 +166,9 @@ void bh_cond_destroy(bh_cond_t *cond)
|
||||
int bh_cond_wait(bh_cond_t *cond,
|
||||
bh_mutex_t *mutex)
|
||||
{
|
||||
return pthread_cond_wait(&cond->handle, &mutex->handle);
|
||||
if (pthread_cond_wait(&cond->handle, &mutex->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_wait_for(bh_cond_t *cond,
|
||||
@@ -148,17 +180,23 @@ int bh_cond_wait_for(bh_cond_t *cond,
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000;
|
||||
|
||||
return pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts);
|
||||
if (pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts))
|
||||
return BH_TIMEOUT;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_signal(bh_cond_t *cond)
|
||||
{
|
||||
return pthread_cond_signal(&cond->handle);
|
||||
if (pthread_cond_signal(&cond->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_broadcast(bh_cond_t *cond)
|
||||
{
|
||||
return pthread_cond_broadcast(&cond->handle);
|
||||
if (pthread_cond_broadcast(&cond->handle))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_thread_pool_init(bh_thread_pool_t *pool,
|
||||
@@ -215,7 +253,7 @@ int bh_thread_pool_init(bh_thread_pool_t *pool,
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
|
||||
queue_fail:
|
||||
free(pool->threads);
|
||||
@@ -230,7 +268,7 @@ task_fail:
|
||||
bh_mutex_destroy(&pool->lock);
|
||||
|
||||
lock_fail:
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
bh_thread_pool_t *bh_thread_pool_new(size_t size)
|
||||
|
||||
@@ -4,15 +4,18 @@ static unsigned __stdcall bh_thread_run(void *arg)
|
||||
{
|
||||
bh_thread_data_t data;
|
||||
|
||||
/* Fetch thread data, store it on stack and free from heap */
|
||||
data = *(bh_thread_data_t *)arg;
|
||||
free(arg);
|
||||
|
||||
/* Do the task, mark as done, and if required free it */
|
||||
data.task->func(data.task->data);
|
||||
data.task->flags |= BH_THREAD_DONE;
|
||||
|
||||
if (data.task->flags & BH_THREAD_CLEANUP)
|
||||
bh_task_free(data.task);
|
||||
|
||||
/* Call thread specific end function (deallocate TLS) */
|
||||
data.end(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -24,23 +27,27 @@ int bh_thread_init_base(bh_thread_t *thread,
|
||||
{
|
||||
bh_thread_data_t *data;
|
||||
|
||||
/* Allocate thread specific data */
|
||||
data = malloc(sizeof(*data));
|
||||
if (!data)
|
||||
return -1;
|
||||
return BH_OOM;
|
||||
|
||||
/* Setup thread specific data */
|
||||
data->task = task;
|
||||
data->end = end;
|
||||
|
||||
/* Create and setup thread (relative to the callers libc) */
|
||||
thread->allocated = 0;
|
||||
thread->handle = (HANDLE)_beginthreadex(NULL, 0, bh_thread_run, data, 0, NULL);
|
||||
|
||||
/* Check for errors */
|
||||
if (!thread->handle)
|
||||
{
|
||||
free(data);
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
bh_thread_t *bh_thread_new_base(bh_task_t *task,
|
||||
@@ -49,6 +56,7 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task,
|
||||
{
|
||||
bh_thread_t *result;
|
||||
|
||||
/* Allocate thread object */
|
||||
result = malloc(sizeof(*result));
|
||||
if (result && !bh_thread_init_base(result, task, begin, end))
|
||||
{
|
||||
@@ -56,6 +64,7 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task,
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
/* Mark thread as allocated for deallocation in join/detach */
|
||||
if (result)
|
||||
result->allocated = 1;
|
||||
|
||||
@@ -64,30 +73,35 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task,
|
||||
|
||||
int bh_thread_join(bh_thread_t *thread)
|
||||
{
|
||||
/* Join the thread */
|
||||
WaitForSingleObject(thread->handle, INFINITE);
|
||||
CloseHandle(thread->handle);
|
||||
|
||||
/* If thread is allocated, deallocate it */
|
||||
if (thread->allocated)
|
||||
free(thread);
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_thread_detach(bh_thread_t *thread)
|
||||
{
|
||||
/* Detach from thread */
|
||||
CloseHandle(thread->handle);
|
||||
|
||||
/* If thread is allocated, deallocate it */
|
||||
if (thread->allocated)
|
||||
free(thread);
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_mutex_init(bh_mutex_t *mutex)
|
||||
{
|
||||
/* TODO: Is this spincount needed or sane? */
|
||||
if (!InitializeCriticalSectionAndSpinCount(&mutex->handle, 0x400))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_mutex_destroy(bh_mutex_t *mutex)
|
||||
@@ -98,29 +112,30 @@ void bh_mutex_destroy(bh_mutex_t *mutex)
|
||||
int bh_mutex_lock(bh_mutex_t *mutex)
|
||||
{
|
||||
EnterCriticalSection(&mutex->handle);
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_mutex_try_lock(bh_mutex_t *mutex)
|
||||
{
|
||||
if (!TryEnterCriticalSection(&mutex->handle))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_mutex_unlock(bh_mutex_t *mutex)
|
||||
{
|
||||
LeaveCriticalSection(&mutex->handle);
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_init(bh_semaphore_t *semaphore, int count)
|
||||
{
|
||||
/* Create semaphore with max value of 32767 (to match POSIX) */
|
||||
semaphore->handle = CreateSemaphore(NULL, count, 0x7FFF, NULL);
|
||||
if (!semaphore->handle)
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_semaphore_destroy(bh_semaphore_t *semaphore)
|
||||
@@ -131,37 +146,38 @@ void bh_semaphore_destroy(bh_semaphore_t *semaphore)
|
||||
int bh_semaphore_post(bh_semaphore_t *semaphore)
|
||||
{
|
||||
if (!ReleaseSemaphore(semaphore->handle, 1, NULL))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_wait(bh_semaphore_t *semaphore)
|
||||
{
|
||||
if (WaitForSingleObject(semaphore->handle, INFINITE))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_semaphore_wait_for(bh_semaphore_t *semaphore,
|
||||
unsigned long timeout)
|
||||
{
|
||||
/* FIXME: Check if we timed out or errored out */
|
||||
if (WaitForSingleObject(semaphore->handle, timeout))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_TIMEOUT;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
int bh_semaphore_try_wait(bh_semaphore_t *semaphore)
|
||||
{
|
||||
if (WaitForSingleObject(semaphore->handle, 0))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
#if WINVER >= _WIN32_WINNT_VISTA
|
||||
int bh_cond_init(bh_cond_t *cond)
|
||||
{
|
||||
InitializeConditionVariable(&cond->handle);
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
void bh_cond_destroy(bh_cond_t *cond)
|
||||
@@ -179,43 +195,46 @@ int bh_cond_wait_for(bh_cond_t *cond,
|
||||
bh_mutex_t *mutex,
|
||||
unsigned long timeout)
|
||||
{
|
||||
/* FIXME: Check if we timed out or errored out */
|
||||
if (!SleepConditionVariableCS(&cond->handle, &mutex->handle, timeout))
|
||||
return -1;
|
||||
return 0;
|
||||
return BH_TIMEOUT;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_signal(bh_cond_t *cond)
|
||||
{
|
||||
WakeConditionVariable(&cond->handle);
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_broadcast(bh_cond_t *cond)
|
||||
{
|
||||
WakeAllConditionVariable(&cond->handle);
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
#else
|
||||
/* Condition variable implementation based on BeOS article
|
||||
* http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
|
||||
*
|
||||
* Slow, but correct implementation of CVs.
|
||||
*/
|
||||
|
||||
int bh_cond_init(bh_cond_t *cond)
|
||||
{
|
||||
if (bh_mutex_init(&cond->lock))
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
|
||||
if (bh_semaphore_init(&cond->wait, 0))
|
||||
{
|
||||
bh_mutex_destroy(&cond->lock);
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
if (bh_semaphore_init(&cond->done, 0))
|
||||
{
|
||||
bh_semaphore_destroy(&cond->wait);
|
||||
bh_mutex_destroy(&cond->lock);
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
}
|
||||
cond->waiting = 0;
|
||||
cond->signals = 0;
|
||||
@@ -302,7 +321,7 @@ int bh_cond_signal(bh_cond_t *cond)
|
||||
else
|
||||
bh_mutex_unlock(&cond->lock);
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
int bh_cond_broadcast(bh_cond_t *cond)
|
||||
@@ -326,7 +345,7 @@ int bh_cond_broadcast(bh_cond_t *cond)
|
||||
else
|
||||
bh_mutex_unlock(&cond->lock);
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -386,7 +405,7 @@ int bh_thread_pool_init_base(bh_thread_pool_t *pool,
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return BH_OK;
|
||||
|
||||
queue_fail:
|
||||
free(pool->threads);
|
||||
@@ -401,7 +420,7 @@ task_fail:
|
||||
bh_mutex_destroy(&pool->lock);
|
||||
|
||||
lock_fail:
|
||||
return -1;
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
bh_thread_pool_t *bh_thread_pool_new_base(size_t size,
|
||||
@@ -409,6 +428,7 @@ bh_thread_pool_t *bh_thread_pool_new_base(size_t size,
|
||||
bh_thread_end_cb_t end)
|
||||
{
|
||||
bh_thread_pool_t *result;
|
||||
|
||||
result = malloc(sizeof(*result));
|
||||
if (result && bh_thread_pool_init_base(result, size, begin, end))
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BHLIB_UNIT_H
|
||||
#define BHLIB_UNIT_H
|
||||
#ifndef BH_UNIT_H
|
||||
#define BH_UNIT_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -21,4 +21,4 @@ typedef int (*bh_unit_cb_t)(void);
|
||||
void bh_unit_add(const char *name, bh_unit_cb_t func);
|
||||
int bh_unit_run(void);
|
||||
|
||||
#endif /* BHLIB_UNIT_H */
|
||||
#endif /* BH_UNIT_H */
|
||||
|
||||
Reference in New Issue
Block a user