Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a65eb5c161 | |||
| 9b8c0f8763 | |||
| c04c2e8f12 | |||
| b8cf2b379b | |||
| 274a48a845 | |||
| 47feee7b1a | |||
| 7db5fefe25 | |||
| b072632499 | |||
| 15a9147e15 | |||
| d24592dde4 | |||
| ce56eacafe | |||
| dbf50395d0 | |||
| 4aaa165e5f | |||
| 4fcbcfdfb2 | |||
| cb39baa233 | |||
| 5646c8c2b8 | |||
| 3529e8525a | |||
| 6a26e00438 | |||
| c76008e498 | |||
| 321622ac16 | |||
| c39f50a0ee | |||
| 5ab348fd30 | |||
| 709d11331c | |||
| 912c450e6e | |||
| fc43d104dc | |||
| 8eba5c7462 | |||
| 5212ef4bc8 | |||
| fc4a422a79 | |||
| ef3f64f095 | |||
| 467c13e161 | |||
| 6b04920d29 | |||
| e4bacb7360 | |||
| 9c34aa7996 | |||
| e9d0e323f0 |
+73
-15
@@ -1,7 +1,7 @@
|
||||
BasedOnStyle: WebKit
|
||||
IndentWidth: 8
|
||||
---
|
||||
Language: Cpp
|
||||
Language: C
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 80
|
||||
@@ -26,8 +26,8 @@ AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: OnePerLine
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BitFieldColonSpacing: Both
|
||||
BreakBeforeBraces: Linux
|
||||
@@ -47,17 +47,17 @@ SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PenaltyExcessCharacter: 5
|
||||
PenaltyExcessCharacter: 999999999
|
||||
PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- BLUELIB_API
|
||||
- FX_API
|
||||
ForEachMacros:
|
||||
- b_btree_foreach
|
||||
- b_queue_foreach
|
||||
MacroBlockBegin: "B_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "B_TYPE_.*_END"
|
||||
- fx_btree_foreach
|
||||
- fx_queue_foreach
|
||||
MacroBlockBegin: "FX_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "FX_TYPE_.*_END"
|
||||
---
|
||||
Language: ObjC
|
||||
DerivePointerAlignment: false
|
||||
@@ -84,7 +84,7 @@ AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: true
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BitFieldColonSpacing: Both
|
||||
@@ -110,9 +110,67 @@ PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- BLUELIB_API
|
||||
- FX_API
|
||||
ForEachMacros:
|
||||
- b_btree_foreach
|
||||
- b_queue_foreach
|
||||
MacroBlockBegin: "B_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "B_TYPE_.*_END"
|
||||
- fx_btree_foreach
|
||||
- fx_queue_foreach
|
||||
MacroBlockBegin: "FX_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "FX_TYPE_.*_END"
|
||||
---
|
||||
Language: Cpp
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
ColumnLimit: 80
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: OnePerLine
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
BitFieldColonSpacing: Both
|
||||
BreakBeforeBraces: Linux
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ContinuationIndentWidth: 8
|
||||
Cpp11BracedListStyle: true
|
||||
IncludeBlocks: Regroup
|
||||
SortIncludes: true
|
||||
IndentRequires: true
|
||||
NamespaceIndentation: Inner
|
||||
ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000
|
||||
PenaltyExcessCharacter: 9999999
|
||||
PenaltyBreakOpenParenthesis: 5
|
||||
PenaltyBreakBeforeFirstCallParameter: 5
|
||||
PenaltyIndentedWhitespace: 0
|
||||
AttributeMacros:
|
||||
- FX_API
|
||||
ForEachMacros:
|
||||
- fx_btree_foreach
|
||||
- fx_queue_foreach
|
||||
MacroBlockBegin: "FX_TYPE_.*_BEGIN"
|
||||
MacroBlockEnd: "FX_TYPE_.*_END"
|
||||
|
||||
+43
-28
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(bluelib C)
|
||||
project(fx C)
|
||||
|
||||
include (TestBigEndian)
|
||||
|
||||
@@ -9,58 +9,73 @@ set(CMAKE_C_EXTENSIONS OFF)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
set(b_modules core ds serial term cmd io compress)
|
||||
if (NOT DEFINED fx_modules)
|
||||
set(fx_modules core ds serial term cmd io compress)
|
||||
endif ()
|
||||
|
||||
set(b_system_name ${CMAKE_SYSTEM_NAME})
|
||||
string(TOLOWER ${b_system_name} b_system_name)
|
||||
if (NOT DEFINED fx_enable_floating_point)
|
||||
set(fx_enable_floating_point 1)
|
||||
endif ()
|
||||
|
||||
message(STATUS "System name: ${b_system_name}")
|
||||
if (NOT DEFINED fx_enable_tests)
|
||||
set(fx_enable_tests 1)
|
||||
endif ()
|
||||
|
||||
message(STATUS "Floating point support: ${fx_enable_floating_point}")
|
||||
|
||||
set(fx_system_name ${CMAKE_SYSTEM_NAME})
|
||||
string(TOLOWER ${fx_system_name} fx_system_name)
|
||||
|
||||
message(STATUS "System name: ${fx_system_name}")
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
|
||||
|
||||
foreach (module ${b_modules})
|
||||
foreach (module ${fx_modules})
|
||||
add_subdirectory(${module})
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/${module})
|
||||
message(STATUS "Building unit tests for module ${module}")
|
||||
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c)
|
||||
add_executable(blue-${module}-units
|
||||
if (fx_enable_tests AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c)
|
||||
add_executable(fx-${module}-units
|
||||
test/${module}/${module}-units.c
|
||||
misc/AllTests.c
|
||||
misc/CuTest.c
|
||||
misc/CuTest.h)
|
||||
target_link_libraries(blue-${module}-units blue-${module})
|
||||
target_include_directories(blue-${module}-units PRIVATE misc/)
|
||||
set_target_properties(blue-${module}-units PROPERTIES FOLDER "Tests/${module}")
|
||||
|
||||
target_link_libraries(fx-${module}-units fx-${module})
|
||||
target_include_directories(fx-${module}-units PRIVATE misc/)
|
||||
set_target_properties(fx-${module}-units PROPERTIES FOLDER "Tests/${module}")
|
||||
endif ()
|
||||
|
||||
file(GLOB test_sources test/${module}/*.c)
|
||||
list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/${module}/${module}-units.c")
|
||||
|
||||
foreach (test_file ${test_sources})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
add_executable(blue-${module}-${test_name} ${test_file})
|
||||
if (fx_enable_tests)
|
||||
foreach (test_file ${test_sources})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
add_executable(fx-${module}-${test_name} ${test_file})
|
||||
|
||||
set_target_properties(blue-${module}-${test_name} PROPERTIES FOLDER "Tests/${module}")
|
||||
set_target_properties(fx-${module}-${test_name} PROPERTIES FOLDER "Tests/${module}")
|
||||
|
||||
target_link_libraries(blue-${module}-${test_name} blue-${module})
|
||||
endforeach (test_file)
|
||||
target_link_libraries(fx-${module}-${test_name} fx-${module})
|
||||
endforeach (test_file)
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach (module)
|
||||
|
||||
file(GLOB test_sources test/*.c)
|
||||
list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/units.c")
|
||||
if (fx_enable_tests)
|
||||
file(GLOB test_sources test/*.c)
|
||||
list(REMOVE_ITEM test_sources "${CMAKE_CURRENT_SOURCE_DIR}/test/units.c")
|
||||
|
||||
foreach (test_file ${test_sources})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
add_executable(blue-${test_name} ${test_file})
|
||||
foreach (test_file ${test_sources})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
add_executable(fx-${test_name} ${test_file})
|
||||
|
||||
set_target_properties(blue-${test_name} PROPERTIES FOLDER "Tests")
|
||||
set_target_properties(fx-${test_name} PROPERTIES FOLDER "Tests")
|
||||
|
||||
foreach (module ${b_modules})
|
||||
target_link_libraries(blue-${test_name} blue-${module})
|
||||
endforeach (module)
|
||||
endforeach (test_file)
|
||||
foreach (module ${fx_modules})
|
||||
target_link_libraries(fx-${test_name} fx-${module})
|
||||
endforeach (module)
|
||||
endforeach (test_file)
|
||||
endif ()
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
#[=======================================================================[.rst:
|
||||
FindBluelib
|
||||
------------
|
||||
|
||||
Find the Bluelib library and header directories
|
||||
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module defines the following :prop_tgt:`IMPORTED` target:
|
||||
|
||||
``Bluelib::Bluelib``
|
||||
The Bluelib library, if found
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module will set the following variables in your project:
|
||||
|
||||
``Bluelib_FOUND``
|
||||
true if the Bluelib C headers and libraries were found
|
||||
``Bluelib_INCLUDE_DIR``
|
||||
directories containing the Bluelib C headers.
|
||||
|
||||
``Bluelib_LIBRARY``
|
||||
the C library to link against
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
The user may set the environment variable ``Bluelib_PREFIX`` to the root
|
||||
directory of a Bluelib library installation.
|
||||
#]=======================================================================]
|
||||
|
||||
set (Bluelib_SEARCH_PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr/local/share
|
||||
/usr
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
${Bluelib_PREFIX}
|
||||
$ENV{Bluelib_PREFIX})
|
||||
|
||||
if (Bluelib_STATIC)
|
||||
set(_lib_suffix "-s")
|
||||
endif ()
|
||||
|
||||
set(supported_components Core Ds Term Cmd Io Serial Compress)
|
||||
set(components ${Bluelib_FIND_COMPONENTS})
|
||||
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
|
||||
|
||||
if (NOT components)
|
||||
set(components ${supported_components})
|
||||
endif ()
|
||||
|
||||
set(required_vars)
|
||||
|
||||
foreach (component ${components})
|
||||
if (NOT "${component}" IN_LIST supported_components)
|
||||
message(FATAL_ERROR "'${component}' is not a valid Bluelib module.\nSupported modules: ${supported_components_string_list}")
|
||||
endif ()
|
||||
|
||||
string(TOLOWER ${component} header_name)
|
||||
set(lib_name ${header_name}${_lib_suffix})
|
||||
|
||||
if (NOT Bluelib_${component}_INCLUDE_DIR)
|
||||
find_path(Bluelib_${component}_INCLUDE_DIR
|
||||
NAMES blue/${header_name}.h ${Bluelib_FIND_ARGS}
|
||||
PATH_SUFFIXES include
|
||||
PATHS ${Bluelib_SEARCH_PATHS})
|
||||
endif ()
|
||||
|
||||
if (NOT Bluelib_${component}_LIBRARY)
|
||||
find_library(Bluelib_${component}_LIBRARY
|
||||
NAMES blue-${lib_name} ${Bluelib_FIND_ARGS}
|
||||
PATH_SUFFIXES lib
|
||||
PATHS ${Bluelib_SEARCH_PATHS})
|
||||
else ()
|
||||
# on Windows, ensure paths are in canonical format (forward slahes):
|
||||
file(TO_CMAKE_PATH "${Bluelib_${component}_LIBRARY}" Bluelib_${component}_LIBRARY)
|
||||
endif()
|
||||
|
||||
list(APPEND required_vars Bluelib_${component}_INCLUDE_DIR Bluelib_${component}_LIBRARY)
|
||||
endforeach (component)
|
||||
|
||||
unset(Bluelib_FIND_ARGS)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(Bluelib
|
||||
REQUIRED_VARS ${required_vars})
|
||||
|
||||
if (Bluelib_FOUND)
|
||||
set(created_targets)
|
||||
foreach (component ${components})
|
||||
string(TOLOWER ${component} header_name)
|
||||
set(lib_name ${header_name}${_lib_suffix})
|
||||
|
||||
if(NOT TARGET Bluelib::${component})
|
||||
add_library(Bluelib::${component} UNKNOWN IMPORTED)
|
||||
set_target_properties(Bluelib::${component} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Bluelib_${component}_INCLUDE_DIR}")
|
||||
target_compile_definitions(Bluelib::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
|
||||
|
||||
if (Bluelib_STATIC)
|
||||
target_compile_definitions(Bluelib::${component} INTERFACE BLUELIB_STATIC=1)
|
||||
endif ()
|
||||
|
||||
set_target_properties(Bluelib::${component} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${Bluelib_${component}_LIBRARY}")
|
||||
set(created_targets ${created_targets} ${component})
|
||||
endif ()
|
||||
endforeach (component)
|
||||
|
||||
foreach (component ${created_targets})
|
||||
if ("${component}" STREQUAL "Ds")
|
||||
if (NOT TARGET Bluelib::Core)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Ds' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(Bluelib::Ds INTERFACE Bluelib::Core)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Term")
|
||||
if (NOT TARGET Bluelib::Core)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET Bluelib::Ds)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(Bluelib::Term INTERFACE Bluelib::Core Bluelib::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Serial")
|
||||
if (NOT TARGET Bluelib::Core)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET Bluelib::Ds)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(Bluelib::Serial INTERFACE Bluelib::Core Bluelib::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Cmd")
|
||||
if (NOT TARGET Bluelib::Core)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET Bluelib::Ds)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET Bluelib::Term)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(Bluelib::Cmd INTERFACE Bluelib::Core Bluelib::Ds Bluelib::Term)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Io")
|
||||
if (NOT TARGET Bluelib::Core)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET Bluelib::Ds)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Io' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(Bluelib::Io INTERFACE Bluelib::Core Bluelib::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Compress")
|
||||
if (NOT TARGET Bluelib::Core)
|
||||
message(FATAL_ERROR "Bluelib: Module 'Compress' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(Bluelib::Compress INTERFACE Bluelib::Core Bluelib::Ds)
|
||||
endif ()
|
||||
endforeach (component)
|
||||
endif()
|
||||
@@ -0,0 +1,189 @@
|
||||
#[=======================================================================[.rst:
|
||||
FindFX
|
||||
------------
|
||||
|
||||
Find the FX library and header directories
|
||||
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module defines the following :prop_tgt:`IMPORTED` target:
|
||||
|
||||
``FX::FX``
|
||||
The FX library, if found
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This module will set the following variables in your project:
|
||||
|
||||
``FX_FOUND``
|
||||
true if the FX C headers and libraries were found
|
||||
``FX_INCLUDE_DIR``
|
||||
directories containing the FX C headers.
|
||||
|
||||
``FX_LIBRARY``
|
||||
the C library to link against
|
||||
|
||||
Hints
|
||||
^^^^^
|
||||
|
||||
The user may set the environment variable ``FX_PREFIX`` to the root
|
||||
directory of a FX library installation.
|
||||
#]=======================================================================]
|
||||
|
||||
set (FX_SEARCH_PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr/local/share
|
||||
/usr
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
${FX_PREFIX}
|
||||
$ENV{FX_PREFIX})
|
||||
|
||||
if (FX_STATIC)
|
||||
set(_lib_suffix "-s")
|
||||
endif ()
|
||||
|
||||
set(supported_components Core Ds Term Cmd Io Serial Compress)
|
||||
set(components ${FX_FIND_COMPONENTS})
|
||||
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
|
||||
|
||||
if (NOT components)
|
||||
set(components ${supported_components})
|
||||
endif ()
|
||||
|
||||
set(required_vars)
|
||||
|
||||
foreach (component ${components})
|
||||
if (NOT "${component}" IN_LIST supported_components)
|
||||
message(FATAL_ERROR "'${component}' is not a valid FX module.\nSupported modules: ${supported_components_string_list}")
|
||||
endif ()
|
||||
|
||||
string(TOLOWER ${component} header_name)
|
||||
set(lib_name ${header_name}${_lib_suffix})
|
||||
|
||||
if (NOT FX_${component}_INCLUDE_DIR)
|
||||
find_path(FX_${component}_INCLUDE_DIR
|
||||
NAMES fx/${header_name}.h ${FX_FIND_ARGS}
|
||||
PATH_SUFFIXES include
|
||||
PATHS ${FX_SEARCH_PATHS})
|
||||
endif ()
|
||||
|
||||
if (NOT FX_${component}_LIBRARY)
|
||||
find_library(FX_${component}_LIBRARY
|
||||
NAMES fx-${lib_name} ${FX_FIND_ARGS}
|
||||
PATH_SUFFIXES lib
|
||||
PATHS ${FX_SEARCH_PATHS})
|
||||
else ()
|
||||
# on Windows, ensure paths are in canonical format (forward slahes):
|
||||
file(TO_CMAKE_PATH "${FX_${component}_LIBRARY}" FX_${component}_LIBRARY)
|
||||
endif()
|
||||
|
||||
list(APPEND required_vars FX_${component}_INCLUDE_DIR FX_${component}_LIBRARY)
|
||||
endforeach (component)
|
||||
|
||||
unset(FX_FIND_ARGS)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(FX
|
||||
REQUIRED_VARS ${required_vars})
|
||||
|
||||
if (FX_FOUND)
|
||||
set(created_targets)
|
||||
foreach (component ${components})
|
||||
string(TOLOWER ${component} header_name)
|
||||
set(lib_name ${header_name}${_lib_suffix})
|
||||
|
||||
if(NOT TARGET FX::${component})
|
||||
add_library(FX::${component} UNKNOWN IMPORTED)
|
||||
set_target_properties(FX::${component} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${FX_${component}_INCLUDE_DIR}")
|
||||
target_compile_definitions(FX::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
|
||||
|
||||
if (FX_STATIC)
|
||||
target_compile_definitions(FX::${component} INTERFACE FX_STATIC=1)
|
||||
endif ()
|
||||
|
||||
set_target_properties(FX::${component} PROPERTIES
|
||||
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
|
||||
IMPORTED_LOCATION "${FX_${component}_LIBRARY}")
|
||||
set(created_targets ${created_targets} ${component})
|
||||
endif ()
|
||||
endforeach (component)
|
||||
|
||||
foreach (component ${created_targets})
|
||||
if ("${component}" STREQUAL "Ds")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Ds' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Ds INTERFACE FX::Core)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Term")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Term' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Term' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Term INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Serial")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Serial INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Cmd")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Term)
|
||||
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Cmd INTERFACE FX::Core FX::Ds FX::Term)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Io")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Io' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET FX::Ds)
|
||||
message(FATAL_ERROR "FX: Module 'Io' depends on 'Ds', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Io INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
|
||||
if ("${component}" STREQUAL "Compress")
|
||||
if (NOT TARGET FX::Core)
|
||||
message(FATAL_ERROR "FX: Module 'Compress' depends on 'Core', which was not specified in find_package()")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(FX::Compress INTERFACE FX::Core FX::Ds)
|
||||
endif ()
|
||||
endforeach (component)
|
||||
endif()
|
||||
+35
-33
@@ -1,4 +1,4 @@
|
||||
function(add_bluelib_module)
|
||||
function(add_fx_module)
|
||||
set(options)
|
||||
set(one_value_args NAME)
|
||||
set(multi_value_args
|
||||
@@ -22,86 +22,88 @@ function(add_bluelib_module)
|
||||
set(sources ${sources} ${dir_sources})
|
||||
endforeach (dir)
|
||||
|
||||
file(GLOB sys_sources sys/${b_system_name}/*.c sys/${b_system_name}/*.h)
|
||||
set(root_header include/blue/${module_name}.h)
|
||||
file(GLOB headers include/blue/${module_name}/*.h)
|
||||
file(GLOB sys_sources sys/${fx_system_name}/*.c sys/${fx_system_name}/*.h)
|
||||
set(root_header include/fx/${module_name}.h)
|
||||
file(GLOB headers include/fx/${module_name}/*.h)
|
||||
|
||||
string(REPLACE "-" "_" module_preproc_token ${module_name})
|
||||
string(TOUPPER ${module_preproc_token} module_preproc_token)
|
||||
set(module_preproc_token BLUELIB_${module_preproc_token})
|
||||
set(module_preproc_token FX_${module_preproc_token})
|
||||
|
||||
message(STATUS "Building module ${module_name} (shared)")
|
||||
add_library(blue-${module_name} SHARED
|
||||
add_library(fx-${module_name} SHARED
|
||||
${sources}
|
||||
${sys_sources}
|
||||
${root_header}
|
||||
${headers}
|
||||
${arg_EXTRA_SOURCES})
|
||||
message(STATUS "Building module ${module_name} (static)")
|
||||
add_library(blue-${module_name}-s STATIC
|
||||
add_library(fx-${module_name}-s STATIC
|
||||
${sources}
|
||||
${sys_sources}
|
||||
${root_header}
|
||||
${headers}
|
||||
${arg_EXTRA_SOURCES})
|
||||
|
||||
target_include_directories(blue-${module_name} PUBLIC include/)
|
||||
target_include_directories(blue-${module_name}-s PUBLIC include/)
|
||||
target_include_directories(fx-${module_name} PUBLIC include/)
|
||||
target_include_directories(fx-${module_name}-s PUBLIC include/)
|
||||
|
||||
target_compile_definitions(blue-${module_name} PUBLIC
|
||||
target_compile_definitions(fx-${module_name} PUBLIC
|
||||
${module_preproc_token}
|
||||
BLUELIB_EXPORT=1)
|
||||
target_compile_definitions(blue-${module_name}-s PUBLIC
|
||||
FX_EXPORT=1
|
||||
FX_ENABLE_FLOATING_POINT=${fx_enable_floating_point})
|
||||
target_compile_definitions(fx-${module_name}-s PUBLIC
|
||||
${module_preproc_token}
|
||||
BLUELIB_EXPORT=1
|
||||
BLUELIB_STATIC=1)
|
||||
FX_EXPORT=1
|
||||
FX_STATIC=1
|
||||
FX_ENABLE_FLOATING_POINT=${fx_enable_floating_point})
|
||||
|
||||
set_target_properties(blue-${module_name}
|
||||
set_target_properties(fx-${module_name}
|
||||
PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
foreach (dep ${arg_DEPENDENCIES})
|
||||
target_link_libraries(blue-${module_name} blue-${dep})
|
||||
target_link_libraries(blue-${module_name}-s blue-${dep}-s)
|
||||
target_link_libraries(fx-${module_name} fx-${dep})
|
||||
target_link_libraries(fx-${module_name}-s fx-${dep}-s)
|
||||
endforeach (dep)
|
||||
|
||||
foreach (lib ${arg_LIBS})
|
||||
target_link_libraries(blue-${module_name} ${lib})
|
||||
target_link_libraries(blue-${module_name}-s ${lib})
|
||||
target_link_libraries(fx-${module_name} ${lib})
|
||||
target_link_libraries(fx-${module_name}-s ${lib})
|
||||
endforeach (lib)
|
||||
|
||||
foreach (dir ${arg_INCLUDE_DIRS})
|
||||
target_include_directories(blue-${module_name} PRIVATE
|
||||
target_include_directories(fx-${module_name} PRIVATE
|
||||
${dir})
|
||||
target_include_directories(blue-${module_name}-s PRIVATE
|
||||
target_include_directories(fx-${module_name}-s PRIVATE
|
||||
${dir})
|
||||
endforeach (dir)
|
||||
|
||||
foreach (def ${arg_DEFINES})
|
||||
target_compile_definitions(blue-${module_name} PRIVATE
|
||||
target_compile_definitions(fx-${module_name} PRIVATE
|
||||
${def})
|
||||
target_compile_definitions(blue-${module_name}-s PRIVATE
|
||||
target_compile_definitions(fx-${module_name}-s PRIVATE
|
||||
${def})
|
||||
endforeach (def)
|
||||
|
||||
set_target_properties(blue-${module_name} PROPERTIES
|
||||
set_target_properties(fx-${module_name} PROPERTIES
|
||||
FOLDER "Shared/${module_name}")
|
||||
set_target_properties(blue-${module_name}-s PROPERTIES
|
||||
set_target_properties(fx-${module_name}-s PROPERTIES
|
||||
FOLDER "Static/${module_name}")
|
||||
|
||||
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||
if(IS_BIG_ENDIAN)
|
||||
target_compile_definitions(blue-${module_name} PRIVATE
|
||||
target_compile_definitions(fx-${module_name} PRIVATE
|
||||
BIG_ENDIAN)
|
||||
target_compile_definitions(blue-${module_name}-s PRIVATE
|
||||
target_compile_definitions(fx-${module_name}-s PRIVATE
|
||||
BIG_ENDIAN)
|
||||
else()
|
||||
target_compile_definitions(blue-${module_name} PRIVATE
|
||||
target_compile_definitions(fx-${module_name} PRIVATE
|
||||
LITTLE_ENDIAN)
|
||||
target_compile_definitions(blue-${module_name}-s PRIVATE
|
||||
target_compile_definitions(fx-${module_name}-s PRIVATE
|
||||
LITTLE_ENDIAN)
|
||||
endif()
|
||||
|
||||
install(TARGETS blue-${module_name} blue-${module_name}-s)
|
||||
install(FILES ${root_header} DESTINATION include/blue)
|
||||
install(FILES ${headers} DESTINATION include/blue/${module_name})
|
||||
endfunction(add_bluelib_module)
|
||||
install(TARGETS fx-${module_name} fx-${module_name}-s)
|
||||
install(FILES ${root_header} DESTINATION include/fx)
|
||||
install(FILES ${headers} DESTINATION include/fx/${module_name})
|
||||
endfunction(add_fx_module)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
include(../cmake/Templates.cmake)
|
||||
|
||||
add_bluelib_module(NAME cmd DEPENDENCIES core ds term)
|
||||
-1050
File diff suppressed because it is too large
Load Diff
-1076
File diff suppressed because it is too large
Load Diff
-151
@@ -1,151 +0,0 @@
|
||||
#ifndef _B_COMMAND_H_
|
||||
#define _B_COMMAND_H_
|
||||
|
||||
#include <blue/cmd.h>
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/ds/string.h>
|
||||
|
||||
#define F_RED "[bright_red]"
|
||||
#define F_GREEN "[bright_green]"
|
||||
#define F_YELLOW "[bright_yellow]"
|
||||
|
||||
#define F_RED_BOLD "[bright_red,bold]"
|
||||
#define F_GREEN_BOLD "[bright_green,bold]"
|
||||
#define F_YELLOW_BOLD "[bright_yellow,bold]"
|
||||
#define F_RESET "[reset]"
|
||||
|
||||
enum cmd_string_flags {
|
||||
CMD_STR_COLOUR = 0x01u,
|
||||
CMD_STR_DIRECT_USAGE = 0x02u,
|
||||
};
|
||||
|
||||
enum b_command_usage_entry_type {
|
||||
CMD_USAGE_NONE = 0,
|
||||
CMD_USAGE_ARG,
|
||||
CMD_USAGE_OPT,
|
||||
CMD_USAGE_COMMAND,
|
||||
};
|
||||
|
||||
struct b_command {
|
||||
unsigned int b_id;
|
||||
unsigned int b_parent_id;
|
||||
struct b_command *b_parent;
|
||||
enum b_command_flags b_flags;
|
||||
|
||||
char *b_name;
|
||||
char *b_long_name;
|
||||
char b_short_name;
|
||||
char *b_description;
|
||||
struct b_queue b_opt;
|
||||
struct b_queue b_arg;
|
||||
struct b_queue b_subcommands;
|
||||
struct b_queue b_usage;
|
||||
|
||||
b_command_callback b_callback;
|
||||
struct b_queue_entry b_entry;
|
||||
struct b_btree_node b_node;
|
||||
};
|
||||
|
||||
struct b_command_usage_entry {
|
||||
struct b_queue_entry e_entry;
|
||||
enum b_command_usage_entry_type e_type;
|
||||
|
||||
union {
|
||||
struct b_command_option *e_opt;
|
||||
struct b_command_arg *e_arg;
|
||||
unsigned int e_cmd_id;
|
||||
};
|
||||
};
|
||||
|
||||
struct b_command_usage {
|
||||
b_command_usage_flags u_flags;
|
||||
struct b_queue_entry u_entry;
|
||||
|
||||
struct b_queue u_parts;
|
||||
};
|
||||
|
||||
struct b_command_option {
|
||||
unsigned int opt_id;
|
||||
|
||||
char *opt_long_name;
|
||||
char opt_short_name;
|
||||
char *opt_description;
|
||||
|
||||
// b_command_arg_value_count arg_nr_values;
|
||||
// char **arg_allowed_values;
|
||||
|
||||
struct b_queue opt_args;
|
||||
struct b_queue_entry opt_entry;
|
||||
};
|
||||
|
||||
struct b_command_arg {
|
||||
unsigned int arg_id;
|
||||
char *arg_name;
|
||||
char *arg_description;
|
||||
|
||||
b_command_arg_value_count arg_nr_values;
|
||||
char **arg_allowed_values;
|
||||
|
||||
struct b_queue_entry arg_entry;
|
||||
};
|
||||
|
||||
struct b_arglist_option {
|
||||
unsigned int opt_id;
|
||||
struct b_btree opt_values;
|
||||
struct b_btree_node opt_node;
|
||||
};
|
||||
|
||||
struct b_arglist {
|
||||
size_t list_argc;
|
||||
const char **list_argv;
|
||||
unsigned int list_argv_last_command;
|
||||
struct b_command *list_command;
|
||||
struct b_btree list_options;
|
||||
};
|
||||
|
||||
BLUE_API struct b_command *b_command_get_subcommand_with_name(
|
||||
struct b_command *cmd, const char *name);
|
||||
BLUE_API struct b_command *b_command_get_subcommand_with_long_name(
|
||||
struct b_command *cmd, const char *long_name);
|
||||
BLUE_API struct b_command *b_command_get_subcommand_with_short_name(
|
||||
struct b_command *cmd, char short_name);
|
||||
|
||||
BLUE_API struct b_command_option *b_command_get_option_with_long_name(
|
||||
struct b_command *cmd, const char *long_name);
|
||||
BLUE_API struct b_command_option *b_command_get_option_with_short_name(
|
||||
struct b_command *cmd, char short_name);
|
||||
BLUE_API struct b_command_option *b_command_get_option_with_id(
|
||||
struct b_command *cmd, unsigned int id);
|
||||
BLUE_API struct b_command_arg *b_command_get_arg_with_id(
|
||||
struct b_command *cmd, unsigned int id);
|
||||
|
||||
BLUE_API struct b_command_arg *b_command_option_get_arg_with_id(
|
||||
struct b_command_option *opt, unsigned int id);
|
||||
|
||||
BLUE_API struct b_command_option *b_command_option_create(void);
|
||||
BLUE_API void b_command_option_destroy(struct b_command_option *opt);
|
||||
|
||||
BLUE_API struct b_command_arg *b_command_arg_create(void);
|
||||
BLUE_API void b_command_arg_destroy(struct b_command_arg *arg);
|
||||
|
||||
BLUE_API struct b_arglist *b_arglist_create(void);
|
||||
BLUE_API b_status b_arglist_parse(
|
||||
struct b_arglist *args, struct b_command **cmd, int argc,
|
||||
const char **argv);
|
||||
BLUE_API void b_arglist_destroy(struct b_arglist *args);
|
||||
|
||||
BLUE_API b_string *z__b_command_default_usage_string(
|
||||
struct b_command *cmd, struct b_command_option *with_opt,
|
||||
const struct b_arglist *args);
|
||||
|
||||
BLUE_API void z__b_get_arg_usage_string(
|
||||
struct b_command_arg *arg, bool colour, b_string *out);
|
||||
BLUE_API void z__b_get_arg_description(struct b_command_arg *arg, b_string *out);
|
||||
|
||||
BLUE_API void z__b_get_option_usage_string(
|
||||
struct b_command_option *opt, enum cmd_string_flags flags, b_string *out);
|
||||
BLUE_API void z__b_get_option_description(
|
||||
struct b_command_option *opt, b_string *out);
|
||||
|
||||
#endif
|
||||
@@ -1,289 +0,0 @@
|
||||
#ifndef BLUE_CMD_H_
|
||||
#define BLUE_CMD_H_
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/init.h>
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/ds/array.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define b_arglist_foreach(it, q) \
|
||||
for (int z__b_unique_name() = b_arglist_iterator_begin( \
|
||||
q, B_COMMAND_INVALID_ID, B_COMMAND_INVALID_ID, (it)); \
|
||||
b_arglist_iterator_is_valid(it); b_arglist_iterator_next(it))
|
||||
|
||||
#define b_arglist_foreach_filtered(it, q, opt_id, arg_id) \
|
||||
for (int z__b_unique_name() \
|
||||
= b_arglist_iterator_begin(q, opt_id, arg_id, (it)); \
|
||||
b_arglist_iterator_is_valid(it); b_arglist_iterator_next(it))
|
||||
|
||||
#define b_arglist_option_foreach(it, q) \
|
||||
for (int z__b_unique_name() \
|
||||
= b_arglist_option_iterator_begin(q, B_COMMAND_INVALID_ID, (it)); \
|
||||
b_arglist_option_iterator_is_valid(it); \
|
||||
b_arglist_option_iterator_next(it))
|
||||
|
||||
#define b_arglist_option_foreach_filtered(it, q, opt_id) \
|
||||
for (int z__b_unique_name() \
|
||||
= b_arglist_option_iterator_begin(q, opt_id, (it)); \
|
||||
b_arglist_option_iterator_is_valid(it); \
|
||||
b_arglist_option_iterator_next(it))
|
||||
|
||||
#define B_COMMAND(id, parent_id) \
|
||||
static b_command *command_##id = NULL; \
|
||||
static void __init_##id( \
|
||||
b_command *, b_command_option *, b_command_arg *, \
|
||||
b_command_usage *); \
|
||||
B_INIT(init_##id) \
|
||||
{ \
|
||||
command_##id = b_command_create(id); \
|
||||
if ((parent_id) != B_COMMAND_INVALID_ID) { \
|
||||
b_command_set_parent(command_##id, parent_id); \
|
||||
} \
|
||||
__init_##id(command_##id, NULL, NULL, NULL); \
|
||||
b_command_register(command_##id); \
|
||||
} \
|
||||
static void __init_##id( \
|
||||
b_command *this_cmd, b_command_option *this_opt, \
|
||||
b_command_arg *this_arg, b_command_usage *this_usage)
|
||||
|
||||
#define B_COMMAND_NAME(name) b_command_set_name(this_cmd, (name))
|
||||
#define B_COMMAND_LONG_NAME(name) b_command_set_long_name(this_cmd, (name))
|
||||
#define B_COMMAND_SHORT_NAME(name) b_command_set_short_name(this_cmd, (name))
|
||||
#define B_COMMAND_DESC(desc) b_command_set_description(this_cmd, (desc))
|
||||
#define B_COMMAND_FLAGS(flags) b_command_set_flags(this_cmd, (flags))
|
||||
#define B_COMMAND_FUNCTION(fn) b_command_set_callback(this_cmd, (fn))
|
||||
|
||||
#define B_COMMAND_OPTION(id) \
|
||||
b_command_option *opt_##id = b_command_add_option(this_cmd, (id)); \
|
||||
this_opt = opt_##id; \
|
||||
if (this_opt)
|
||||
|
||||
#define B_COMMAND_OPTION_GEN(id) \
|
||||
b_command_option *z__b_unique_name() \
|
||||
= b_command_add_option(this_cmd, (id)); \
|
||||
this_opt = z__b_unique_name(); \
|
||||
if (this_opt)
|
||||
|
||||
#define B_COMMAND_HELP_OPTION() \
|
||||
do { \
|
||||
b_command_option *opt \
|
||||
= b_command_add_option(this_cmd, B_COMMAND_OPTION_HELP); \
|
||||
b_command_option_set_description(opt, "Show this help message"); \
|
||||
b_command_option_set_short_name(opt, 'h'); \
|
||||
b_command_option_set_long_name(opt, "help"); \
|
||||
} while (0)
|
||||
|
||||
#define B_OPTION_LONG_NAME(name) \
|
||||
b_command_option_set_long_name(this_opt, (name))
|
||||
|
||||
#define B_OPTION_SHORT_NAME(name) \
|
||||
b_command_option_set_short_name(this_opt, (name))
|
||||
|
||||
#define B_OPTION_DESC(desc) b_command_option_set_description(this_opt, (desc))
|
||||
|
||||
#define B_OPTION_ARG(id) \
|
||||
b_command_arg *arg_##id = b_command_option_add_arg(this_opt, (id)); \
|
||||
this_arg = arg_##id; \
|
||||
if (this_arg)
|
||||
|
||||
#define B_COMMAND_ARG(id) \
|
||||
b_command_arg *arg_##id = b_command_add_arg(this_cmd, (id)); \
|
||||
this_arg = arg_##id; \
|
||||
if (this_arg)
|
||||
|
||||
#define B_ARG_NAME(name) b_command_arg_set_name(this_arg, (name))
|
||||
|
||||
#define B_ARG_DESC(desc) b_command_arg_set_description(this_arg, (desc))
|
||||
|
||||
#define B_ARG_NR_VALUES(nr_values) \
|
||||
b_command_arg_set_nr_values(this_arg, (nr_values))
|
||||
|
||||
#define B_ARG_ALLOWED_VALUES(...) \
|
||||
static const char *allowed_values[] = { \
|
||||
__VA_ARGS__, \
|
||||
NULL, \
|
||||
}; \
|
||||
b_command_arg_set_allowed_values(this_arg, allowed_values)
|
||||
|
||||
#define B_COMMAND_USAGE() \
|
||||
b_command_usage *z__b_unique_name() = b_command_add_usage(this_cmd); \
|
||||
this_usage = z__b_unique_name(); \
|
||||
if (this_usage)
|
||||
|
||||
#define B_COMMAND_USAGE_COMMAND(cmd_id) \
|
||||
b_command_usage_add_command(this_usage, cmd_id)
|
||||
|
||||
#define B_COMMAND_USAGE_COMMAND_PLACEHOLDER() \
|
||||
b_command_usage_add_command(this_usage, B_COMMAND_INVALID_ID)
|
||||
|
||||
#define B_COMMAND_USAGE_OPT(opt_id) \
|
||||
b_command_usage_add_option(this_usage, opt_##opt_id)
|
||||
|
||||
#define B_COMMAND_USAGE_OPT_PLACEHOLDER() \
|
||||
b_command_usage_add_option(this_usage, NULL)
|
||||
|
||||
#define B_COMMAND_USAGE_ARG(opt_id) \
|
||||
b_command_usage_add_arg(this_usage, arg_##opt_id)
|
||||
|
||||
#define B_COMMAND_USAGE_ARG_PLACEHOLDER() \
|
||||
b_command_usage_add_arg(this_usage, NULL)
|
||||
|
||||
#define B_COMMAND_OPTION_HELP ((uintptr_t)0xF0000001)
|
||||
#define B_COMMAND_INVALID_ID ((uintptr_t)0xFFFFFFFF)
|
||||
|
||||
typedef enum b_command_arg_value_count {
|
||||
B_ARG_0_OR_1_VALUES = -1,
|
||||
B_ARG_0_OR_MORE_VALUES = -2,
|
||||
B_ARG_1_OR_MORE_VALUES = -3,
|
||||
} b_command_arg_value_count;
|
||||
|
||||
typedef enum b_command_arg_type {
|
||||
B_COMMAND_ARG_NONE = 0,
|
||||
B_COMMAND_ARG_STRING,
|
||||
B_COMMAND_ARG_SIGNED_INT,
|
||||
B_COMMAND_ARG_UNSIGNED_INT,
|
||||
|
||||
B_COMMAND_ARG_INT = B_COMMAND_ARG_SIGNED_INT,
|
||||
} b_command_arg_type;
|
||||
|
||||
typedef enum b_command_flags {
|
||||
B_COMMAND_SHOW_HELP_BY_DEFAULT = 0x01u,
|
||||
} b_command_flags;
|
||||
|
||||
typedef enum b_command_usage_flags {
|
||||
B_COMMAND_USAGE_SHOW_OPTIONS = 0x01u,
|
||||
} b_command_usage_flags;
|
||||
|
||||
typedef struct b_arglist_value {
|
||||
unsigned int val_id;
|
||||
b_command_arg_type val_type;
|
||||
struct b_btree_node val_node;
|
||||
|
||||
union {
|
||||
char *val_str;
|
||||
long long val_int;
|
||||
unsigned long long val_uint;
|
||||
};
|
||||
} b_arglist_value;
|
||||
|
||||
typedef struct b_arglist_iterator {
|
||||
size_t i;
|
||||
|
||||
unsigned int opt_id;
|
||||
struct b_arglist_value *value;
|
||||
|
||||
b_btree_node *_opt_it, *_arg_it;
|
||||
unsigned int _opt_filter, _arg_filter;
|
||||
} b_arglist_iterator;
|
||||
|
||||
typedef struct b_arglist_option_iterator {
|
||||
size_t i;
|
||||
|
||||
unsigned int opt_id;
|
||||
struct b_arglist_option *opt;
|
||||
|
||||
b_btree_node *_opt_it;
|
||||
unsigned int _opt_filter;
|
||||
} b_arglist_option_iterator;
|
||||
|
||||
typedef struct b_command b_command;
|
||||
typedef struct b_command_option b_command_option;
|
||||
typedef struct b_command_arg b_command_arg;
|
||||
typedef struct b_command_usage b_command_usage;
|
||||
typedef struct b_arglist b_arglist;
|
||||
typedef struct b_arglist_option b_arglist_option;
|
||||
|
||||
typedef int (*b_command_callback)(
|
||||
const b_command *, const b_arglist *, const b_array *);
|
||||
|
||||
BLUE_API b_command *b_command_create(unsigned int id);
|
||||
BLUE_API void b_command_destroy(b_command *cmd);
|
||||
BLUE_API b_status b_command_register(b_command *cmd);
|
||||
BLUE_API int b_command_dispatch(unsigned int cmd_id, int argc, const char **argv);
|
||||
|
||||
BLUE_API b_status b_command_set_name(b_command *cmd, const char *name);
|
||||
BLUE_API b_status b_command_set_long_name(b_command *cmd, const char *name);
|
||||
BLUE_API b_status b_command_set_short_name(b_command *cmd, char name);
|
||||
BLUE_API b_status b_command_set_flags(b_command *cmd, b_command_flags flags);
|
||||
BLUE_API b_status b_command_set_description(b_command *cmd, const char *description);
|
||||
BLUE_API b_status b_command_set_callback(
|
||||
b_command *cmd, b_command_callback callback);
|
||||
BLUE_API b_status b_command_set_parent(b_command *cmd, unsigned int parent_id);
|
||||
BLUE_API b_command_option *b_command_add_option(b_command *cmd, int id);
|
||||
BLUE_API b_command_arg *b_command_add_arg(b_command *cmd, int id);
|
||||
BLUE_API b_command_usage *b_command_add_usage(b_command *cmd);
|
||||
|
||||
BLUE_API const b_command_option *b_command_get_option(const b_command *cmd, int id);
|
||||
|
||||
BLUE_API const char *b_command_option_get_long_name(const b_command_option *opt);
|
||||
BLUE_API char b_command_option_get_short_name(const b_command_option *opt);
|
||||
BLUE_API const char *b_command_option_get_description(b_command_option *opt);
|
||||
BLUE_API b_status b_command_option_set_long_name(
|
||||
b_command_option *opt, const char *name);
|
||||
BLUE_API b_status b_command_option_set_short_name(b_command_option *opt, char name);
|
||||
BLUE_API b_status b_command_option_set_description(
|
||||
b_command_option *opt, const char *description);
|
||||
BLUE_API b_command_arg *b_command_option_add_arg(b_command_option *opt, int id);
|
||||
|
||||
BLUE_API b_status b_command_arg_set_name(b_command_arg *arg, const char *name);
|
||||
BLUE_API b_status b_command_arg_set_description(
|
||||
b_command_arg *arg, const char *description);
|
||||
BLUE_API b_status b_command_arg_set_nr_values(
|
||||
b_command_arg *arg, b_command_arg_value_count nr_values);
|
||||
BLUE_API b_status b_command_arg_set_allowed_values(
|
||||
b_command_arg *arg, const char **allowed_values);
|
||||
|
||||
BLUE_API b_status b_command_usage_add_option(
|
||||
b_command_usage *usage, b_command_option *opt);
|
||||
BLUE_API b_status b_command_usage_add_arg(
|
||||
b_command_usage *usage, b_command_arg *opt);
|
||||
BLUE_API b_status b_command_usage_add_command(
|
||||
b_command_usage *usage, unsigned int cmd_id);
|
||||
|
||||
BLUE_API b_status b_arglist_get_string(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
unsigned int index, const char **out);
|
||||
BLUE_API b_status b_arglist_get_int(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
unsigned int index, long long *out);
|
||||
BLUE_API b_status b_arglist_get_uint(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
unsigned int index, unsigned long long *out);
|
||||
BLUE_API b_status b_arglist_get_option(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int index,
|
||||
b_arglist_option **out);
|
||||
BLUE_API size_t b_arglist_get_count(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id);
|
||||
|
||||
BLUE_API b_status b_arglist_report_missing_option(
|
||||
const b_arglist *args, unsigned int opt_id);
|
||||
BLUE_API b_status b_arglist_report_unexpected_arg(
|
||||
const b_arglist *args, const char *value);
|
||||
BLUE_API b_status b_arglist_report_invalid_arg_value(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
const char *value);
|
||||
BLUE_API b_status b_arglist_report_missing_args(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
size_t nr_supplied);
|
||||
|
||||
BLUE_API b_status b_arglist_option_get_value(
|
||||
const b_arglist_option *opt, unsigned int arg_id, unsigned int index,
|
||||
b_arglist_value **out);
|
||||
|
||||
BLUE_API int b_arglist_iterator_begin(
|
||||
const b_arglist *args, unsigned int opt_filter, unsigned int arg_filter,
|
||||
b_arglist_iterator *it);
|
||||
BLUE_API bool b_arglist_iterator_next(b_arglist_iterator *it);
|
||||
BLUE_API bool b_arglist_iterator_is_valid(const b_arglist_iterator *it);
|
||||
|
||||
BLUE_API int b_arglist_option_iterator_begin(
|
||||
const b_arglist *args, unsigned int opt_filter,
|
||||
b_arglist_option_iterator *it);
|
||||
BLUE_API bool b_arglist_option_iterator_next(b_arglist_option_iterator *it);
|
||||
BLUE_API bool b_arglist_option_iterator_is_valid(
|
||||
const b_arglist_option_iterator *it);
|
||||
|
||||
#endif
|
||||
-273
@@ -1,273 +0,0 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct b_command_option *b_command_option_create(void)
|
||||
{
|
||||
struct b_command_option *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void b_command_option_destroy(struct b_command_option *opt)
|
||||
{
|
||||
if (opt->opt_long_name) {
|
||||
free(opt->opt_long_name);
|
||||
}
|
||||
|
||||
if (opt->opt_description) {
|
||||
free(opt->opt_description);
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
struct b_queue_entry *next = b_queue_next(entry);
|
||||
b_queue_delete(&opt->opt_args, entry);
|
||||
|
||||
b_command_arg_destroy(arg);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
free(opt);
|
||||
}
|
||||
|
||||
const char *b_command_option_get_long_name(const struct b_command_option *opt)
|
||||
{
|
||||
return opt->opt_long_name;
|
||||
}
|
||||
|
||||
char b_command_option_get_short_name(const struct b_command_option *opt)
|
||||
{
|
||||
return opt->opt_short_name;
|
||||
}
|
||||
|
||||
const char *b_command_option_get_description(struct b_command_option *opt)
|
||||
{
|
||||
return opt->opt_description;
|
||||
}
|
||||
|
||||
b_status b_command_option_set_long_name(
|
||||
struct b_command_option *opt, const char *name)
|
||||
{
|
||||
char *n = b_strdup(name);
|
||||
if (!n) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (opt->opt_long_name) {
|
||||
free(opt->opt_long_name);
|
||||
opt->opt_long_name = NULL;
|
||||
}
|
||||
|
||||
opt->opt_long_name = n;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_command_option_set_short_name(struct b_command_option *opt, char name)
|
||||
{
|
||||
opt->opt_short_name = name;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_command_option_set_description(
|
||||
struct b_command_option *opt, const char *description)
|
||||
{
|
||||
char *desc = b_strdup(description);
|
||||
if (!desc) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (opt->opt_description) {
|
||||
free(opt->opt_description);
|
||||
opt->opt_description = NULL;
|
||||
}
|
||||
|
||||
opt->opt_description = desc;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
struct b_command_arg *b_command_option_add_arg(struct b_command_option *opt, int id)
|
||||
{
|
||||
struct b_command_arg *arg = malloc(sizeof *arg);
|
||||
if (!arg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(arg, 0x0, sizeof *arg);
|
||||
|
||||
arg->arg_id = id;
|
||||
|
||||
b_queue_push_back(&opt->opt_args, &arg->arg_entry);
|
||||
return arg;
|
||||
}
|
||||
|
||||
void z__b_get_option_description(struct b_command_option *opt, b_string *out)
|
||||
{
|
||||
if (opt->opt_description) {
|
||||
b_string_append_cstr(out, opt->opt_description);
|
||||
}
|
||||
|
||||
size_t nr_args = b_queue_length(&opt->opt_args);
|
||||
bool close_bracket = false;
|
||||
|
||||
size_t i = 0;
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
if (!arg || !arg->arg_allowed_values) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
b_string_append_cstr(out, "; ");
|
||||
} else {
|
||||
b_string_append_cstr(out, " [[");
|
||||
close_bracket = true;
|
||||
}
|
||||
|
||||
if (nr_args > 1) {
|
||||
b_string_append_cstrf(
|
||||
out, "values for `%s`:", arg->arg_name);
|
||||
} else {
|
||||
b_string_append_cstr(out, "values:");
|
||||
}
|
||||
|
||||
for (size_t i = 0; arg->arg_allowed_values[i]; i++) {
|
||||
if (i > 0) {
|
||||
b_string_append_cstr(out, ",");
|
||||
}
|
||||
|
||||
b_string_append_cstrf(
|
||||
out, " " F_GREEN "%s" F_RESET,
|
||||
arg->arg_allowed_values[i]);
|
||||
}
|
||||
|
||||
skip:
|
||||
i++;
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
if (close_bracket) {
|
||||
b_string_append_cstr(out, "]");
|
||||
}
|
||||
}
|
||||
|
||||
void z__b_get_option_usage_string(
|
||||
struct b_command_option *opt, enum cmd_string_flags flags, b_string *out)
|
||||
{
|
||||
if (flags & CMD_STR_DIRECT_USAGE) {
|
||||
b_string_append_cstr(out, "{");
|
||||
}
|
||||
|
||||
if (opt->opt_short_name) {
|
||||
b_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? F_GREEN "-%c" F_RESET : "-%c",
|
||||
opt->opt_short_name);
|
||||
}
|
||||
|
||||
if (opt->opt_short_name && opt->opt_long_name) {
|
||||
b_string_append_cstr(
|
||||
out, (flags & CMD_STR_DIRECT_USAGE) ? "|" : ", ");
|
||||
}
|
||||
|
||||
if (opt->opt_long_name) {
|
||||
b_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? F_GREEN "--%s" F_RESET : "--%s",
|
||||
opt->opt_long_name);
|
||||
}
|
||||
|
||||
if (flags & CMD_STR_DIRECT_USAGE) {
|
||||
b_string_append_cstr(out, "}");
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
if (!arg) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
bool optional = false, multi = false;
|
||||
switch (arg->arg_nr_values) {
|
||||
case B_ARG_0_OR_1_VALUES:
|
||||
optional = true;
|
||||
multi = false;
|
||||
break;
|
||||
case B_ARG_0_OR_MORE_VALUES:
|
||||
optional = true;
|
||||
multi = true;
|
||||
break;
|
||||
case B_ARG_1_OR_MORE_VALUES:
|
||||
optional = false;
|
||||
multi = true;
|
||||
break;
|
||||
default:
|
||||
optional = false;
|
||||
multi = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (optional) {
|
||||
b_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? " " F_GREEN "[%s]"
|
||||
: " [%s]",
|
||||
arg->arg_name);
|
||||
} else {
|
||||
b_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? " " F_GREEN "<%s>"
|
||||
: " <%s>",
|
||||
arg->arg_name);
|
||||
}
|
||||
|
||||
for (int i = 1; i < arg->arg_nr_values; i++) {
|
||||
b_string_append_cstrf(out, " <%s>", arg->arg_name);
|
||||
}
|
||||
|
||||
if (multi) {
|
||||
b_string_append_cstr(out, "...");
|
||||
}
|
||||
|
||||
if (flags & CMD_STR_COLOUR) {
|
||||
b_string_append_cstr(out, F_RESET);
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
}
|
||||
|
||||
struct b_command_arg *b_command_option_get_arg_with_id(
|
||||
struct b_command_option *opt, unsigned int id)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_first(&opt->opt_args);
|
||||
|
||||
while (entry) {
|
||||
struct b_command_arg *arg
|
||||
= b_unbox(struct b_command_arg, entry, arg_entry);
|
||||
|
||||
if (arg->arg_id == id) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <blue/core/stringstream.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <blue/term/print.h>
|
||||
#include <stdio.h>
|
||||
|
||||
enum b_status b_arglist_report_missing_option(
|
||||
const b_arglist *args, unsigned int opt_id)
|
||||
{
|
||||
struct b_command_option *opt = NULL;
|
||||
|
||||
if (opt_id != B_COMMAND_INVALID_ID) {
|
||||
opt = b_command_get_option_with_id(args->list_command, opt_id);
|
||||
}
|
||||
|
||||
if (!opt) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
b_string *opt_string = b_string_create();
|
||||
z__b_get_option_usage_string(opt, 0, opt_string);
|
||||
|
||||
b_stringstream *opt_name = b_stringstream_create();
|
||||
|
||||
int opt_names = 0;
|
||||
if (opt->opt_short_name) {
|
||||
opt_names++;
|
||||
}
|
||||
|
||||
if (opt->opt_long_name) {
|
||||
opt_names++;
|
||||
}
|
||||
|
||||
if (opt_names == 2) {
|
||||
b_stream_write_fmt(
|
||||
opt_name, NULL, "-%c / --%s", opt->opt_short_name,
|
||||
opt->opt_long_name);
|
||||
} else if (opt->opt_short_name) {
|
||||
b_stream_write_fmt(opt_name, NULL, "-%c", opt->opt_short_name);
|
||||
} else if (opt->opt_long_name) {
|
||||
b_stream_write_fmt(opt_name, NULL, "--%s", opt->opt_long_name);
|
||||
}
|
||||
|
||||
b_err("required option `" F_YELLOW "%s" F_RESET "` was not specified.",
|
||||
b_stringstream_ptr(opt_name));
|
||||
b_i("usage: %s", b_string_ptr(opt_string));
|
||||
b_i("for more information, use `" F_YELLOW "--help" F_RESET "`");
|
||||
|
||||
b_string_unref(opt_string);
|
||||
b_stringstream_unref(opt_name);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_arglist_report_unexpected_arg(
|
||||
const b_arglist *args, const char *value)
|
||||
{
|
||||
b_string *usage = z__b_command_default_usage_string(
|
||||
args->list_command, NULL, args);
|
||||
|
||||
b_err("unexpected argument '" F_YELLOW "%s" F_RESET "' found.", value);
|
||||
b_i("usage: %s", b_string_ptr(usage));
|
||||
b_i("for more information, use '" F_YELLOW "--help" F_RESET "'");
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_arglist_report_invalid_arg_value(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
const char *value)
|
||||
{
|
||||
struct b_command_option *opt = NULL;
|
||||
struct b_command_arg *arg = NULL;
|
||||
|
||||
if (opt_id != B_COMMAND_INVALID_ID) {
|
||||
opt = b_command_get_option_with_id(args->list_command, opt_id);
|
||||
}
|
||||
|
||||
if (arg_id != B_COMMAND_INVALID_ID) {
|
||||
arg = opt ? b_command_option_get_arg_with_id(opt, arg_id)
|
||||
: b_command_get_arg_with_id(args->list_command, arg_id);
|
||||
}
|
||||
|
||||
b_string *usage = z__b_command_default_usage_string(
|
||||
args->list_command, opt, args);
|
||||
b_string *opt_string = b_string_create();
|
||||
|
||||
if (opt) {
|
||||
z__b_get_option_usage_string(opt, 0, opt_string);
|
||||
} else {
|
||||
z__b_get_arg_usage_string(arg, 0, opt_string);
|
||||
}
|
||||
|
||||
b_err("invalid value '" F_YELLOW "%s" F_RESET "' for '" F_YELLOW
|
||||
"%s" F_RESET "'.",
|
||||
value, b_string_ptr(opt_string));
|
||||
|
||||
if (opt) {
|
||||
b_i("'" F_YELLOW "%s" F_RESET
|
||||
"' accepts the following values for '" F_YELLOW "%s" F_RESET
|
||||
"':",
|
||||
b_string_ptr(opt_string), arg->arg_name);
|
||||
} else {
|
||||
b_i("'" F_YELLOW "%s" F_RESET "' accepts the following values:",
|
||||
b_string_ptr(opt_string));
|
||||
}
|
||||
|
||||
for (int i = 0; arg->arg_allowed_values[i]; i++) {
|
||||
b_printf(
|
||||
" * " F_GREEN "%s" F_RESET "\n",
|
||||
arg->arg_allowed_values[i]);
|
||||
}
|
||||
|
||||
b_printf("\n");
|
||||
b_i("usage: %s", b_string_ptr(usage));
|
||||
b_i("for more information, use '" F_YELLOW "--help" F_RESET);
|
||||
|
||||
b_string_unref(usage);
|
||||
b_string_unref(opt_string);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_arglist_report_missing_args(
|
||||
const b_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
size_t args_supplied)
|
||||
{
|
||||
struct b_command_option *opt = NULL;
|
||||
struct b_command_arg *arg = NULL;
|
||||
|
||||
if (opt_id != B_COMMAND_INVALID_ID) {
|
||||
opt = b_command_get_option_with_id(args->list_command, opt_id);
|
||||
assert(opt);
|
||||
}
|
||||
|
||||
if (arg_id != B_COMMAND_INVALID_ID) {
|
||||
arg = opt ? b_command_option_get_arg_with_id(opt, arg_id)
|
||||
: b_command_get_arg_with_id(args->list_command, arg_id);
|
||||
assert(arg);
|
||||
}
|
||||
|
||||
b_string *usage = z__b_command_default_usage_string(
|
||||
args->list_command, opt, args);
|
||||
b_string *opt_string = b_string_create();
|
||||
|
||||
if (opt) {
|
||||
z__b_get_option_usage_string(opt, 0, opt_string);
|
||||
} else {
|
||||
z__b_get_arg_usage_string(arg, 0, opt_string);
|
||||
}
|
||||
|
||||
char supplied_arg_str[64];
|
||||
if (args_supplied == 0) {
|
||||
snprintf(
|
||||
supplied_arg_str, sizeof supplied_arg_str,
|
||||
F_RED_BOLD "none" F_RESET " were provided");
|
||||
} else if (args_supplied == 1) {
|
||||
snprintf(
|
||||
supplied_arg_str, sizeof supplied_arg_str,
|
||||
"only " F_YELLOW_BOLD "%zu" F_RESET " was provided",
|
||||
args_supplied);
|
||||
} else {
|
||||
snprintf(
|
||||
supplied_arg_str, sizeof supplied_arg_str,
|
||||
"only " F_YELLOW_BOLD "%zu" F_RESET " were provided",
|
||||
args_supplied);
|
||||
}
|
||||
|
||||
char required_arg_count[64];
|
||||
switch (arg->arg_nr_values) {
|
||||
case B_ARG_1_OR_MORE_VALUES:
|
||||
snprintf(
|
||||
required_arg_count, sizeof required_arg_count,
|
||||
"one or more");
|
||||
break;
|
||||
default:
|
||||
snprintf(
|
||||
required_arg_count, sizeof required_arg_count, "%d",
|
||||
arg->arg_nr_values);
|
||||
}
|
||||
|
||||
b_err("argument `" F_YELLOW "%s" F_RESET "` requires " F_GREEN_BOLD
|
||||
"%s" F_RESET " `" F_YELLOW "%s" F_RESET "` value%s, but %s.",
|
||||
b_string_ptr(opt_string), required_arg_count, arg->arg_name,
|
||||
(arg->arg_nr_values == 1) ? "" : "s", supplied_arg_str);
|
||||
b_i("usage: %s", b_string_ptr(usage));
|
||||
b_i("for more information, use '" F_YELLOW "--help" F_RESET "'");
|
||||
|
||||
b_string_unref(usage);
|
||||
b_string_unref(opt_string);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <blue/compress/compressor.h>
|
||||
#include <blue/core/ringbuffer.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define COMPRESSOR_DISPATCH_STATIC(func, compressor, ...) \
|
||||
do { \
|
||||
struct compressor_data _compressor; \
|
||||
enum b_status status \
|
||||
= compressor_get_data(compressor, &_compressor); \
|
||||
if (!B_OK(status)) { \
|
||||
return status; \
|
||||
} \
|
||||
return func(&_compressor, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define COMPRESSOR_DISPATCH_STATIC_0(func, compressor) \
|
||||
do { \
|
||||
struct compressor_data _compressor; \
|
||||
enum b_status status \
|
||||
= compressor_get_data(compressor, &_compressor); \
|
||||
if (!B_OK(status)) { \
|
||||
return status; \
|
||||
} \
|
||||
return func(&_compressor); \
|
||||
} while (0)
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct compressor_data {
|
||||
b_compressor *c_obj;
|
||||
b_compressor_class *c_ops;
|
||||
b_compressor_data *c_data;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static enum b_status compressor_get_data(
|
||||
b_compressor *compressor, struct compressor_data *out)
|
||||
{
|
||||
out->c_obj = compressor;
|
||||
return b_object_get_data(
|
||||
compressor, B_TYPE_COMPRESSOR, NULL, (void **)&out->c_data,
|
||||
(void **)&out->c_ops);
|
||||
}
|
||||
|
||||
static enum b_status compressor_get_mode(
|
||||
struct compressor_data *p, enum b_compressor_mode *out)
|
||||
{
|
||||
if (out) {
|
||||
*out = p->c_data->c_mode;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status compressor_set_mode(
|
||||
struct compressor_data *p, enum b_compressor_mode mode)
|
||||
{
|
||||
if (!p->c_ops->c_set_mode) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return p->c_ops->c_set_mode(p->c_obj, mode);
|
||||
}
|
||||
|
||||
static enum b_status compressor_set_buffer(
|
||||
struct compressor_data *p, b_ringbuffer *inbuf, b_ringbuffer *outbuf)
|
||||
{
|
||||
p->c_data->c_in = inbuf;
|
||||
p->c_data->c_out = outbuf;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status compress(struct compressor_data *p)
|
||||
{
|
||||
if (p->c_data->c_mode != B_COMPRESSOR_MODE_COMPRESS) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!p->c_ops->c_compress) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return p->c_ops->c_compress(p->c_obj);
|
||||
}
|
||||
|
||||
static enum b_status decompress(struct compressor_data *p)
|
||||
{
|
||||
if (p->c_data->c_mode != B_COMPRESSOR_MODE_DECOMPRESS) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!p->c_ops->c_decompress) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return p->c_ops->c_decompress(p->c_obj);
|
||||
}
|
||||
|
||||
static enum b_status compressor_step(struct compressor_data *p)
|
||||
{
|
||||
switch (p->c_data->c_mode) {
|
||||
case B_COMPRESSOR_MODE_COMPRESS:
|
||||
return compress(p);
|
||||
case B_COMPRESSOR_MODE_DECOMPRESS:
|
||||
return decompress(p);
|
||||
default:
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
static enum b_status compressor_end(struct compressor_data *p)
|
||||
{
|
||||
if (p->c_data->c_mode != B_COMPRESSOR_MODE_COMPRESS) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
if (!p->c_ops->c_compress_end) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
while (b_ringbuffer_available_data_remaining(p->c_data->c_in)) {
|
||||
if (!b_ringbuffer_write_capacity_remaining(p->c_data->c_out)) {
|
||||
return B_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
enum b_status status = compressor_step(p);
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return p->c_ops->c_compress_end(p->c_obj);
|
||||
}
|
||||
|
||||
static enum b_status compressor_reset(struct compressor_data *p)
|
||||
{
|
||||
p->c_data->c_flags &= ~B_COMPRESSOR_EOF;
|
||||
|
||||
if (p->c_ops->c_reset) {
|
||||
return p->c_ops->c_reset(p->c_obj);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static bool compressor_eof(const struct compressor_data *p)
|
||||
{
|
||||
return (p->c_data->c_flags & B_COMPRESSOR_EOF) != 0;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
enum b_status b_compressor_get_buffer_size(
|
||||
b_type type, b_compressor_mode mode, size_t *inbuf_size, size_t *outbuf_size)
|
||||
{
|
||||
b_class *c = b_class_get(type);
|
||||
if (!c) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
b_compressor_class *ops = b_class_get_interface(c, B_TYPE_COMPRESSOR);
|
||||
if (!ops) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!ops->c_buffer_size) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return ops->c_buffer_size(mode, inbuf_size, outbuf_size);
|
||||
}
|
||||
|
||||
enum b_status b_compressor_get_mode(
|
||||
const b_compressor *compressor, enum b_compressor_mode *out)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC(
|
||||
compressor_get_mode, (b_compressor *)compressor, out);
|
||||
}
|
||||
|
||||
enum b_status b_compressor_set_mode(
|
||||
b_compressor *compressor, enum b_compressor_mode mode)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC(compressor_set_mode, compressor, mode);
|
||||
}
|
||||
|
||||
enum b_status b_compressor_set_buffer(
|
||||
b_compressor *compressor, b_ringbuffer *inbuf, b_ringbuffer *outbuf)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC(compressor_set_buffer, compressor, inbuf, outbuf);
|
||||
}
|
||||
|
||||
enum b_status b_compressor_step(b_compressor *compressor)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC_0(compressor_step, compressor);
|
||||
}
|
||||
|
||||
enum b_status b_compressor_end(b_compressor *compressor)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC_0(compressor_end, compressor);
|
||||
}
|
||||
|
||||
enum b_status b_compressor_reset(b_compressor *compressor)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC_0(compressor_reset, compressor);
|
||||
}
|
||||
|
||||
bool b_compressor_eof(const b_compressor *compressor)
|
||||
{
|
||||
COMPRESSOR_DISPATCH_STATIC_0(compressor_eof, (b_compressor *)compressor);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void compressor_init(b_object *obj, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static void compressor_fini(b_object *obj, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_compressor)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_compressor)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_compressor)
|
||||
B_TYPE_ID(0x452ee0f9, 0xfe12, 0x48a1, 0xb596, 0xad5b7a3940e7);
|
||||
B_TYPE_CLASS(b_compressor_class);
|
||||
B_TYPE_INSTANCE_PROTECTED(b_compressor_data);
|
||||
B_TYPE_INSTANCE_INIT(compressor_init);
|
||||
B_TYPE_INSTANCE_FINI(compressor_fini);
|
||||
B_TYPE_DEFINITION_END(b_compressor)
|
||||
@@ -1,362 +0,0 @@
|
||||
#include <blue/compress/zstd.h>
|
||||
#include <blue/core/ringbuffer.h>
|
||||
#include <zstd.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_zstd_compressor_p {
|
||||
union {
|
||||
ZSTD_CCtx *zstd_c;
|
||||
ZSTD_DCtx *zstd_d;
|
||||
};
|
||||
};
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_status b_zstd_compressor_get_buffer_size(
|
||||
b_compressor_mode mode, size_t *inbuf_size, size_t *outbuf_size)
|
||||
{
|
||||
switch (mode) {
|
||||
case B_COMPRESSOR_MODE_COMPRESS:
|
||||
*inbuf_size = ZSTD_CStreamInSize();
|
||||
*outbuf_size = ZSTD_CStreamOutSize();
|
||||
break;
|
||||
case B_COMPRESSOR_MODE_DECOMPRESS:
|
||||
*inbuf_size = ZSTD_DStreamInSize();
|
||||
*outbuf_size = ZSTD_DStreamOutSize();
|
||||
break;
|
||||
default:
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void zstd_compressor_init(b_object *obj, void *priv)
|
||||
{
|
||||
}
|
||||
|
||||
static void zstd_compressor_fini(b_object *obj, void *priv)
|
||||
{
|
||||
b_compressor_data *c = b_object_get_protected(obj, B_TYPE_COMPRESSOR);
|
||||
struct b_zstd_compressor_p *ctx = priv;
|
||||
switch (c->c_mode) {
|
||||
case B_COMPRESSOR_MODE_COMPRESS:
|
||||
ZSTD_freeCCtx(ctx->zstd_c);
|
||||
break;
|
||||
case B_COMPRESSOR_MODE_DECOMPRESS:
|
||||
ZSTD_freeDCtx(ctx->zstd_d);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static enum b_status reset(b_compressor *compressor)
|
||||
{
|
||||
struct b_zstd_compressor_p *ctx
|
||||
= b_object_get_private(compressor, B_TYPE_ZSTD_COMPRESSOR);
|
||||
b_compressor_data *data
|
||||
= b_object_get_protected(compressor, B_TYPE_COMPRESSOR);
|
||||
|
||||
if (!ctx || !data) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
switch (data->c_mode) {
|
||||
case B_COMPRESSOR_MODE_COMPRESS:
|
||||
ZSTD_CCtx_reset(ctx->zstd_c, ZSTD_reset_session_only);
|
||||
break;
|
||||
case B_COMPRESSOR_MODE_DECOMPRESS:
|
||||
ZSTD_DCtx_reset(ctx->zstd_d, ZSTD_reset_session_only);
|
||||
break;
|
||||
default:
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status compress(b_compressor *compressor)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
struct b_zstd_compressor_p *ctx
|
||||
= b_object_get_private(compressor, B_TYPE_ZSTD_COMPRESSOR);
|
||||
b_compressor_data *data
|
||||
= b_object_get_protected(compressor, B_TYPE_COMPRESSOR);
|
||||
|
||||
if (!ctx || !data) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
b_ringbuffer *in = data->c_in;
|
||||
b_ringbuffer *out = data->c_out;
|
||||
|
||||
if (b_ringbuffer_available_data_remaining(in) == 0) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (b_ringbuffer_write_capacity_remaining(out) == 0) {
|
||||
return B_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
size_t nr_consumed = 0;
|
||||
|
||||
while (1) {
|
||||
size_t in_available = 0, out_capacity = 0;
|
||||
const void *in_buf = NULL;
|
||||
void *out_buf = NULL;
|
||||
|
||||
status = b_ringbuffer_open_read_buffer(in, &in_buf, &in_available);
|
||||
if (!B_OK(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
status = b_ringbuffer_open_write_buffer(
|
||||
out, &out_buf, &out_capacity);
|
||||
if (!B_OK(status)) {
|
||||
b_ringbuffer_close_read_buffer(in, &in_buf, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
ZSTD_inBuffer z_in = {
|
||||
.src = in_buf,
|
||||
.pos = 0,
|
||||
.size = in_available,
|
||||
};
|
||||
|
||||
ZSTD_outBuffer z_out = {
|
||||
.dst = out_buf,
|
||||
.pos = 0,
|
||||
.size = out_capacity,
|
||||
};
|
||||
|
||||
do {
|
||||
size_t ret = ZSTD_compressStream2(
|
||||
ctx->zstd_c, &z_out, &z_in, ZSTD_e_continue);
|
||||
if (ZSTD_isError(ret)) {
|
||||
status = B_ERR_COMPRESSION_FAILURE;
|
||||
break;
|
||||
}
|
||||
} while (z_in.pos < z_in.size && z_out.pos < z_out.size);
|
||||
|
||||
nr_consumed += z_in.pos;
|
||||
|
||||
b_ringbuffer_close_read_buffer(in, &in_buf, z_in.pos);
|
||||
b_ringbuffer_close_write_buffer(out, &out_buf, z_out.pos);
|
||||
}
|
||||
|
||||
if ((status == B_ERR_NO_SPACE || status == B_ERR_NO_DATA)
|
||||
&& nr_consumed > 0) {
|
||||
status = B_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status compress_end(b_compressor *compressor)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
struct b_zstd_compressor_p *ctx
|
||||
= b_object_get_private(compressor, B_TYPE_ZSTD_COMPRESSOR);
|
||||
b_compressor_data *data
|
||||
= b_object_get_protected(compressor, B_TYPE_COMPRESSOR);
|
||||
|
||||
if (!ctx || !data) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
b_ringbuffer *out = data->c_out;
|
||||
if (b_ringbuffer_write_capacity_remaining(out) == 0) {
|
||||
return B_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
bool finished = false;
|
||||
do {
|
||||
void *out_buf = NULL;
|
||||
size_t out_capacity = 0;
|
||||
status = b_ringbuffer_open_write_buffer(
|
||||
out, &out_buf, &out_capacity);
|
||||
if (!B_OK(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ZSTD_inBuffer z_in = {0};
|
||||
ZSTD_outBuffer z_out = {
|
||||
.dst = out_buf,
|
||||
.pos = 0,
|
||||
.size = out_capacity,
|
||||
};
|
||||
|
||||
do {
|
||||
size_t ret = ZSTD_compressStream2(
|
||||
ctx->zstd_c, &z_out, &z_in, ZSTD_e_end);
|
||||
if (ZSTD_isError(ret)) {
|
||||
status = B_ERR_COMPRESSION_FAILURE;
|
||||
finished = true;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
data->c_flags |= B_COMPRESSOR_EOF;
|
||||
finished = true;
|
||||
}
|
||||
} while (!finished && z_out.pos < z_out.size);
|
||||
|
||||
b_ringbuffer_close_write_buffer(out, &out_buf, z_out.pos);
|
||||
} while (!finished);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status decompress(b_compressor *compressor)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
struct b_zstd_compressor_p *ctx
|
||||
= b_object_get_private(compressor, B_TYPE_ZSTD_COMPRESSOR);
|
||||
b_compressor_data *data
|
||||
= b_object_get_protected(compressor, B_TYPE_COMPRESSOR);
|
||||
|
||||
if (!ctx || !data) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
b_ringbuffer *in = data->c_in;
|
||||
b_ringbuffer *out = data->c_out;
|
||||
|
||||
if (b_ringbuffer_available_data_remaining(in) == 0) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
if (b_ringbuffer_write_capacity_remaining(out) == 0) {
|
||||
return B_ERR_NO_SPACE;
|
||||
}
|
||||
|
||||
size_t nr_consumed = 0;
|
||||
|
||||
while (!(data->c_flags & B_COMPRESSOR_EOF)) {
|
||||
size_t in_available = 0, out_capacity = 0;
|
||||
const void *in_buf = NULL;
|
||||
void *out_buf = NULL;
|
||||
|
||||
status = b_ringbuffer_open_read_buffer(in, &in_buf, &in_available);
|
||||
if (!B_OK(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
status = b_ringbuffer_open_write_buffer(
|
||||
out, &out_buf, &out_capacity);
|
||||
if (!B_OK(status)) {
|
||||
b_ringbuffer_close_read_buffer(in, &in_buf, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
ZSTD_inBuffer z_in = {
|
||||
.src = in_buf,
|
||||
.pos = 0,
|
||||
.size = in_available,
|
||||
};
|
||||
|
||||
ZSTD_outBuffer z_out = {
|
||||
.dst = out_buf,
|
||||
.pos = 0,
|
||||
.size = out_capacity,
|
||||
};
|
||||
|
||||
do {
|
||||
size_t ret = ZSTD_decompressStream(
|
||||
ctx->zstd_d, &z_out, &z_in);
|
||||
if (ZSTD_isError(ret)) {
|
||||
status = B_ERR_COMPRESSION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
data->c_flags |= B_COMPRESSOR_EOF;
|
||||
break;
|
||||
}
|
||||
} while (z_in.pos < z_in.size && z_out.pos < z_out.size);
|
||||
|
||||
nr_consumed += z_in.pos;
|
||||
|
||||
b_ringbuffer_close_read_buffer(in, &in_buf, z_in.pos);
|
||||
b_ringbuffer_close_write_buffer(out, &out_buf, z_out.pos);
|
||||
}
|
||||
|
||||
if ((status == B_ERR_NO_SPACE || status == B_ERR_NO_DATA)
|
||||
&& nr_consumed > 0) {
|
||||
status = B_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum b_status set_mode(b_compressor *compressor, b_compressor_mode mode)
|
||||
{
|
||||
struct b_zstd_compressor_p *ctx
|
||||
= b_object_get_private(compressor, B_TYPE_ZSTD_COMPRESSOR);
|
||||
b_compressor_data *data
|
||||
= b_object_get_protected(compressor, B_TYPE_COMPRESSOR);
|
||||
|
||||
if (!ctx || !data) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (mode == data->c_mode) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
switch (data->c_mode) {
|
||||
case B_COMPRESSOR_MODE_COMPRESS:
|
||||
ZSTD_freeCCtx(ctx->zstd_c);
|
||||
break;
|
||||
case B_COMPRESSOR_MODE_DECOMPRESS:
|
||||
ZSTD_freeDCtx(ctx->zstd_d);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
data->c_mode = mode;
|
||||
|
||||
switch (data->c_mode) {
|
||||
case B_COMPRESSOR_MODE_COMPRESS:
|
||||
ctx->zstd_c = ZSTD_createCCtx();
|
||||
break;
|
||||
case B_COMPRESSOR_MODE_DECOMPRESS:
|
||||
ctx->zstd_d = ZSTD_createDCtx();
|
||||
break;
|
||||
default:
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_zstd_compressor)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_compressor, B_TYPE_COMPRESSOR)
|
||||
B_INTERFACE_ENTRY(c_buffer_size)
|
||||
= b_zstd_compressor_get_buffer_size;
|
||||
B_INTERFACE_ENTRY(c_compress) = compress;
|
||||
B_INTERFACE_ENTRY(c_compress_end) = compress_end;
|
||||
B_INTERFACE_ENTRY(c_decompress) = decompress;
|
||||
B_INTERFACE_ENTRY(c_reset) = reset;
|
||||
B_INTERFACE_ENTRY(c_set_mode) = set_mode;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_compressor, B_TYPE_COMPRESSOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_zstd_compressor)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_zstd_compressor)
|
||||
B_TYPE_ID(0x51d437fc, 0xe789, 0x4105, 0xbac7, 0xe6b3f45df198);
|
||||
B_TYPE_EXTENDS(B_TYPE_COMPRESSOR);
|
||||
B_TYPE_CLASS(b_zstd_compressor_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_zstd_compressor_p);
|
||||
B_TYPE_INSTANCE_INIT(zstd_compressor_init);
|
||||
B_TYPE_INSTANCE_FINI(zstd_compressor_fini);
|
||||
B_TYPE_DEFINITION_END(b_zstd_compressor)
|
||||
@@ -1,67 +0,0 @@
|
||||
#ifndef BLUE_COMPRESS_COMPRESSOR_H_
|
||||
#define BLUE_COMPRESS_COMPRESSOR_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/ringbuffer.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
typedef enum b_compressor_mode {
|
||||
B_COMPRESSOR_MODE_NONE = 0,
|
||||
B_COMPRESSOR_MODE_COMPRESS,
|
||||
B_COMPRESSOR_MODE_DECOMPRESS,
|
||||
} b_compressor_mode;
|
||||
|
||||
typedef enum b_compressor_flags {
|
||||
B_COMPRESSOR_EOF = 0x01u,
|
||||
} b_compressor_flags;
|
||||
|
||||
#define B_TYPE_COMPRESSOR (b_compressor_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_compressor);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_compressor)
|
||||
b_status (*c_buffer_size)(b_compressor_mode, size_t *, size_t *);
|
||||
b_status (*c_set_mode)(b_compressor *, b_compressor_mode);
|
||||
b_status (*c_compress)(b_compressor *);
|
||||
b_status (*c_compress_end)(b_compressor *);
|
||||
b_status (*c_decompress)(b_compressor *);
|
||||
b_status (*c_reset)(b_compressor *);
|
||||
B_TYPE_CLASS_DECLARATION_END(b_compressor)
|
||||
|
||||
typedef struct b_compressor_data {
|
||||
b_compressor_flags c_flags;
|
||||
b_compressor_mode c_mode;
|
||||
b_ringbuffer *c_in, *c_out;
|
||||
} b_compressor_data;
|
||||
|
||||
BLUE_API b_type b_compressor_get_type(void);
|
||||
|
||||
#if 0
|
||||
BLUE_API b_status b_compressor_create(
|
||||
const struct b_compression_function *func, enum b_compression_mode mode,
|
||||
struct b_ringbuffer *inbuf, struct b_ringbuffer *outbuf,
|
||||
b_compressor **out);
|
||||
#endif
|
||||
|
||||
BLUE_API b_status b_compressor_get_buffer_size(
|
||||
b_type type, b_compressor_mode mode, size_t *inbuf_size,
|
||||
size_t *outbuf_size);
|
||||
|
||||
BLUE_API b_status b_compressor_get_mode(
|
||||
const b_compressor *compressor, b_compressor_mode *out);
|
||||
BLUE_API b_status b_compressor_set_mode(
|
||||
b_compressor *compressor, b_compressor_mode mode);
|
||||
BLUE_API b_status b_compressor_set_buffer(
|
||||
b_compressor *compressor, b_ringbuffer *inbuf, b_ringbuffer *outbuf);
|
||||
BLUE_API b_status b_compressor_step(b_compressor *compressor);
|
||||
BLUE_API b_status b_compressor_end(b_compressor *compressor);
|
||||
BLUE_API b_status b_compressor_reset(b_compressor *compressor);
|
||||
BLUE_API bool b_compressor_eof(const b_compressor *compressor);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef BLUE_COMPRESS_CSTREAM_H_
|
||||
#define BLUE_COMPRESS_CSTREAM_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
enum b_compressor_mode;
|
||||
|
||||
#define B_TYPE_CSTREAM (b_cstream_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_cstream);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_cstream)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_cstream)
|
||||
|
||||
BLUE_API b_type b_cstream_get_type(void);
|
||||
|
||||
BLUE_API b_status b_cstream_open(
|
||||
b_stream *endpoint, b_type compressor_type, enum b_compressor_mode mode,
|
||||
b_cstream **out);
|
||||
|
||||
BLUE_API b_status b_cstream_read(
|
||||
b_cstream *stream, void *buf, size_t count, size_t *nr_read);
|
||||
BLUE_API b_status b_cstream_write(
|
||||
b_cstream *stream, const void *buf, size_t count, size_t *nr_written);
|
||||
BLUE_API b_status b_cstream_skip(
|
||||
b_cstream *stream, size_t count, size_t *nr_skipped);
|
||||
BLUE_API b_status b_cstream_reset(b_cstream *stream);
|
||||
|
||||
BLUE_API b_status b_cstream_begin_compressed_section(
|
||||
b_cstream *stream, size_t *tx_uncompressed_bytes);
|
||||
BLUE_API b_status b_cstream_end_compressed_section(
|
||||
b_cstream *stream, size_t *tx_compressed_bytes,
|
||||
size_t *tx_uncompressed_bytes);
|
||||
BLUE_API bool b_cstream_in_compressed_section(const b_cstream *stream);
|
||||
BLUE_API b_status b_cstream_tx_bytes(const b_cstream *stream, size_t *out);
|
||||
BLUE_API b_status b_cstream_tx_bytes_compressed(
|
||||
const b_cstream *stream, size_t *out);
|
||||
BLUE_API b_status b_cstream_tx_bytes_uncompressed(
|
||||
const b_cstream *stream, size_t *out);
|
||||
|
||||
BLUE_API b_status b_cstream_set_cursor_position(b_cstream *stream, size_t pos);
|
||||
BLUE_API b_status b_cstream_restore_cursor_position(b_cstream *stream);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef BLUE_COMPRESS_ZSTD_H_
|
||||
#define BLUE_COMPRESS_ZSTD_H_
|
||||
|
||||
#include <blue/compress/compressor.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_ZSTD_COMPRESSOR (b_zstd_compressor_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_zstd_compressor);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_zstd_compressor)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_compressor)
|
||||
|
||||
BLUE_API b_type b_zstd_compressor_get_type(void);
|
||||
|
||||
BLUE_API b_status b_zstd_compressor_get_buffer_size(
|
||||
b_compressor_mode mode, size_t *inbuf_size, size_t *outbuf_size);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_zstd_compressor, B_TYPE_ZSTD_COMPRESSOR);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,79 +0,0 @@
|
||||
#include "class.h"
|
||||
|
||||
#include "type.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <blue/core/class.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void *b_class_get(b_type id)
|
||||
{
|
||||
struct b_type_registration *r = b_type_get_registration(id);
|
||||
if (!r) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r->r_class;
|
||||
}
|
||||
|
||||
const char *b_class_get_name(const struct _b_class *c)
|
||||
{
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(c->c_magic == B_CLASS_MAGIC);
|
||||
|
||||
return c->c_type->r_info->t_name;
|
||||
}
|
||||
|
||||
void *b_class_get_interface(const struct _b_class *c, const union b_type *id)
|
||||
{
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(c->c_magic == B_CLASS_MAGIC);
|
||||
|
||||
const struct b_type_registration *type_reg = c->c_type;
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&type_reg->r_components, id);
|
||||
|
||||
if (!comp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)c + comp->c_class_data_offset;
|
||||
}
|
||||
|
||||
b_result b_class_instantiate(
|
||||
struct b_type_registration *type, struct _b_class **out_class)
|
||||
{
|
||||
struct _b_class *out = malloc(type->r_class_size);
|
||||
if (!out) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
memset(out, 0x0, type->r_class_size);
|
||||
|
||||
out->c_magic = B_CLASS_MAGIC;
|
||||
out->c_type = type;
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&type->r_class_hierarchy);
|
||||
while (entry) {
|
||||
struct b_type_component *comp
|
||||
= b_unbox(struct b_type_component, entry, c_entry);
|
||||
const struct b_type_info *class_info = comp->c_type->r_info;
|
||||
void *class_data = (char *)out + comp->c_class_data_offset;
|
||||
|
||||
if (class_info->t_class_init) {
|
||||
class_info->t_class_init(out, class_data);
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
*out_class = out;
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef _CLASS_H_
|
||||
#define _CLASS_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct b_type_registration;
|
||||
|
||||
struct _b_class {
|
||||
uint64_t c_magic;
|
||||
const struct b_type_registration *c_type;
|
||||
};
|
||||
|
||||
extern b_result b_class_instantiate(
|
||||
struct b_type_registration *type, struct _b_class **out);
|
||||
|
||||
#endif
|
||||
-1059
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
#ifndef _BLUELIB_ERROR_H_
|
||||
#define _BLUELIB_ERROR_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/queue.h>
|
||||
|
||||
struct b_error_stack_frame {
|
||||
b_queue_entry f_entry;
|
||||
const char *f_file;
|
||||
unsigned int f_line_number;
|
||||
const char *f_function;
|
||||
};
|
||||
|
||||
struct b_error_submsg {
|
||||
b_queue_entry msg_entry;
|
||||
b_error_submsg_type msg_type;
|
||||
char *msg_content;
|
||||
const struct b_error_msg *msg_msg;
|
||||
struct b_error_template_parameter msg_params[B_ERROR_TEMPLATE_PARAMETER_MAX];
|
||||
};
|
||||
|
||||
struct b_error {
|
||||
const struct b_error_vendor *err_vendor;
|
||||
b_error_status_code err_code;
|
||||
|
||||
const struct b_error_definition *err_def;
|
||||
const struct b_error_msg *err_msg;
|
||||
char *err_description;
|
||||
struct b_error_template_parameter err_params[B_ERROR_TEMPLATE_PARAMETER_MAX];
|
||||
|
||||
struct b_queue err_submsg;
|
||||
struct b_queue err_stack;
|
||||
b_queue_entry err_entry;
|
||||
struct b_error *err_caused_by;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,178 +0,0 @@
|
||||
#include "hash.h"
|
||||
|
||||
#include <blue/core/hash.h>
|
||||
#include <blue/core/rope.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FNV1_OFFSET_BASIS 0xcbf29ce484222325
|
||||
#define FNV1_PRIME 0x100000001b3
|
||||
|
||||
extern struct b_hash_function_ops z__b_md4_ops;
|
||||
extern struct b_hash_function_ops z__b_md5_ops;
|
||||
extern struct b_hash_function_ops z__b_sha1_ops;
|
||||
extern struct b_hash_function_ops z__b_sha2_224_ops;
|
||||
extern struct b_hash_function_ops z__b_sha2_256_ops;
|
||||
extern struct b_hash_function_ops z__b_sha2_384_ops;
|
||||
extern struct b_hash_function_ops z__b_sha2_512_ops;
|
||||
extern struct b_hash_function_ops z__b_sha3_224_ops;
|
||||
extern struct b_hash_function_ops z__b_sha3_256_ops;
|
||||
extern struct b_hash_function_ops z__b_sha3_384_ops;
|
||||
extern struct b_hash_function_ops z__b_sha3_512_ops;
|
||||
extern struct b_hash_function_ops z__b_shake128_ops;
|
||||
extern struct b_hash_function_ops z__b_shake256_ops;
|
||||
|
||||
static const struct b_hash_function_ops *hash_functions[] = {
|
||||
[B_HASH_NONE] = NULL,
|
||||
[B_HASH_MD4] = &z__b_md4_ops,
|
||||
[B_HASH_MD5] = &z__b_md5_ops,
|
||||
[B_HASH_SHA1] = &z__b_sha1_ops,
|
||||
[B_HASH_SHA2_224] = &z__b_sha2_224_ops,
|
||||
[B_HASH_SHA2_256] = &z__b_sha2_256_ops,
|
||||
[B_HASH_SHA2_384] = &z__b_sha2_384_ops,
|
||||
[B_HASH_SHA2_512] = &z__b_sha2_512_ops,
|
||||
[B_HASH_SHA3_224] = &z__b_sha3_224_ops,
|
||||
[B_HASH_SHA3_256] = &z__b_sha3_256_ops,
|
||||
[B_HASH_SHA3_384] = &z__b_sha3_384_ops,
|
||||
[B_HASH_SHA3_512] = &z__b_sha3_512_ops,
|
||||
[B_HASH_SHAKE128] = &z__b_shake128_ops,
|
||||
[B_HASH_SHAKE256] = &z__b_shake256_ops,
|
||||
};
|
||||
static const size_t nr_hash_functions
|
||||
= sizeof hash_functions / sizeof hash_functions[0];
|
||||
|
||||
uint64_t b_hash_cstr(const char *s)
|
||||
{
|
||||
size_t x = 0;
|
||||
return b_hash_cstr_ex(s, &x);
|
||||
}
|
||||
|
||||
uint64_t b_hash_cstr_ex(const char *s, size_t *len)
|
||||
{
|
||||
uint64_t hash = FNV1_OFFSET_BASIS;
|
||||
size_t i = 0;
|
||||
|
||||
for (i = 0; s[i]; i++) {
|
||||
hash ^= s[i];
|
||||
hash *= FNV1_PRIME;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
*len = i;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_init(struct b_hash_ctx *ctx, enum b_hash_function func)
|
||||
{
|
||||
if (func < 0 || func >= nr_hash_functions) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const struct b_hash_function_ops *hash_function = hash_functions[func];
|
||||
if (!hash_function) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
memset(ctx, 0x0, sizeof *ctx);
|
||||
|
||||
ctx->ctx_func = func;
|
||||
ctx->ctx_ops = hash_function;
|
||||
|
||||
if (hash_function->hash_init) {
|
||||
hash_function->hash_init(ctx);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_reset(struct b_hash_ctx *ctx)
|
||||
{
|
||||
if (ctx->ctx_func == B_HASH_NONE || !ctx->ctx_ops) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
memset(&ctx->ctx_state, 0x0, sizeof ctx->ctx_state);
|
||||
|
||||
if (ctx->ctx_ops->hash_init) {
|
||||
ctx->ctx_ops->hash_init(ctx);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_update(struct b_hash_ctx *ctx, const void *p, size_t len)
|
||||
{
|
||||
if (!ctx->ctx_ops) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!ctx->ctx_ops->hash_update) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
ctx->ctx_ops->hash_update(ctx, p, len);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static void update_rope(const b_rope *rope, void *arg)
|
||||
{
|
||||
struct b_hash_ctx *ctx = arg;
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
char tmp[64];
|
||||
size_t len = 0;
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
b_hash_ctx_update(ctx, &rope->r_v.v_char, sizeof rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
b_hash_ctx_update(
|
||||
ctx, rope->r_v.v_cstr.s, strlen(rope->r_v.v_cstr.s));
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
len = snprintf(tmp, sizeof tmp, "%" PRIdPTR, rope->r_v.v_int);
|
||||
b_hash_ctx_update(ctx, tmp, len);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
len = snprintf(tmp, sizeof tmp, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
b_hash_ctx_update(ctx, tmp, len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_update_rope(
|
||||
struct b_hash_ctx *ctx, const struct b_rope *rope)
|
||||
{
|
||||
b_rope_iterate(rope, update_rope, ctx);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
enum b_status b_hash_ctx_finish(
|
||||
struct b_hash_ctx *ctx, void *out_digest, size_t out_max)
|
||||
{
|
||||
if (!ctx->ctx_ops) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!ctx->ctx_ops->hash_finish) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
ctx->ctx_ops->hash_finish(ctx, out_digest, out_max);
|
||||
|
||||
memset(&ctx->ctx_state, 0x0, sizeof ctx->ctx_state);
|
||||
|
||||
if (ctx->ctx_ops->hash_init) {
|
||||
ctx->ctx_ops->hash_init(ctx);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef _HASH_H_
|
||||
#define _HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct b_hash_ctx;
|
||||
|
||||
struct b_hash_function_ops {
|
||||
void (*hash_init)(struct b_hash_ctx *);
|
||||
void (*hash_update)(struct b_hash_ctx *, const void *, size_t);
|
||||
void (*hash_finish)(struct b_hash_ctx *, void *, size_t);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
#ifndef BLUE_CORE_BSTR_H_
|
||||
#define BLUE_CORE_BSTR_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define B_BSTR_MAGIC 0x5005500550055005ULL
|
||||
|
||||
struct b_rope;
|
||||
|
||||
enum b_bstr_flags {
|
||||
B_BSTR_F_NONE = 0x00u,
|
||||
B_BSTR_F_ALLOC = 0x01u,
|
||||
};
|
||||
|
||||
typedef struct b_bstr {
|
||||
uint64_t bstr_magic;
|
||||
enum b_bstr_flags bstr_flags;
|
||||
char *bstr_buf;
|
||||
/* total number of characters in bstr_buf, not including null terminator */
|
||||
size_t bstr_len;
|
||||
/* number of bytes allocated for bstr_buf (includes space for the null
|
||||
* terminator) */
|
||||
size_t bstr_capacity;
|
||||
int *bstr_istack;
|
||||
int bstr_add_indent;
|
||||
size_t bstr_istack_ptr, bstr_istack_size;
|
||||
} b_bstr;
|
||||
|
||||
BLUE_API void b_bstr_begin(b_bstr *strv, char *buf, size_t max);
|
||||
BLUE_API void b_bstr_begin_dynamic(b_bstr *strv);
|
||||
BLUE_API char *b_bstr_end(b_bstr *strv);
|
||||
BLUE_API b_status b_bstr_reserve(b_bstr *strv, size_t len);
|
||||
|
||||
static inline size_t b_bstr_get_size(const b_bstr *str)
|
||||
{
|
||||
return str->bstr_len;
|
||||
}
|
||||
|
||||
static inline size_t b_bstr_get_capacity(const b_bstr *str)
|
||||
{
|
||||
return str->bstr_capacity;
|
||||
}
|
||||
|
||||
BLUE_API b_status b_bstr_push_indent(b_bstr *strv, int indent);
|
||||
BLUE_API b_status b_bstr_pop_indent(b_bstr *strv);
|
||||
|
||||
BLUE_API b_status b_bstr_write_char(b_bstr *strv, char c);
|
||||
BLUE_API b_status b_bstr_write_chars(
|
||||
b_bstr *strv, const char *cs, size_t len, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr(
|
||||
b_bstr *strv, const char *str, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr_list(
|
||||
b_bstr *strv, const char **strs, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr_array(
|
||||
b_bstr *strv, const char **strs, size_t count, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_cstr_varg(b_bstr *strv, size_t *nr_written, ...);
|
||||
BLUE_API b_status b_bstr_write_rope(
|
||||
b_bstr *strv, const struct b_rope *rope, size_t *nr_written);
|
||||
BLUE_API b_status b_bstr_write_fmt(
|
||||
b_bstr *strv, size_t *nr_written, const char *format, ...);
|
||||
BLUE_API b_status b_bstr_write_vfmt(
|
||||
b_bstr *strv, size_t *nr_written, const char *format, va_list arg);
|
||||
|
||||
BLUE_API char *b_bstr_rope(const struct b_rope *rope, size_t *nr_written);
|
||||
BLUE_API char *b_bstr_fmt(size_t *nr_written, const char *format, ...);
|
||||
BLUE_API char *b_bstr_vfmt(size_t *nr_written, const char *format, va_list arg);
|
||||
|
||||
#endif
|
||||
@@ -1,359 +0,0 @@
|
||||
#ifndef BLUELIB_CORE_BTREE_H_
|
||||
#define BLUELIB_CORE_BTREE_H_
|
||||
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_BTREE_INIT {0}
|
||||
#define B_TYPE_BTREE_ITERATOR (b_btree_iterator_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_btree_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_btree_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_btree_iterator)
|
||||
|
||||
/* defines a simple node insertion function.
|
||||
this function assumes that your nodes have simple integer keys that can be
|
||||
compared with the usual operators.
|
||||
|
||||
EXAMPLE:
|
||||
if you have a tree node type like this:
|
||||
|
||||
struct my_tree_node {
|
||||
int key;
|
||||
b_btree_node base;
|
||||
}
|
||||
|
||||
You would use the following call to generate an insert function for a tree
|
||||
with this node type:
|
||||
|
||||
BTREE_DEFINE_SIMPLE_INSERT(
|
||||
struct my_tree_node,
|
||||
base,
|
||||
key,
|
||||
my_tree_node_insert);
|
||||
|
||||
Which would emit a function defined like:
|
||||
|
||||
static void my_tree_node_insert(b_btree *tree, struct my_tree_node *node);
|
||||
|
||||
@param node_type your custom tree node type. usually a structure that
|
||||
contains a b_btree_node member.
|
||||
@param container_node_member the name of the b_btree_node member variable
|
||||
within your custom type.
|
||||
@param container_key_member the name of the key member variable within your
|
||||
custom type.
|
||||
@param function_name the name of the function to generate.
|
||||
*/
|
||||
#define B_BTREE_DEFINE_SIMPLE_INSERT( \
|
||||
node_type, container_node_member, container_key_member, function_name) \
|
||||
void function_name(b_btree *tree, node_type *node) \
|
||||
{ \
|
||||
if (!tree->b_root) { \
|
||||
tree->b_root = &node->container_node_member; \
|
||||
b_btree_insert_fixup(tree, &node->container_node_member); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
b_btree_node *cur = tree->b_root; \
|
||||
while (1) { \
|
||||
node_type *cur_node = b_unbox( \
|
||||
node_type, cur, container_node_member); \
|
||||
b_btree_node *next = NULL; \
|
||||
\
|
||||
if (node->container_key_member \
|
||||
>= cur_node->container_key_member) { \
|
||||
next = b_btree_right(cur); \
|
||||
\
|
||||
if (!next) { \
|
||||
b_btree_put_right( \
|
||||
cur, \
|
||||
&node->container_node_member); \
|
||||
break; \
|
||||
} \
|
||||
} else if ( \
|
||||
node->container_key_member \
|
||||
< cur_node->container_key_member) { \
|
||||
next = b_btree_left(cur); \
|
||||
\
|
||||
if (!next) { \
|
||||
b_btree_put_left( \
|
||||
cur, \
|
||||
&node->container_node_member); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
cur = next; \
|
||||
} \
|
||||
\
|
||||
b_btree_insert_fixup(tree, &node->container_node_member); \
|
||||
}
|
||||
|
||||
/* defines a node insertion function.
|
||||
this function should be used for trees with complex node keys that cannot be
|
||||
directly compared. a comparator for your keys must be supplied.
|
||||
|
||||
EXAMPLE:
|
||||
if you have a tree node type like this:
|
||||
|
||||
struct my_tree_node {
|
||||
complex_key_t key;
|
||||
b_btree_node base;
|
||||
}
|
||||
|
||||
You would need to define a comparator function or macro with the following
|
||||
signature:
|
||||
|
||||
int my_comparator(struct my_tree_node *a, struct my_tree_node *b);
|
||||
|
||||
Which implements the following:
|
||||
|
||||
return -1 if a < b
|
||||
return 0 if a == b
|
||||
return 1 if a > b
|
||||
|
||||
You would use the following call to generate an insert function for a tree
|
||||
with this node type:
|
||||
|
||||
BTREE_DEFINE_INSERT(struct my_tree_node, base, key, my_tree_node_insert,
|
||||
my_comparator);
|
||||
|
||||
Which would emit a function defined like:
|
||||
|
||||
static void my_tree_node_insert(b_btree *tree, struct my_tree_node *node);
|
||||
|
||||
@param node_type your custom tree node type. usually a structure that
|
||||
contains a b_btree_node member.
|
||||
@param container_node_member the name of the b_btree_node member variable
|
||||
within your custom type.
|
||||
@param container_key_member the name of the key member variable within your
|
||||
custom type.
|
||||
@param function_name the name of the function to generate.
|
||||
@param comparator the name of a comparator function or functional-macro that
|
||||
conforms to the requirements listed above.
|
||||
*/
|
||||
#define B_BTREE_DEFINE_INSERT( \
|
||||
node_type, container_node_member, container_key_member, function_name, \
|
||||
comparator) \
|
||||
void function_name(b_btree *tree, node_type *node) \
|
||||
{ \
|
||||
if (!tree->b_root) { \
|
||||
tree->b_root = &node->container_node_member; \
|
||||
b_btree_insert_fixup(tree, &node->container_node_member); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
b_btree_node *cur = tree->b_root; \
|
||||
while (1) { \
|
||||
node_type *cur_node = b_unbox( \
|
||||
node_type, cur, container_node_member); \
|
||||
b_btree_node *next = NULL; \
|
||||
int cmp = comparator(node, cur_node); \
|
||||
\
|
||||
if (cmp >= 0) { \
|
||||
next = b_btree_right(cur); \
|
||||
\
|
||||
if (!next) { \
|
||||
b_btree_put_right( \
|
||||
cur, \
|
||||
&node->container_node_member); \
|
||||
break; \
|
||||
} \
|
||||
} else if (cmp < 0) { \
|
||||
next = b_btree_left(cur); \
|
||||
\
|
||||
if (!next) { \
|
||||
b_btree_put_left( \
|
||||
cur, \
|
||||
&node->container_node_member); \
|
||||
break; \
|
||||
} \
|
||||
} else { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
cur = next; \
|
||||
} \
|
||||
\
|
||||
b_btree_insert_fixup(tree, &node->container_node_member); \
|
||||
}
|
||||
|
||||
/* defines a simple tree search function.
|
||||
this function assumes that your nodes have simple integer keys that can be
|
||||
compared with the usual operators.
|
||||
|
||||
EXAMPLE:
|
||||
if you have a tree node type like this:
|
||||
|
||||
struct my_tree_node {
|
||||
int key;
|
||||
b_btree_node base;
|
||||
}
|
||||
|
||||
You would use the following call to generate a search function for a tree
|
||||
with this node type:
|
||||
|
||||
BTREE_DEFINE_SIMPLE_GET(struct my_tree_node, int, base, key,
|
||||
my_tree_node_get);
|
||||
|
||||
Which would emit a function defined like:
|
||||
|
||||
static struct my_tree_node *my_tree_node_get(b_btree *tree, int key);
|
||||
|
||||
@param node_type your custom tree node type. usually a structure that
|
||||
contains a b_btree_node member.
|
||||
@param key_type the type name of the key embedded in your custom tree node
|
||||
type. this type must be compatible with the builtin comparison operators.
|
||||
@param container_node_member the name of the b_btree_node member variable
|
||||
within your custom type.
|
||||
@param container_key_member the name of the key member variable within your
|
||||
custom type.
|
||||
@param function_name the name of the function to generate.
|
||||
*/
|
||||
#define B_BTREE_DEFINE_SIMPLE_GET( \
|
||||
node_type, key_type, container_node_member, container_key_member, \
|
||||
function_name) \
|
||||
node_type *function_name(const b_btree *tree, key_type key) \
|
||||
{ \
|
||||
b_btree_node *cur = tree->b_root; \
|
||||
while (cur) { \
|
||||
node_type *cur_node = b_unbox( \
|
||||
node_type, cur, container_node_member); \
|
||||
if (key > cur_node->container_key_member) { \
|
||||
cur = b_btree_right(cur); \
|
||||
} else if (key < cur_node->container_key_member) { \
|
||||
cur = b_btree_left(cur); \
|
||||
} else { \
|
||||
return cur_node; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#define b_btree_foreach(it, btree) \
|
||||
for (int z__b_unique_name() = b_btree_iterator_begin(btree, it); \
|
||||
(it)->node != NULL; b_btree_iterator_next(it))
|
||||
|
||||
/* binary tree nodes. this *cannot* be used directly. you need to define a
|
||||
custom node type that contains a member variable of type b_btree_node.
|
||||
|
||||
you would then use the supplied macros to define functions to manipulate your
|
||||
custom binary tree.
|
||||
*/
|
||||
typedef struct b_btree_node {
|
||||
struct b_btree_node *b_parent, *b_left, *b_right;
|
||||
unsigned short b_height;
|
||||
} b_btree_node;
|
||||
|
||||
/* binary tree. unlike b_btree_node, you can define variables of type b_btree.
|
||||
*/
|
||||
typedef struct b_btree {
|
||||
b_btree_node *b_root;
|
||||
} b_btree;
|
||||
|
||||
BLUE_API b_type b_btree_iterator_get_type(void);
|
||||
|
||||
/* re-balance a binary tree after an insertion operation.
|
||||
|
||||
NOTE that, if you define an insertion function using BTREE_DEFINE_INSERT or
|
||||
similar, this function will automatically called for you.
|
||||
|
||||
@param tree the tree to re-balance.
|
||||
@param node the node that was just inserted into the tree.
|
||||
*/
|
||||
BLUE_API void b_btree_insert_fixup(b_btree *tree, b_btree_node *node);
|
||||
|
||||
/* delete a node from a binary tree and re-balance the tree afterwards.
|
||||
|
||||
@param tree the tree to delete from
|
||||
@param node the node to delete.
|
||||
*/
|
||||
BLUE_API void b_btree_delete(b_btree *tree, b_btree_node *node);
|
||||
|
||||
/* get the first node in a binary tree.
|
||||
|
||||
this will be the node with the smallest key (i.e. the node that is
|
||||
furthest-left from the root)
|
||||
*/
|
||||
BLUE_API b_btree_node *b_btree_first(const b_btree *tree);
|
||||
|
||||
/* get the last node in a binary tree.
|
||||
|
||||
this will be the node with the largest key (i.e. the node that is
|
||||
furthest-right from the root)
|
||||
*/
|
||||
BLUE_API b_btree_node *b_btree_last(const b_btree *tree);
|
||||
/* for any binary tree node, this function returns the node with the
|
||||
* next-largest key value */
|
||||
BLUE_API b_btree_node *b_btree_next(const b_btree_node *node);
|
||||
/* for any binary tree node, this function returns the node with the
|
||||
* next-smallest key value */
|
||||
BLUE_API b_btree_node *b_btree_prev(const b_btree_node *node);
|
||||
/* return true if the btree is empty, false otherwise */
|
||||
static inline bool b_btree_empty(const b_btree *tree)
|
||||
{
|
||||
return tree->b_root == NULL;
|
||||
}
|
||||
|
||||
/* sets `child` as the immediate left-child of `parent` */
|
||||
static inline void b_btree_put_left(b_btree_node *parent, b_btree_node *child)
|
||||
{
|
||||
parent->b_left = child;
|
||||
child->b_parent = parent;
|
||||
}
|
||||
|
||||
/* sets `child` as the immediate right-child of `parent` */
|
||||
static inline void b_btree_put_right(b_btree_node *parent, b_btree_node *child)
|
||||
{
|
||||
parent->b_right = child;
|
||||
child->b_parent = parent;
|
||||
}
|
||||
|
||||
/* get the immediate left-child of `node` */
|
||||
static inline b_btree_node *b_btree_left(b_btree_node *node)
|
||||
{
|
||||
return node->b_left;
|
||||
}
|
||||
|
||||
/* get the immediate right-child of `node` */
|
||||
static inline b_btree_node *b_btree_right(b_btree_node *node)
|
||||
{
|
||||
return node->b_right;
|
||||
}
|
||||
|
||||
/* get the immediate parent of `node` */
|
||||
static inline b_btree_node *b_btree_parent(b_btree_node *node)
|
||||
{
|
||||
return node->b_parent;
|
||||
}
|
||||
|
||||
BLUE_API void b_btree_move(b_btree *tree, b_btree_node *dest, b_btree_node *src);
|
||||
|
||||
/* get the height of `node`.
|
||||
|
||||
the height of a node is defined as the length of the longest path
|
||||
between the node and a leaf node.
|
||||
|
||||
this count includes the node itself, so the height of a leaf node will be 1.
|
||||
*/
|
||||
static inline unsigned short b_btree_height(b_btree_node *node)
|
||||
{
|
||||
return node->b_height;
|
||||
}
|
||||
|
||||
BLUE_API b_iterator *b_btree_begin(b_btree *tree);
|
||||
BLUE_API const b_iterator *b_btree_cbegin(const b_btree *tree);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef BLUE_OBJECT_CLASS_H_
|
||||
#define BLUE_OBJECT_CLASS_H_
|
||||
|
||||
#include <blue/core/type.h>
|
||||
|
||||
#define B_CLASS_MAGIC 0xDEADFACEDCAFEBEDULL
|
||||
#define B_CLASS(p) ((b_class *)(p))
|
||||
|
||||
typedef struct _b_class b_class;
|
||||
|
||||
BLUE_API void *b_class_get(b_type id);
|
||||
BLUE_API const char *b_class_get_name(const b_class *c);
|
||||
BLUE_API void *b_class_get_interface(const b_class *c, b_type id);
|
||||
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef BLUE_CORE_ENCODING_H_
|
||||
#define BLUE_CORE_ENCODING_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define B_WCHAR_INVALID ((b_wchar) - 1)
|
||||
|
||||
typedef int32_t b_wchar;
|
||||
|
||||
BLUE_API bool b_wchar_is_alpha(b_wchar c);
|
||||
BLUE_API bool b_wchar_is_number(b_wchar c);
|
||||
static inline bool b_wchar_is_bin_digit(b_wchar c)
|
||||
{
|
||||
return c >= '0' && c <= '1';
|
||||
}
|
||||
static inline bool b_wchar_is_oct_digit(b_wchar c)
|
||||
{
|
||||
return c >= '0' && c <= '7';
|
||||
}
|
||||
BLUE_API bool b_wchar_is_hex_digit(b_wchar c);
|
||||
BLUE_API bool b_wchar_is_space(b_wchar c);
|
||||
static inline bool b_wchar_is_alnum(b_wchar c)
|
||||
{
|
||||
return b_wchar_is_alpha(c) || b_wchar_is_number(c);
|
||||
}
|
||||
|
||||
BLUE_API bool b_wchar_is_punct(b_wchar c);
|
||||
|
||||
BLUE_API bool b_wchar_utf8_is_valid_scalar(b_wchar c);
|
||||
BLUE_API unsigned int b_wchar_utf8_header_decode(char c);
|
||||
BLUE_API unsigned int b_wchar_utf8_codepoint_size(b_wchar c);
|
||||
BLUE_API b_wchar b_wchar_utf8_codepoint_decode(const char *s);
|
||||
BLUE_API unsigned int b_wchar_utf8_codepoint_encode(b_wchar c, char s[4]);
|
||||
BLUE_API unsigned int b_wchar_utf8_codepoint_stride(const char *s);
|
||||
BLUE_API size_t b_wchar_utf8_codepoint_count(const char *s, size_t nr_bytes);
|
||||
BLUE_API size_t b_wchar_utf8_string_encoded_size(
|
||||
const b_wchar *s, size_t nr_codepoints);
|
||||
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
#ifndef BLUELIB_CORE_ENDIAN_H_
|
||||
#define BLUELIB_CORE_ENDIAN_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
unsigned char i_bytes[sizeof(uint16_t)];
|
||||
int16_t i_val;
|
||||
uint16_t i_uval;
|
||||
};
|
||||
} b_i16;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
unsigned char i_bytes[sizeof(uint32_t)];
|
||||
int32_t i_val;
|
||||
uint32_t i_uval;
|
||||
};
|
||||
} b_i32;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
unsigned char i_bytes[sizeof(uint64_t)];
|
||||
int64_t i_val;
|
||||
uint64_t i_uval;
|
||||
};
|
||||
} b_i64;
|
||||
|
||||
BLUE_API b_i16 b_i16_htob(uint16_t v);
|
||||
BLUE_API b_i16 b_i16_htos(uint16_t v);
|
||||
|
||||
BLUE_API uint16_t b_i16_btoh(b_i16 v);
|
||||
BLUE_API uint16_t b_i16_stoh(b_i16 v);
|
||||
|
||||
BLUE_API b_i32 b_i32_htob(uint32_t v);
|
||||
BLUE_API b_i32 b_i32_htos(uint32_t v);
|
||||
|
||||
BLUE_API uint32_t b_i32_btoh(b_i32 v);
|
||||
BLUE_API uint32_t b_i32_stoh(b_i32 v);
|
||||
|
||||
BLUE_API b_i64 b_i64_htob(uint64_t v);
|
||||
BLUE_API b_i64 b_i64_htos(uint64_t v);
|
||||
|
||||
BLUE_API uint64_t b_i64_btoh(b_i64 v);
|
||||
BLUE_API uint64_t b_i64_stoh(b_i64 v);
|
||||
|
||||
#endif
|
||||
@@ -1,418 +0,0 @@
|
||||
#ifndef BLUE_CORE_ERROR_H_
|
||||
#define BLUE_CORE_ERROR_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define B_ERROR_TEMPLATE_PARAMETER_MAX 4
|
||||
#define B_ERROR_MSG_ID_INVALID ((unsigned long)-1)
|
||||
|
||||
#define B_CATCH(err, expr) ((err = (expr)) != NULL)
|
||||
|
||||
#define b_result_is_error(result) ((result) != NULL)
|
||||
#define b_result_is_success(result) ((result) == NULL)
|
||||
|
||||
#define B_RESULT_SUCCESS ((b_result)NULL)
|
||||
#define B_RESULT_ERR(err_name) \
|
||||
b_error_with_code(b_error_vendor_get_builtin(), B_ERR_##err_name)
|
||||
#define B_RESULT_ERR_WITH_STRING(err_name, ...) \
|
||||
b_error_with_string( \
|
||||
b_error_vendor_get_builtin(), B_ERR_##err_name, __VA_ARGS__)
|
||||
#define B_RESULT_STATUS(code) \
|
||||
((code) == B_SUCCESS \
|
||||
? B_RESULT_SUCCESS \
|
||||
: (b_error_with_code(b_error_vendor_get_builtin(), code)))
|
||||
#define B_RESULT_STATUS_WITH_STRING(code, ...) \
|
||||
((code) == B_SUCCESS \
|
||||
? B_RESULT_SUCCESS \
|
||||
: (b_error_with_string( \
|
||||
b_error_vendor_get_builtin(), code, __VA_ARGS__)))
|
||||
|
||||
#define B_ERRORS_BUILTIN (b_error_vendor_get_builtin())
|
||||
#define B_ERRORS_ERRNO (b_error_vendor_get_errno())
|
||||
|
||||
#define B_ERROR_PARAM(name, value) \
|
||||
(b_error_template_parameter) \
|
||||
{ \
|
||||
.param_name = (name), .param_value = (uintptr_t)(value), \
|
||||
}
|
||||
|
||||
#define B_ERROR_TEMPLATE_PARAM(name, type, format) \
|
||||
(b_error_template_parameter_definition) \
|
||||
{ \
|
||||
.param_name = (name), .param_type = (type), \
|
||||
.param_format = (format), \
|
||||
}
|
||||
#define B_ERROR_DEFINITION(code, name, msg) \
|
||||
[code] = (b_error_definition) \
|
||||
{ \
|
||||
.err_name = (name), .err_message = (msg), \
|
||||
}
|
||||
#define B_ERROR_DEFINITION_TEMPLATE(code, name, msg, ...) \
|
||||
[code] = (b_error_definition) \
|
||||
{ \
|
||||
.err_name = (name), .err_message = (msg), \
|
||||
.err_params = __VA_ARGS__, \
|
||||
}
|
||||
|
||||
#define B_ERROR_MSG(id, content) \
|
||||
[id] = (b_error_msg) \
|
||||
{ \
|
||||
.msg_message = (content), \
|
||||
}
|
||||
#define B_ERROR_MSG_TEMPLATE(id, content, ...) \
|
||||
[id] = (b_error_msg) \
|
||||
{ \
|
||||
.msg_message = (content), .msg_params = __VA_ARGS__, \
|
||||
}
|
||||
|
||||
#define z__b_error_create_status(status_code) \
|
||||
(z__b_error_create( \
|
||||
b_error_vendor_get_builtin(), status_code, NULL, NULL, 0, \
|
||||
NULL, NULL))
|
||||
|
||||
/* Error creation macros */
|
||||
#define b_error_with_code(vendor, code) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, NULL))
|
||||
#define b_error_caused_by_error(vendor, code, cause_error) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, NULL))
|
||||
#define b_error_caused_by_status(vendor, code, cause_status) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, z__b_error_create_status(cause_status), \
|
||||
__FILE__, __LINE__, __FUNCTION__, NULL))
|
||||
#define b_error_caused_by_code(vendor, code, cause_vendor, cause_code) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, b_error_with_code(cause_vendor, cause_code), \
|
||||
__FILE__, __LINE__, __FUNCTION__, NULL))
|
||||
#define b_error_with_string(vendor, code, ...) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__))
|
||||
#define b_error_with_string_caused_by_error(vendor, code, cause_error, ...) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
|
||||
__VA_ARGS__))
|
||||
#define b_error_with_string_caused_by_status(vendor, code, cause_status, ...) \
|
||||
(z__b_error_create( \
|
||||
vendor, code, z__b_error_create_status(cause_status), \
|
||||
__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__))
|
||||
#define b_error_with_msg(vendor, code, msg_id) \
|
||||
(z__b_error_create_msg( \
|
||||
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, msg_id, \
|
||||
(b_error_template_parameter[]) {{}}))
|
||||
#define b_error_with_msg_caused_by_error(vendor, code, cause_error, msg_id) \
|
||||
(z__b_error_create_msg( \
|
||||
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
|
||||
msg_id, (b_error_template_parameter[]) {{}}))
|
||||
#define b_error_with_msg_caused_by_status(vendor, code, cause_status, msg_id) \
|
||||
(z__b_error_create_msg( \
|
||||
vendor, code, z__b_error_create_status(cause_status), \
|
||||
__FILE__, __LINE__, __FUNCTION__, msg_id, \
|
||||
(b_error_template_parameter[]) {{}}))
|
||||
#define b_error_with_msg_template(vendor, code, msg_id, ...) \
|
||||
(z__b_error_create_msg( \
|
||||
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, msg_id, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
#define b_error_with_msg_template_caused_by_error( \
|
||||
vendor, code, cause_error, msg_id, ...) \
|
||||
(z__b_error_create_msg( \
|
||||
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
|
||||
msg_id, (b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
#define b_error_with_msg_template_caused_by_status( \
|
||||
vendor, code, cause_status, msg_id, ...) \
|
||||
(z__b_error_create_msg( \
|
||||
vendor, code, z__b_error_create_status(cause_status), \
|
||||
__FILE__, __LINE__, __FUNCTION__, msg_id, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
#define b_error_with_template(vendor, code, ...) \
|
||||
(z__b_error_create_template( \
|
||||
vendor, code, NULL, __FILE__, __LINE__, __FUNCTION__, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
#define b_error_with_template_caused_by_error(vendor, code, cause_error, ...) \
|
||||
(z__b_error_create_template( \
|
||||
vendor, code, cause_error, __FILE__, __LINE__, __FUNCTION__, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
#define b_error_with_template_caused_by_status(vendor, code, cause_status, ...) \
|
||||
(z__b_error_create_template( \
|
||||
vendor, code, z__b_error_create_status(cause_status), \
|
||||
__FILE__, __LINE__, __FUNCTION__, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
|
||||
/* Error propagation macros */
|
||||
#define b_result_propagate(err) \
|
||||
(z__b_error_propagate(err, __FILE__, __LINE__, __FUNCTION__))
|
||||
#define b_error_caused_by(err, caused_by) (z__b_error_caused_by(err, caused_by))
|
||||
#define b_error_caused_by_b_status(err, status) \
|
||||
(z__b_error_caused_by_b_status(err, status))
|
||||
#define b_error_replace(err, caused_by) \
|
||||
(z__b_error_propagate(err, __FILE__, __LINE__, __FUNCTION__))
|
||||
|
||||
/* Error throw macros */
|
||||
#define z__b_throw(err) (z__b_error_throw(err, NULL, 0, NULL))
|
||||
#define b_throw(err) (z__b_error_throw(err, __FILE__, __LINE__, __FUNCTION__))
|
||||
#define b_throw_status(status) \
|
||||
(z__b_error_throw( \
|
||||
z__b_error_create( \
|
||||
b_error_vendor_get_builtin(), status, NULL, NULL, 0, \
|
||||
NULL, NULL), \
|
||||
__FILE__, __LINE__, __FUNCTION__))
|
||||
|
||||
#define b_throw_status_string(status, ...) \
|
||||
(z__b_error_throw( \
|
||||
z__b_error_create( \
|
||||
b_error_vendor_get_builtin(), status, NULL, NULL, 0, \
|
||||
NULL, __VA_ARGS__), \
|
||||
__FILE__, __LINE__, __FUNCTION__))
|
||||
#define b_throw_error_code(vendor, code) \
|
||||
z__b_throw(b_error_with_code(vendor, code))
|
||||
#define b_throw_error_caused_by_error(vendor, code, cause) \
|
||||
z__b_throw(b_error_caused_by_error(vendor, code, cause))
|
||||
#define b_throw_error_caused_by_status(vendor, code, cause) \
|
||||
z__b_throw(b_error_caused_by_status(vendor, code, cause))
|
||||
#define b_throw_error_with_string(vendor, code, ...) \
|
||||
z__b_throw(b_error_with_string(vendor, code, __VA_ARGS__))
|
||||
#define b_throw_error_with_string_caused_by_error(vendor, code, cause, ...) \
|
||||
z__b_throw(b_error_with_string_caused_by_error( \
|
||||
vendor, code, cause, __VA_ARGS__))
|
||||
#define b_throw_error_with_string_caused_by_status(vendor, code, cause, ...) \
|
||||
z__b_throw(b_error_with_string_caused_by_status( \
|
||||
vendor, code, cause, __VA_ARGS__))
|
||||
|
||||
#define b_throw_error_with_msg(vendor, code, msg_id) \
|
||||
z__b_throw(b_error_with_msg(vendor, code, msg_id))
|
||||
#define b_throw_error_with_msg_caused_by_error(vendor, code, cause, msg_id) \
|
||||
z__b_throw(b_error_with_msg_caused_by_error(vendor, code, cause, msg_id))
|
||||
#define b_throw_error_with_msg_caused_by_status(vendor, code, cause, msg_id) \
|
||||
z__b_throw(b_error_with_msg_caused_by_status(vendor, code, cause, msg_id))
|
||||
|
||||
#define b_throw_error_with_msg_template(vendor, code, msg_id, ...) \
|
||||
z__b_throw(b_error_with_msg_template(vendor, code, msg_id, __VA_ARGS__))
|
||||
#define b_throw_error_with_msg_template_caused_by_error( \
|
||||
vendor, code, cause, msg_id, ...) \
|
||||
z__b_throw(b_error_with_msg_template_caused_by_error( \
|
||||
vendor, code, cause, msg_id, __VA_ARGS__))
|
||||
#define b_throw_error_with_msg_template_caused_by_status( \
|
||||
vendor, code, cause, msg_id, ...) \
|
||||
z__b_throw(b_error_with_msg_template_caused_by_status( \
|
||||
vendor, code, cause, msg_id, __VA_ARGS__))
|
||||
|
||||
#define b_throw_error_with_template(vendor, code, ...) \
|
||||
z__b_throw(b_error_with_template(vendor, code, __VA_ARGS__))
|
||||
#define b_throw_error_with_template_caused_by_error(vendor, code, cause, ...) \
|
||||
z__b_throw(b_error_with_template_caused_by_error( \
|
||||
vendor, code, cause, __VA_ARGS__))
|
||||
#define b_throw_error_with_template_caused_by_status(vendor, code, cause, ...) \
|
||||
z__b_throw(b_error_with_template_caused_by_status( \
|
||||
vendor, code, cause, __VA_ARGS__))
|
||||
|
||||
#define B_ERR_MSG(s) \
|
||||
{ \
|
||||
.msg_type = B_ERROR_MESSAGE_ERROR, \
|
||||
.msg_content = (s), \
|
||||
}
|
||||
#define B_ERR_MSG_WARN(s) \
|
||||
{ \
|
||||
.msg_type = B_ERROR_MESSAGE_WARN, \
|
||||
.msg_content = (s), \
|
||||
}
|
||||
#define B_ERR_MSG_INFO(s) \
|
||||
{ \
|
||||
.msg_type = B_ERROR_MESSAGE_INFO, \
|
||||
.msg_content = (s), \
|
||||
}
|
||||
#define B_ERR_MSG_END(s) \
|
||||
{ \
|
||||
.msg_type = B_ERROR_MESSAGE_NONE, \
|
||||
.msg_content = NULL, \
|
||||
}
|
||||
|
||||
typedef enum b_error_submsg_type {
|
||||
B_ERROR_SUBMSG_NONE = 0,
|
||||
B_ERROR_SUBMSG_ERROR,
|
||||
B_ERROR_SUBMSG_WARNING,
|
||||
B_ERROR_SUBMSG_INFO,
|
||||
} b_error_submsg_type;
|
||||
|
||||
typedef enum b_error_report_flags {
|
||||
B_ERROR_REPORT_NONE = 0,
|
||||
B_ERROR_REPORT_STATUS = 0x01u,
|
||||
B_ERROR_REPORT_DESCRIPTION = 0x02u,
|
||||
B_ERROR_REPORT_SUBMSG = 0x04u,
|
||||
B_ERROR_REPORT_STACK_TRACE = 0x08u,
|
||||
B_ERROR_REPORT_CAUSE = 0x10u,
|
||||
|
||||
B_ERROR_REPORT_MINIMAL = B_ERROR_REPORT_STATUS | B_ERROR_REPORT_DESCRIPTION,
|
||||
B_ERROR_REPORT_DEFAULT = B_ERROR_REPORT_MINIMAL | B_ERROR_REPORT_SUBMSG
|
||||
| B_ERROR_REPORT_CAUSE,
|
||||
B_ERROR_REPORT_ALL = B_ERROR_REPORT_DEFAULT | B_ERROR_REPORT_STACK_TRACE,
|
||||
} b_error_report_flags;
|
||||
|
||||
typedef enum b_error_template_parameter_type {
|
||||
B_ERROR_TEMPLATE_PARAM_NONE = 0,
|
||||
B_ERROR_TEMPLATE_PARAM_STRING,
|
||||
B_ERROR_TEMPLATE_PARAM_CHAR,
|
||||
B_ERROR_TEMPLATE_PARAM_INT,
|
||||
B_ERROR_TEMPLATE_PARAM_UINT,
|
||||
B_ERROR_TEMPLATE_PARAM_LONG,
|
||||
B_ERROR_TEMPLATE_PARAM_ULONG,
|
||||
B_ERROR_TEMPLATE_PARAM_LONGLONG,
|
||||
B_ERROR_TEMPLATE_PARAM_ULONGLONG,
|
||||
B_ERROR_TEMPLATE_PARAM_SIZE_T,
|
||||
B_ERROR_TEMPLATE_PARAM_INTPTR,
|
||||
B_ERROR_TEMPLATE_PARAM_UINTPTR,
|
||||
B_ERROR_TEMPLATE_PARAM_PTR,
|
||||
} b_error_template_parameter_type;
|
||||
|
||||
typedef struct b_error_template_parameter_definition {
|
||||
const char *param_name;
|
||||
b_error_template_parameter_type param_type;
|
||||
const char *param_format;
|
||||
} b_error_template_parameter_definition;
|
||||
|
||||
typedef struct b_error_template_parameter {
|
||||
const char *param_name;
|
||||
uintptr_t param_value;
|
||||
const struct b_error_template_parameter_definition *__param_def;
|
||||
} b_error_template_parameter;
|
||||
|
||||
struct b_error_vendor;
|
||||
|
||||
typedef struct b_error b_error;
|
||||
typedef struct b_error *b_result;
|
||||
typedef struct b_error_submsg b_error_submsg;
|
||||
typedef struct b_error_stack_frame b_error_stack_frame;
|
||||
typedef long b_error_status_code;
|
||||
typedef unsigned long b_error_msg_id;
|
||||
|
||||
typedef struct b_error_definition {
|
||||
const char *err_name;
|
||||
const char *err_message;
|
||||
const b_error_template_parameter_definition err_params[B_ERROR_TEMPLATE_PARAMETER_MAX];
|
||||
} b_error_definition;
|
||||
|
||||
typedef struct b_error_msg {
|
||||
const char *msg_message;
|
||||
const b_error_template_parameter_definition msg_params[B_ERROR_TEMPLATE_PARAMETER_MAX];
|
||||
} b_error_msg;
|
||||
|
||||
typedef const b_error_definition *(*b_error_status_code_get_definition)(
|
||||
const struct b_error_vendor *, b_error_status_code);
|
||||
typedef const b_error_msg *(*b_error_msg_get_definition)(
|
||||
const struct b_error_vendor *, b_error_msg_id);
|
||||
typedef void (*b_error_report_function)(
|
||||
const struct b_error *, b_error_report_flags);
|
||||
|
||||
typedef struct b_error_vendor {
|
||||
const char *v_name;
|
||||
|
||||
b_error_status_code_get_definition v_status_get_definition;
|
||||
b_error_msg_get_definition v_msg_get_definition;
|
||||
|
||||
const b_error_definition *v_error_definitions;
|
||||
size_t v_error_definitions_length;
|
||||
|
||||
const b_error_msg *v_msg;
|
||||
size_t v_msg_length;
|
||||
} b_error_vendor;
|
||||
|
||||
BLUE_API b_error *z__b_error_create_template(
|
||||
const b_error_vendor *, b_error_status_code, b_error *, const char *,
|
||||
unsigned int, const char *, const b_error_template_parameter[]);
|
||||
BLUE_API b_error *z__b_error_create_string(
|
||||
const b_error_vendor *, b_error_status_code, b_error *, const char *,
|
||||
unsigned int, const char *, const char *, va_list);
|
||||
BLUE_API b_error *z__b_error_create_msg(
|
||||
const b_error_vendor *, b_error_status_code, b_error *, const char *,
|
||||
unsigned int, const char *, b_error_msg_id,
|
||||
const b_error_template_parameter[]);
|
||||
BLUE_API b_error *z__b_error_propagate(
|
||||
b_error *, const char *, unsigned int, const char *);
|
||||
BLUE_API b_error *z__b_error_caused_by(b_error *, b_error *);
|
||||
BLUE_API b_error *z__b_error_caused_by_b_status(b_error *, b_status);
|
||||
BLUE_API void z__b_error_throw(b_error *, const char *, unsigned int, const char *);
|
||||
|
||||
BLUE_API bool b_result_is(
|
||||
b_result result, const b_error_vendor *vendor, b_error_status_code code);
|
||||
|
||||
BLUE_API const b_error_vendor *b_error_vendor_get_builtin(void);
|
||||
BLUE_API const b_error_vendor *b_error_vendor_get_errno(void);
|
||||
BLUE_API const b_error_definition *b_error_vendor_get_error_definition(
|
||||
const b_error_vendor *vendor, b_error_status_code code);
|
||||
BLUE_API const char *b_error_vendor_get_status_code_name(
|
||||
const b_error_vendor *vendor, b_error_status_code code);
|
||||
BLUE_API const char *b_error_vendor_get_status_code_description(
|
||||
const b_error_vendor *vendor, b_error_status_code code);
|
||||
BLUE_API const b_error_msg *b_error_vendor_get_msg(
|
||||
const b_error_vendor *vendor, b_error_msg_id msg_id);
|
||||
|
||||
static inline b_error *z__b_error_create(
|
||||
const b_error_vendor *v, b_error_status_code c, b_error *c2,
|
||||
const char *f0, unsigned int l, const char *f1, const char *d, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, d);
|
||||
b_error *err = z__b_error_create_string(v, c, c2, f0, l, f1, d, arg);
|
||||
va_end(arg);
|
||||
return err;
|
||||
}
|
||||
|
||||
BLUE_API enum b_status b_error_add_submsg_string(
|
||||
b_error *error, b_error_submsg_type type, const char *msg, ...);
|
||||
BLUE_API enum b_status z__b_error_add_submsg_template(
|
||||
b_error *error, b_error_submsg_type type, b_error_msg_id msg_id,
|
||||
b_error_template_parameter param[]);
|
||||
#define b_error_add_submsg(error, type, msg_id) \
|
||||
(z__b_error_add_submsg_template( \
|
||||
error, type, msg_id, (b_error_template_parameter[]) {{}}))
|
||||
#define b_error_add_submsg_template(error, type, msg_id, ...) \
|
||||
(z__b_error_add_submsg_template( \
|
||||
error, type, msg_id, \
|
||||
(b_error_template_parameter[]) {__VA_ARGS__, {}}))
|
||||
|
||||
BLUE_API void b_error_discard(b_error *error);
|
||||
|
||||
BLUE_API b_error_status_code b_error_get_status_code(const b_error *error);
|
||||
BLUE_API const b_error_vendor *b_error_get_vendor(const b_error *error);
|
||||
BLUE_API const b_error_definition *b_error_get_definition(const b_error *error);
|
||||
BLUE_API const b_error_template_parameter *b_error_get_template_parameter(
|
||||
const b_error *error, const char *param_name);
|
||||
BLUE_API const b_error_template_parameter *b_error_get_template_parameters(
|
||||
const b_error *error);
|
||||
BLUE_API const char *b_error_get_description(const b_error *error);
|
||||
BLUE_API const b_error_msg *b_error_get_msg(const b_error *error);
|
||||
BLUE_API const b_error_submsg *b_error_get_first_submsg(const b_error *error);
|
||||
BLUE_API const b_error_submsg *b_error_get_next_submsg(
|
||||
const b_error *error, const b_error_submsg *msg);
|
||||
BLUE_API const b_error_stack_frame *b_error_get_first_stack_frame(
|
||||
const b_error *error);
|
||||
BLUE_API const b_error_stack_frame *b_error_get_next_stack_frame(
|
||||
const b_error *error, const b_error_stack_frame *frame);
|
||||
BLUE_API const b_error *b_error_get_caused_by(const b_error *error);
|
||||
|
||||
BLUE_API b_error_submsg_type b_error_submsg_get_type(const b_error_submsg *msg);
|
||||
BLUE_API const char *b_error_submsg_get_content(const b_error_submsg *msg);
|
||||
BLUE_API const b_error_msg *b_error_submsg_get_msg(const b_error_submsg *msg);
|
||||
BLUE_API const b_error_template_parameter *b_error_submsg_get_template_parameters(
|
||||
const b_error_submsg *msg);
|
||||
|
||||
BLUE_API const char *b_error_stack_frame_get_filepath(
|
||||
const b_error_stack_frame *frame);
|
||||
BLUE_API unsigned int b_error_stack_frame_get_line_number(
|
||||
const b_error_stack_frame *frame);
|
||||
BLUE_API const char *b_error_stack_frame_get_function_name(
|
||||
const b_error_stack_frame *frame);
|
||||
|
||||
BLUE_API const b_error_template_parameter_definition *b_error_definition_get_template_parameter(
|
||||
const b_error_definition *error_def, const char *param_name);
|
||||
|
||||
BLUE_API const char *b_error_msg_get_content(const b_error_msg *msg);
|
||||
BLUE_API const b_error_template_parameter_definition *b_error_msg_get_template_parameter(
|
||||
const b_error_msg *msg, const char *param_name);
|
||||
|
||||
BLUE_API void b_set_error_report_function(
|
||||
b_error_report_function func, b_error_report_flags flags);
|
||||
|
||||
#endif
|
||||
@@ -1,111 +0,0 @@
|
||||
#ifndef BLUELIB_CORE_HASH_H_
|
||||
#define BLUELIB_CORE_HASH_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define B_DIGEST_LENGTH_128 16
|
||||
#define B_DIGEST_LENGTH_160 20
|
||||
#define B_DIGEST_LENGTH_192 24
|
||||
#define B_DIGEST_LENGTH_224 28
|
||||
#define B_DIGEST_LENGTH_256 32
|
||||
#define B_DIGEST_LENGTH_384 48
|
||||
#define B_DIGEST_LENGTH_512 64
|
||||
|
||||
#define B_DIGEST_LENGTH_MD4 B_DIGEST_LENGTH_128
|
||||
#define B_DIGEST_LENGTH_MD5 B_DIGEST_LENGTH_128
|
||||
#define B_DIGEST_LENGTH_SHA1 B_DIGEST_LENGTH_160
|
||||
#define B_DIGEST_LENGTH_SHA2_224 B_DIGEST_LENGTH_224
|
||||
#define B_DIGEST_LENGTH_SHA2_256 B_DIGEST_LENGTH_256
|
||||
#define B_DIGEST_LENGTH_SHA2_384 B_DIGEST_LENGTH_384
|
||||
#define B_DIGEST_LENGTH_SHA2_512 B_DIGEST_LENGTH_512
|
||||
#define B_DIGEST_LENGTH_SHA3_224 B_DIGEST_LENGTH_224
|
||||
#define B_DIGEST_LENGTH_SHA3_256 B_DIGEST_LENGTH_256
|
||||
#define B_DIGEST_LENGTH_SHA3_384 B_DIGEST_LENGTH_384
|
||||
#define B_DIGEST_LENGTH_SHA3_512 B_DIGEST_LENGTH_512
|
||||
#define B_DIGEST_LENGTH_SHAKE128 B_DIGEST_LENGTH_128
|
||||
#define B_DIGEST_LENGTH_SHAKE256 B_DIGEST_LENGTH_256
|
||||
|
||||
struct b_hash_function_ops;
|
||||
struct b_rope;
|
||||
|
||||
typedef enum b_hash_function {
|
||||
B_HASH_NONE = 0,
|
||||
B_HASH_MD4,
|
||||
B_HASH_MD5,
|
||||
B_HASH_SHA1,
|
||||
B_HASH_SHA2_224,
|
||||
B_HASH_SHA2_256,
|
||||
B_HASH_SHA2_384,
|
||||
B_HASH_SHA2_512,
|
||||
B_HASH_SHA3_224,
|
||||
B_HASH_SHA3_256,
|
||||
B_HASH_SHA3_384,
|
||||
B_HASH_SHA3_512,
|
||||
B_HASH_SHAKE128,
|
||||
B_HASH_SHAKE256,
|
||||
} b_hash_function;
|
||||
|
||||
typedef struct b_hash_ctx {
|
||||
b_hash_function ctx_func;
|
||||
const struct b_hash_function_ops *ctx_ops;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t lo, hi;
|
||||
uint32_t a, b, c, d;
|
||||
uint32_t block[16];
|
||||
unsigned char buffer[64];
|
||||
} md4;
|
||||
|
||||
struct {
|
||||
unsigned int count[2];
|
||||
unsigned int a, b, c, d;
|
||||
unsigned int block[16];
|
||||
unsigned char input[64];
|
||||
} md5;
|
||||
|
||||
struct {
|
||||
uint32_t state[5];
|
||||
uint32_t count[2];
|
||||
unsigned char buffer[64];
|
||||
} sha1;
|
||||
|
||||
struct {
|
||||
uint64_t curlen;
|
||||
uint64_t length;
|
||||
unsigned char buf[128];
|
||||
uint32_t state[8];
|
||||
} sha2_256;
|
||||
|
||||
struct {
|
||||
uint64_t curlen;
|
||||
uint64_t length;
|
||||
unsigned char block[256];
|
||||
uint64_t state[8];
|
||||
} sha2_512;
|
||||
|
||||
struct {
|
||||
union {
|
||||
uint8_t b[200];
|
||||
uint64_t q[25];
|
||||
} st;
|
||||
|
||||
int pt, rsiz, mdlen;
|
||||
} sha3;
|
||||
} ctx_state;
|
||||
} b_hash_ctx;
|
||||
|
||||
BLUE_API uint64_t b_hash_cstr(const char *s);
|
||||
BLUE_API uint64_t b_hash_cstr_ex(const char *s, size_t *len);
|
||||
|
||||
BLUE_API b_status b_hash_ctx_init(b_hash_ctx *ctx, b_hash_function func);
|
||||
BLUE_API b_status b_hash_ctx_reset(b_hash_ctx *ctx);
|
||||
BLUE_API b_status b_hash_ctx_update(b_hash_ctx *ctx, const void *p, size_t len);
|
||||
BLUE_API b_status b_hash_ctx_update_rope(b_hash_ctx *ctx, const struct b_rope *rope);
|
||||
BLUE_API b_status b_hash_ctx_finish(
|
||||
b_hash_ctx *ctx, void *out_digest, size_t out_max);
|
||||
|
||||
#endif
|
||||
@@ -1,93 +0,0 @@
|
||||
#ifndef BLUE_CORE_ITERATOR_H_
|
||||
#define BLUE_CORE_ITERATOR_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define b_foreach(type, var, iterator) \
|
||||
for (type var = (type)b_iterator_get_value(iterator).v_int; \
|
||||
B_OK(b_iterator_get_status(iterator)); \
|
||||
b_iterator_move_next(iterator), \
|
||||
var = (type)b_iterator_get_value(iterator).v_int)
|
||||
#define b_foreach_ptr(type, var, iterator) \
|
||||
for (type *var = (type *)b_iterator_get_value(iterator).v_ptr; \
|
||||
B_OK(b_iterator_get_status(iterator)); \
|
||||
b_iterator_move_next(iterator), \
|
||||
var = (type *)b_iterator_get_value(iterator).v_ptr)
|
||||
#define b_foreach_c(type, var, iterator) \
|
||||
for (type var = (type)b_iterator_get_cvalue(iterator).v_int; \
|
||||
B_OK(b_iterator_get_status(iterator)); \
|
||||
b_iterator_move_next(iterator), \
|
||||
var = (type)b_iterator_get_cvalue(iterator).v_int)
|
||||
#define b_foreach_cptr(type, var, iterator) \
|
||||
for (const type *var \
|
||||
= (const type *)b_iterator_get_cvalue(iterator).v_cptr; \
|
||||
B_OK(b_iterator_get_status(iterator)); \
|
||||
b_iterator_move_next(iterator), \
|
||||
var = (const type *)b_iterator_get_cvalue(iterator).v_cptr)
|
||||
|
||||
#define B_ITERATOR_VALUE_INT(v) ((b_iterator_value) {.v_int = (v)})
|
||||
#define B_ITERATOR_VALUE_PTR(v) ((b_iterator_value) {.v_ptr = (v)})
|
||||
#define B_ITERATOR_VALUE_CPTR(v) ((const b_iterator_value) {.v_cptr = (v)})
|
||||
#define B_ITERATOR_VALUE_NULL ((b_iterator_value) {})
|
||||
#define B_ITERATOR_VALUE_IS_NULL(v) ((v)->v_ptr == NULL)
|
||||
|
||||
#define B_TYPE_ITERATOR (b_iterator_get_type())
|
||||
#define B_TYPE_ITERABLE (b_iterable_get_type())
|
||||
|
||||
typedef union b_iterator_value {
|
||||
uintptr_t v_int;
|
||||
void *v_ptr;
|
||||
const void *v_cptr;
|
||||
} b_iterator_value;
|
||||
|
||||
__B_DECLARE_TYPE(b_iterator);
|
||||
|
||||
B_DECLARE_TYPE(b_iterable);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_iterator)
|
||||
b_status (*it_move_next)(const b_iterator *);
|
||||
b_status (*it_erase)(b_iterator *);
|
||||
b_iterator_value (*it_get_value)(b_iterator *);
|
||||
const b_iterator_value (*it_get_cvalue)(const b_iterator *);
|
||||
B_TYPE_CLASS_DECLARATION_END(b_iterator)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_iterable)
|
||||
b_iterator *(*it_begin)(b_iterable *);
|
||||
const b_iterator *(*it_cbegin)(const b_iterable *);
|
||||
B_TYPE_CLASS_DECLARATION_END(b_iterable)
|
||||
|
||||
BLUE_API b_type b_iterator_get_type(void);
|
||||
BLUE_API b_type b_iterable_get_type(void);
|
||||
|
||||
static inline const b_iterator *b_iterator_ref(const b_iterator *p)
|
||||
{
|
||||
return b_object_ref((b_object *)p);
|
||||
}
|
||||
static inline void b_iterator_unref(const b_iterator *p)
|
||||
{
|
||||
b_object_unref((b_object *)p);
|
||||
}
|
||||
|
||||
BLUE_API b_iterator *b_iterator_begin(b_iterable *it);
|
||||
BLUE_API const b_iterator *b_iterator_cbegin(const b_iterable *it);
|
||||
|
||||
BLUE_API b_status b_iterator_get_status(const b_iterator *it);
|
||||
BLUE_API b_status b_iterator_set_status(const b_iterator *it, b_status status);
|
||||
|
||||
BLUE_API b_status b_iterator_move_next(const b_iterator *it);
|
||||
BLUE_API b_iterator_value b_iterator_get_value(b_iterator *it);
|
||||
BLUE_API const b_iterator_value b_iterator_get_cvalue(const b_iterator *it);
|
||||
BLUE_API b_status b_iterator_erase(b_iterator *it);
|
||||
static inline bool b_iterator_is_valid(const b_iterator *it)
|
||||
{
|
||||
return B_OK(b_iterator_get_status(it));
|
||||
}
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,197 +0,0 @@
|
||||
#ifndef BLUE_CORE_MACROS_H_
|
||||
#define BLUE_CORE_MACROS_H_
|
||||
|
||||
#include <blue/core/class.h>
|
||||
#include <blue/core/object.h>
|
||||
#include <blue/core/thread.h>
|
||||
#include <blue/core/type.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define __B_IFACE_I0(p, x) p##x
|
||||
#define __B_IFACE_I1(p, x) __B_IFACE_I0(p, x)
|
||||
|
||||
/* Type definitions macros (for use in .c source file) */
|
||||
|
||||
#define B_TYPE_CLASS_DEFINITION_BEGIN(type_name) \
|
||||
static void type_name##_class_init(b_class *p, void *d) \
|
||||
{
|
||||
#define B_TYPE_CLASS_DEFINITION_END(type_name) }
|
||||
|
||||
#define B_TYPE_CLASS_INTERFACE_BEGIN(interface_name, interface_id) \
|
||||
interface_name##_class *__B_IFACE_I1(iface, __LINE__) \
|
||||
= b_class_get_interface(p, interface_id); \
|
||||
if (!__B_IFACE_I1(iface, __LINE__)) { \
|
||||
b_throw_error_with_msg_template( \
|
||||
B_ERRORS_BUILTIN, B_ERR_CLASS_INIT_FAILURE, \
|
||||
B_MSG_CLASS_SPECIFIES_UNKNOWN_INTERFACE, \
|
||||
B_ERROR_PARAM("class_name", b_class_get_name(p)), \
|
||||
B_ERROR_PARAM("interface_name", #interface_name)); \
|
||||
exit(-1); \
|
||||
} else { \
|
||||
interface_name##_class *iface = __B_IFACE_I1(iface, __LINE__);
|
||||
#define B_TYPE_CLASS_INTERFACE_END(interface_name, interface_id) }
|
||||
#define B_INTERFACE_ENTRY(slot) iface->slot
|
||||
|
||||
#define B_TYPE_DEFINITION_BEGIN(name) \
|
||||
static b_type_info name##_type_info = {0}; \
|
||||
static void name##_class_init(b_class *, void *); \
|
||||
static void name##_type_init(void) \
|
||||
{ \
|
||||
b_type_info *type_info = &name##_type_info; \
|
||||
unsigned int nr_vtables = 0; \
|
||||
type_info->t_name = #name; \
|
||||
type_info->t_class_init = name##_class_init;
|
||||
#define B_TYPE_DEFINITION_END(name) \
|
||||
b_result result = b_type_register(type_info); \
|
||||
if (b_result_is_error(result)) { \
|
||||
b_throw_error_caused_by_error( \
|
||||
B_ERRORS_BUILTIN, B_ERR_TYPE_REGISTRATION_FAILURE, \
|
||||
result); \
|
||||
abort(); \
|
||||
} \
|
||||
} \
|
||||
b_type name##_get_type(void) \
|
||||
{ \
|
||||
static b_once static_type_init = B_ONCE_INIT; \
|
||||
\
|
||||
if (b_init_once(&static_type_init)) { \
|
||||
name##_type_init(); \
|
||||
} \
|
||||
\
|
||||
return &name##_type_info.t_id; \
|
||||
}
|
||||
|
||||
#define B_TYPE_ID(a, b, c, d, e) b_type_id_init(&type_info->t_id, a, b, c, d, e)
|
||||
#define B_TYPE_EXTENDS(parent_id) \
|
||||
b_type_id_copy(parent_id, &type_info->t_parent_id)
|
||||
#define B_TYPE_IMPLEMENTS(interface_id) \
|
||||
b_type_id_copy( \
|
||||
interface_id, \
|
||||
&type_info->t_interfaces[type_info->t_nr_interfaces++])
|
||||
#define B_TYPE_CLASS(class_struct) \
|
||||
type_info->t_class_size = sizeof(class_struct)
|
||||
#define B_TYPE_FLAGS(flags) type_info->t_flags = (flags)
|
||||
#define B_TYPE_INSTANCE_INIT(func) type_info->t_instance_init = (func)
|
||||
#define B_TYPE_INSTANCE_FINI(func) type_info->t_instance_fini = (func)
|
||||
|
||||
#if 0
|
||||
#define B_TYPE_VTABLE_BEGIN(vtable_struct, interface_id) \
|
||||
vtable_struct __B_IFACE_I1(iface, __LINE__) = {0}; \
|
||||
{ \
|
||||
vtable_struct *iface = &__B_IFACE_I1(iface, __LINE__); \
|
||||
type_info->t_vtables[nr_vtables].v_vtable = iface; \
|
||||
type_info->t_vtables[nr_vtables].v_interface_id = interface_id; \
|
||||
nr_vtables++;
|
||||
#define B_TYPE_VTABLE_END(vtable_struct, interface_id) }
|
||||
#endif
|
||||
|
||||
#define B_TYPE_INSTANCE_PRIVATE(instance_struct) \
|
||||
type_info->t_instance_private_size = sizeof(instance_struct)
|
||||
#define B_TYPE_INSTANCE_PROTECTED(instance_struct) \
|
||||
type_info->t_instance_protected_size = sizeof(instance_struct)
|
||||
|
||||
/* Type declaration macros (for use in .h header file) */
|
||||
|
||||
#define __B_DECLARE_TYPE(name) \
|
||||
typedef B_TYPE_FWDREF(name) name; \
|
||||
typedef struct _##name##_class name##_class;
|
||||
|
||||
#define B_DECLARE_TYPE(name) \
|
||||
__B_DECLARE_TYPE(name); \
|
||||
static inline name *name##_ref(name *p) \
|
||||
{ \
|
||||
return b_object_ref(p); \
|
||||
} \
|
||||
static inline void name##_unref(name *p) \
|
||||
{ \
|
||||
b_object_unref(p); \
|
||||
}
|
||||
|
||||
#define B_TYPE_CLASS_DECLARATION_BEGIN(name) struct _##name##_class {
|
||||
#define B_TYPE_CLASS_DECLARATION_END(name) \
|
||||
} \
|
||||
;
|
||||
|
||||
#define B_TYPE_VIRTUAL_METHOD(return_type, method_name) \
|
||||
return_type(*method_name)
|
||||
|
||||
#define B_TYPE_DEFAULT_CONSTRUCTOR(type_name, type_id) \
|
||||
static inline type_name *type_name##_create(void) \
|
||||
{ \
|
||||
return b_object_create(type_id); \
|
||||
}
|
||||
|
||||
/* Other macros */
|
||||
|
||||
#define B_CLASS_DISPATCH_VIRTUAL( \
|
||||
type_name, type_id, default_value, func, object, ...) \
|
||||
do { \
|
||||
type_name##_class *iface \
|
||||
= b_object_get_interface(object, type_id); \
|
||||
if (iface && iface->func) { \
|
||||
return iface->func(object, __VA_ARGS__); \
|
||||
} else { \
|
||||
return default_value; \
|
||||
} \
|
||||
} while (0)
|
||||
#define B_CLASS_DISPATCH_VIRTUAL_0(type_name, type_id, default_value, func, object) \
|
||||
do { \
|
||||
type_name##_class *iface \
|
||||
= b_object_get_interface(object, type_id); \
|
||||
if (iface && iface->func) { \
|
||||
return iface->func(object); \
|
||||
} else { \
|
||||
return default_value; \
|
||||
} \
|
||||
} while (0)
|
||||
#define B_CLASS_DISPATCH_VIRTUAL_V(type_name, type_id, func, object, ...) \
|
||||
do { \
|
||||
type_name##_class *iface \
|
||||
= b_object_get_interface(object, type_id); \
|
||||
if (iface && iface->func) { \
|
||||
iface->func(object, __VA_ARGS__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
#define B_CLASS_DISPATCH_VIRTUAL_V0(type_name, type_id, func, object) \
|
||||
do { \
|
||||
type_name##_class *iface \
|
||||
= b_object_get_interface(object, type_id); \
|
||||
if (iface && iface->func) { \
|
||||
iface->func(object); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define B_CLASS_DISPATCH_STATIC(type_id, func_name, obj, ...) \
|
||||
do { \
|
||||
void *priv = b_object_get_private(obj, type_id); \
|
||||
return func_name(priv, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define B_CLASS_DISPATCH_STATIC_V(type_id, func_name, obj, ...) \
|
||||
do { \
|
||||
void *priv = b_object_get_private(obj, type_id); \
|
||||
func_name(priv, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define B_CLASS_DISPATCH_STATIC_0(type_id, func_name, obj) \
|
||||
do { \
|
||||
void *priv = b_object_get_private(obj, type_id); \
|
||||
return func_name(priv); \
|
||||
} while (0)
|
||||
|
||||
#define B_CLASS_DISPATCH_STATIC_V0(type_id, func_name, obj) \
|
||||
do { \
|
||||
void *priv = b_object_get_private(obj, type_id); \
|
||||
func_name(priv); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define B_DECLS_BEGIN extern "C" {
|
||||
#define B_DECLS_END }
|
||||
#else
|
||||
#define B_DECLS_BEGIN
|
||||
#define B_DECLS_END
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,118 +0,0 @@
|
||||
#ifndef BLUE_CORE_MISC_H_
|
||||
#define BLUE_CORE_MISC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef _Nonnull
|
||||
#define _Nonnull
|
||||
#endif
|
||||
|
||||
#define B_NPOS ((size_t)-1)
|
||||
|
||||
#define b_min(type, x, y) (z__b_min_##type(x, y))
|
||||
#define b_max(type, x, y) (z__b_max_##type(x, y))
|
||||
|
||||
#define b_unbox(type, box, member) \
|
||||
((type *_Nonnull)((box) ? (uintptr_t)(box) - (offsetof(type, member)) : 0))
|
||||
|
||||
#define z__b_merge_(a, b) a##b
|
||||
#define z__b_label_(a) z__b_merge_(__unique_name_, a)
|
||||
#define z__b_unique_name() z__b_label_(__LINE__)
|
||||
#define z__b_numargs(arg_type, ...) \
|
||||
(sizeof((arg_type[]) {__VA_ARGS__}) / sizeof(arg_type))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef BLUELIB_STATIC
|
||||
#define BLUE_API extern
|
||||
#else
|
||||
#ifdef BLUELIB_EXPORT
|
||||
#define BLUE_API extern __declspec(dllexport)
|
||||
#else
|
||||
#define BLUE_API extern __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define BLUE_API extern
|
||||
#endif
|
||||
|
||||
static inline char z__b_min_char(char x, char y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline unsigned char z__b_min_uchar(unsigned char x, unsigned char y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline int z__b_min_int(int x, int y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline unsigned int z__b_min_uint(unsigned int x, unsigned int y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline long z__b_min_long(long x, long y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline unsigned int z__b_min_ulong(unsigned long x, unsigned long y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline long long z__b_min_longlong(long long x, long long y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline unsigned long long z__b_min_ulonglong(
|
||||
unsigned long long x, unsigned long long y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
static inline size_t z__b_min_size_t(size_t x, size_t y)
|
||||
{
|
||||
return x < y ? x : y;
|
||||
}
|
||||
|
||||
static inline char z__b_max_char(char x, char y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline unsigned char z__b_max_uchar(unsigned char x, unsigned char y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline int z__b_max_int(int x, int y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline unsigned int z__b_max_uint(unsigned int x, unsigned int y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline long z__b_max_long(long x, long y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline unsigned int z__b_max_ulong(unsigned long x, unsigned long y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline long long z__b_max_longlong(long long x, long long y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline unsigned long long z__b_max_ulonglong(
|
||||
unsigned long long x, unsigned long long y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
static inline size_t z__b_max_size_t(size_t x, size_t y)
|
||||
{
|
||||
return x > y ? x : y;
|
||||
}
|
||||
|
||||
BLUE_API size_t b_int_length(intptr_t v);
|
||||
BLUE_API size_t b_uint_length(uintptr_t v);
|
||||
|
||||
#endif // BLUE_CORE_MISC_H_
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef BLUE_CORE_OBJECT_H_
|
||||
#define BLUE_CORE_OBJECT_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/type.h>
|
||||
|
||||
#define B_OBJECT_MAGIC 0xDECAFC0C0ABEEF13ULL
|
||||
|
||||
#define B_OBJECT(p) ((b_object *)(p))
|
||||
#define B_TYPE_OBJECT (b_object_get_type())
|
||||
|
||||
#define B_TYPE_FWDREF(name) struct _b_object
|
||||
|
||||
#define B_RV(p) (b_object_make_rvalue(p))
|
||||
|
||||
typedef B_TYPE_FWDREF(b_object) b_object;
|
||||
|
||||
typedef struct _b_object_class {
|
||||
void (*to_string)(const b_object *, B_TYPE_FWDREF(b_stream) *);
|
||||
} b_object_class;
|
||||
|
||||
BLUE_API b_type b_object_get_type(void);
|
||||
|
||||
BLUE_API void *b_object_get_private(const b_object *object, b_type type);
|
||||
BLUE_API void *b_object_get_protected(const b_object *object, b_type type);
|
||||
BLUE_API void *b_object_get_interface(const b_object *object, b_type type);
|
||||
BLUE_API b_status b_object_get_data(
|
||||
const b_object *object, b_type type, void **priv, void **prot,
|
||||
void **iface);
|
||||
|
||||
BLUE_API b_object *b_object_ref(b_object *p);
|
||||
BLUE_API void b_object_unref(b_object *p);
|
||||
BLUE_API b_object *b_object_make_rvalue(b_object *p);
|
||||
|
||||
BLUE_API b_object *b_object_create(b_type type);
|
||||
BLUE_API void b_object_to_string(const b_object *p, B_TYPE_FWDREF(b_stream) * out);
|
||||
BLUE_API bool b_object_is_type(const b_object *p, b_type type);
|
||||
|
||||
#endif
|
||||
@@ -1,82 +0,0 @@
|
||||
#ifndef BLUE_CORE_QUEUE_H_
|
||||
#define BLUE_CORE_QUEUE_H_
|
||||
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_QUEUE_ITERATOR (b_queue_iterator_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_queue_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_queue_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_queue_iterator)
|
||||
|
||||
#define B_QUEUE_INIT ((b_queue) {.q_first = NULL, .q_last = NULL})
|
||||
#define B_QUEUE_ENTRY_INIT ((b_queue_entry) {.qe_next = NULL, .qe_prev = NULL})
|
||||
|
||||
typedef struct b_queue_entry {
|
||||
struct b_queue_entry *qe_next;
|
||||
struct b_queue_entry *qe_prev;
|
||||
} b_queue_entry;
|
||||
|
||||
typedef struct b_queue {
|
||||
b_queue_entry *q_first;
|
||||
b_queue_entry *q_last;
|
||||
} b_queue;
|
||||
|
||||
static inline void b_queue_init(b_queue *q)
|
||||
{
|
||||
memset(q, 0x00, sizeof *q);
|
||||
}
|
||||
static inline bool b_queue_empty(const b_queue *q)
|
||||
{
|
||||
return q ? (q->q_first == NULL) : true;
|
||||
}
|
||||
|
||||
static inline b_queue_entry *b_queue_first(const b_queue *q)
|
||||
{
|
||||
return q ? q->q_first : NULL;
|
||||
}
|
||||
static inline b_queue_entry *b_queue_last(const b_queue *q)
|
||||
{
|
||||
return q ? q->q_last : NULL;
|
||||
}
|
||||
static inline b_queue_entry *b_queue_next(const b_queue_entry *entry)
|
||||
{
|
||||
return entry ? entry->qe_next : NULL;
|
||||
}
|
||||
static inline b_queue_entry *b_queue_prev(const b_queue_entry *entry)
|
||||
{
|
||||
return entry ? entry->qe_prev : NULL;
|
||||
}
|
||||
|
||||
BLUE_API b_type b_queue_iterator_get_type(void);
|
||||
|
||||
BLUE_API size_t b_queue_length(const b_queue *q);
|
||||
|
||||
BLUE_API void b_queue_insert_before(
|
||||
b_queue *q, b_queue_entry *entry, b_queue_entry *before);
|
||||
BLUE_API void b_queue_insert_after(
|
||||
b_queue *q, b_queue_entry *entry, b_queue_entry *after);
|
||||
|
||||
BLUE_API void b_queue_push_front(b_queue *q, b_queue_entry *entry);
|
||||
BLUE_API void b_queue_push_back(b_queue *q, b_queue_entry *entry);
|
||||
|
||||
BLUE_API b_queue_entry *b_queue_pop_front(b_queue *q);
|
||||
BLUE_API b_queue_entry *b_queue_pop_back(b_queue *q);
|
||||
|
||||
BLUE_API void b_queue_move(b_queue *q, b_queue_entry *dest, b_queue_entry *src);
|
||||
BLUE_API void b_queue_delete(b_queue *q, b_queue_entry *entry);
|
||||
BLUE_API void b_queue_delete_all(b_queue *q);
|
||||
|
||||
BLUE_API b_iterator *b_queue_begin(b_queue *q);
|
||||
BLUE_API b_iterator *b_queue_cbegin(const b_queue *q);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef BLUELIB_RANDOM_H_
|
||||
#define BLUELIB_RANDOM_H_
|
||||
|
||||
#include <blue/core/status.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct b_random_algorithm;
|
||||
|
||||
typedef enum b_random_flags {
|
||||
/* algorithm selection */
|
||||
B_RANDOM_MT19937 = 0x01u,
|
||||
|
||||
/* generation flags */
|
||||
B_RANDOM_SECURE = 0x100u,
|
||||
} b_random_flags;
|
||||
|
||||
typedef struct b_random_ctx {
|
||||
b_random_flags __f;
|
||||
struct b_random_algorithm *__a;
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned long long mt[312];
|
||||
size_t mti;
|
||||
} __mt19937;
|
||||
};
|
||||
} b_random_ctx;
|
||||
|
||||
BLUE_API b_random_ctx *b_random_global_ctx(void);
|
||||
|
||||
BLUE_API b_status b_random_init(b_random_ctx *ctx, b_random_flags flags);
|
||||
BLUE_API unsigned long long b_random_next_int64(b_random_ctx *ctx);
|
||||
BLUE_API double b_random_next_double(b_random_ctx *ctx);
|
||||
BLUE_API void b_random_next_bytes(
|
||||
b_random_ctx *ctx, unsigned char *out, size_t nbytes);
|
||||
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
#ifndef BLUE_CORE_RINGBUFFER_H_
|
||||
#define BLUE_CORE_RINGBUFFER_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_RINGBUFFER (b_ringbuffer_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_ringbuffer);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_ringbuffer)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_ringbuffer)
|
||||
|
||||
BLUE_API b_type b_ringbuffer_get_type(void);
|
||||
|
||||
BLUE_API b_ringbuffer *b_ringbuffer_create(size_t capacity);
|
||||
BLUE_API b_ringbuffer *b_ringbuffer_create_with_buffer(void *ptr, size_t capacity);
|
||||
|
||||
BLUE_API b_status b_ringbuffer_clear(b_ringbuffer *buf);
|
||||
|
||||
BLUE_API b_status b_ringbuffer_read(
|
||||
b_ringbuffer *buf, void *p, size_t count, size_t *nr_read);
|
||||
BLUE_API b_status b_ringbuffer_write(
|
||||
b_ringbuffer *buf, const void *p, size_t count, size_t *nr_written);
|
||||
|
||||
BLUE_API int b_ringbuffer_getc(b_ringbuffer *buf);
|
||||
BLUE_API b_status b_ringbuffer_putc(b_ringbuffer *buf, int c);
|
||||
|
||||
BLUE_API size_t b_ringbuffer_write_capacity_remaining(const b_ringbuffer *buf);
|
||||
BLUE_API size_t b_ringbuffer_available_data_remaining(const b_ringbuffer *buf);
|
||||
|
||||
BLUE_API b_status b_ringbuffer_open_read_buffer(
|
||||
b_ringbuffer *buf, const void **ptr, size_t *length);
|
||||
BLUE_API b_status b_ringbuffer_close_read_buffer(
|
||||
b_ringbuffer *buf, const void **ptr, size_t nr_read);
|
||||
|
||||
BLUE_API b_status b_ringbuffer_open_write_buffer(
|
||||
b_ringbuffer *buf, void **ptr, size_t *capacity);
|
||||
BLUE_API b_status b_ringbuffer_close_write_buffer(
|
||||
b_ringbuffer *buf, void **ptr, size_t nr_written);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
#ifndef BLUE_CORE_ROPE_H_
|
||||
#define BLUE_CORE_ROPE_H_
|
||||
|
||||
#include <blue/core/hash.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
struct b_string;
|
||||
struct b_bstr;
|
||||
|
||||
#define B_ROPE_TYPE(f) ((f) & 0xFF)
|
||||
|
||||
#define B_ROPE_CHAR(c) \
|
||||
\
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_CHAR, .r_len_total = 1, \
|
||||
.r_v = {.v_char = (c) } \
|
||||
}
|
||||
|
||||
#define B_ROPE_CSTR(str) \
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_CSTR_BORROWED, \
|
||||
.r_len_total = strlen(str), \
|
||||
.r_v = { \
|
||||
.v_cstr = { \
|
||||
.s = (str), \
|
||||
.hash = b_hash_cstr(str), \
|
||||
}, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define B_ROPE_CSTR_STATIC(str) \
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_CSTR_STATIC, \
|
||||
.r_len_total = strlen(str), \
|
||||
.r_v = { \
|
||||
.v_cstr = { \
|
||||
.s = (str), \
|
||||
.hash = b_hash_cstr(str), \
|
||||
}, \
|
||||
}, \
|
||||
}
|
||||
#define B_ROPE_INT(v) \
|
||||
\
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_INT, .r_len_total = b_int_length(v), \
|
||||
.r_v = {.v_int = (v) } \
|
||||
}
|
||||
#define B_ROPE_UINT(v) \
|
||||
\
|
||||
{ \
|
||||
.r_flags = B_ROPE_F_UINT, .r_len_total = b_uint_length(v), \
|
||||
.r_v = {.v_uint = (v) } \
|
||||
}
|
||||
|
||||
typedef enum b_rope_flags {
|
||||
B_ROPE_F_NONE = 0x0000u,
|
||||
B_ROPE_F_CHAR = 0x0001u,
|
||||
B_ROPE_F_CSTR = 0x0002u,
|
||||
B_ROPE_F_CSTR_BORROWED = 0x0003u,
|
||||
B_ROPE_F_CSTR_STATIC = 0x0004u,
|
||||
B_ROPE_F_INT = 0x0005u,
|
||||
B_ROPE_F_UINT = 0x0006u,
|
||||
B_ROPE_F_COMPOSITE = 0x0007u,
|
||||
B_ROPE_F_MALLOC = 0x0100u,
|
||||
} b_rope_flags;
|
||||
|
||||
typedef struct b_rope {
|
||||
b_rope_flags r_flags;
|
||||
unsigned long r_len_left, r_len_total;
|
||||
|
||||
union {
|
||||
char v_char;
|
||||
intptr_t v_int;
|
||||
uintptr_t v_uint;
|
||||
|
||||
struct {
|
||||
const char *s;
|
||||
uint64_t hash;
|
||||
} v_cstr;
|
||||
|
||||
struct {
|
||||
const struct b_rope *r_left, *r_right;
|
||||
} v_composite;
|
||||
} r_v;
|
||||
} b_rope;
|
||||
|
||||
BLUE_API void b_rope_init_char(b_rope *rope, char c);
|
||||
BLUE_API void b_rope_init_cstr(b_rope *rope, const char *s);
|
||||
BLUE_API void b_rope_init_cstr_borrowed(b_rope *rope, const char *s);
|
||||
BLUE_API void b_rope_init_cstr_static(b_rope *rope, const char *s);
|
||||
BLUE_API void b_rope_init_int(b_rope *rope, intptr_t v);
|
||||
BLUE_API void b_rope_init_uint(b_rope *rope, uintptr_t v);
|
||||
|
||||
BLUE_API void b_rope_destroy(b_rope *rope);
|
||||
|
||||
BLUE_API void b_rope_iterate(
|
||||
const b_rope *rope, void (*func)(const b_rope *, void *), void *arg);
|
||||
BLUE_API size_t b_rope_get_size(const b_rope *rope);
|
||||
BLUE_API void b_rope_concat(b_rope *result, const b_rope *left, const b_rope *right);
|
||||
BLUE_API void b_rope_join(b_rope *result, const b_rope **ropes, size_t nr_ropes);
|
||||
|
||||
BLUE_API b_status b_rope_to_cstr(const b_rope *rope, char *out, size_t max);
|
||||
BLUE_API b_status b_rope_to_bstr(const b_rope *rope, struct b_bstr *str);
|
||||
BLUE_API b_status b_rope_to_string(const b_rope *rope, b_stream *out);
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
#ifndef BLUELIB_CORE_STATUS_H_
|
||||
#define BLUELIB_CORE_STATUS_H_
|
||||
|
||||
#include <blue/core/misc.h>
|
||||
|
||||
#define B_OK(status) ((enum b_status)((uintptr_t)(status)) == B_SUCCESS)
|
||||
#define B_ERR(status) ((status) != B_SUCCESS)
|
||||
|
||||
typedef enum b_status {
|
||||
B_SUCCESS = 0x00u,
|
||||
B_ERR_NO_MEMORY,
|
||||
B_ERR_OUT_OF_BOUNDS,
|
||||
B_ERR_INVALID_ARGUMENT,
|
||||
B_ERR_NAME_EXISTS,
|
||||
B_ERR_NOT_SUPPORTED,
|
||||
B_ERR_BAD_STATE,
|
||||
B_ERR_NO_ENTRY,
|
||||
B_ERR_NO_DATA,
|
||||
B_ERR_NO_SPACE,
|
||||
B_ERR_UNKNOWN_FUNCTION,
|
||||
B_ERR_BAD_FORMAT,
|
||||
B_ERR_IO_FAILURE,
|
||||
B_ERR_IS_DIRECTORY,
|
||||
B_ERR_NOT_DIRECTORY,
|
||||
B_ERR_PERMISSION_DENIED,
|
||||
B_ERR_BUSY,
|
||||
|
||||
/* blue-compress specific code */
|
||||
B_ERR_COMPRESSION_FAILURE,
|
||||
|
||||
/* blue-object specific code */
|
||||
B_ERR_TYPE_REGISTRATION_FAILURE,
|
||||
B_ERR_CLASS_INIT_FAILURE,
|
||||
} b_status;
|
||||
|
||||
typedef enum b_status_msg {
|
||||
B_MSG_SUCCESS = 0,
|
||||
|
||||
/* blue-object specific messages */
|
||||
B_MSG_TYPE_REGISTRATION_FAILURE,
|
||||
B_MSG_CLASS_INIT_FAILURE,
|
||||
B_MSG_CLASS_SPECIFIES_UNKNOWN_INTERFACE,
|
||||
} b_status_msg;
|
||||
|
||||
BLUE_API const char *b_status_to_string(b_status status);
|
||||
BLUE_API const char *b_status_description(b_status status);
|
||||
|
||||
#endif
|
||||
@@ -1,100 +0,0 @@
|
||||
#ifndef BLUE_CORE_STREAM_H_
|
||||
#define BLUE_CORE_STREAM_H_
|
||||
|
||||
#include <blue/core/encoding.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define b_stdin (z__b_stream_get_stdin())
|
||||
#define b_stdout (z__b_stream_get_stdout())
|
||||
#define b_stderr (z__b_stream_get_stderr())
|
||||
|
||||
#define B_TYPE_STREAM (b_stream_get_type())
|
||||
#define B_TYPE_STREAM_BUFFER (b_stream_buffer_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_stream);
|
||||
B_DECLARE_TYPE(b_stream_buffer);
|
||||
|
||||
typedef enum b_stream_mode {
|
||||
B_STREAM_READ = 0x01u,
|
||||
B_STREAM_WRITE = 0x02u,
|
||||
B_STREAM_BINARY = 0x10u,
|
||||
Z__B_STREAM_STATIC = 0x80u,
|
||||
} b_stream_mode;
|
||||
|
||||
typedef enum b_stream_seek_origin {
|
||||
B_STREAM_SEEK_START = 0x01u,
|
||||
B_STREAM_SEEK_CURRENT = 0x02u,
|
||||
B_STREAM_SEEK_END = 0x03u,
|
||||
} b_stream_seek_origin;
|
||||
|
||||
typedef struct b_stream_cfg {
|
||||
b_stream_mode s_mode;
|
||||
} b_stream_cfg;
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_stream)
|
||||
b_status (*s_close)(b_stream *);
|
||||
b_status (*s_seek)(b_stream *, long long, b_stream_seek_origin);
|
||||
b_status (*s_tell)(const b_stream *, size_t *);
|
||||
b_status (*s_getc)(b_stream *, b_wchar *);
|
||||
b_status (*s_read)(b_stream *, void *, size_t, size_t *);
|
||||
b_status (*s_write)(b_stream *, const void *, size_t, size_t *);
|
||||
b_status (*s_reserve)(b_stream *, size_t);
|
||||
B_TYPE_CLASS_DECLARATION_END(b_stream)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_stream_buffer)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_stream_buffer)
|
||||
|
||||
BLUE_API b_type b_stream_get_type();
|
||||
BLUE_API b_type b_stream_buffer_get_type();
|
||||
|
||||
BLUE_API b_stream *z__b_stream_get_stdin(void);
|
||||
BLUE_API b_stream *z__b_stream_get_stdout(void);
|
||||
BLUE_API b_stream *z__b_stream_get_stderr(void);
|
||||
|
||||
BLUE_API b_stream_buffer *b_stream_buffer_create(void *p, size_t len);
|
||||
BLUE_API b_stream_buffer *b_stream_buffer_create_dynamic(size_t buffer_size);
|
||||
|
||||
BLUE_API b_stream *b_stream_open_fp(FILE *fp);
|
||||
|
||||
BLUE_API b_status b_stream_reserve(b_stream *stream, size_t len);
|
||||
BLUE_API b_status b_stream_seek(
|
||||
b_stream *stream, long long offset, b_stream_seek_origin origin);
|
||||
BLUE_API size_t b_stream_cursor(const b_stream *stream);
|
||||
|
||||
BLUE_API b_status b_stream_push_indent(b_stream *stream, int indent);
|
||||
BLUE_API b_status b_stream_pop_indent(b_stream *stream);
|
||||
|
||||
BLUE_API b_status b_stream_read_char(b_stream *stream, b_wchar *c);
|
||||
|
||||
BLUE_API b_status b_stream_read_bytes(
|
||||
b_stream *stream, void *buf, size_t count, size_t *nr_read);
|
||||
|
||||
BLUE_API b_status b_stream_read_line(b_stream *stream, char *s, size_t max);
|
||||
BLUE_API b_status b_stream_read_line_s(b_stream *src, b_stream *dest);
|
||||
|
||||
BLUE_API b_status b_stream_read_all_bytes(
|
||||
b_stream *stream, void *p, size_t max, size_t *nr_read);
|
||||
BLUE_API b_status b_stream_read_all_bytes_s(
|
||||
b_stream *src, b_stream *dest, b_stream_buffer *buffer, size_t *nr_read);
|
||||
|
||||
BLUE_API b_status b_stream_write_char(b_stream *stream, b_wchar c);
|
||||
BLUE_API b_status b_stream_write_string(
|
||||
b_stream *stream, const char *s, size_t *nr_written);
|
||||
|
||||
BLUE_API b_status b_stream_write_bytes(
|
||||
b_stream *stream, const void *buf, size_t count, size_t *nr_written);
|
||||
|
||||
BLUE_API b_status b_stream_write_fmt(
|
||||
b_stream *stream, size_t *nr_written, const char *format, ...);
|
||||
BLUE_API b_status b_stream_write_vfmt(
|
||||
b_stream *stream, size_t *nr_written, const char *format, va_list arg);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef BLUE_CORE_STRINGSTREAM_H_
|
||||
#define BLUE_CORE_STRINGSTREAM_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <stddef.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_STRINGSTREAM (b_stringstream_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_stringstream);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_stringstream)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_stringstream)
|
||||
|
||||
BLUE_API b_type b_stringstream_get_type(void);
|
||||
|
||||
BLUE_API b_stringstream *b_stringstream_create(void);
|
||||
BLUE_API b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max);
|
||||
|
||||
BLUE_API b_status b_stringstream_reset(b_stringstream *strv);
|
||||
BLUE_API b_status b_stringstream_reset_with_buffer(
|
||||
b_stringstream *strv, char *buf, size_t max);
|
||||
|
||||
BLUE_API const char *b_stringstream_ptr(const b_stringstream *strv);
|
||||
BLUE_API char *b_stringstream_steal(b_stringstream *strv);
|
||||
|
||||
BLUE_API size_t b_stringstream_get_length(const b_stringstream *strv);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef BLUELIB_CORE_THREAD_H_
|
||||
#define BLUELIB_CORE_THREAD_H_
|
||||
|
||||
#include <blue/core/bitop.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if defined(__APPLE__) || defined(__linux__)
|
||||
#include <pthread.h>
|
||||
|
||||
#define B_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
|
||||
|
||||
typedef pthread_mutex_t b_mutex;
|
||||
#else
|
||||
#error Unsupported compiler/system
|
||||
#endif
|
||||
|
||||
#define B_ONCE_INIT ((b_once)0)
|
||||
|
||||
typedef struct b_thread b_thread;
|
||||
|
||||
typedef int b_once;
|
||||
|
||||
static inline bool b_init_once(b_once *once)
|
||||
{
|
||||
int x = 0;
|
||||
return b_cmpxchg(once, &x, 1);
|
||||
}
|
||||
|
||||
BLUE_API b_thread *b_thread_self(void);
|
||||
|
||||
BLUE_API bool b_mutex_lock(b_mutex *mut);
|
||||
BLUE_API bool b_mutex_trylock(b_mutex *mut);
|
||||
BLUE_API bool b_mutex_unlock(b_mutex *mut);
|
||||
|
||||
#endif
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef BLUE_CORE_TYPE_H_
|
||||
#define BLUE_CORE_TYPE_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define B_TYPE_MAX_INTERFACES 64
|
||||
|
||||
struct _b_class;
|
||||
struct _b_object;
|
||||
|
||||
typedef void (*b_class_init_function)(struct _b_class *, void *);
|
||||
typedef void (*b_instance_init_function)(struct _b_object *, void *);
|
||||
typedef void (*b_instance_fini_function)(struct _b_object *, void *);
|
||||
|
||||
typedef const union b_type {
|
||||
struct {
|
||||
uint64_t p00, p01;
|
||||
} a;
|
||||
|
||||
unsigned char b[16];
|
||||
} *b_type;
|
||||
|
||||
typedef enum b_type_flags {
|
||||
B_TYPE_F_ABSTRACT = 0x01u,
|
||||
} b_type_flags;
|
||||
|
||||
typedef struct b_type_info {
|
||||
union b_type t_id;
|
||||
union b_type t_parent_id;
|
||||
const char *t_name;
|
||||
b_type_flags t_flags;
|
||||
union b_type t_interfaces[B_TYPE_MAX_INTERFACES];
|
||||
size_t t_nr_interfaces;
|
||||
size_t t_class_size;
|
||||
b_class_init_function t_class_init;
|
||||
size_t t_instance_private_size;
|
||||
size_t t_instance_protected_size;
|
||||
b_instance_init_function t_instance_init;
|
||||
b_instance_fini_function t_instance_fini;
|
||||
} b_type_info;
|
||||
|
||||
BLUE_API void b_type_id_init(
|
||||
union b_type *out, uint32_t a, uint16_t b, uint16_t c, uint16_t d,
|
||||
uint64_t e);
|
||||
static inline void b_type_id_copy(b_type src, union b_type *dest)
|
||||
{
|
||||
dest->a.p00 = src->a.p00;
|
||||
dest->a.p01 = src->a.p01;
|
||||
}
|
||||
|
||||
static inline int b_type_id_compare(b_type a, b_type b)
|
||||
{
|
||||
if (a == b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return memcmp(a, b, sizeof(union b_type));
|
||||
}
|
||||
|
||||
BLUE_API b_result b_type_register(b_type_info *info);
|
||||
|
||||
#endif
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
#include <blue/core/iterator.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_iterator_p {
|
||||
enum b_status it_status;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static enum b_status iterator_get_status(const struct b_iterator_p *it)
|
||||
{
|
||||
return it->it_status;
|
||||
}
|
||||
|
||||
static enum b_status iterator_set_status(struct b_iterator_p *it, b_status status)
|
||||
{
|
||||
it->it_status = status;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_iterator *b_iterator_begin(b_iterable *it)
|
||||
{
|
||||
B_CLASS_DISPATCH_VIRTUAL_0(b_iterable, B_TYPE_ITERABLE, NULL, it_begin, it);
|
||||
}
|
||||
|
||||
const b_iterator *b_iterator_cbegin(const b_iterable *it)
|
||||
{
|
||||
B_CLASS_DISPATCH_VIRTUAL_0(b_iterable, B_TYPE_ITERABLE, NULL, it_cbegin, it);
|
||||
}
|
||||
|
||||
enum b_status b_iterator_get_status(const b_iterator *it)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ITERATOR, iterator_get_status, it);
|
||||
}
|
||||
|
||||
enum b_status b_iterator_set_status(const b_iterator *it, b_status status)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_ITERATOR, iterator_set_status, it, status);
|
||||
}
|
||||
|
||||
enum b_status b_iterator_move_next(const b_iterator *it)
|
||||
{
|
||||
enum b_status status = B_ERR_NOT_SUPPORTED;
|
||||
|
||||
b_iterator_class *iface = b_object_get_interface(it, B_TYPE_ITERATOR);
|
||||
if (iface && iface->it_move_next) {
|
||||
status = iface->it_move_next(it);
|
||||
}
|
||||
|
||||
struct b_iterator_p *p = b_object_get_private(it, B_TYPE_ITERATOR);
|
||||
p->it_status = status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
b_iterator_value b_iterator_get_value(b_iterator *it)
|
||||
{
|
||||
B_CLASS_DISPATCH_VIRTUAL_0(
|
||||
b_iterator, B_TYPE_ITERATOR, B_ITERATOR_VALUE_NULL,
|
||||
it_get_value, it);
|
||||
}
|
||||
|
||||
const b_iterator_value b_iterator_get_cvalue(const b_iterator *it)
|
||||
{
|
||||
B_CLASS_DISPATCH_VIRTUAL_0(
|
||||
b_iterator, B_TYPE_ITERATOR, B_ITERATOR_VALUE_NULL,
|
||||
it_get_cvalue, it);
|
||||
}
|
||||
|
||||
b_status b_iterator_erase(b_iterator *it)
|
||||
{
|
||||
enum b_status status = B_ERR_NOT_SUPPORTED;
|
||||
|
||||
b_iterator_class *iface = b_object_get_interface(it, B_TYPE_ITERATOR);
|
||||
if (iface && iface->it_erase) {
|
||||
status = iface->it_erase(it);
|
||||
}
|
||||
|
||||
struct b_iterator_p *p = b_object_get_private(it, B_TYPE_ITERATOR);
|
||||
p->it_status = status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_iterator)
|
||||
B_TYPE_FLAGS(B_TYPE_F_ABSTRACT);
|
||||
B_TYPE_ID(0xfd40b67f, 0x7087, 0x40a9, 0x8fd8, 0x8ae27bd58c9e);
|
||||
B_TYPE_CLASS(b_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_iterator)
|
||||
|
||||
// ---- b_iterable DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_iterable)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_iterable)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_iterable)
|
||||
B_TYPE_FLAGS(B_TYPE_F_ABSTRACT);
|
||||
B_TYPE_ID(0x4bbabf2d, 0xfc5d, 0x40cc, 0x89fc, 0x164085e47f73);
|
||||
B_TYPE_CLASS(b_iterable_class);
|
||||
B_TYPE_DEFINITION_END(b_iterable)
|
||||
-219
@@ -1,219 +0,0 @@
|
||||
#include "object.h"
|
||||
|
||||
#include "type.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <blue/core/class.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/object.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <blue/core/thread.h>
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_object)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_object)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_object)
|
||||
B_TYPE_ID(0x45f15a2c, 0x6831, 0x4bef, 0xb350, 0x15c650679211);
|
||||
B_TYPE_CLASS(b_object_class);
|
||||
B_TYPE_DEFINITION_END(b_object)
|
||||
|
||||
b_result b_object_instantiate(
|
||||
struct b_type_registration *type, struct _b_object **out_object)
|
||||
{
|
||||
struct _b_object *out = malloc(type->r_instance_size);
|
||||
if (!out) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
memset(out, 0x0, type->r_instance_size);
|
||||
|
||||
out->obj_magic = B_OBJECT_MAGIC;
|
||||
out->obj_type = type;
|
||||
out->obj_ref = 1;
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&type->r_class_hierarchy);
|
||||
while (entry) {
|
||||
struct b_type_component *comp
|
||||
= b_unbox(struct b_type_component, entry, c_entry);
|
||||
const struct b_type_info *class_info = comp->c_type->r_info;
|
||||
void *private_data
|
||||
= (char *)out + comp->c_instance_private_data_offset;
|
||||
|
||||
if (class_info->t_instance_init) {
|
||||
class_info->t_instance_init(out, private_data);
|
||||
}
|
||||
|
||||
if (comp->c_type == type) {
|
||||
out->obj_main_priv_offset
|
||||
= comp->c_instance_private_data_offset;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
*out_object = out;
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
struct _b_object *b_object_create(b_type type)
|
||||
{
|
||||
struct b_type_registration *type_reg = b_type_get_registration(type);
|
||||
if (!type_reg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct _b_object *out = NULL;
|
||||
b_result result = b_object_instantiate(type_reg, &out);
|
||||
if (b_result_is_error(result)) {
|
||||
b_error_discard(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void b_object_to_string(const struct _b_object *p, b_stream *out)
|
||||
{
|
||||
B_CLASS_DISPATCH_VIRTUAL_V(b_object, B_TYPE_OBJECT, to_string, p, out);
|
||||
b_stream_write_fmt(out, NULL, "<%s@%p>", p->obj_type->r_info->t_name, p);
|
||||
}
|
||||
|
||||
bool b_object_is_type(const struct _b_object *p, b_type type)
|
||||
{
|
||||
if (b_type_id_compare(&p->obj_type->r_info->t_id, type) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&p->obj_type->r_components, type);
|
||||
|
||||
return comp != NULL;
|
||||
}
|
||||
|
||||
void *b_object_get_private(const struct _b_object *object, b_type type)
|
||||
{
|
||||
if (!object) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(object->obj_magic == B_OBJECT_MAGIC);
|
||||
|
||||
if (b_type_id_compare(&object->obj_type->r_info->t_id, type) == 0) {
|
||||
return (char *)object + object->obj_main_priv_offset;
|
||||
}
|
||||
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&object->obj_type->r_components, type);
|
||||
if (!comp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)object + comp->c_instance_private_data_offset;
|
||||
}
|
||||
|
||||
void *b_object_get_protected(const struct _b_object *object, b_type type)
|
||||
{
|
||||
if (!object) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(object->obj_magic == B_OBJECT_MAGIC);
|
||||
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&object->obj_type->r_components, type);
|
||||
if (!comp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (char *)object + comp->c_instance_protected_data_offset;
|
||||
}
|
||||
|
||||
void *b_object_get_interface(const struct _b_object *object, b_type type)
|
||||
{
|
||||
if (!object) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(object->obj_magic == B_OBJECT_MAGIC);
|
||||
|
||||
return b_class_get_interface(object->obj_type->r_class, type);
|
||||
}
|
||||
|
||||
enum b_status b_object_get_data(
|
||||
const struct _b_object *object, b_type type, void **priv, void **prot,
|
||||
void **iface)
|
||||
{
|
||||
if (!object) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
assert(object->obj_magic == B_OBJECT_MAGIC);
|
||||
|
||||
struct b_type_component *comp
|
||||
= b_type_get_component(&object->obj_type->r_components, type);
|
||||
if (!comp) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
*priv = (char *)object + comp->c_instance_private_data_offset;
|
||||
}
|
||||
|
||||
if (prot) {
|
||||
*prot = (char *)object + comp->c_instance_protected_data_offset;
|
||||
}
|
||||
|
||||
if (iface) {
|
||||
*iface = (char *)object->obj_type->r_class
|
||||
+ comp->c_class_data_offset;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
struct _b_object *b_object_ref(struct _b_object *p)
|
||||
{
|
||||
p->obj_ref++;
|
||||
return p;
|
||||
}
|
||||
|
||||
void b_object_unref(struct _b_object *p)
|
||||
{
|
||||
if (p->obj_ref > 1) {
|
||||
p->obj_ref--;
|
||||
return;
|
||||
}
|
||||
|
||||
p->obj_ref = 0;
|
||||
const struct b_type_registration *type = p->obj_type;
|
||||
|
||||
struct b_queue_entry *cur = b_queue_last(&type->r_class_hierarchy);
|
||||
while (cur) {
|
||||
struct b_type_component *comp
|
||||
= b_unbox(struct b_type_component, cur, c_entry);
|
||||
|
||||
const struct b_type_info *class_info = comp->c_type->r_info;
|
||||
void *private_data
|
||||
= (char *)p + comp->c_instance_private_data_offset;
|
||||
|
||||
if (class_info->t_instance_fini) {
|
||||
class_info->t_instance_fini(p, private_data);
|
||||
}
|
||||
|
||||
cur = b_queue_prev(cur);
|
||||
}
|
||||
|
||||
p->obj_magic = 0;
|
||||
p->obj_type = NULL;
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
struct _b_object *b_object_make_rvalue(struct _b_object *p)
|
||||
{
|
||||
p->obj_ref = 0;
|
||||
return p;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef _OBJECT_H_
|
||||
#define _OBJECT_H_
|
||||
|
||||
#include <blue/core/error.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct b_type_registration;
|
||||
|
||||
struct _b_object {
|
||||
uint64_t obj_magic;
|
||||
const struct b_type_registration *obj_type;
|
||||
unsigned int obj_ref, obj_main_priv_offset;
|
||||
};
|
||||
|
||||
extern b_result b_object_instantiate(
|
||||
struct b_type_registration *type, struct _b_object **out);
|
||||
|
||||
#endif
|
||||
-245
@@ -1,245 +0,0 @@
|
||||
#include <blue/core/queue.h>
|
||||
|
||||
struct b_queue_iterator_p {
|
||||
size_t i;
|
||||
b_queue_entry *entry;
|
||||
b_queue *_q;
|
||||
};
|
||||
|
||||
size_t b_queue_length(const struct b_queue *q)
|
||||
{
|
||||
size_t i = 0;
|
||||
struct b_queue_entry *x = q->q_first;
|
||||
while (x) {
|
||||
i++;
|
||||
x = x->qe_next;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void b_queue_insert_before(
|
||||
struct b_queue *q, struct b_queue_entry *entry, struct b_queue_entry *before)
|
||||
{
|
||||
struct b_queue_entry *x = before->qe_prev;
|
||||
if (x) {
|
||||
x->qe_next = entry;
|
||||
} else {
|
||||
q->q_first = entry;
|
||||
}
|
||||
|
||||
entry->qe_prev = x;
|
||||
|
||||
before->qe_prev = entry;
|
||||
entry->qe_next = before;
|
||||
}
|
||||
|
||||
void b_queue_insert_after(
|
||||
struct b_queue *q, struct b_queue_entry *entry, struct b_queue_entry *after)
|
||||
{
|
||||
struct b_queue_entry *x = after->qe_next;
|
||||
if (x) {
|
||||
x->qe_prev = entry;
|
||||
} else {
|
||||
q->q_last = entry;
|
||||
}
|
||||
|
||||
entry->qe_next = x;
|
||||
|
||||
after->qe_next = entry;
|
||||
entry->qe_prev = after;
|
||||
}
|
||||
|
||||
void b_queue_push_front(struct b_queue *q, struct b_queue_entry *entry)
|
||||
{
|
||||
if (q->q_first) {
|
||||
q->q_first->qe_prev = entry;
|
||||
}
|
||||
|
||||
entry->qe_next = q->q_first;
|
||||
entry->qe_prev = NULL;
|
||||
|
||||
q->q_first = entry;
|
||||
|
||||
if (!q->q_last) {
|
||||
q->q_last = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void b_queue_push_back(struct b_queue *q, struct b_queue_entry *entry)
|
||||
{
|
||||
if (q->q_last) {
|
||||
q->q_last->qe_next = entry;
|
||||
}
|
||||
|
||||
entry->qe_prev = q->q_last;
|
||||
entry->qe_next = NULL;
|
||||
|
||||
q->q_last = entry;
|
||||
|
||||
if (!q->q_first) {
|
||||
q->q_first = entry;
|
||||
}
|
||||
}
|
||||
|
||||
struct b_queue_entry *b_queue_pop_front(struct b_queue *q)
|
||||
{
|
||||
struct b_queue_entry *x = q->q_first;
|
||||
if (x) {
|
||||
b_queue_delete(q, x);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
struct b_queue_entry *b_queue_pop_back(struct b_queue *q)
|
||||
{
|
||||
struct b_queue_entry *x = q->q_last;
|
||||
if (x) {
|
||||
b_queue_delete(q, x);
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void b_queue_move(b_queue *q, b_queue_entry *dest, b_queue_entry *src)
|
||||
{
|
||||
if (src->qe_next) {
|
||||
src->qe_next->qe_prev = dest;
|
||||
}
|
||||
|
||||
if (src->qe_prev) {
|
||||
src->qe_prev->qe_next = dest;
|
||||
}
|
||||
|
||||
if (q->q_first == src) {
|
||||
q->q_first = dest;
|
||||
}
|
||||
|
||||
if (q->q_last == src) {
|
||||
q->q_last = dest;
|
||||
}
|
||||
|
||||
memmove(dest, src, sizeof *src);
|
||||
}
|
||||
|
||||
void b_queue_delete(struct b_queue *q, struct b_queue_entry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry == q->q_first) {
|
||||
q->q_first = q->q_first->qe_next;
|
||||
}
|
||||
|
||||
if (entry == q->q_last) {
|
||||
q->q_last = q->q_last->qe_prev;
|
||||
}
|
||||
|
||||
if (entry->qe_next) {
|
||||
entry->qe_next->qe_prev = entry->qe_prev;
|
||||
}
|
||||
|
||||
if (entry->qe_prev) {
|
||||
entry->qe_prev->qe_next = entry->qe_next;
|
||||
}
|
||||
|
||||
entry->qe_next = entry->qe_prev = NULL;
|
||||
}
|
||||
|
||||
void b_queue_delete_all(struct b_queue *q)
|
||||
{
|
||||
struct b_queue_entry *x = q->q_first;
|
||||
while (x) {
|
||||
struct b_queue_entry *next = x->qe_next;
|
||||
x->qe_next = x->qe_prev = NULL;
|
||||
x = next;
|
||||
}
|
||||
|
||||
q->q_first = q->q_last = NULL;
|
||||
}
|
||||
|
||||
b_iterator *b_queue_begin(struct b_queue *q)
|
||||
{
|
||||
b_queue_iterator *it_obj = b_object_create(B_TYPE_QUEUE_ITERATOR);
|
||||
struct b_queue_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_QUEUE_ITERATOR);
|
||||
|
||||
it->_q = (struct b_queue *)q;
|
||||
it->entry = q->q_first;
|
||||
it->i = 0;
|
||||
|
||||
if (!it->entry) {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_queue_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_QUEUE_ITERATOR);
|
||||
|
||||
if (!it->entry) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->entry = it->entry->qe_next;
|
||||
it->i++;
|
||||
|
||||
return (it->entry != NULL) ? B_SUCCESS : B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
struct b_queue_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_QUEUE_ITERATOR);
|
||||
|
||||
if (!it->entry) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
struct b_queue_entry *next = it->entry->qe_next;
|
||||
b_queue_delete(it->_q, it->entry);
|
||||
it->entry = next;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_queue_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_QUEUE_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_PTR(it->entry);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_queue_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_QUEUE_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_CPTR(it->entry);
|
||||
}
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_queue_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_queue_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_queue_iterator)
|
||||
B_TYPE_ID(0x560dc263, 0xff98, 0x4812, 0x9b29, 0xa1218bd70881);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_queue_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_queue_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_queue_iterator)
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef _BLUELIB_RANDOM_H_
|
||||
#define _BLUELIB_RANDOM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <blue/core/misc.h>
|
||||
|
||||
struct b_random_ctx;
|
||||
|
||||
struct b_random_algorithm {
|
||||
const char *gen_name;
|
||||
void(*gen_init)(struct b_random_ctx *, unsigned long long seed);
|
||||
uint64_t(*gen_getrand)(struct b_random_ctx *);
|
||||
};
|
||||
|
||||
BLUE_API uint64_t z__b_platform_random_seed(void);
|
||||
BLUE_API uint64_t z__b_platform_random_seed_secure(void);
|
||||
|
||||
#endif
|
||||
-275
@@ -1,275 +0,0 @@
|
||||
#include <blue/core/bstr.h>
|
||||
#include <blue/core/rope.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void b_rope_init_char(struct b_rope *rope, char c)
|
||||
{
|
||||
memset(rope, 0x0, sizeof *rope);
|
||||
rope->r_flags = B_ROPE_F_CHAR;
|
||||
rope->r_len_left = rope->r_len_total = 1;
|
||||
rope->r_v.v_char = c;
|
||||
}
|
||||
|
||||
void b_rope_init_cstr(struct b_rope *rope, const char *s)
|
||||
{
|
||||
memset(rope, 0x0, sizeof *rope);
|
||||
rope->r_flags = B_ROPE_F_CSTR;
|
||||
rope->r_v.v_cstr.hash = b_hash_cstr_ex(s, &rope->r_len_total);
|
||||
rope->r_len_left = rope->r_len_total;
|
||||
|
||||
char *s2 = malloc(rope->r_len_total + 1);
|
||||
|
||||
if (!s2) {
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(s2, s);
|
||||
s2[rope->r_len_total] = '\0';
|
||||
|
||||
rope->r_v.v_cstr.s = s2;
|
||||
}
|
||||
|
||||
void b_rope_init_cstr_borrowed(struct b_rope *rope, const char *s)
|
||||
{
|
||||
memset(rope, 0x0, sizeof *rope);
|
||||
rope->r_flags = B_ROPE_F_CSTR_BORROWED;
|
||||
rope->r_v.v_cstr.s = s;
|
||||
rope->r_v.v_cstr.hash = b_hash_cstr_ex(s, &rope->r_len_total);
|
||||
rope->r_len_left = rope->r_len_total;
|
||||
}
|
||||
|
||||
void b_rope_init_cstr_static(struct b_rope *rope, const char *s)
|
||||
{
|
||||
memset(rope, 0x0, sizeof *rope);
|
||||
rope->r_flags = B_ROPE_F_CSTR_STATIC;
|
||||
rope->r_v.v_cstr.s = s;
|
||||
rope->r_v.v_cstr.hash = b_hash_cstr_ex(s, &rope->r_len_total);
|
||||
rope->r_len_left = rope->r_len_total;
|
||||
}
|
||||
|
||||
void b_rope_init_int(struct b_rope *rope, intptr_t v)
|
||||
{
|
||||
memset(rope, 0x0, sizeof *rope);
|
||||
rope->r_flags = B_ROPE_F_INT;
|
||||
rope->r_len_left = rope->r_len_total = b_int_length(v);
|
||||
rope->r_v.v_int = v;
|
||||
}
|
||||
|
||||
void b_rope_init_uint(struct b_rope *rope, uintptr_t v)
|
||||
{
|
||||
memset(rope, 0x0, sizeof *rope);
|
||||
rope->r_flags = B_ROPE_F_UINT;
|
||||
rope->r_len_left = rope->r_len_total = b_uint_length(v);
|
||||
rope->r_v.v_uint = v;
|
||||
}
|
||||
|
||||
void b_rope_destroy(struct b_rope *rope)
|
||||
{
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CSTR:
|
||||
free((char *)rope->r_v.v_cstr.s);
|
||||
break;
|
||||
case B_ROPE_F_COMPOSITE:
|
||||
b_rope_destroy((struct b_rope *)rope->r_v.v_composite.r_left);
|
||||
b_rope_destroy((struct b_rope *)rope->r_v.v_composite.r_right);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rope->r_flags & B_ROPE_F_MALLOC) {
|
||||
free(rope);
|
||||
}
|
||||
}
|
||||
|
||||
void b_rope_iterate(
|
||||
const struct b_rope *rope, void (*func)(const b_rope *, void *), void *arg)
|
||||
{
|
||||
if (B_ROPE_TYPE(rope->r_flags) != B_ROPE_F_COMPOSITE) {
|
||||
func(rope, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rope->r_v.v_composite.r_left) {
|
||||
b_rope_iterate(rope->r_v.v_composite.r_left, func, arg);
|
||||
}
|
||||
|
||||
if (rope->r_v.v_composite.r_right) {
|
||||
b_rope_iterate(rope->r_v.v_composite.r_right, func, arg);
|
||||
}
|
||||
}
|
||||
|
||||
size_t b_rope_get_size(const struct b_rope *rope)
|
||||
{
|
||||
return rope->r_len_total;
|
||||
}
|
||||
|
||||
void b_rope_concat(
|
||||
struct b_rope *result, const struct b_rope *left, const struct b_rope *right)
|
||||
{
|
||||
memset(result, 0x0, sizeof *result);
|
||||
|
||||
result->r_flags = B_ROPE_F_COMPOSITE;
|
||||
result->r_len_left = left->r_len_total;
|
||||
result->r_len_total = left->r_len_total + right->r_len_total;
|
||||
result->r_v.v_composite.r_left = left;
|
||||
result->r_v.v_composite.r_right = right;
|
||||
}
|
||||
|
||||
static struct b_rope *create_composite_node(void)
|
||||
{
|
||||
struct b_rope *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
out->r_flags = B_ROPE_F_COMPOSITE | B_ROPE_F_MALLOC;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void b_rope_join(b_rope *result, const b_rope **ropes, size_t nr_ropes)
|
||||
{
|
||||
if (nr_ropes == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr_ropes == 1) {
|
||||
*result = *ropes[0];
|
||||
return;
|
||||
}
|
||||
|
||||
struct b_rope *prev = NULL;
|
||||
|
||||
for (size_t i = 0; i < nr_ropes - 1; i++) {
|
||||
const struct b_rope *left = ropes[i];
|
||||
const struct b_rope *right = ropes[i + 1];
|
||||
|
||||
if (prev) {
|
||||
left = prev;
|
||||
}
|
||||
|
||||
struct b_rope *composite = create_composite_node();
|
||||
if (!composite) {
|
||||
return;
|
||||
}
|
||||
|
||||
composite->r_len_left = left->r_len_total;
|
||||
composite->r_len_total = left->r_len_total + right->r_len_total;
|
||||
composite->r_v.v_composite.r_left = left;
|
||||
composite->r_v.v_composite.r_right = right;
|
||||
|
||||
prev = composite;
|
||||
}
|
||||
|
||||
*result = *prev;
|
||||
|
||||
result->r_flags &= ~B_ROPE_F_MALLOC;
|
||||
free(prev);
|
||||
}
|
||||
|
||||
static void rope_iterate(
|
||||
const struct b_rope *rope,
|
||||
void (*callback)(const struct b_rope *, void *), void *arg)
|
||||
{
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
case B_ROPE_F_INT:
|
||||
case B_ROPE_F_UINT:
|
||||
callback(rope, arg);
|
||||
break;
|
||||
case B_ROPE_F_COMPOSITE:
|
||||
rope_iterate(rope->r_v.v_composite.r_left, callback, arg);
|
||||
rope_iterate(rope->r_v.v_composite.r_right, callback, arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void to_bstr(const struct b_rope *rope, void *arg)
|
||||
{
|
||||
b_bstr *str = arg;
|
||||
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
b_bstr_write_char(str, rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
b_bstr_write_cstr(str, rope->r_v.v_cstr.s, NULL);
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
b_bstr_write_fmt(str, NULL, "%" PRIdPTR, rope->r_v.v_int);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
b_bstr_write_fmt(str, NULL, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void to_stream(const struct b_rope *rope, void *arg)
|
||||
{
|
||||
b_stream *out = arg;
|
||||
|
||||
unsigned int type = B_ROPE_TYPE(rope->r_flags);
|
||||
|
||||
switch (type) {
|
||||
case B_ROPE_F_CHAR:
|
||||
b_stream_write_char(out, rope->r_v.v_char);
|
||||
break;
|
||||
case B_ROPE_F_CSTR:
|
||||
case B_ROPE_F_CSTR_BORROWED:
|
||||
case B_ROPE_F_CSTR_STATIC:
|
||||
b_stream_write_string(out, rope->r_v.v_cstr.s, NULL);
|
||||
break;
|
||||
case B_ROPE_F_INT:
|
||||
b_stream_write_fmt(out, NULL, "%" PRIdPTR, rope->r_v.v_int);
|
||||
break;
|
||||
case B_ROPE_F_UINT:
|
||||
b_stream_write_fmt(out, NULL, "%" PRIuPTR, rope->r_v.v_uint);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
b_status b_rope_to_cstr(const struct b_rope *rope, char *out, size_t max)
|
||||
{
|
||||
b_bstr str;
|
||||
b_bstr_begin(&str, out, max);
|
||||
rope_iterate(rope, to_bstr, &str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_rope_to_bstr(const struct b_rope *rope, b_bstr *str)
|
||||
{
|
||||
rope_iterate(rope, to_bstr, str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_rope_to_string(const struct b_rope *rope, b_stream *out)
|
||||
{
|
||||
rope_iterate(rope, to_stream, out);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
#include <blue/core/status.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define ENUM_STR(s) \
|
||||
case s: \
|
||||
return #s;
|
||||
|
||||
#define ENUM_STR2(c, s) \
|
||||
case c: \
|
||||
return s;
|
||||
|
||||
const char *b_status_to_string(b_status status)
|
||||
{
|
||||
switch (status) {
|
||||
ENUM_STR(B_SUCCESS);
|
||||
ENUM_STR(B_ERR_NO_MEMORY);
|
||||
ENUM_STR(B_ERR_OUT_OF_BOUNDS);
|
||||
ENUM_STR(B_ERR_INVALID_ARGUMENT);
|
||||
ENUM_STR(B_ERR_NAME_EXISTS);
|
||||
ENUM_STR(B_ERR_NOT_SUPPORTED);
|
||||
ENUM_STR(B_ERR_BAD_STATE);
|
||||
ENUM_STR(B_ERR_NO_ENTRY);
|
||||
ENUM_STR(B_ERR_NO_DATA);
|
||||
ENUM_STR(B_ERR_NO_SPACE);
|
||||
ENUM_STR(B_ERR_UNKNOWN_FUNCTION);
|
||||
ENUM_STR(B_ERR_BAD_FORMAT);
|
||||
ENUM_STR(B_ERR_IO_FAILURE);
|
||||
ENUM_STR(B_ERR_IS_DIRECTORY);
|
||||
ENUM_STR(B_ERR_NOT_DIRECTORY);
|
||||
ENUM_STR(B_ERR_PERMISSION_DENIED);
|
||||
ENUM_STR(B_ERR_BUSY);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char *b_status_description(b_status status)
|
||||
{
|
||||
switch (status) {
|
||||
ENUM_STR2(B_SUCCESS, "Success");
|
||||
ENUM_STR2(B_ERR_NO_MEMORY, "Out of memory");
|
||||
ENUM_STR2(B_ERR_OUT_OF_BOUNDS, "Argument out of bounds");
|
||||
ENUM_STR2(B_ERR_INVALID_ARGUMENT, "Invalid argument");
|
||||
ENUM_STR2(B_ERR_NAME_EXISTS, "Name already exists");
|
||||
ENUM_STR2(B_ERR_NOT_SUPPORTED, "Operation not supported");
|
||||
ENUM_STR2(B_ERR_BAD_STATE, "Bad state");
|
||||
ENUM_STR2(B_ERR_NO_ENTRY, "No entry");
|
||||
ENUM_STR2(B_ERR_NO_DATA, "No data available");
|
||||
ENUM_STR2(B_ERR_NO_SPACE, "No space available");
|
||||
ENUM_STR2(B_ERR_UNKNOWN_FUNCTION, "Unknown function");
|
||||
ENUM_STR2(B_ERR_BAD_FORMAT, "Bad format");
|
||||
ENUM_STR2(B_ERR_IO_FAILURE, "I/O failure");
|
||||
ENUM_STR2(B_ERR_IS_DIRECTORY, "Object is a directory");
|
||||
ENUM_STR2(B_ERR_NOT_DIRECTORY, "Object is not a directory");
|
||||
ENUM_STR2(B_ERR_PERMISSION_DENIED, "Permission denied");
|
||||
ENUM_STR2(B_ERR_BUSY, "Resource busy or locked");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
-1134
File diff suppressed because it is too large
Load Diff
@@ -1,297 +0,0 @@
|
||||
#include <blue/core/stringstream.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEFAULT_CAPACITY 15
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_stringstream_p {
|
||||
char *ss_buf;
|
||||
size_t ss_ptr;
|
||||
size_t ss_len;
|
||||
size_t ss_max;
|
||||
unsigned char ss_alloc;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static enum b_status __getc(struct b_stringstream_p *ss, b_wchar *out)
|
||||
{
|
||||
size_t available = ss->ss_len - ss->ss_ptr;
|
||||
|
||||
const char *p = ss->ss_buf + ss->ss_ptr;
|
||||
|
||||
size_t to_copy = b_wchar_utf8_codepoint_stride(p);
|
||||
if (to_copy > available) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
b_wchar c = b_wchar_utf8_codepoint_decode(p);
|
||||
*out = c;
|
||||
|
||||
if (c == B_WCHAR_INVALID) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
ss->ss_ptr += to_copy;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status __gets(
|
||||
struct b_stringstream_p *ss, char *s, size_t len, size_t *nr_read)
|
||||
{
|
||||
size_t available = ss->ss_len - ss->ss_ptr;
|
||||
size_t to_copy = len;
|
||||
|
||||
if (available < to_copy) {
|
||||
to_copy = available;
|
||||
}
|
||||
|
||||
memcpy(s, ss->ss_buf + ss->ss_ptr, to_copy);
|
||||
|
||||
ss->ss_ptr += to_copy;
|
||||
|
||||
if (nr_read) {
|
||||
*nr_read = to_copy;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status __puts(
|
||||
struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
|
||||
{
|
||||
size_t available = ss->ss_max - ss->ss_len;
|
||||
size_t to_copy = len;
|
||||
|
||||
if (to_copy > available && ss->ss_alloc == 1) {
|
||||
char *new_buf = realloc(ss->ss_buf, ss->ss_len + to_copy + 1);
|
||||
if (!new_buf) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
ss->ss_buf = new_buf;
|
||||
ss->ss_max = ss->ss_len + to_copy;
|
||||
available = ss->ss_max - ss->ss_len;
|
||||
}
|
||||
|
||||
if (available < to_copy) {
|
||||
to_copy = available;
|
||||
}
|
||||
|
||||
memcpy(ss->ss_buf + ss->ss_len, s, to_copy);
|
||||
|
||||
/* increment the length by the full string length, even if only a
|
||||
* portion was copied */
|
||||
ss->ss_len += len;
|
||||
|
||||
if (nr_written) {
|
||||
*nr_written = to_copy;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status stringstream_reset(struct b_stringstream_p *ss)
|
||||
{
|
||||
ss->ss_len = 0;
|
||||
|
||||
if (ss->ss_buf) {
|
||||
*ss->ss_buf = 0;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status stringstream_reset_with_buffer(
|
||||
struct b_stringstream_p *ss, char *buf, size_t max)
|
||||
{
|
||||
ss->ss_len = 0;
|
||||
|
||||
if (ss->ss_buf && ss->ss_alloc) {
|
||||
free(ss->ss_buf);
|
||||
}
|
||||
|
||||
ss->ss_buf = buf;
|
||||
ss->ss_max = max;
|
||||
ss->ss_alloc = 0;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static size_t stringstream_get_length(const struct b_stringstream_p *strv)
|
||||
{
|
||||
return strv->ss_len;
|
||||
}
|
||||
|
||||
static const char *stringstream_ptr(const struct b_stringstream_p *ss)
|
||||
{
|
||||
return ss->ss_buf;
|
||||
}
|
||||
|
||||
static char *stringstream_steal(struct b_stringstream_p *ss)
|
||||
{
|
||||
char *out = ss->ss_buf;
|
||||
|
||||
memset(ss, 0x0, sizeof *ss);
|
||||
|
||||
ss->ss_alloc = 1;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max)
|
||||
{
|
||||
b_stringstream *s = b_object_create(B_TYPE_STRINGSTREAM);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
|
||||
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
|
||||
|
||||
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
|
||||
p->ss_buf = buf;
|
||||
p->ss_max = max;
|
||||
p->ss_len = 0;
|
||||
p->ss_alloc = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
b_stringstream *b_stringstream_create(void)
|
||||
{
|
||||
b_stringstream *s = b_object_create(B_TYPE_STRINGSTREAM);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
|
||||
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
|
||||
|
||||
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
|
||||
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
|
||||
if (!p->ss_buf) {
|
||||
b_stringstream_unref(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(p->ss_buf, 0x0, DEFAULT_CAPACITY + 1);
|
||||
p->ss_max = DEFAULT_CAPACITY;
|
||||
p->ss_len = 0;
|
||||
p->ss_alloc = 1;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t b_stringstream_get_length(const b_stringstream *strv)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(
|
||||
B_TYPE_STRINGSTREAM, stringstream_get_length, strv);
|
||||
}
|
||||
|
||||
enum b_status b_stringstream_reset(b_stringstream *strv)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_reset, strv);
|
||||
}
|
||||
|
||||
enum b_status b_stringstream_reset_with_buffer(
|
||||
b_stringstream *strv, char *buf, size_t max)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(
|
||||
B_TYPE_STRINGSTREAM, stringstream_reset_with_buffer, strv, buf,
|
||||
max);
|
||||
}
|
||||
|
||||
const char *b_stringstream_ptr(const b_stringstream *ss)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_ptr, ss);
|
||||
}
|
||||
|
||||
char *b_stringstream_steal(b_stringstream *ss)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_steal, ss);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void stringstream_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_stringstream_p *stream = priv;
|
||||
}
|
||||
|
||||
static void stringstream_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_stringstream_p *stream = priv;
|
||||
|
||||
if (stream->ss_alloc && stream->ss_buf) {
|
||||
free(stream->ss_buf);
|
||||
}
|
||||
}
|
||||
|
||||
enum b_status stream_getc(b_stream *stream, b_wchar *c)
|
||||
{
|
||||
struct b_stringstream_p *s
|
||||
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||
|
||||
enum b_status status = __getc(s, c);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status stream_read(b_stream *stream, void *buf, size_t count, size_t *nr_read)
|
||||
{
|
||||
struct b_stringstream_p *s
|
||||
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||
|
||||
enum b_status status = __gets(s, buf, count, nr_read);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
enum b_status stream_write(
|
||||
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
||||
{
|
||||
struct b_stringstream_p *s
|
||||
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||
|
||||
enum b_status status = __puts(s, (const char *)buf, count, nr_written);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_stringstream)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_stream, B_TYPE_STREAM)
|
||||
B_INTERFACE_ENTRY(s_close) = NULL;
|
||||
B_INTERFACE_ENTRY(s_seek) = NULL;
|
||||
B_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
B_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||
B_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
B_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
B_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_stringstream)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_stringstream)
|
||||
B_TYPE_ID(0x508a609a, 0xfac5, 0x4d31, 0x843a, 0x44b68ad329f3);
|
||||
B_TYPE_EXTENDS(B_TYPE_STREAM);
|
||||
B_TYPE_CLASS(b_stringstream_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_stringstream_p);
|
||||
B_TYPE_INSTANCE_INIT(stringstream_init);
|
||||
B_TYPE_INSTANCE_FINI(stringstream_fini);
|
||||
B_TYPE_DEFINITION_END(b_stringstream)
|
||||
-319
@@ -1,319 +0,0 @@
|
||||
#include "type.h"
|
||||
|
||||
#include "class.h"
|
||||
#include "object.h"
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/endian.h>
|
||||
#include <blue/core/object.h>
|
||||
#include <blue/core/type.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct b_btree type_list = B_BTREE_INIT;
|
||||
static union b_type zero_id = {0};
|
||||
|
||||
struct type_init_ctx {
|
||||
size_t ctx_class_offset;
|
||||
size_t ctx_instance_offset;
|
||||
};
|
||||
|
||||
static inline int registration_compare(
|
||||
const struct b_type_registration *a, const struct b_type_registration *b)
|
||||
{
|
||||
return b_type_id_compare(&a->r_info->t_id, &b->r_info->t_id);
|
||||
}
|
||||
|
||||
static inline int component_compare(
|
||||
const struct b_type_component *a, const struct b_type_component *b)
|
||||
{
|
||||
return b_type_id_compare(&a->c_type->r_info->t_id, &b->c_type->r_info->t_id);
|
||||
}
|
||||
|
||||
B_BTREE_DEFINE_INSERT(
|
||||
struct b_type_registration, r_node, r_info->r_id, put_type,
|
||||
registration_compare)
|
||||
B_BTREE_DEFINE_INSERT(
|
||||
struct b_type_component, c_node, &c_type->r_info->t_id,
|
||||
put_type_component, component_compare)
|
||||
|
||||
static struct b_type_registration *get_type(
|
||||
const b_btree *tree, const union b_type *key)
|
||||
{
|
||||
b_btree_node *cur = tree->b_root;
|
||||
while (cur) {
|
||||
struct b_type_registration *cur_node
|
||||
= b_unbox(struct b_type_registration, cur, r_node);
|
||||
int cmp = b_type_id_compare(key, &cur_node->r_info->t_id);
|
||||
|
||||
if (cmp > 0) {
|
||||
cur = b_btree_right(cur);
|
||||
} else if (cmp < 0) {
|
||||
cur = b_btree_left(cur);
|
||||
} else {
|
||||
return cur_node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_type_component *b_type_get_component(
|
||||
const b_btree *tree, const union b_type *key)
|
||||
{
|
||||
b_btree_node *cur = tree->b_root;
|
||||
while (cur) {
|
||||
struct b_type_component *cur_node
|
||||
= b_unbox(struct b_type_component, cur, c_node);
|
||||
int cmp = b_type_id_compare(key, &cur_node->c_type->r_info->t_id);
|
||||
|
||||
if (cmp > 0) {
|
||||
cur = b_btree_right(cur);
|
||||
} else if (cmp < 0) {
|
||||
cur = b_btree_left(cur);
|
||||
} else {
|
||||
return cur_node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct b_type_component *create_type_component(
|
||||
const struct b_type_registration *type_reg)
|
||||
{
|
||||
struct b_type_component *c = malloc(sizeof *c);
|
||||
if (!c) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(c, 0x0, sizeof *c);
|
||||
|
||||
c->c_type = type_reg;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void b_type_id_init(
|
||||
union b_type *out, uint32_t a, uint16_t b, uint16_t c, uint16_t d,
|
||||
uint64_t e)
|
||||
{
|
||||
b_i32 x_a = b_i32_htob(a);
|
||||
b_i16 x_b = b_i16_htob(b);
|
||||
b_i16 x_c = b_i16_htob(c);
|
||||
b_i16 x_d = b_i16_htob(d);
|
||||
b_i64 x_e = b_i64_htob(e);
|
||||
|
||||
memcpy(&out->b[0], x_a.i_bytes, sizeof x_a.i_bytes);
|
||||
memcpy(&out->b[4], x_b.i_bytes, sizeof x_b.i_bytes);
|
||||
memcpy(&out->b[6], x_c.i_bytes, sizeof x_c.i_bytes);
|
||||
memcpy(&out->b[8], x_d.i_bytes, sizeof x_d.i_bytes);
|
||||
memcpy(&out->b[10], &x_e.i_bytes[2], sizeof x_e.i_bytes - 2);
|
||||
}
|
||||
|
||||
static void initialise_type_component(
|
||||
struct b_type_component *comp, const struct b_type_info *info,
|
||||
struct type_init_ctx *init_ctx)
|
||||
{
|
||||
comp->c_class_data_offset = init_ctx->ctx_class_offset;
|
||||
comp->c_class_data_size = info->t_class_size;
|
||||
init_ctx->ctx_class_offset += comp->c_class_data_size;
|
||||
|
||||
comp->c_instance_private_data_offset = init_ctx->ctx_instance_offset;
|
||||
comp->c_instance_private_data_size = info->t_instance_private_size;
|
||||
init_ctx->ctx_instance_offset += comp->c_instance_private_data_size;
|
||||
|
||||
comp->c_instance_protected_data_offset = init_ctx->ctx_instance_offset;
|
||||
comp->c_instance_protected_data_size = info->t_instance_protected_size;
|
||||
init_ctx->ctx_instance_offset += comp->c_instance_protected_data_size;
|
||||
}
|
||||
|
||||
static b_result locate_interface(
|
||||
b_type interface_id, struct b_type_registration *dest,
|
||||
struct type_init_ctx *init_ctx)
|
||||
{
|
||||
struct b_type_component *interface_comp
|
||||
= b_type_get_component(&dest->r_components, interface_id);
|
||||
if (interface_comp) {
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
struct b_type_registration *interface_reg
|
||||
= get_type(&type_list, interface_id);
|
||||
if (!interface_reg) {
|
||||
return B_RESULT_ERR(NO_ENTRY);
|
||||
}
|
||||
|
||||
interface_comp = create_type_component(interface_reg);
|
||||
if (!interface_comp) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
initialise_type_component(interface_comp, interface_reg->r_info, init_ctx);
|
||||
|
||||
put_type_component(&dest->r_components, interface_comp);
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static b_result locate_interfaces(
|
||||
const union b_type *interfaces, size_t nr_interfaces,
|
||||
struct b_type_registration *dest, struct type_init_ctx *init_ctx)
|
||||
{
|
||||
b_result result = B_RESULT_SUCCESS;
|
||||
for (size_t i = 0; i < nr_interfaces; i++) {
|
||||
b_type interface_id = &interfaces[i];
|
||||
result = locate_interface(interface_id, dest, init_ctx);
|
||||
|
||||
if (b_result_is_error(result)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static b_result find_type_components(struct b_type_registration *reg)
|
||||
{
|
||||
const struct b_type_info *current = reg->r_info;
|
||||
struct b_type_component *comp = create_type_component(reg);
|
||||
if (!comp) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
struct type_init_ctx init_ctx = {
|
||||
.ctx_instance_offset = sizeof(struct _b_object),
|
||||
.ctx_class_offset = sizeof(struct _b_class),
|
||||
};
|
||||
|
||||
put_type_component(®->r_components, comp);
|
||||
b_queue_push_front(®->r_class_hierarchy, &comp->c_entry);
|
||||
|
||||
b_result result = locate_interfaces(
|
||||
current->t_interfaces, current->t_nr_interfaces, reg, &init_ctx);
|
||||
|
||||
if (b_result_is_error(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
b_type current_id = ¤t->t_parent_id;
|
||||
if (!current_id || b_type_id_compare(current_id, &zero_id) == 0) {
|
||||
goto skip_class_hierarchy;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct b_type_registration *dep_class
|
||||
= get_type(&type_list, current_id);
|
||||
if (!dep_class) {
|
||||
return B_RESULT_ERR(NO_ENTRY);
|
||||
}
|
||||
|
||||
comp = b_type_get_component(®->r_components, current_id);
|
||||
if (comp) {
|
||||
/* circular class dependency */
|
||||
// result = B_RESULT_ERR(INVALID_ARGUMENT);
|
||||
// break;
|
||||
current_id = &dep_class->r_info->t_parent_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
comp = create_type_component(dep_class);
|
||||
|
||||
result = locate_interfaces(
|
||||
dep_class->r_info->t_interfaces,
|
||||
dep_class->r_info->t_nr_interfaces, reg, &init_ctx);
|
||||
if (b_result_is_error(result)) {
|
||||
break;
|
||||
}
|
||||
|
||||
put_type_component(®->r_components, comp);
|
||||
b_queue_push_front(®->r_class_hierarchy, &comp->c_entry);
|
||||
|
||||
if (b_type_id_compare(current_id, B_TYPE_OBJECT) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
current_id = &dep_class->r_info->t_parent_id;
|
||||
}
|
||||
|
||||
b_queue_entry *entry = b_queue_first(®->r_class_hierarchy);
|
||||
while (entry) {
|
||||
comp = b_unbox(struct b_type_component, entry, c_entry);
|
||||
initialise_type_component(comp, comp->c_type->r_info, &init_ctx);
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
b_btree_node *node = b_btree_first(®->r_components);
|
||||
while (node) {
|
||||
comp = b_unbox(struct b_type_component, node, c_node);
|
||||
if (comp->c_type->r_category == B_TYPE_CLASS) {
|
||||
/* this component was already initialised above */
|
||||
node = b_btree_next(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
initialise_type_component(comp, comp->c_type->r_info, &init_ctx);
|
||||
node = b_btree_next(node);
|
||||
}
|
||||
|
||||
skip_class_hierarchy:
|
||||
reg->r_instance_size = init_ctx.ctx_instance_offset;
|
||||
reg->r_class_size = init_ctx.ctx_class_offset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool type_has_base_class(struct b_type_info *info)
|
||||
{
|
||||
if (b_type_id_compare(&info->t_id, B_TYPE_OBJECT) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return b_type_id_compare(&info->t_parent_id, &zero_id) != 0;
|
||||
}
|
||||
|
||||
b_result b_type_register(struct b_type_info *info)
|
||||
{
|
||||
if (!type_has_base_class(info)) {
|
||||
b_type_id_copy(B_TYPE_OBJECT, &info->t_parent_id);
|
||||
}
|
||||
|
||||
struct b_type_registration *r = get_type(&type_list, &info->t_id);
|
||||
if (r) {
|
||||
return B_RESULT_ERR(NAME_EXISTS);
|
||||
}
|
||||
|
||||
r = malloc(sizeof *r);
|
||||
if (!r) {
|
||||
return B_RESULT_ERR(NO_MEMORY);
|
||||
}
|
||||
|
||||
memset(r, 0x0, sizeof *r);
|
||||
|
||||
r->r_category = B_TYPE_CLASS;
|
||||
r->r_info = info;
|
||||
|
||||
b_result result = find_type_components(r);
|
||||
if (b_result_is_error(result)) {
|
||||
free(r);
|
||||
return b_result_propagate(result);
|
||||
}
|
||||
|
||||
result = b_class_instantiate(r, &r->r_class);
|
||||
if (!r->r_class) {
|
||||
free(r);
|
||||
return b_error_with_msg_template_caused_by_error(
|
||||
B_ERRORS_BUILTIN, B_ERR_TYPE_REGISTRATION_FAILURE,
|
||||
result, B_MSG_TYPE_REGISTRATION_FAILURE,
|
||||
B_ERROR_PARAM("typename", info->t_name));
|
||||
}
|
||||
|
||||
put_type(&type_list, r);
|
||||
|
||||
return B_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
struct b_type_registration *b_type_get_registration(b_type id)
|
||||
{
|
||||
return get_type(&type_list, id);
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
#ifndef _TYPE_H_
|
||||
#define _TYPE_H_
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/core/type.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum b_type_category {
|
||||
B_TYPE_NONE = 0,
|
||||
B_TYPE_CLASS,
|
||||
B_TYPE_INTERFACE,
|
||||
};
|
||||
|
||||
struct b_type_component {
|
||||
struct b_btree_node c_node;
|
||||
struct b_queue_entry c_entry;
|
||||
const struct b_type_registration *c_type;
|
||||
|
||||
size_t c_class_data_offset, c_class_data_size;
|
||||
size_t c_instance_private_data_offset, c_instance_private_data_size;
|
||||
size_t c_instance_protected_data_offset, c_instance_protected_data_size;
|
||||
};
|
||||
|
||||
struct b_type_registration {
|
||||
enum b_type_category r_category;
|
||||
struct b_btree_node r_node;
|
||||
const b_type_info *r_info;
|
||||
struct _b_class *r_class;
|
||||
struct b_btree r_components;
|
||||
struct b_queue r_class_hierarchy;
|
||||
|
||||
size_t r_instance_size, r_class_size;
|
||||
};
|
||||
|
||||
extern struct b_type_registration *b_type_get_registration(b_type id);
|
||||
extern struct b_type_component *b_type_get_component(
|
||||
const b_btree *tree, const union b_type *key);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +0,0 @@
|
||||
include(../cmake/Templates.cmake)
|
||||
|
||||
add_bluelib_module(NAME ds DEPENDENCIES core)
|
||||
-521
@@ -1,521 +0,0 @@
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <blue/ds/array.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_array_p {
|
||||
/* number of items in array */
|
||||
size_t ar_len;
|
||||
/* maximum number of items that can currently be stored in array */
|
||||
size_t ar_cap;
|
||||
b_object **ar_data;
|
||||
};
|
||||
|
||||
struct b_array_iterator_p {
|
||||
b_array *_a;
|
||||
struct b_array_p *_a_p;
|
||||
|
||||
/** The index of the current value */
|
||||
size_t i;
|
||||
/** The current value */
|
||||
b_object *value;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static b_status resize_array(struct b_array_p *array, size_t new_capacity)
|
||||
{
|
||||
if (array->ar_cap < new_capacity) {
|
||||
void *new_data = realloc(
|
||||
array->ar_data, new_capacity * sizeof(struct b_dsref *));
|
||||
if (!new_data) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
array->ar_data = new_data;
|
||||
} else {
|
||||
for (size_t i = new_capacity; i < array->ar_len; i++) {
|
||||
b_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
void *new_data = realloc(
|
||||
array->ar_data, new_capacity * sizeof(struct b_dsref *));
|
||||
if (!new_data) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
array->ar_data = new_data;
|
||||
}
|
||||
|
||||
array->ar_cap = new_capacity;
|
||||
if (array->ar_len > new_capacity) {
|
||||
array->ar_len = new_capacity;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status array_insert(struct b_array_p *array, b_object *value, size_t at)
|
||||
{
|
||||
if (at == B_NPOS) {
|
||||
at = array->ar_len;
|
||||
}
|
||||
|
||||
if (at > array->ar_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
b_status status = B_SUCCESS;
|
||||
|
||||
if (array->ar_len + 1 > array->ar_cap) {
|
||||
status = resize_array(array, array->ar_cap + 8);
|
||||
|
||||
if (status != B_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
b_object **src = array->ar_data + at;
|
||||
b_object **dest = src + 1;
|
||||
size_t move_len = (array->ar_len - at) * sizeof(struct b_dsref *);
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
array->ar_data[at] = b_object_ref(value);
|
||||
array->ar_len++;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status array_remove(struct b_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
b_object **src = array->ar_data + at;
|
||||
b_object **dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(struct b_dsref *);
|
||||
|
||||
b_object_unref(array->ar_data[at]);
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
array->ar_len--;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status array_remove_front(struct b_array_p *array)
|
||||
{
|
||||
return array_remove(array, 0);
|
||||
}
|
||||
|
||||
static b_status array_remove_back(struct b_array_p *array)
|
||||
{
|
||||
return array_remove(array, array->ar_len - 1);
|
||||
}
|
||||
|
||||
static b_object *array_pop(struct b_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_object **src = array->ar_data + at;
|
||||
b_object **dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(struct b_dsref *);
|
||||
|
||||
b_object *out = array->ar_data[at];
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
array->ar_len--;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static b_object *array_pop_front(struct b_array_p *array)
|
||||
{
|
||||
return array_pop(array, 0);
|
||||
}
|
||||
|
||||
static b_object *array_pop_back(struct b_array_p *array)
|
||||
{
|
||||
return array_pop(array, array->ar_len - 1);
|
||||
}
|
||||
|
||||
static b_object *array_at(const struct b_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return array->ar_data[at];
|
||||
}
|
||||
|
||||
static b_object *array_get(struct b_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_object_ref(array->ar_data[at]);
|
||||
}
|
||||
|
||||
static size_t array_size(const struct b_array_p *array)
|
||||
{
|
||||
return array->ar_len;
|
||||
}
|
||||
|
||||
static size_t array_capacity(const struct b_array_p *array)
|
||||
{
|
||||
return array->ar_cap;
|
||||
}
|
||||
|
||||
static void array_clear(struct b_array_p *array)
|
||||
{
|
||||
if (!array->ar_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
b_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
memset(array->ar_data, 0x0, array->ar_cap * sizeof(b_object *));
|
||||
array->ar_len = 0;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_array *b_array_create_with_values(b_object *const *values, size_t nr_values)
|
||||
{
|
||||
b_array *array = b_array_create();
|
||||
if (!array) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_array_p *p = b_object_get_private(array, B_TYPE_ARRAY);
|
||||
|
||||
size_t real_nr_values = 0;
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
if (values[i]) {
|
||||
real_nr_values++;
|
||||
}
|
||||
}
|
||||
|
||||
p->ar_len = real_nr_values;
|
||||
p->ar_cap = real_nr_values;
|
||||
p->ar_data = calloc(real_nr_values, sizeof(struct b_dsref *));
|
||||
if (!p->ar_data) {
|
||||
b_array_unref(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
p->ar_data[index++] = b_object_ref(values[i]);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
b_status b_array_insert(b_array *array, b_object *value, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_ARRAY, array_insert, array, value, at);
|
||||
}
|
||||
|
||||
b_status b_array_remove(b_array *array, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_ARRAY, array_remove, array, at);
|
||||
}
|
||||
|
||||
b_status b_array_remove_front(b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_remove_front, array);
|
||||
}
|
||||
|
||||
b_status b_array_remove_back(b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_remove_back, array);
|
||||
}
|
||||
|
||||
b_object *b_array_pop(b_array *array, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_ARRAY, array_pop, array, at);
|
||||
}
|
||||
|
||||
b_object *b_array_pop_front(b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_pop_front, array);
|
||||
}
|
||||
|
||||
b_object *b_array_pop_back(b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_pop_back, array);
|
||||
}
|
||||
|
||||
b_object *b_array_at(const b_array *array, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_ARRAY, array_at, array, at);
|
||||
}
|
||||
|
||||
b_object *b_array_get(b_array *array, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_ARRAY, array_get, array, at);
|
||||
}
|
||||
|
||||
size_t b_array_size(const b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_size, array);
|
||||
}
|
||||
|
||||
size_t b_array_capacity(const b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_capacity, array);
|
||||
}
|
||||
|
||||
void b_array_clear(b_array *array)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_ARRAY, array_clear, array);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
b_status b_array_append(b_array *array, b_object *value)
|
||||
{
|
||||
return b_array_insert(array, value, B_NPOS);
|
||||
}
|
||||
|
||||
b_status b_array_prepend(b_array *array, b_object *value)
|
||||
{
|
||||
return b_array_insert(array, value, 0);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void array_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_array_p *array = priv;
|
||||
}
|
||||
|
||||
static void array_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_array_p *array = priv;
|
||||
|
||||
if (array->ar_data) {
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
b_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
free(array->ar_data);
|
||||
array->ar_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void array_to_string(const b_object *obj, b_stream *out)
|
||||
{
|
||||
struct b_array_p *array = b_object_get_private(obj, B_TYPE_ARRAY);
|
||||
|
||||
if (!array->ar_len) {
|
||||
b_stream_write_string(out, "[]", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
b_stream_write_string(out, "[\n", NULL);
|
||||
|
||||
b_stream_push_indent(out, 1);
|
||||
size_t len = array_size(array);
|
||||
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
b_object *value = array->ar_data[i];
|
||||
bool is_string = b_object_is_type(value, B_TYPE_STRING);
|
||||
|
||||
if (is_string) {
|
||||
b_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
b_object_to_string(value, out);
|
||||
|
||||
if (is_string) {
|
||||
b_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
if (i < len - 1) {
|
||||
b_stream_write_string(out, ",", NULL);
|
||||
}
|
||||
|
||||
b_stream_write_char(out, '\n');
|
||||
}
|
||||
|
||||
b_stream_pop_indent(out);
|
||||
b_stream_write_char(out, ']');
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static b_iterator *iterable_begin(b_object *obj)
|
||||
{
|
||||
b_array_iterator *it_obj = b_object_create(B_TYPE_ARRAY_ITERATOR);
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_ARRAY_ITERATOR);
|
||||
it->_a = obj;
|
||||
it->_a_p = b_object_get_private(obj, B_TYPE_ARRAY);
|
||||
it->i = 0;
|
||||
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const b_iterator *iterable_cbegin(const b_object *obj)
|
||||
{
|
||||
b_array_iterator *it_obj = b_object_create(B_TYPE_ARRAY_ITERATOR);
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_ARRAY_ITERATOR);
|
||||
it->_a = (b_array *)obj;
|
||||
it->_a_p = b_object_get_private(obj, B_TYPE_ARRAY);
|
||||
it->i = 0;
|
||||
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_ARRAY_ITERATOR);
|
||||
struct b_array_p *array = it->_a_p;
|
||||
|
||||
if (it->value == NULL || it->i >= array->ar_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
it->value = NULL;
|
||||
} else {
|
||||
it->value = array->ar_data[it->i];
|
||||
}
|
||||
|
||||
return (it->value != NULL) ? B_SUCCESS : B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_ARRAY_ITERATOR);
|
||||
struct b_array_p *array = it->_a_p;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
if (array->ar_data[it->i] != it->value) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
array_remove(array, it->i);
|
||||
|
||||
if (it->i < array->ar_len) {
|
||||
it->value = array->ar_data[it->i];
|
||||
} else {
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_ARRAY_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_PTR(it->value);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_ARRAY_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_CPTR(it->value);
|
||||
}
|
||||
|
||||
static enum b_status iterator_is_valid(const b_iterator *obj)
|
||||
{
|
||||
struct b_array_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_ARRAY_ITERATOR);
|
||||
struct b_array_p *array = it->_a_p;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array->ar_data[it->i] != it->value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (it->value != NULL) ? B_SUCCESS : B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_array DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_array)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = array_to_string;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_array)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_array)
|
||||
B_TYPE_ID(0xe3c46da1, 0x5f37, 0x4e44, 0xb53b, 0xff5a6200191b);
|
||||
B_TYPE_CLASS(b_array_class);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_array_p);
|
||||
B_TYPE_INSTANCE_INIT(array_init);
|
||||
B_TYPE_INSTANCE_FINI(array_fini);
|
||||
B_TYPE_DEFINITION_END(b_array)
|
||||
|
||||
// ---- b_array_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_array_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_array_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_array_iterator)
|
||||
B_TYPE_ID(0xe5e9e8b8, 0x14cb, 0x4192, 0x8138, 0xf45238a2ae73);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_array_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_array_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_array_iterator)
|
||||
@@ -1,38 +0,0 @@
|
||||
#include <blue/ds/bitbuffer.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_bitbuffer_p {
|
||||
int x;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void bitbuffer_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_bitbuffer_p *bitbuffer = priv;
|
||||
}
|
||||
|
||||
static void bitbuffer_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_bitbuffer_p *bitbuffer = priv;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_bitbuffer)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_bitbuffer)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_bitbuffer)
|
||||
B_TYPE_ID(0x628e33da, 0x3109, 0x4a5d, 0x98d5, 0xb0e4cb3ccb65);
|
||||
B_TYPE_CLASS(b_bitbuffer_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_bitbuffer_p);
|
||||
B_TYPE_INSTANCE_INIT(bitbuffer_init);
|
||||
B_TYPE_INSTANCE_FINI(bitbuffer_fini);
|
||||
B_TYPE_DEFINITION_END(b_bitbuffer)
|
||||
-441
@@ -1,441 +0,0 @@
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/ds/buffer.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_buffer_p {
|
||||
/* number of items in buffer */
|
||||
unsigned int buf_len;
|
||||
/* maximum number of items that can currently be stored in array */
|
||||
unsigned int buf_cap;
|
||||
/* the size of each individual item in the buffer */
|
||||
unsigned int buf_itemsz;
|
||||
void *buf_data;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static b_status resize_buffer(struct b_buffer_p *buffer, size_t new_capacity)
|
||||
{
|
||||
if (buffer->buf_cap < new_capacity) {
|
||||
void *new_data = realloc(
|
||||
buffer->buf_data, new_capacity * buffer->buf_itemsz);
|
||||
if (!new_data) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
buffer->buf_data = new_data;
|
||||
} else {
|
||||
void *new_data = realloc(
|
||||
buffer->buf_data, new_capacity * buffer->buf_itemsz);
|
||||
if (!new_data) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
buffer->buf_data = new_data;
|
||||
}
|
||||
|
||||
buffer->buf_cap = new_capacity;
|
||||
if (buffer->buf_len > new_capacity) {
|
||||
buffer->buf_len = new_capacity;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static void *buffer_steal(struct b_buffer_p *buf)
|
||||
{
|
||||
void *p = buf->buf_data;
|
||||
|
||||
buf->buf_data = NULL;
|
||||
buf->buf_len = 0;
|
||||
buf->buf_cap = 0;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static enum b_status buffer_reserve(struct b_buffer_p *buf, size_t capacity)
|
||||
{
|
||||
if (buf->buf_cap >= capacity) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
return resize_buffer(buf, capacity);
|
||||
}
|
||||
|
||||
static enum b_status buffer_resize(struct b_buffer_p *buf, size_t length)
|
||||
{
|
||||
enum b_status status = resize_buffer(buf, length);
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
buf->buf_len = length;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status buffer_insert(
|
||||
struct b_buffer_p *buffer, const void *p, size_t count, size_t at)
|
||||
{
|
||||
if (at == B_NPOS) {
|
||||
at = buffer->buf_len;
|
||||
}
|
||||
|
||||
if (at > buffer->buf_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
b_status status = B_SUCCESS;
|
||||
|
||||
if (buffer->buf_len + count > buffer->buf_cap) {
|
||||
status = resize_buffer(buffer, buffer->buf_cap + count);
|
||||
|
||||
if (status != B_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *src
|
||||
= (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
|
||||
unsigned char *dest = src + (count * buffer->buf_itemsz);
|
||||
size_t move_len = (buffer->buf_len - at) * buffer->buf_itemsz;
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
memcpy(src, p, count * buffer->buf_itemsz);
|
||||
|
||||
buffer->buf_len += count;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status buffer_remove(struct b_buffer_p *buffer, size_t at, size_t count)
|
||||
{
|
||||
if (at >= buffer->buf_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
if (at + count >= buffer->buf_len) {
|
||||
count = buffer->buf_len - at;
|
||||
}
|
||||
|
||||
unsigned char *dest = buffer->buf_data + (at * buffer->buf_itemsz);
|
||||
unsigned char *src = dest + (count * buffer->buf_itemsz);
|
||||
size_t move_len = (buffer->buf_len - at - count) * buffer->buf_itemsz;
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
buffer->buf_len -= count;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static void *buffer_ptr(const struct b_buffer_p *buffer)
|
||||
{
|
||||
return buffer->buf_data;
|
||||
}
|
||||
|
||||
static void *buffer_get(const struct b_buffer_p *buffer, size_t at)
|
||||
{
|
||||
if (at >= buffer->buf_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
|
||||
}
|
||||
|
||||
static size_t buffer_size(const struct b_buffer_p *buffer)
|
||||
{
|
||||
return buffer->buf_len;
|
||||
}
|
||||
|
||||
static size_t buffer_capacity(const struct b_buffer_p *buffer)
|
||||
{
|
||||
return buffer->buf_cap;
|
||||
}
|
||||
|
||||
static enum b_status buffer_clear(struct b_buffer_p *buffer)
|
||||
{
|
||||
buffer->buf_len = 0;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status buffer_push_back(
|
||||
struct b_buffer_p *buf, size_t count, void **p)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
|
||||
if (buf->buf_len + count > buf->buf_cap) {
|
||||
status = resize_buffer(buf, buf->buf_len + count);
|
||||
}
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
buf->buf_len += count;
|
||||
*p = buffer_get(buf, buf->buf_len - count);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status buffer_push_front(
|
||||
struct b_buffer_p *buf, size_t count, void **p)
|
||||
{
|
||||
enum b_status status = B_SUCCESS;
|
||||
|
||||
if (buf->buf_len + count > buf->buf_cap) {
|
||||
status = resize_buffer(buf, buf->buf_len + count);
|
||||
}
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
void *src = buf->buf_data;
|
||||
void *dest = b_buffer_get(buf->buf_data, count);
|
||||
size_t len = count * buf->buf_itemsz;
|
||||
|
||||
memmove(dest, src, len);
|
||||
buf->buf_len += count;
|
||||
|
||||
*p = buffer_get(buf, 0);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status buffer_pop_back(struct b_buffer_p *buf, size_t count)
|
||||
{
|
||||
if (count > buf->buf_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
buf->buf_len -= count;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status buffer_pop_front(struct b_buffer_p *buf, size_t count)
|
||||
{
|
||||
if (count > buf->buf_len) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
void *src = b_buffer_get(buf->buf_data, count);
|
||||
void *dest = buf->buf_data;
|
||||
size_t len = (buf->buf_len - count) * buf->buf_itemsz;
|
||||
|
||||
memmove(dest, src, len);
|
||||
buf->buf_len -= count;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static size_t buffer_get_size(const struct b_buffer_p *buf)
|
||||
{
|
||||
return buf->buf_len;
|
||||
}
|
||||
|
||||
static size_t buffer_get_item_size(const struct b_buffer_p *buf)
|
||||
{
|
||||
return buf->buf_itemsz;
|
||||
}
|
||||
|
||||
static size_t buffer_get_capacity(const struct b_buffer_p *buf)
|
||||
{
|
||||
return buf->buf_cap;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_buffer *b_buffer_create(size_t item_sz)
|
||||
{
|
||||
b_buffer *buffer = b_object_create(B_TYPE_BUFFER);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_buffer_p *p = b_object_get_private(buffer, B_TYPE_BUFFER);
|
||||
|
||||
p->buf_itemsz = item_sz;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
b_buffer *b_buffer_create_from_bytes(const void *buf, size_t len)
|
||||
{
|
||||
b_buffer *buffer = b_object_create(B_TYPE_BUFFER);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_buffer_p *p = b_object_get_private(buffer, B_TYPE_BUFFER);
|
||||
|
||||
p->buf_len = len;
|
||||
p->buf_cap = len;
|
||||
p->buf_itemsz = 1;
|
||||
p->buf_data = calloc(len, 1);
|
||||
if (!p->buf_data) {
|
||||
b_buffer_unref(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(p->buf_data, buf, len);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
b_buffer *b_buffer_create_from_array(const void *buf, size_t item_sz, size_t len)
|
||||
{
|
||||
b_buffer *buffer = b_object_create(B_TYPE_BUFFER);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_buffer_p *p = b_object_get_private(buffer, B_TYPE_BUFFER);
|
||||
|
||||
p->buf_len = len;
|
||||
p->buf_cap = len;
|
||||
p->buf_itemsz = item_sz;
|
||||
p->buf_data = calloc(len, item_sz);
|
||||
if (!p->buf_data) {
|
||||
b_buffer_unref(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(p->buf_data, buf, len * item_sz);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void *b_buffer_steal(b_buffer *buf)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_steal, buf);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_reserve(b_buffer *buf, size_t capacity)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_reserve, buf, capacity);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_resize(b_buffer *buf, size_t length)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_resize, buf, length);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_insert(
|
||||
b_buffer *buffer, const void *p, size_t count, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_insert, buffer, p, count, at);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_remove(b_buffer *buffer, size_t at, size_t count)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_remove, buffer, at, count);
|
||||
}
|
||||
|
||||
void *b_buffer_ptr(const b_buffer *buffer)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_ptr, buffer);
|
||||
}
|
||||
|
||||
void *b_buffer_get(const b_buffer *buffer, size_t at)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_get, buffer, at);
|
||||
}
|
||||
|
||||
size_t b_buffer_size(const b_buffer *buffer)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_size, buffer);
|
||||
}
|
||||
|
||||
size_t b_buffer_capacity(const b_buffer *buffer)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_capacity, buffer);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_clear(b_buffer *buffer)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_clear, buffer);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_push_back(b_buffer *buf, size_t count, void **p)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_push_back, buf, count, p);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_push_front(b_buffer *buf, size_t count, void **p)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_push_front, buf, count, p);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_pop_back(b_buffer *buf, size_t count)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_pop_back, buf, count);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_pop_front(b_buffer *buf, size_t count)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BUFFER, buffer_pop_front, buf, count);
|
||||
}
|
||||
|
||||
size_t b_buffer_get_size(const b_buffer *buf)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_get_size, buf);
|
||||
}
|
||||
|
||||
size_t b_buffer_get_item_size(const b_buffer *buf)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_get_item_size, buf);
|
||||
}
|
||||
|
||||
size_t b_buffer_get_capacity(const b_buffer *buf)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BUFFER, buffer_get_capacity, buf);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
enum b_status b_buffer_append(b_buffer *buffer, const void *p, size_t count)
|
||||
{
|
||||
return b_buffer_insert(buffer, p, count, B_NPOS);
|
||||
}
|
||||
|
||||
enum b_status b_buffer_prepend(b_buffer *buffer, const void *p, size_t count)
|
||||
{
|
||||
return b_buffer_insert(buffer, p, count, 0);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
void buffer_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_buffer_p *buffer = priv;
|
||||
}
|
||||
|
||||
void buffer_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_buffer_p *buffer = priv;
|
||||
|
||||
if (buffer->buf_data) {
|
||||
free(buffer->buf_data);
|
||||
buffer->buf_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_buffer)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_buffer)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_buffer)
|
||||
B_TYPE_ID(0x323e6858, 0x7a43, 0x4484, 0xa6fb, 0xe3d1e47ae637);
|
||||
B_TYPE_CLASS(b_buffer_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_buffer_p);
|
||||
B_TYPE_INSTANCE_INIT(buffer_init);
|
||||
B_TYPE_INSTANCE_FINI(buffer_fini);
|
||||
B_TYPE_DEFINITION_END(b_buffer)
|
||||
@@ -1,723 +0,0 @@
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <blue/ds/dict.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
|
||||
#define HASH_PRIME 0x100000001b3
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_dict_bucket_item {
|
||||
b_queue_entry bi_entry;
|
||||
b_string *bi_str;
|
||||
b_object *bi_value;
|
||||
};
|
||||
|
||||
struct b_dict_bucket {
|
||||
b_btree_node bk_node;
|
||||
uint64_t bk_hash;
|
||||
b_queue bk_items;
|
||||
};
|
||||
|
||||
struct b_dict_p {
|
||||
b_btree d_buckets;
|
||||
};
|
||||
|
||||
struct b_dict_iterator_p {
|
||||
size_t i;
|
||||
b_dict_item item;
|
||||
|
||||
b_dict *_d;
|
||||
struct b_dict_p *_d_p;
|
||||
b_btree_node *_cbn;
|
||||
b_queue_entry *_cqe;
|
||||
};
|
||||
|
||||
/*** MISC FUNCTIONS ***********************************************************/
|
||||
|
||||
static B_BTREE_DEFINE_SIMPLE_GET(
|
||||
struct b_dict_bucket, uint64_t, bk_node, bk_hash, get_bucket);
|
||||
static B_BTREE_DEFINE_SIMPLE_INSERT(
|
||||
struct b_dict_bucket, bk_node, bk_hash, put_bucket);
|
||||
|
||||
uint64_t b_cstr_hash(const char *s)
|
||||
{
|
||||
uint64_t hash = HASH_OFFSET_BASIS;
|
||||
|
||||
for (size_t i = 0; s[i]; i++) {
|
||||
hash *= HASH_PRIME;
|
||||
hash ^= s[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static struct b_dict_bucket *create_bucket(void)
|
||||
{
|
||||
struct b_dict_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct b_dict_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct b_dict_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static b_status dict_put(struct b_dict_p *dict, const char *key, b_object *value)
|
||||
{
|
||||
uint64_t hash = b_cstr_hash(key);
|
||||
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&dict->d_buckets, bucket);
|
||||
}
|
||||
|
||||
struct b_dict_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item->bi_str = b_string_create_from_cstr(key);
|
||||
item->bi_value = b_object_ref(value);
|
||||
|
||||
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status dict_put_sk(
|
||||
struct b_dict_p *dict, const b_string *key, b_object *value)
|
||||
{
|
||||
uint64_t hash = b_string_hash(key);
|
||||
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&dict->d_buckets, bucket);
|
||||
}
|
||||
|
||||
struct b_dict_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item->bi_str = b_string_duplicate(key);
|
||||
item->bi_value = b_object_ref(value);
|
||||
|
||||
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_object *dict_at(const struct b_dict_p *dict, const char *key)
|
||||
{
|
||||
uint64_t hash = b_cstr_hash(key);
|
||||
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_dict_bucket_item *item
|
||||
= b_unbox(struct b_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
if (!strcmp(b_string_ptr(item->bi_str), key)) {
|
||||
return item->bi_value;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static b_object *dict_at_sk(const struct b_dict_p *dict, const b_string *key)
|
||||
{
|
||||
uint64_t hash = b_string_hash(key);
|
||||
struct b_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_dict_bucket_item *item
|
||||
= b_unbox(struct b_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
if (b_string_compare(item->bi_str, key)) {
|
||||
return item->bi_value;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static b_object *dict_get(struct b_dict_p *dict, const char *key)
|
||||
{
|
||||
b_object *value = dict_at(dict, key);
|
||||
if (value) {
|
||||
b_object_ref(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static b_object *dict_get_sk(struct b_dict_p *dict, const b_string *key)
|
||||
{
|
||||
b_object *value = dict_at_sk(dict, key);
|
||||
if (value) {
|
||||
b_object_ref(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool dict_has_key(const struct b_dict_p *dict, const char *key)
|
||||
{
|
||||
return dict_at(dict, key) != NULL;
|
||||
}
|
||||
|
||||
static bool dict_has_skey(const struct b_dict_p *dict, const b_string *key)
|
||||
{
|
||||
return dict_at_sk(dict, key) != NULL;
|
||||
}
|
||||
|
||||
static size_t dict_get_size(const struct b_dict_p *dict)
|
||||
{
|
||||
size_t count = 0;
|
||||
#if 0
|
||||
b_btree_iterator it1;
|
||||
b_queue_iterator it2;
|
||||
|
||||
b_btree_foreach (&it1, &dict->d_buckets) {
|
||||
struct b_dict_bucket *bucket
|
||||
= b_unbox(struct b_dict_bucket, it1.node, bk_node);
|
||||
|
||||
b_queue_foreach (&it2, &bucket->bk_items) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool dict_is_empty(const struct b_dict_p *dict)
|
||||
{
|
||||
b_btree_node *first_node = b_btree_first(&dict->d_buckets);
|
||||
struct b_dict_bucket *first_bucket
|
||||
= b_unbox(struct b_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_dict_bucket_item *first_item
|
||||
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool get_next_node(
|
||||
struct b_btree_node *cur_node, struct b_queue_entry *cur_entry,
|
||||
struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry)
|
||||
{
|
||||
struct b_dict_bucket *cur_bucket
|
||||
= b_unbox(struct b_dict_bucket, cur_node, bk_node);
|
||||
if (!cur_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_dict_bucket_item *cur_item
|
||||
= b_unbox(struct b_dict_bucket_item, cur_entry, bi_entry);
|
||||
if (!cur_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_btree_node *next_node = cur_node;
|
||||
struct b_queue_entry *next_entry = b_queue_next(cur_entry);
|
||||
if (!next_entry) {
|
||||
next_node = b_btree_next(cur_node);
|
||||
if (!next_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_dict_bucket *next_bucket
|
||||
= b_unbox(struct b_dict_bucket, next_node, bk_node);
|
||||
if (!next_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
next_entry = b_queue_first(&next_bucket->bk_items);
|
||||
if (!next_entry) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct b_dict_bucket_item *next_item
|
||||
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
|
||||
if (!next_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_next_node = next_node;
|
||||
*out_next_entry = next_entry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static b_status delete_item(
|
||||
struct b_dict_p *dict, struct b_dict_bucket *bucket,
|
||||
struct b_dict_bucket_item *item)
|
||||
{
|
||||
b_queue_delete(&bucket->bk_items, &item->bi_entry);
|
||||
free(item);
|
||||
|
||||
if (b_queue_empty(&bucket->bk_items)) {
|
||||
b_btree_delete(&dict->d_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
#if 0
|
||||
b_dict *b_dict_create_with_items(const b_dict_item *items)
|
||||
{
|
||||
b_dict *dict = b_dict_create();
|
||||
if (!dict) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_dict_p *p = b_object_get_private(dict, B_TYPE_DICT);
|
||||
|
||||
for (size_t i = 0; items[i].key; i++) {
|
||||
dict_put(p, items[i].key, items[i].value);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
#endif
|
||||
|
||||
b_status b_dict_put(b_dict *dict, const char *key, b_object *value)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_put, dict, key, value);
|
||||
}
|
||||
|
||||
b_status b_dict_put_sk(b_dict *dict, const b_string *key, b_object *value)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_put_sk, dict, key, value);
|
||||
}
|
||||
|
||||
b_object *b_dict_at(const b_dict *dict, const char *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_at, dict, key);
|
||||
}
|
||||
|
||||
b_object *b_dict_at_sk(const b_dict *dict, const b_string *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_at_sk, dict, key);
|
||||
}
|
||||
|
||||
b_object *b_dict_get(b_dict *dict, const char *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_get, dict, key);
|
||||
}
|
||||
|
||||
b_object *b_dict_get_sk(b_dict *dict, const b_string *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_get_sk, dict, key);
|
||||
}
|
||||
|
||||
bool b_dict_has_key(const b_dict *dict, const char *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_has_key, dict, key);
|
||||
}
|
||||
|
||||
bool b_dict_has_skey(const b_dict *dict, const b_string *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_DICT, dict_has_skey, dict, key);
|
||||
}
|
||||
|
||||
size_t b_dict_get_size(const b_dict *dict)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DICT, dict_get_size, dict);
|
||||
}
|
||||
|
||||
bool b_dict_is_empty(const b_dict *dict)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DICT, dict_is_empty, dict);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void dict_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_dict_p *dict = priv;
|
||||
}
|
||||
|
||||
static void dict_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_dict_p *dict = priv;
|
||||
|
||||
struct b_btree_node *node = b_btree_first(&dict->d_buckets);
|
||||
while (node) {
|
||||
struct b_dict_bucket *bucket
|
||||
= b_unbox(struct b_dict_bucket, node, bk_node);
|
||||
struct b_btree_node *next_node = b_btree_next(node);
|
||||
b_btree_delete(&dict->d_buckets, node);
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_dict_bucket_item *item = b_unbox(
|
||||
struct b_dict_bucket_item, entry, bi_entry);
|
||||
struct b_queue_entry *next_entry = b_queue_next(entry);
|
||||
b_queue_delete(&bucket->bk_items, entry);
|
||||
|
||||
free(item->bi_str);
|
||||
b_object_unref(item->bi_value);
|
||||
free(item);
|
||||
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
free(bucket);
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
static void dict_to_string(const b_object *obj, b_stream *out)
|
||||
{
|
||||
struct b_dict_p *dict = b_object_get_private(obj, B_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(dict)) {
|
||||
b_stream_write_string(out, "{}", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
b_stream_write_string(out, "{\n", NULL);
|
||||
|
||||
b_stream_push_indent(out, 1);
|
||||
size_t len = dict_get_size(dict);
|
||||
size_t i = 0;
|
||||
|
||||
struct b_btree_node *node = b_btree_first(&dict->d_buckets);
|
||||
while (node) {
|
||||
struct b_dict_bucket *bucket
|
||||
= b_unbox(struct b_dict_bucket, node, bk_node);
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_dict_bucket_item *item = b_unbox(
|
||||
struct b_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
b_object_to_string(item->bi_str, out);
|
||||
b_stream_write_string(out, ": ", NULL);
|
||||
|
||||
bool is_string
|
||||
= b_object_is_type(item->bi_value, B_TYPE_STRING);
|
||||
|
||||
if (is_string) {
|
||||
b_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
b_object_to_string(item->bi_value, out);
|
||||
|
||||
if (is_string) {
|
||||
b_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
if (i < len - 1) {
|
||||
b_stream_write_string(out, ",", NULL);
|
||||
}
|
||||
|
||||
b_stream_write_char(out, '\n');
|
||||
entry = b_queue_next(entry);
|
||||
i++;
|
||||
}
|
||||
node = b_btree_next(node);
|
||||
}
|
||||
|
||||
b_stream_pop_indent(out);
|
||||
b_stream_write_char(out, '}');
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static b_iterator *iterable_begin(b_dict *dict)
|
||||
{
|
||||
b_iterator *it_obj = b_object_create(B_TYPE_DICT_ITERATOR);
|
||||
if (!it_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_dict_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_DICT_ITERATOR);
|
||||
|
||||
it->i = 0;
|
||||
it->_d = dict;
|
||||
it->_d_p = b_object_get_private(dict, B_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(it->_d_p)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
b_btree_node *first_node = b_btree_first(&it->_d_p->d_buckets);
|
||||
struct b_dict_bucket *first_bucket
|
||||
= b_unbox(struct b_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_dict_bucket_item *first_item
|
||||
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
it->item.key = first_item->bi_str;
|
||||
it->item.value = first_item->bi_value;
|
||||
|
||||
it->_d = dict;
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const b_iterator *iterable_cbegin(const b_dict *dict)
|
||||
{
|
||||
b_iterator *it_obj = b_object_create(B_TYPE_DICT_ITERATOR);
|
||||
if (!it_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_dict_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_DICT_ITERATOR);
|
||||
|
||||
it->i = 0;
|
||||
it->_d = (b_dict *)dict;
|
||||
it->_d_p = b_object_get_private(dict, B_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(it->_d_p)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
b_btree_node *first_node = b_btree_first(&it->_d_p->d_buckets);
|
||||
struct b_dict_bucket *first_bucket
|
||||
= b_unbox(struct b_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_dict_bucket_item *first_item
|
||||
= b_unbox(struct b_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
it->item.key = first_item->bi_str;
|
||||
it->item.value = first_item->bi_value;
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_dict_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DICT_ITERATOR);
|
||||
|
||||
struct b_btree_node *next_node;
|
||||
struct b_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct b_dict_bucket_item *next_item
|
||||
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
|
||||
|
||||
if (!next_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
it->item.key = next_item->bi_str;
|
||||
it->item.value = next_item->bi_value;
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
struct b_dict_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DICT_ITERATOR);
|
||||
|
||||
if ((it->item.key || it->item.value) && !(it->_cbn && it->_cqe)) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!it->item.key || !it->_cqe) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct b_btree_node *next_node;
|
||||
struct b_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct b_dict_bucket *cur_bucket
|
||||
= b_unbox(struct b_dict_bucket, it->_cbn, bk_node);
|
||||
struct b_dict_bucket_item *cur_item
|
||||
= b_unbox(struct b_dict_bucket_item, it->_cqe, bi_entry);
|
||||
|
||||
struct b_dict_bucket_item *next_item
|
||||
= b_unbox(struct b_dict_bucket_item, next_entry, bi_entry);
|
||||
|
||||
b_status status = delete_item(it->_d_p, cur_bucket, cur_item);
|
||||
if (B_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (next_item) {
|
||||
it->item.key = next_item->bi_str;
|
||||
it->item.value = next_item->bi_value;
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
} else {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
|
||||
it->_cbn = NULL;
|
||||
it->_cqe = NULL;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_dict_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DICT_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_PTR(&it->item);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_dict_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_DICT_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_CPTR(&it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_dict DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_dict)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = dict_to_string;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_dict)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_dict)
|
||||
B_TYPE_ID(0xd2af61d9, 0xd0be, 0x4960, 0xbe3f, 0x509749814c10);
|
||||
B_TYPE_CLASS(b_dict_class);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_dict_p);
|
||||
B_TYPE_INSTANCE_INIT(dict_init);
|
||||
B_TYPE_INSTANCE_FINI(dict_fini);
|
||||
B_TYPE_DEFINITION_END(b_dict)
|
||||
|
||||
// ---- b_dict_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_dict_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_dict_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_dict_iterator)
|
||||
B_TYPE_ID(0x9ea96701, 0x1713, 0x4a3e, 0xbf63, 0xdc856b456f3b);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_dict_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_dict_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_dict_iterator)
|
||||
-598
@@ -1,598 +0,0 @@
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/ds/hashmap.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
|
||||
#define HASH_PRIME 0x100000001b3
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_hashmap_bucket_item {
|
||||
struct b_queue_entry bi_entry;
|
||||
struct b_hashmap_key bi_key;
|
||||
struct b_hashmap_value bi_value;
|
||||
};
|
||||
|
||||
struct b_hashmap_bucket {
|
||||
struct b_btree_node bk_node;
|
||||
uint64_t bk_hash;
|
||||
struct b_queue bk_items;
|
||||
};
|
||||
|
||||
struct b_hashmap_p {
|
||||
size_t h_count;
|
||||
struct b_btree h_buckets;
|
||||
b_hashmap_key_destructor h_key_dtor;
|
||||
b_hashmap_value_destructor h_value_dtor;
|
||||
};
|
||||
|
||||
struct b_hashmap_iterator_p {
|
||||
size_t i;
|
||||
b_hashmap_item item;
|
||||
|
||||
b_hashmap *_h;
|
||||
struct b_hashmap_p *_h_p;
|
||||
b_btree_node *_cbn;
|
||||
b_queue_entry *_cqe;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static B_BTREE_DEFINE_SIMPLE_GET(
|
||||
struct b_hashmap_bucket, uint64_t, bk_node, bk_hash, get_bucket);
|
||||
static B_BTREE_DEFINE_SIMPLE_INSERT(
|
||||
struct b_hashmap_bucket, bk_node, bk_hash, put_bucket);
|
||||
|
||||
static uint64_t hash_data(const void *p, size_t size)
|
||||
{
|
||||
const unsigned char *s = p;
|
||||
uint64_t hash = HASH_OFFSET_BASIS;
|
||||
|
||||
for (size_t i = 0; s[i]; i++) {
|
||||
hash *= HASH_PRIME;
|
||||
hash ^= s[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static uint64_t hash_key(const struct b_hashmap_key *key)
|
||||
{
|
||||
if (key->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
|
||||
return hash_data(&key->key_data, sizeof key->key_data);
|
||||
} else {
|
||||
return hash_data(key->key_data, key->key_size);
|
||||
}
|
||||
}
|
||||
|
||||
static bool compare_key(
|
||||
const struct b_hashmap_key *a, const struct b_hashmap_key *b)
|
||||
{
|
||||
const void *a_data = NULL, *b_data = NULL;
|
||||
size_t a_len = 0, b_len = 0;
|
||||
|
||||
if (a->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
|
||||
a_data = &a->key_data;
|
||||
a_len = sizeof a->key_data;
|
||||
} else {
|
||||
a_data = a->key_data;
|
||||
a_len = a->key_size;
|
||||
}
|
||||
|
||||
if (b->key_flags & B_HASHMAP_KEY_F_INTVALUE) {
|
||||
b_data = &b->key_data;
|
||||
b_len = sizeof b->key_data;
|
||||
} else {
|
||||
b_data = b->key_data;
|
||||
b_len = b->key_size;
|
||||
}
|
||||
|
||||
if (a_len != b_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t cmp_len = a_len;
|
||||
return memcmp(a_data, b_data, cmp_len) == 0;
|
||||
}
|
||||
|
||||
static bool get_next_node(
|
||||
struct b_btree_node *cur_node, struct b_queue_entry *cur_entry,
|
||||
struct b_btree_node **out_next_node, struct b_queue_entry **out_next_entry)
|
||||
{
|
||||
struct b_hashmap_bucket *cur_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, cur_node, bk_node);
|
||||
if (!cur_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket_item *cur_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, cur_entry, bi_entry);
|
||||
if (!cur_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_btree_node *next_node = cur_node;
|
||||
struct b_queue_entry *next_entry = b_queue_next(cur_entry);
|
||||
if (!next_entry) {
|
||||
next_node = b_btree_next(cur_node);
|
||||
if (!next_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket *next_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, next_node, bk_node);
|
||||
if (!next_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
next_entry = b_queue_first(&next_bucket->bk_items);
|
||||
if (!next_entry) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket_item *next_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
|
||||
if (!next_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_next_node = next_node;
|
||||
*out_next_entry = next_entry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct b_hashmap_bucket *create_bucket(void)
|
||||
{
|
||||
struct b_hashmap_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct b_hashmap_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct b_hashmap_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static b_status hashmap_put(
|
||||
struct b_hashmap_p *hashmap, const b_hashmap_key *key,
|
||||
const b_hashmap_value *value)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&hashmap->h_buckets, bucket);
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_hashmap_bucket_item *item
|
||||
= b_unbox(struct b_hashmap_bucket_item, entry, bi_entry);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(&item->bi_key, key, sizeof *key);
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
|
||||
b_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
hashmap->h_count++;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct b_hashmap_value *hashmap_get(
|
||||
const struct b_hashmap_p *hashmap, const struct b_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_hashmap_bucket_item *item
|
||||
= b_unbox(struct b_hashmap_bucket_item, entry, bi_entry);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return &item->bi_value;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hashmap_has_key(
|
||||
const struct b_hashmap_p *hashmap, const b_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct b_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct b_hashmap_bucket_item *item
|
||||
= b_unbox(struct b_hashmap_bucket_item, entry, bi_entry);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t hashmap_get_size(const struct b_hashmap_p *hashmap)
|
||||
{
|
||||
return hashmap->h_count;
|
||||
}
|
||||
|
||||
static bool hashmap_is_empty(const struct b_hashmap_p *hashmap)
|
||||
{
|
||||
b_btree_node *first_node = b_btree_first(&hashmap->h_buckets);
|
||||
struct b_hashmap_bucket *first_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_hashmap_bucket_item *first_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static b_status delete_item(
|
||||
struct b_hashmap_p *hashmap, struct b_hashmap_bucket *bucket,
|
||||
struct b_hashmap_bucket_item *item)
|
||||
{
|
||||
b_queue_delete(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
if (hashmap->h_key_dtor) {
|
||||
hashmap->h_key_dtor((void *)item->bi_key.key_data);
|
||||
}
|
||||
|
||||
if (hashmap->h_value_dtor) {
|
||||
hashmap->h_value_dtor((void *)item->bi_value.value_data);
|
||||
}
|
||||
|
||||
free(item);
|
||||
|
||||
if (b_queue_empty(&bucket->bk_items)) {
|
||||
b_btree_delete(&hashmap->h_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
hashmap->h_count--;
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_hashmap *b_hashmap_create(
|
||||
b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor)
|
||||
{
|
||||
b_hashmap *hashmap = b_object_create(B_TYPE_HASHMAP);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items)
|
||||
{
|
||||
b_hashmap *hashmap = b_hashmap_create(NULL, NULL);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_hashmap_p *p = b_object_get_private(hashmap, B_TYPE_HASHMAP);
|
||||
|
||||
for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) {
|
||||
hashmap_put(p, &items[i].key, &items[i].value);
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
b_status b_hashmap_put(
|
||||
b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_HASHMAP, hashmap_put, hashmap, key, value);
|
||||
}
|
||||
|
||||
const struct b_hashmap_value *b_hashmap_get(
|
||||
const b_hashmap *hashmap, const struct b_hashmap_key *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_HASHMAP, hashmap_get, hashmap, key);
|
||||
}
|
||||
|
||||
bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *key)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_HASHMAP, hashmap_has_key, hashmap, key);
|
||||
}
|
||||
|
||||
size_t b_hashmap_get_size(const b_hashmap *hashmap)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_HASHMAP, hashmap_get_size, hashmap);
|
||||
}
|
||||
|
||||
bool b_hashmap_is_empty(const b_hashmap *hashmap)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_HASHMAP, hashmap_is_empty, hashmap);
|
||||
}
|
||||
|
||||
b_iterator *b_hashmap_begin(b_hashmap *hashmap)
|
||||
{
|
||||
b_hashmap_iterator *it_obj = b_object_create(B_TYPE_HASHMAP_ITERATOR);
|
||||
struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
it->_h = hashmap;
|
||||
it->_h_p = b_object_get_private(hashmap, B_TYPE_HASHMAP);
|
||||
|
||||
it->i = 0;
|
||||
if (b_hashmap_is_empty(hashmap)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct b_btree_node *first_node = b_btree_first(&it->_h_p->h_buckets);
|
||||
struct b_hashmap_bucket *first_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct b_queue_entry *first_entry = b_queue_first(&first_bucket->bk_items);
|
||||
struct b_hashmap_bucket_item *first_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const b_iterator *b_hashmap_cbegin(const b_hashmap *hashmap)
|
||||
{
|
||||
return b_hashmap_begin((b_hashmap *)hashmap);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void hashmap_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_hashmap_p *map = priv;
|
||||
}
|
||||
|
||||
static void hashmap_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_hashmap_p *map = priv;
|
||||
|
||||
struct b_btree_node *node = b_btree_first(&map->h_buckets);
|
||||
while (node) {
|
||||
struct b_hashmap_bucket *b
|
||||
= b_unbox(struct b_hashmap_bucket, node, bk_node);
|
||||
struct b_btree_node *next_node = b_btree_next(node);
|
||||
b_btree_delete(&map->h_buckets, node);
|
||||
|
||||
struct b_queue_entry *entry = b_queue_first(&b->bk_items);
|
||||
while (entry) {
|
||||
struct b_hashmap_bucket_item *item = b_unbox(
|
||||
struct b_hashmap_bucket_item, entry, bi_entry);
|
||||
struct b_queue_entry *next_entry = b_queue_next(entry);
|
||||
b_queue_delete(&b->bk_items, entry);
|
||||
|
||||
if (map->h_key_dtor) {
|
||||
map->h_key_dtor((void *)item->bi_key.key_data);
|
||||
}
|
||||
|
||||
if (map->h_value_dtor) {
|
||||
map->h_value_dtor((void *)item->bi_value.value_data);
|
||||
}
|
||||
|
||||
free(item);
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
free(b);
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
struct b_btree_node *next_node;
|
||||
struct b_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket_item *next_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
if (!next_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &next_item->bi_value, sizeof it->item.value);
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
if ((it->item.key.key_data || it->item.value.value_data)
|
||||
&& !(it->_cbn && it->_cqe)) {
|
||||
return B_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!it->item.key.key_data || !it->_cqe) {
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct b_btree_node *next_node;
|
||||
struct b_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct b_hashmap_bucket *cur_bucket
|
||||
= b_unbox(struct b_hashmap_bucket, it->_cbn, bk_node);
|
||||
struct b_hashmap_bucket_item *cur_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, it->_cqe, bi_entry);
|
||||
|
||||
struct b_hashmap_bucket_item *next_item
|
||||
= b_unbox(struct b_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
b_status status = delete_item(it->_h_p, cur_bucket, cur_item);
|
||||
if (B_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (next_item) {
|
||||
memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &next_item->bi_value,
|
||||
sizeof it->item.value);
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
} else {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
|
||||
it->_cbn = NULL;
|
||||
it->_cqe = NULL;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
return B_ITERATOR_VALUE_PTR(&it->item);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
const struct b_hashmap_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_HASHMAP_ITERATOR);
|
||||
return B_ITERATOR_VALUE_CPTR(&it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_hashmap DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = b_hashmap_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = b_hashmap_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_hashmap)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_hashmap)
|
||||
B_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf);
|
||||
B_TYPE_CLASS(b_hashmap_class);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_hashmap_p);
|
||||
B_TYPE_INSTANCE_INIT(hashmap_init);
|
||||
B_TYPE_INSTANCE_FINI(hashmap_fini);
|
||||
B_TYPE_DEFINITION_END(b_hashmap)
|
||||
|
||||
// ---- b_hashmap_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_hashmap_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_hashmap_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_hashmap_iterator)
|
||||
B_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_hashmap_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_hashmap_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_hashmap_iterator)
|
||||
@@ -1,218 +0,0 @@
|
||||
/**
|
||||
* A heterogeneous array of objects. b_array only stores references
|
||||
* to the objects that it contains, not the object data itself.
|
||||
*
|
||||
* b_array stores pointers to objects in a single contiguous array,
|
||||
* but this is an implementation detail that may change in the future.
|
||||
* Users of b_array should not rely on this being the case.
|
||||
*/
|
||||
#ifndef BLUE_DS_ARRAY_H_
|
||||
#define BLUE_DS_ARRAY_H_
|
||||
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/status.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_ARRAY (b_array_get_type())
|
||||
#define B_TYPE_ARRAY_ITERATOR (b_array_iterator_get_type())
|
||||
|
||||
struct b_array_p;
|
||||
|
||||
B_DECLARE_TYPE(b_array);
|
||||
B_DECLARE_TYPE(b_array_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_array)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_array)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_array_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_array_iterator)
|
||||
|
||||
BLUE_API b_type b_array_get_type(void);
|
||||
BLUE_API b_type b_array_iterator_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_array, B_TYPE_ARRAY);
|
||||
|
||||
/**
|
||||
* Creates an b_array initialised with the contents of the provided
|
||||
* b_object pointer array. The b_array will take a reference to each
|
||||
* object specified in `values`, and will increment the reference count.
|
||||
* The order of objects in the new b_array will be the same as the order
|
||||
* of objects in `values`. Any NULL pointers in the `values` array will
|
||||
* be ignored, and will not result in gaps in the created b_array.
|
||||
* However, `nr_values` should be large enough to cover the final
|
||||
* non-NULL pointer in `values`, including any NULL pointers in-between.
|
||||
*
|
||||
* @param values The list of object pointers which should make up the
|
||||
* contents of the new b_array.
|
||||
* @param nr_values The size of the `values` array.
|
||||
* @return A pointer to the new b_array, or NULL if an error occurred.
|
||||
*/
|
||||
BLUE_API b_array *b_array_create_with_values(
|
||||
b_object *const *values, size_t nr_values);
|
||||
|
||||
/**
|
||||
* Remove all object references from an b_array, resetting the size of the array to zero.
|
||||
* The reference counts of all objects in the array will be decremented.
|
||||
*
|
||||
* @param array The b_array to clear.
|
||||
*/
|
||||
BLUE_API void b_array_clear(b_array *array);
|
||||
|
||||
/**
|
||||
* Inserts an object at the end of an b_array. The reference count of
|
||||
* the object will be incremented.
|
||||
*
|
||||
* @param array The b_array to append the object to.
|
||||
* @param value The object to append.
|
||||
* @return B_SUCCESS if the object was appended successfully, or an
|
||||
* error code if an error occurred.
|
||||
*/
|
||||
BLUE_API b_status b_array_append(b_array *array, b_object *value);
|
||||
|
||||
/**
|
||||
* Inserts an object at the beginning of an b_array. The reference count
|
||||
* of the object will be incremented. All other objects in the array
|
||||
* will be moved to make space for the object being pre-pended.
|
||||
*
|
||||
* @param array The b_array to prepend the object to.
|
||||
* @param value The object to prepend.
|
||||
* @return B_SUCCESS if the object was prepended successfully, or an
|
||||
* error code if an error occurred.
|
||||
*/
|
||||
BLUE_API b_status b_array_prepend(b_array *array, b_object *value);
|
||||
|
||||
/**
|
||||
* Inserts an object into an b_array at a given index. The reference
|
||||
* count of the object will be incremented. If the specified index is at
|
||||
* the beginning or mid-way through the array (i.e. not at the end),
|
||||
* some or all of the objects already in the array will be moved to make
|
||||
* space for the object being inserted.
|
||||
*
|
||||
* @param array The b_array to insert the object into.
|
||||
* @param value The object to insert.
|
||||
* @param at The index to insert the object at. If the index is
|
||||
* `B_NPOS`, the object will be inserted at the end of the b_array.
|
||||
* @return B_SUCCESS if the object was inserted, or a status code
|
||||
* describing any error that occurred.
|
||||
*/
|
||||
BLUE_API b_status b_array_insert(b_array *array, b_object *value, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the specified index from an b_array. The
|
||||
* reference count of the removed object will be decremented. If the
|
||||
* specified index is at the beginning or mid-way through the array
|
||||
* (i.e. not at the end), the remaining objects will be moved to fill
|
||||
* the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The b_array to remove the object from.
|
||||
* @param at The index of the object to be removed.
|
||||
* @return B_SUCCESS if the object was removed, or a status code
|
||||
* describing any error that occurred.
|
||||
*/
|
||||
BLUE_API b_status b_array_remove(b_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the beginning of an b_array. The reference count
|
||||
* of the removed object will be decremented. The remaining objects will be moved
|
||||
* to fill the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The b_array to remove the object from.
|
||||
* @return B_SUCCESS if the object was removed, or a status code describing any error that occurred.
|
||||
*/
|
||||
BLUE_API b_status b_array_remove_front(b_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the end of an b_array. The reference count
|
||||
* of the removed object will be decremented.
|
||||
*
|
||||
* @param array The b_array to remove the object from.
|
||||
* @return B_SUCCESS if the object was removed, or a status code describing any error that occurred.
|
||||
*/
|
||||
BLUE_API b_status b_array_remove_back(b_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the specified index of an b_array, and returns
|
||||
* a pointer to it. The reference count of the removed object will NOT
|
||||
* be decremented. The caller becomes the owner of the array's reference
|
||||
* to the object. If the specified index is at the beginning or mid-way
|
||||
* through the array (i.e. not at the end), the remaining objects will
|
||||
* be moved to fill the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The b_array to remove the object from.
|
||||
* @param at The index of the object to be removed.
|
||||
* @return An pointer to the removed object. This pointer is owned by
|
||||
* the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
BLUE_API b_object *b_array_pop(b_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the beginning of an b_array, and returns a
|
||||
* pointer to it. The reference count of the removed object will NOT be
|
||||
* decremented. The caller becomes the owner of the array's reference to
|
||||
* the object. The remaining objects in the b_array will be moved to
|
||||
* fill the empty space left by the removed object.
|
||||
*
|
||||
* @param array The b_array to remove the object from.
|
||||
* @return An pointer to the removed object. This pointer is owned by
|
||||
* the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
BLUE_API b_object *b_array_pop_front(b_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the end of an b_array, and returns a pointer to it. The
|
||||
* reference count of the removed object will NOT be decremented. The caller
|
||||
* becomes the owner of the array's reference to the object.
|
||||
*
|
||||
* @param array The b_array to remove the object from.
|
||||
* @return An pointer to the removed object. This pointer is owned by the
|
||||
* caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
BLUE_API b_object *b_array_pop_back(b_array *array);
|
||||
|
||||
/**
|
||||
* Returns an unowned pointer to the object at the given index of an b_array.
|
||||
* The caller does not own the returned pointer, and MUST NOT release it.
|
||||
*
|
||||
* @param array The b_array.
|
||||
* @param at The index of the object to return.
|
||||
* @return A pointer to the object at the given index. This pointer is NOT owned
|
||||
* by the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
BLUE_API b_object *b_array_at(const b_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Returns an owned pointer to the object at the given index of an
|
||||
* b_array. The caller owns the returned pointer, and must release it
|
||||
* when they are finished with it.
|
||||
*
|
||||
* @param array The b_array.
|
||||
* @param at The index of the object to return.
|
||||
* @return A pointer to the object at the given index. This pointer is
|
||||
* owned by the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
BLUE_API b_object *b_array_get(b_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Returns the number of objects contained in an b_array.
|
||||
*
|
||||
* @param array The b_array.
|
||||
* @return The number of objects contained in the b_array.
|
||||
*/
|
||||
BLUE_API size_t b_array_size(const b_array *array);
|
||||
|
||||
/**
|
||||
* Returns the current maximum capacity of an b_array. This represents
|
||||
* the number of objects that can be stored in an b_array before its
|
||||
* internal buffer would need to be re-sized.
|
||||
*
|
||||
* @param array The b_array.
|
||||
* @return The maximum capacity of the b_array.
|
||||
*/
|
||||
BLUE_API size_t b_array_capacity(const b_array *array);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef BLUE_DS_BITBUFFER_H_
|
||||
#define BLUE_DS_BITBUFFER_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
B_DECLARE_TYPE(b_bitbuffer);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_bitbuffer)
|
||||
;
|
||||
B_TYPE_CLASS_DECLARATION_END(b_bitbuffer);
|
||||
|
||||
BLUE_API b_status b_bitbuffer_put_bit(b_bitbuffer *buf, int bit);
|
||||
BLUE_API b_status b_bitbuffer_put_bool(b_bitbuffer *buf, bool b);
|
||||
BLUE_API b_status b_bitbuffer_put_int(
|
||||
b_bitbuffer *buf, uint64_t v, unsigned int nr_bits);
|
||||
BLUE_API b_status b_bitbuffer_put_bytes(
|
||||
b_bitbuffer *buf, const void *p, size_t len, size_t bits_per_byte);
|
||||
BLUE_API b_status b_bitbuffer_put_string(
|
||||
b_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef BLUE_DS_BITMAP_H_
|
||||
#define BLUE_DS_BITMAP_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_BITMAP (b_bitmap_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_bitmap);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_bitmap)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_bitmap)
|
||||
|
||||
BLUE_API b_type b_bitmap_get_type(void);
|
||||
|
||||
BLUE_API b_bitmap *b_bitmap_create(size_t nr_bits);
|
||||
|
||||
BLUE_API void b_bitmap_set_bit(b_bitmap *map, size_t bit);
|
||||
BLUE_API void b_bitmap_clear_bit(b_bitmap *map, size_t bit);
|
||||
BLUE_API void b_bitmap_set_range(b_bitmap *map, size_t first_bit, size_t nbits);
|
||||
BLUE_API void b_bitmap_clear_range(b_bitmap *map, size_t first_bit, size_t nbits);
|
||||
BLUE_API void b_bitmap_set_all(b_bitmap *map);
|
||||
BLUE_API void b_bitmap_clear_all(b_bitmap *map);
|
||||
|
||||
BLUE_API bool b_bitmap_check_bit(const b_bitmap *map, size_t bit);
|
||||
|
||||
BLUE_API size_t b_bitmap_count_set_bits(const b_bitmap *map);
|
||||
BLUE_API size_t b_bitmap_count_clear_bits(const b_bitmap *map);
|
||||
|
||||
BLUE_API size_t b_bitmap_highest_set_bit(const b_bitmap *map);
|
||||
BLUE_API size_t b_bitmap_highest_clear_bit(const b_bitmap *map);
|
||||
BLUE_API size_t b_bitmap_lowest_set_bit(const b_bitmap *map);
|
||||
BLUE_API size_t b_bitmap_lowest_clear_bit(const b_bitmap *map);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
#ifndef BLUE_DS_BUFFER_H_
|
||||
#define BLUE_DS_BUFFER_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <stddef.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_BUFFER (b_buffer_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_buffer);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_buffer)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_buffer)
|
||||
|
||||
BLUE_API b_type b_buffer_get_type(void);
|
||||
|
||||
BLUE_API b_buffer *b_buffer_create(size_t item_sz);
|
||||
BLUE_API b_buffer *b_buffer_create_from_bytes(const void *p, size_t len);
|
||||
BLUE_API b_buffer *b_buffer_create_from_array(
|
||||
const void *p, size_t item_sz, size_t len);
|
||||
|
||||
BLUE_API void *b_buffer_steal(b_buffer *buf);
|
||||
BLUE_API b_status b_buffer_reserve(b_buffer *buf, size_t capacity);
|
||||
BLUE_API b_status b_buffer_resize(b_buffer *buf, size_t length);
|
||||
|
||||
BLUE_API b_status b_buffer_append(b_buffer *dest, const void *p, size_t count);
|
||||
BLUE_API b_status b_buffer_prepend(b_buffer *dest, const void *p, size_t count);
|
||||
BLUE_API b_status b_buffer_insert(
|
||||
b_buffer *dest, const void *p, size_t count, size_t at);
|
||||
BLUE_API b_status b_buffer_remove(b_buffer *dest, size_t at, size_t count);
|
||||
BLUE_API b_status b_buffer_clear(b_buffer *buf);
|
||||
|
||||
BLUE_API b_status b_buffer_push_back(b_buffer *buf, size_t count, void **p);
|
||||
BLUE_API b_status b_buffer_push_front(b_buffer *buf, size_t count, void **p);
|
||||
|
||||
BLUE_API b_status b_buffer_pop_back(b_buffer *buf, size_t count);
|
||||
BLUE_API b_status b_buffer_pop_front(b_buffer *buf, size_t count);
|
||||
|
||||
BLUE_API size_t b_buffer_get_size(const b_buffer *buf);
|
||||
BLUE_API size_t b_buffer_get_item_size(const b_buffer *buf);
|
||||
BLUE_API size_t b_buffer_get_capacity(const b_buffer *buf);
|
||||
|
||||
BLUE_API void *b_buffer_ptr(const b_buffer *buf);
|
||||
BLUE_API void *b_buffer_get(const b_buffer *buf, size_t at);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
#ifndef BLUE_DS_DATETIME_H_
|
||||
#define BLUE_DS_DATETIME_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <ctype.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_DATETIME (b_datetime_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_datetime);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_datetime)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_datetime)
|
||||
|
||||
typedef enum b_datetime_format {
|
||||
B_DATETIME_FORMAT_RFC3339 = 1,
|
||||
} b_datetime_format;
|
||||
|
||||
BLUE_API b_type b_datetime_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_datetime, B_TYPE_DATETIME);
|
||||
|
||||
BLUE_API b_datetime *b_datetime_parse(b_datetime_format format, const char *s);
|
||||
BLUE_API void b_datetime_to_string(
|
||||
const b_datetime *dt, b_datetime_format format,
|
||||
B_TYPE_FWDREF(b_stream) * dest);
|
||||
|
||||
BLUE_API bool b_datetime_is_localtime(const b_datetime *dt);
|
||||
BLUE_API bool b_datetime_has_date(const b_datetime *dt);
|
||||
BLUE_API bool b_datetime_has_time(const b_datetime *dt);
|
||||
|
||||
BLUE_API long b_datetime_year(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_month(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_day(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_hour(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_minute(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_second(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_subsecond(const b_datetime *dt);
|
||||
|
||||
BLUE_API bool b_datetime_zone_offset_is_negative(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_zone_offset_hour(const b_datetime *dt);
|
||||
BLUE_API long b_datetime_zone_offset_minute(const b_datetime *dt);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,62 +0,0 @@
|
||||
#ifndef BLUE_DS_DICT_H_
|
||||
#define BLUE_DS_DICT_H_
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/ds/string.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_DICT (b_dict_get_type())
|
||||
#define B_TYPE_DICT_ITERATOR (b_dict_iterator_get_type())
|
||||
|
||||
struct b_dict_p;
|
||||
|
||||
B_DECLARE_TYPE(b_dict);
|
||||
B_DECLARE_TYPE(b_dict_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_dict)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_dict)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_dict_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_dict_iterator)
|
||||
|
||||
#define B_DICT_ITEM(k, v) {.key = (k), .value = (v)}
|
||||
#define B_DICT_ITEM_END {.key = NULL, .value = NULL}
|
||||
|
||||
#define b_dict_foreach(it, dict) \
|
||||
for (int z__b_unique_name() = b_dict_iterator_begin(dict, it); \
|
||||
(it)->key != NULL; b_dict_iterator_next(it))
|
||||
|
||||
typedef struct b_dict_item {
|
||||
const b_string *key;
|
||||
b_object *value;
|
||||
} b_dict_item;
|
||||
|
||||
BLUE_API b_type b_dict_get_type(void);
|
||||
BLUE_API b_type b_dict_iterator_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_dict, B_TYPE_DICT);
|
||||
|
||||
#if 0
|
||||
BLUE_API b_dict *b_dict_create_with_items(const b_dict_item *items);
|
||||
#endif
|
||||
|
||||
BLUE_API b_status b_dict_put(b_dict *dict, const char *key, b_object *value);
|
||||
BLUE_API b_status b_dict_put_sk(b_dict *dict, const b_string *key, b_object *value);
|
||||
BLUE_API b_object *b_dict_at(const b_dict *dict, const char *key);
|
||||
BLUE_API b_object *b_dict_at_sk(const b_dict *dict, const b_string *key);
|
||||
BLUE_API b_object *b_dict_get(b_dict *dict, const char *key);
|
||||
BLUE_API b_object *b_dict_get_sk(b_dict *dict, const b_string *key);
|
||||
|
||||
BLUE_API bool b_dict_has_key(const b_dict *dict, const char *key);
|
||||
BLUE_API bool b_dict_has_skey(const b_dict *dict, const b_string *key);
|
||||
BLUE_API size_t b_dict_get_size(const b_dict *dict);
|
||||
BLUE_API bool b_dict_is_empty(const b_dict *dict);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,83 +0,0 @@
|
||||
#ifndef BLUE_DS_HASHMAP_H_
|
||||
#define BLUE_DS_HASHMAP_H_
|
||||
|
||||
#include <blue/core/btree.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <stddef.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
struct b_hashmap_p;
|
||||
|
||||
#define B_TYPE_HASHMAP (b_hashmap_get_type())
|
||||
#define B_TYPE_HASHMAP_ITERATOR (b_hashmap_iterator_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_hashmap);
|
||||
B_DECLARE_TYPE(b_hashmap_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_hashmap)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_hashmap)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_hashmap_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_hashmap_iterator)
|
||||
|
||||
#define B_HASHMAP_KEY(k, ks) {.key_data = (k), .key_size = (ks)}
|
||||
#define B_HASHMAP_VALUE(v, vs) {.value_data = (v), .value_size = (vs)}
|
||||
|
||||
#define B_HASHMAP_ITEM(k, ks, v, vs) \
|
||||
{.key = B_HASHMAP_KEY(k, ks), .value = B_HASHMAP_VALUE(v, vs)}
|
||||
|
||||
#define B_HASHMAP_ITEM_END {.key = {0}, .value = {0}}
|
||||
|
||||
#define b_hashmap_foreach(it, hashmap) \
|
||||
for (int z__b_unique_name() = b_hashmap_iterator_begin(hashmap, it); \
|
||||
(it)->key != NULL; b_hashmap_iterator_next(it))
|
||||
|
||||
typedef void (*b_hashmap_key_destructor)(void *);
|
||||
typedef void (*b_hashmap_value_destructor)(void *);
|
||||
|
||||
typedef enum b_hashmap_key_flags {
|
||||
B_HASHMAP_KEY_F_INTVALUE = 0x01u,
|
||||
} b_hashmap_key_flags;
|
||||
|
||||
typedef struct b_hashmap_key {
|
||||
b_hashmap_key_flags key_flags;
|
||||
const void *key_data;
|
||||
size_t key_size;
|
||||
} b_hashmap_key;
|
||||
|
||||
typedef struct b_hashmap_value {
|
||||
void *value_data;
|
||||
size_t value_size;
|
||||
} b_hashmap_value;
|
||||
|
||||
typedef struct b_hashmap_item {
|
||||
b_hashmap_key key;
|
||||
b_hashmap_value value;
|
||||
} b_hashmap_item;
|
||||
|
||||
BLUE_API b_type b_hashmap_get_type(void);
|
||||
BLUE_API b_type b_hashmap_iterator_get_type(void);
|
||||
|
||||
BLUE_API b_hashmap *b_hashmap_create(
|
||||
b_hashmap_key_destructor key_dtor, b_hashmap_value_destructor value_dtor);
|
||||
BLUE_API b_hashmap *b_hashmap_create_with_items(const b_hashmap_item *items);
|
||||
|
||||
BLUE_API b_status b_hashmap_put(
|
||||
b_hashmap *hashmap, const b_hashmap_key *key, const b_hashmap_value *value);
|
||||
BLUE_API const b_hashmap_value *b_hashmap_get(
|
||||
const b_hashmap *hashmap, const b_hashmap_key *key);
|
||||
|
||||
BLUE_API bool b_hashmap_has_key(const b_hashmap *hashmap, const b_hashmap_key *key);
|
||||
BLUE_API size_t b_hashmap_get_size(const b_hashmap *hashmap);
|
||||
BLUE_API bool b_hashmap_is_empty(const b_hashmap *hashmap);
|
||||
|
||||
BLUE_API b_iterator *b_hashmap_begin(b_hashmap *hashmap);
|
||||
BLUE_API const b_iterator *b_hashmap_cbegin(const b_hashmap *hashmap);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
#ifndef BLUE_DS_LIST_H_
|
||||
#define BLUE_DS_LIST_H_
|
||||
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/status.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_LIST (b_list_get_type())
|
||||
#define B_TYPE_LIST_ITERATOR (b_list_iterator_get_type())
|
||||
|
||||
struct b_list_p;
|
||||
|
||||
B_DECLARE_TYPE(b_list);
|
||||
B_DECLARE_TYPE(b_list_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_list)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_list)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_list_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_list_iterator)
|
||||
|
||||
typedef struct b_list_entry b_list_entry;
|
||||
|
||||
BLUE_API b_type b_list_get_type(void);
|
||||
BLUE_API b_type b_list_iterator_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_list, B_TYPE_LIST);
|
||||
|
||||
BLUE_API bool b_list_empty(b_list *q);
|
||||
BLUE_API void *b_list_first_item(const b_list *q);
|
||||
BLUE_API void *b_list_last_item(const b_list *q);
|
||||
BLUE_API b_list_entry *b_list_first_entry(const b_list *q);
|
||||
BLUE_API b_list_entry *b_list_last_entry(const b_list *q);
|
||||
BLUE_API b_list_entry *b_list_next(const b_list_entry *entry);
|
||||
BLUE_API b_list_entry *b_list_prev(const b_list_entry *entry);
|
||||
|
||||
BLUE_API size_t b_list_length(const b_list *q);
|
||||
|
||||
BLUE_API b_list_entry *b_list_insert_before(
|
||||
b_list *q, void *ptr, b_list_entry *before);
|
||||
BLUE_API b_list_entry *b_list_insert_after(
|
||||
b_list *q, void *ptr, b_list_entry *after);
|
||||
|
||||
BLUE_API b_list_entry *b_list_push_front(b_list *q, void *ptr);
|
||||
BLUE_API b_list_entry *b_list_push_back(b_list *q, void *ptr);
|
||||
|
||||
BLUE_API void *b_list_pop_front(b_list *q);
|
||||
BLUE_API void *b_list_pop_back(b_list *q);
|
||||
|
||||
BLUE_API b_status b_list_delete_item(b_list *q, void *ptr);
|
||||
BLUE_API b_status b_list_delete_entry(b_list *q, b_list_entry *entry);
|
||||
BLUE_API void b_list_delete_all(b_list *q);
|
||||
|
||||
BLUE_API void *b_list_entry_value(const b_list_entry *entry);
|
||||
|
||||
BLUE_API b_iterator *b_list_begin(b_list *q);
|
||||
BLUE_API const b_iterator *b_list_cbegin(const b_list *q);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,254 +0,0 @@
|
||||
#ifndef BLUE_DS_NUMBER_H
|
||||
#define BLUE_DS_NUMBER_H
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_INT8(v) (b_number_create_int8(v))
|
||||
#define B_INT16(v) (b_number_create_int16(v))
|
||||
#define B_INT32(v) (b_number_create_int32(v))
|
||||
#define B_INT64(v) (b_number_create_int64(v))
|
||||
#define B_FLOAT32(v) (b_number_create_float32(v))
|
||||
#define B_FLOAT64(v) (b_number_create_float64(v))
|
||||
#define B_CHAR(v) (b_number_create_char(v))
|
||||
#define B_SHORT(v) (b_number_create_short(v))
|
||||
#define B_INT(v) (b_number_create_int(v))
|
||||
#define B_LONG(v) (b_number_create_long(v))
|
||||
#define B_LONGLONG(v) (b_number_create_longlong(v))
|
||||
#define B_FLOAT(v) (b_number_create_float(v))
|
||||
#define B_DOUBLE(v) (b_number_create_double(v))
|
||||
#define B_SIZE_T(v) (b_number_create_size_t(v))
|
||||
|
||||
#define B_RV_INT8(v) B_RV(b_number_create_int8(v))
|
||||
#define B_RV_INT16(v) B_RV(b_number_create_int16(v))
|
||||
#define B_RV_INT32(v) B_RV(b_number_create_int32(v))
|
||||
#define B_RV_INT64(v) B_RV(b_number_create_int64(v))
|
||||
#define B_RV_FLOAT32(v) B_RV(b_number_create_float32(v))
|
||||
#define B_RV_FLOAT64(v) B_RV(b_number_create_float64(v))
|
||||
#define B_RV_CHAR(v) B_RV(b_number_create_char(v))
|
||||
#define B_RV_SHORT(v) B_RV(b_number_create_short(v))
|
||||
#define B_RV_INT(v) B_RV(b_number_create_int(v))
|
||||
#define B_RV_LONG(v) B_RV(b_number_create_long(v))
|
||||
#define B_RV_LONGLONG(v) B_RV(b_number_create_longlong(v))
|
||||
#define B_RV_FLOAT(v) B_RV(b_number_create_float(v))
|
||||
#define B_RV_DOUBLE(v) B_RV(b_number_create_double(v))
|
||||
#define B_RV_SIZE_T(v) B_RV(b_number_create_size_t(v))
|
||||
|
||||
#define B_NUMBER_IVAL(p) (b_number_get_size_t(p))
|
||||
#define B_NUMBER_FVAL(p) (b_number_get_double(p))
|
||||
|
||||
#define B_TYPE_NUMBER (b_number_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_number);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_number)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_number)
|
||||
|
||||
typedef enum b_number_type {
|
||||
B_NUMBER_INT8,
|
||||
B_NUMBER_INT16,
|
||||
B_NUMBER_INT32,
|
||||
B_NUMBER_INT64,
|
||||
B_NUMBER_FLOAT32,
|
||||
B_NUMBER_FLOAT64,
|
||||
B_NUMBER_CHAR,
|
||||
B_NUMBER_SHORT,
|
||||
B_NUMBER_INT,
|
||||
B_NUMBER_LONG,
|
||||
B_NUMBER_LONGLONG,
|
||||
B_NUMBER_FLOAT,
|
||||
B_NUMBER_DOUBLE,
|
||||
B_NUMBER_SIZE_T,
|
||||
B_NUMBER_HANDLE,
|
||||
B_NUMBER_TYPE_COUNT,
|
||||
|
||||
B_NUMBER_BYTE = B_NUMBER_INT8,
|
||||
B_NUMBER_WORD = B_NUMBER_INT16,
|
||||
B_NUMBER_DWORD = B_NUMBER_INT32,
|
||||
B_NUMBER_QWORD = B_NUMBER_INT64,
|
||||
} b_number_type;
|
||||
|
||||
BLUE_API b_type b_number_get_type(void);
|
||||
|
||||
BLUE_API b_number *b_number_create(b_number_type type, void *value_ptr);
|
||||
|
||||
static inline b_number *b_number_create_int8(int8_t value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_INT8, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_int16(int16_t value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_INT16, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_int32(int32_t value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_INT32, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_int64(int64_t value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_INT64, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_float32(float value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_FLOAT32, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_float64(double value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_FLOAT64, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_char(char value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_CHAR, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_short(short value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_SHORT, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_int(int value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_INT, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_long(long value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_LONG, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_longlong(long long value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_LONGLONG, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_float(float value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_FLOAT, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_double(double value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_DOUBLE, &value);
|
||||
}
|
||||
static inline b_number *b_number_create_size_t(size_t value)
|
||||
{
|
||||
return b_number_create(B_NUMBER_SIZE_T, &value);
|
||||
}
|
||||
|
||||
BLUE_API b_number_type b_number_get_number_type(const b_number *number);
|
||||
BLUE_API int b_number_get_value(
|
||||
const b_number *number, b_number_type type, void *value_ptr);
|
||||
|
||||
static inline int8_t b_number_get_int8(const b_number *number)
|
||||
{
|
||||
int8_t v;
|
||||
b_number_get_value(number, B_NUMBER_INT8, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline int16_t b_number_get_int16(const b_number *number)
|
||||
{
|
||||
int16_t v;
|
||||
b_number_get_value(number, B_NUMBER_INT16, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline int32_t b_number_get_int32(const b_number *number)
|
||||
{
|
||||
int32_t v;
|
||||
b_number_get_value(number, B_NUMBER_INT32, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline int64_t b_number_get_int64(const b_number *number)
|
||||
{
|
||||
int64_t v;
|
||||
b_number_get_value(number, B_NUMBER_INT64, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline float b_number_get_float32(const b_number *number)
|
||||
{
|
||||
float v;
|
||||
b_number_get_value(number, B_NUMBER_FLOAT32, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline double b_number_get_float64(const b_number *number)
|
||||
{
|
||||
double v;
|
||||
b_number_get_value(number, B_NUMBER_FLOAT64, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline char b_number_get_char(const b_number *number)
|
||||
{
|
||||
char v;
|
||||
b_number_get_value(number, B_NUMBER_CHAR, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline short b_number_get_short(const b_number *number)
|
||||
{
|
||||
short v;
|
||||
b_number_get_value(number, B_NUMBER_SHORT, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline int b_number_get_int(const b_number *number)
|
||||
{
|
||||
int v;
|
||||
b_number_get_value(number, B_NUMBER_INT, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline long b_number_get_long(const b_number *number)
|
||||
{
|
||||
long v;
|
||||
b_number_get_value(number, B_NUMBER_LONG, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline long long b_number_get_longlong(const b_number *number)
|
||||
{
|
||||
long long v;
|
||||
b_number_get_value(number, B_NUMBER_LONGLONG, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline float b_number_get_float(const b_number *number)
|
||||
{
|
||||
float v;
|
||||
b_number_get_value(number, B_NUMBER_FLOAT, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline double b_number_get_double(const b_number *number)
|
||||
{
|
||||
double v;
|
||||
b_number_get_value(number, B_NUMBER_DOUBLE, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline size_t b_number_get_size_t(const b_number *number)
|
||||
{
|
||||
size_t v;
|
||||
b_number_get_value(number, B_NUMBER_SIZE_T, &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
BLUE_API bool b_number_is_integer(const b_number *number);
|
||||
BLUE_API bool b_number_is_float(const b_number *number);
|
||||
BLUE_API bool b_number_is_inf(const b_number *number);
|
||||
BLUE_API bool b_number_is_inf_positive(const b_number *number);
|
||||
BLUE_API bool b_number_is_inf_negative(const b_number *number);
|
||||
BLUE_API bool b_number_is_nan(const b_number *number);
|
||||
BLUE_API bool b_number_is_nan_positive(const b_number *number);
|
||||
BLUE_API bool b_number_is_nan_negative(const b_number *number);
|
||||
|
||||
BLUE_API void b_number_set_inf_positive(b_number *number, bool v);
|
||||
BLUE_API void b_number_set_inf_negative(b_number *number, bool v);
|
||||
BLUE_API void b_number_set_nan_positive(b_number *number, bool v);
|
||||
BLUE_API void b_number_set_nan_negative(b_number *number, bool v);
|
||||
|
||||
BLUE_API size_t b_number_data_size(const b_number *number);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,129 +0,0 @@
|
||||
#ifndef BLUE_DS_STRING_H_
|
||||
#define BLUE_DS_STRING_H_
|
||||
|
||||
#include <blue/core/encoding.h>
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/core/stringstream.h>
|
||||
#include <ctype.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
struct b_stream;
|
||||
struct b_string_p;
|
||||
|
||||
#define B_TYPE_STRING (b_string_get_type())
|
||||
#define B_TYPE_STRING_ITERATOR (b_string_iterator_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_string);
|
||||
B_DECLARE_TYPE(b_string_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_string)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_string)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_string_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_string_iterator)
|
||||
|
||||
#define B_CSTR(s) (b_string_create_from_cstr(s))
|
||||
#define B_RV_CSTR(s) (B_RV(b_string_create_from_cstr(s)))
|
||||
|
||||
typedef enum b_strlen_flags {
|
||||
B_STRLEN_NORMAL = 0,
|
||||
B_STRLEN_IGNORE_ESC = 0x01u,
|
||||
B_STRLEN_IGNORE_MOD = 0x02u,
|
||||
B_STRLEN_CODEPOINTS = 0x04u,
|
||||
} b_strlen_flags;
|
||||
|
||||
typedef enum b_string_tokenise_flags {
|
||||
B_STRING_TOK_F_NORMAL = 0x00u,
|
||||
B_STRING_TOK_F_INCLUDE_EMPTY_TOKENS = 0x01u,
|
||||
} b_string_tokenise_flags;
|
||||
|
||||
BLUE_API b_type b_string_get_type(void);
|
||||
BLUE_API b_type b_string_iterator_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_string, B_TYPE_STRING);
|
||||
BLUE_API b_string *b_string_create_from_cstr(const char *s);
|
||||
BLUE_API b_string *b_string_create_from_wstr(const b_wchar *s);
|
||||
BLUE_API b_string *b_string_create_from_c(char c, size_t count);
|
||||
BLUE_API b_string *b_string_duplicate(const b_string *str);
|
||||
|
||||
BLUE_API char *b_string_steal(b_string *str);
|
||||
BLUE_API b_status b_string_reserve(b_string *str, size_t capacity);
|
||||
BLUE_API b_status b_string_replace(
|
||||
b_string *str, size_t start, size_t length, const char *new_data);
|
||||
BLUE_API b_status b_string_replace_all(b_string *str, const char *new_data);
|
||||
BLUE_API b_status b_string_replace_all_with_stringstream(
|
||||
b_string *str, const b_stringstream *new_data);
|
||||
BLUE_API b_status b_string_remove(b_string *str, size_t start, size_t length);
|
||||
BLUE_API b_status b_string_transform(b_string *str, int (*transformer)(int));
|
||||
BLUE_API b_status b_string_trim(b_string *str);
|
||||
static inline b_status b_string_toupper(b_string *str)
|
||||
{
|
||||
return b_string_transform(str, toupper);
|
||||
}
|
||||
static inline b_status b_string_tolower(b_string *str)
|
||||
{
|
||||
return b_string_transform(str, tolower);
|
||||
}
|
||||
|
||||
BLUE_API b_status b_string_append_c(b_string *dest, char c);
|
||||
BLUE_API b_status b_string_append_wc(b_string *dest, b_wchar c);
|
||||
BLUE_API b_status b_string_append_s(b_string *dest, const b_string *src);
|
||||
BLUE_API b_status b_string_append_cstr(b_string *dest, const char *src);
|
||||
BLUE_API b_status b_string_append_wstr(b_string *dest, const b_wchar *src);
|
||||
BLUE_API b_status b_string_append_cstrf(b_string *dest, const char *format, ...);
|
||||
|
||||
BLUE_API b_status b_string_prepend_c(b_string *dest, char c);
|
||||
BLUE_API b_status b_string_prepend_wc(b_string *dest, b_wchar c);
|
||||
BLUE_API b_status b_string_prepend_cstr(b_string *dest, const char *src);
|
||||
BLUE_API b_status b_string_prepend_wstr(b_string *dest, const b_wchar *src);
|
||||
BLUE_API b_status b_string_prepend_cstrf(b_string *dest, const char *format, ...);
|
||||
|
||||
BLUE_API b_status b_string_insert_c(b_string *dest, char c, size_t at);
|
||||
BLUE_API b_status b_string_insert_wc(b_string *dest, b_wchar c, size_t at);
|
||||
BLUE_API b_status b_string_insert_s(b_string *dest, const b_string *src, size_t at);
|
||||
BLUE_API b_status b_string_insert_cstr(b_string *dest, const char *src, size_t at);
|
||||
BLUE_API b_status b_string_insert_wstr(
|
||||
b_string *dest, const b_wchar *src, size_t at);
|
||||
BLUE_API b_status b_string_insert_cstrn(
|
||||
b_string *dest, const char *src, size_t len, size_t at);
|
||||
BLUE_API b_status b_string_insert_wstrn(
|
||||
b_string *dest, const char *src, size_t len, size_t at);
|
||||
BLUE_API b_status b_string_insert_cstrf(
|
||||
b_string *dest, size_t at, const char *format, ...);
|
||||
BLUE_API void b_string_clear(b_string *str);
|
||||
|
||||
BLUE_API b_iterator *b_string_tokenise(
|
||||
b_string *str, const char *delims[], size_t nr_delims,
|
||||
b_string_tokenise_flags flags);
|
||||
|
||||
BLUE_API size_t b_string_get_size(const b_string *str, b_strlen_flags flags);
|
||||
BLUE_API size_t b_string_get_capacity(const b_string *str);
|
||||
|
||||
BLUE_API bool b_string_compare(const b_string *a, const b_string *b);
|
||||
|
||||
BLUE_API char b_string_front(const b_string *str);
|
||||
BLUE_API char b_string_back(const b_string *str);
|
||||
|
||||
BLUE_API void b_string_pop_back(b_string *str);
|
||||
|
||||
BLUE_API const char *b_string_ptr(const b_string *str);
|
||||
BLUE_API b_string *b_string_substr(const b_string *str, size_t start, size_t len);
|
||||
|
||||
BLUE_API int b_string_iterator_begin(const b_string *string, b_string_iterator *it);
|
||||
BLUE_API bool b_string_iterator_next(b_string_iterator *it);
|
||||
// BLUE_API b_status b_string_iterator_erase(b_string_iterator *it);
|
||||
BLUE_API bool b_string_iterator_is_valid(const b_string_iterator *it);
|
||||
|
||||
BLUE_API char *b_strdup(const char *s);
|
||||
BLUE_API size_t b_strlen(const char *s, b_strlen_flags flags);
|
||||
BLUE_API b_wchar *b_wstrdup(const b_wchar *s);
|
||||
BLUE_API size_t b_wstrlen(const b_wchar *s);
|
||||
|
||||
BLUE_API uint64_t b_string_hash(const b_string *s);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,57 +0,0 @@
|
||||
#ifndef BLUE_DS_TREE_H_
|
||||
#define BLUE_DS_TREE_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/misc.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/ds/string.h>
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_TREE (b_tree_get_type())
|
||||
#define B_TYPE_TREE_ITERATOR (b_tree_iterator_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_tree);
|
||||
B_DECLARE_TYPE(b_tree_iterator);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_tree)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_tree)
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_tree_iterator)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_tree_iterator)
|
||||
|
||||
#define B_TREE_NODE_INIT ((b_tree_node) {0})
|
||||
|
||||
#define B_TREE_CONTAINER(t, m, v) \
|
||||
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
|
||||
|
||||
typedef struct b_tree_node {
|
||||
struct b_tree_node *__p01, *__p02, *__p03;
|
||||
struct b_queue_entry __q01;
|
||||
} b_tree_node;
|
||||
|
||||
BLUE_API b_type b_tree_get_type(void);
|
||||
BLUE_API b_type b_tree_iterator_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_tree, B_TYPE_TREE);
|
||||
|
||||
BLUE_API void b_tree_set_root(b_tree *tree, struct b_tree_node *node);
|
||||
|
||||
BLUE_API void b_tree_node_add_child(b_tree_node *parent, b_tree_node *child);
|
||||
BLUE_API void b_tree_node_add_sibling(b_tree_node *node, b_tree_node *to_add);
|
||||
|
||||
BLUE_API b_tree_node *b_tree_node_get_child(b_tree_node *node, size_t at);
|
||||
BLUE_API b_tree_node *b_tree_node_get_parent(b_tree_node *node);
|
||||
|
||||
BLUE_API b_iterator *b_tree_begin(b_tree *tree);
|
||||
BLUE_API const b_iterator *b_tree_cbegin(const b_tree *tree);
|
||||
|
||||
BLUE_API b_iterator *b_tree_node_begin(b_tree_node *node);
|
||||
BLUE_API const b_iterator *b_tree_node_cbegin(const b_tree_node *node);
|
||||
|
||||
BLUE_API b_iterator *b_tree_node_begin_recursive(b_tree_node *node);
|
||||
BLUE_API const b_iterator *b_tree_node_cbegin_recursive(const b_tree_node *node);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef BLUE_DS_UUID_H_
|
||||
#define BLUE_DS_UUID_H_
|
||||
|
||||
#include <blue/core/macros.h>
|
||||
#include <blue/core/status.h>
|
||||
#include <blue/ds/string.h>
|
||||
|
||||
#define B_UUID_NBYTES 16
|
||||
#define B_UUID_STRING_MAX 37
|
||||
|
||||
B_DECLS_BEGIN;
|
||||
|
||||
#define B_TYPE_UUID (b_uuid_get_type())
|
||||
|
||||
B_DECLARE_TYPE(b_uuid);
|
||||
|
||||
B_TYPE_CLASS_DECLARATION_BEGIN(b_uuid)
|
||||
B_TYPE_CLASS_DECLARATION_END(b_uuid)
|
||||
|
||||
typedef union b_uuid_bytes {
|
||||
uint8_t uuid_bytes[B_UUID_NBYTES];
|
||||
uint16_t uuid_words[B_UUID_NBYTES / 2];
|
||||
uint32_t uuid_dwords[B_UUID_NBYTES / 4];
|
||||
uint64_t uuid_qwords[B_UUID_NBYTES / 8];
|
||||
} b_uuid_bytes;
|
||||
|
||||
BLUE_API b_type b_uuid_get_type(void);
|
||||
|
||||
B_TYPE_DEFAULT_CONSTRUCTOR(b_uuid, B_TYPE_UUID);
|
||||
|
||||
BLUE_API b_uuid *b_uuid_create_from_bytes(
|
||||
unsigned char u00, unsigned char u01, unsigned char u02,
|
||||
unsigned char u03, unsigned char u04, unsigned char u05,
|
||||
unsigned char u06, unsigned char u07, unsigned char u08,
|
||||
unsigned char u09, unsigned char u10, unsigned char u11, unsigned char u12,
|
||||
unsigned char u13, unsigned char u14, unsigned char u15);
|
||||
BLUE_API b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES]);
|
||||
BLUE_API b_uuid *b_uuid_create_from_uuid_bytes(const b_uuid_bytes *bytes);
|
||||
BLUE_API b_uuid *b_uuid_create_from_string(const b_string *string);
|
||||
BLUE_API b_uuid *b_uuid_create_from_cstr(const char *s);
|
||||
|
||||
BLUE_API b_status b_uuid_to_cstr(const b_uuid *uuid, char out[B_UUID_STRING_MAX]);
|
||||
BLUE_API void b_uuid_get_bytes(
|
||||
const b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES]);
|
||||
BLUE_API void b_uuid_get_uuid_bytes(const b_uuid *uuid, b_uuid_bytes *bytes);
|
||||
BLUE_API b_uuid_bytes *b_uuid_ptr(b_uuid *uuid);
|
||||
|
||||
B_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -1,529 +0,0 @@
|
||||
#include <blue/core/iterator.h>
|
||||
#include <blue/core/queue.h>
|
||||
#include <blue/ds/list.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_list_entry {
|
||||
struct b_queue_entry e_entry;
|
||||
void *e_data;
|
||||
};
|
||||
|
||||
struct b_list_p {
|
||||
struct b_queue l_queue;
|
||||
size_t l_len;
|
||||
};
|
||||
|
||||
struct b_list_iterator_p {
|
||||
b_list *_q;
|
||||
struct b_list_p *_q_p;
|
||||
struct b_queue_entry *_q_entry;
|
||||
|
||||
size_t i;
|
||||
void *item;
|
||||
b_list_entry *entry;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static bool list_empty(struct b_list_p *q)
|
||||
{
|
||||
return q->l_len == 0;
|
||||
}
|
||||
|
||||
static void *list_first_item(const struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_first(&q->l_queue);
|
||||
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry->e_data;
|
||||
}
|
||||
|
||||
static void *list_last_item(const struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_last(&q->l_queue);
|
||||
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry->e_data;
|
||||
}
|
||||
|
||||
static struct b_list_entry *list_first_entry(const struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_first(&q->l_queue);
|
||||
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry;
|
||||
}
|
||||
|
||||
static struct b_list_entry *list_last_entry(const struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_last(&q->l_queue);
|
||||
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
return list_entry;
|
||||
}
|
||||
|
||||
static size_t list_length(const struct b_list_p *q)
|
||||
{
|
||||
return q->l_len;
|
||||
}
|
||||
|
||||
static struct b_list_entry *make_entry(void *item)
|
||||
{
|
||||
struct b_list_entry *entry = malloc(sizeof *entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(entry, 0x0, sizeof *entry);
|
||||
|
||||
entry->e_data = item;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static struct b_list_entry *list_insert_before(
|
||||
struct b_list_p *q, void *ptr, struct b_list_entry *before)
|
||||
{
|
||||
struct b_list_entry *entry = make_entry(ptr);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_insert_before(&q->l_queue, &entry->e_entry, &before->e_entry);
|
||||
q->l_len++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static struct b_list_entry *list_insert_after(
|
||||
struct b_list_p *q, void *ptr, struct b_list_entry *after)
|
||||
{
|
||||
struct b_list_entry *entry = make_entry(ptr);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_insert_after(&q->l_queue, &entry->e_entry, &after->e_entry);
|
||||
q->l_len++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static struct b_list_entry *list_push_front(struct b_list_p *q, void *ptr)
|
||||
{
|
||||
struct b_list_entry *entry = make_entry(ptr);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_push_front(&q->l_queue, &entry->e_entry);
|
||||
q->l_len++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static struct b_list_entry *list_push_back(struct b_list_p *q, void *ptr)
|
||||
{
|
||||
struct b_list_entry *entry = make_entry(ptr);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_push_back(&q->l_queue, &entry->e_entry);
|
||||
q->l_len++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void *list_pop_front(struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_pop_front(&q->l_queue);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
void *item = list_entry->e_data;
|
||||
free(list_entry);
|
||||
|
||||
q->l_len--;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static void *list_pop_back(struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_pop_back(&q->l_queue);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
void *item = list_entry->e_data;
|
||||
free(list_entry);
|
||||
|
||||
q->l_len--;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static struct b_list_entry *find_item(struct b_list_p *list, void *item)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_first(&list->l_queue);
|
||||
while (entry) {
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
|
||||
if (list_entry->e_data == item) {
|
||||
return list_entry;
|
||||
}
|
||||
|
||||
entry = b_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static b_status list_delete_item(struct b_list_p *q, void *ptr)
|
||||
{
|
||||
struct b_list_entry *entry = find_item(q, ptr);
|
||||
if (!entry) {
|
||||
return B_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
b_queue_delete(&q->l_queue, &entry->e_entry);
|
||||
q->l_len--;
|
||||
|
||||
free(entry);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status list_delete_entry(struct b_list_p *q, struct b_list_entry *entry)
|
||||
{
|
||||
b_queue_delete(&q->l_queue, &entry->e_entry);
|
||||
q->l_len--;
|
||||
|
||||
free(entry);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static void list_delete_all(struct b_list_p *q)
|
||||
{
|
||||
struct b_queue_entry *entry = b_queue_first(&q->l_queue);
|
||||
while (entry) {
|
||||
struct b_list_entry *list_entry
|
||||
= b_unbox(struct b_list_entry, entry, e_entry);
|
||||
struct b_queue_entry *next = b_queue_next(entry);
|
||||
|
||||
free(list_entry);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
q->l_len = 0;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
bool b_list_empty(b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_empty, q);
|
||||
}
|
||||
|
||||
void *b_list_first_item(const b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_first_item, q);
|
||||
}
|
||||
|
||||
void *b_list_last_item(const b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_last_item, q);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_first_entry(const b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_first_entry, q);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_last_entry(const b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, b_list_last_entry, q);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_next(const struct b_list_entry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_queue_entry *next = b_queue_next(&entry->e_entry);
|
||||
|
||||
if (!next) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_unbox(struct b_list_entry, next, e_entry);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_prev(const struct b_list_entry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_queue_entry *next = b_queue_prev(&entry->e_entry);
|
||||
|
||||
if (!next) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_unbox(struct b_list_entry, next, e_entry);
|
||||
}
|
||||
|
||||
size_t b_list_length(const b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_length, q);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_insert_before(
|
||||
b_list *q, void *ptr, struct b_list_entry *before)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_LIST, list_insert_before, q, ptr, before);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_insert_after(
|
||||
b_list *q, void *ptr, struct b_list_entry *after)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_LIST, list_insert_after, q, ptr, after);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_push_front(b_list *q, void *ptr)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_LIST, list_push_front, q, ptr);
|
||||
}
|
||||
|
||||
struct b_list_entry *b_list_push_back(b_list *q, void *ptr)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_LIST, list_push_back, q, ptr);
|
||||
}
|
||||
|
||||
void *b_list_pop_front(b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_pop_front, q);
|
||||
}
|
||||
|
||||
void *b_list_pop_back(b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_pop_back, q);
|
||||
}
|
||||
|
||||
b_status b_list_delete_item(b_list *q, void *ptr)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_LIST, list_delete_item, q, ptr);
|
||||
}
|
||||
|
||||
b_status b_list_delete_entry(b_list *q, struct b_list_entry *entry)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_LIST, list_delete_entry, q, entry);
|
||||
}
|
||||
|
||||
void b_list_delete_all(b_list *q)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_LIST, list_delete_all, q);
|
||||
}
|
||||
|
||||
void *b_list_entry_value(const struct b_list_entry *entry)
|
||||
{
|
||||
return entry ? entry->e_data : NULL;
|
||||
}
|
||||
|
||||
b_iterator *b_list_begin(b_list *q)
|
||||
{
|
||||
b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
|
||||
struct b_list_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_LIST_ITERATOR);
|
||||
|
||||
it->_q = q;
|
||||
it->_q_p = b_object_get_private(q, B_TYPE_LIST);
|
||||
it->_q_entry = b_queue_first(&it->_q_p->l_queue);
|
||||
|
||||
it->i = 0;
|
||||
it->entry = b_unbox(struct b_list_entry, it->_q_entry, e_entry);
|
||||
if (it->entry) {
|
||||
it->item = it->entry->e_data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const b_iterator *b_list_cbegin(const b_list *q)
|
||||
{
|
||||
b_list_iterator *it_obj = b_object_create(B_TYPE_LIST_ITERATOR);
|
||||
struct b_list_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_LIST_ITERATOR);
|
||||
|
||||
it->_q = (b_list *)q;
|
||||
it->_q_p = b_object_get_private(q, B_TYPE_LIST);
|
||||
it->_q_entry = b_queue_first(&it->_q_p->l_queue);
|
||||
|
||||
it->i = 0;
|
||||
it->entry = b_unbox(struct b_list_entry, it->_q_entry, e_entry);
|
||||
if (it->entry) {
|
||||
it->item = it->entry->e_data;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void list_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_list_p *list = priv;
|
||||
}
|
||||
|
||||
static void list_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_list_p *list = priv;
|
||||
list_delete_all(list);
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_list_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_LIST_ITERATOR);
|
||||
|
||||
if (!it->_q_entry) {
|
||||
it->entry = NULL;
|
||||
it->item = NULL;
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->_q_entry = b_queue_next(it->_q_entry);
|
||||
if (!it->_q_entry) {
|
||||
it->entry = NULL;
|
||||
it->item = NULL;
|
||||
return B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
it->entry = b_unbox(struct b_list_entry, it->_q_entry, e_entry);
|
||||
if (it->entry) {
|
||||
it->item = it->entry->e_data;
|
||||
}
|
||||
|
||||
return it->entry != NULL;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
struct b_list_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_LIST_ITERATOR);
|
||||
|
||||
if (!it->entry || !it->_q_entry) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
struct b_queue_entry *next = b_queue_next(it->_q_entry);
|
||||
|
||||
b_queue_delete(&it->_q_p->l_queue, it->_q_entry);
|
||||
free(it->entry);
|
||||
|
||||
it->_q_entry = next;
|
||||
it->entry = b_unbox(struct b_list_entry, it->_q_entry, e_entry);
|
||||
if (it->entry) {
|
||||
it->item = it->entry->e_data;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_list_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_LIST_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_PTR(it->item);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_list_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_LIST_ITERATOR);
|
||||
|
||||
return B_ITERATOR_VALUE_CPTR(it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_list DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_list)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = b_list_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = b_list_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_list)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_list)
|
||||
B_TYPE_ID(0x8730e66f, 0x0fd9, 0x4773, 0x9bbd, 0x6428f6e495eb);
|
||||
B_TYPE_CLASS(b_list_class);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_list_p);
|
||||
B_TYPE_INSTANCE_INIT(list_init);
|
||||
B_TYPE_INSTANCE_FINI(list_fini);
|
||||
B_TYPE_DEFINITION_END(b_list)
|
||||
|
||||
// ---- b_list_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_list_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_list_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_list_iterator)
|
||||
B_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_list_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_list_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_list_iterator)
|
||||
-2326
File diff suppressed because it is too large
Load Diff
@@ -1,380 +0,0 @@
|
||||
#include <blue/ds/tree.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ITERATOR_RECURSIVE 0x01u
|
||||
|
||||
#define ITERATOR_IS_RECURSIVE(it) (((it)->_f01 & ITERATOR_RECURSIVE) != 0)
|
||||
#define ITERATOR_UNSET_RECURSIVE(it) ((it)->_f01 &= ~ITERATOR_RECURSIVE)
|
||||
#define ITERATOR_SET_RECURSIVE(it) ((it)->_f01 |= ITERATOR_RECURSIVE)
|
||||
|
||||
#define NODE_PARENT(n) ((n)->__p01)
|
||||
#define NODE_FIRST_CHILD(n) ((n)->__p02)
|
||||
#define NODE_NEXT_SIBLING(n) ((n)->__p03)
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_tree_p {
|
||||
struct b_tree_node *t_root;
|
||||
};
|
||||
|
||||
struct b_tree_iterator_p {
|
||||
size_t i, depth;
|
||||
b_tree_node *node;
|
||||
|
||||
unsigned char _f01;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static void tree_set_root(struct b_tree_p *tree, struct b_tree_node *node)
|
||||
{
|
||||
tree->t_root = node;
|
||||
}
|
||||
|
||||
static const struct b_tree_node *next_node(
|
||||
const struct b_tree_node *node, bool recursive, int *depth_diff)
|
||||
{
|
||||
if (!node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!recursive) {
|
||||
node = NODE_NEXT_SIBLING(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
int d = 0;
|
||||
struct b_tree_node *next = NODE_FIRST_CHILD(node);
|
||||
if (next) {
|
||||
d = 1;
|
||||
*depth_diff = d;
|
||||
return next;
|
||||
}
|
||||
|
||||
const struct b_tree_node *n = node;
|
||||
next = NODE_NEXT_SIBLING(n);
|
||||
while (!next) {
|
||||
n = NODE_PARENT(n);
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
d--;
|
||||
next = NODE_NEXT_SIBLING(n);
|
||||
}
|
||||
|
||||
*depth_diff = d;
|
||||
return next;
|
||||
}
|
||||
|
||||
static void remove_node(struct b_tree_node *node)
|
||||
{
|
||||
struct b_tree_node *parent = NODE_PARENT(node);
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct b_tree_node *n0 = NULL, *n1 = NULL;
|
||||
n0 = NODE_FIRST_CHILD(parent);
|
||||
|
||||
while (n0) {
|
||||
if (n0 == node) {
|
||||
break;
|
||||
}
|
||||
|
||||
n1 = n0;
|
||||
n0 = NODE_NEXT_SIBLING(n0);
|
||||
}
|
||||
|
||||
if (!n0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (n1) {
|
||||
NODE_NEXT_SIBLING(n1) = NODE_NEXT_SIBLING(n0);
|
||||
} else {
|
||||
NODE_FIRST_CHILD(parent) = NODE_NEXT_SIBLING(n0);
|
||||
}
|
||||
|
||||
NODE_PARENT(n0) = NODE_NEXT_SIBLING(n0) = NULL;
|
||||
}
|
||||
|
||||
static void reparent_children(
|
||||
struct b_tree_node *old_parent, struct b_tree_node *new_parent)
|
||||
{
|
||||
struct b_tree_node *last = NODE_FIRST_CHILD(new_parent);
|
||||
while (last && NODE_NEXT_SIBLING(last)) {
|
||||
last = NODE_NEXT_SIBLING(last);
|
||||
}
|
||||
|
||||
struct b_tree_node *cur = NODE_FIRST_CHILD(old_parent);
|
||||
while (cur) {
|
||||
struct b_tree_node *next = NODE_NEXT_SIBLING(cur);
|
||||
NODE_PARENT(cur) = new_parent;
|
||||
NODE_NEXT_SIBLING(cur) = NULL;
|
||||
|
||||
if (last) {
|
||||
NODE_NEXT_SIBLING(last) = cur;
|
||||
} else {
|
||||
NODE_FIRST_CHILD(new_parent) = cur;
|
||||
}
|
||||
|
||||
last = cur;
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
void b_tree_set_root(b_tree *tree, struct b_tree_node *node)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_TREE, tree_set_root, tree, node);
|
||||
}
|
||||
|
||||
void b_tree_node_add_child(struct b_tree_node *parent, struct b_tree_node *child)
|
||||
{
|
||||
if (NODE_PARENT(child)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NODE_PARENT(child) = parent;
|
||||
if (!NODE_FIRST_CHILD(parent)) {
|
||||
NODE_FIRST_CHILD(parent) = child;
|
||||
return;
|
||||
}
|
||||
|
||||
struct b_tree_node *cur = NODE_FIRST_CHILD(parent);
|
||||
while (NODE_NEXT_SIBLING(cur)) {
|
||||
cur = NODE_NEXT_SIBLING(cur);
|
||||
}
|
||||
|
||||
NODE_NEXT_SIBLING(cur) = child;
|
||||
}
|
||||
|
||||
void b_tree_node_add_sibling(struct b_tree_node *node, struct b_tree_node *to_add)
|
||||
{
|
||||
if (NODE_PARENT(to_add) || !NODE_PARENT(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
b_tree_node_add_child(NODE_PARENT(node), to_add);
|
||||
}
|
||||
|
||||
struct b_tree_node *b_tree_node_get_child(struct b_tree_node *node, size_t at)
|
||||
{
|
||||
size_t i = 0;
|
||||
struct b_tree_node *cur = NODE_FIRST_CHILD(node);
|
||||
|
||||
while (i < at) {
|
||||
if (!cur) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur = NODE_NEXT_SIBLING(cur);
|
||||
i++;
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
b_iterator *b_tree_begin(b_tree *tree)
|
||||
{
|
||||
struct b_tree_p *p = b_object_get_private(tree, B_TYPE_TREE);
|
||||
return b_tree_node_begin(p->t_root);
|
||||
}
|
||||
|
||||
const b_iterator *b_tree_cbegin(const b_tree *tree)
|
||||
{
|
||||
struct b_tree_p *p = b_object_get_private(tree, B_TYPE_TREE);
|
||||
return b_tree_node_begin(p->t_root);
|
||||
}
|
||||
|
||||
b_iterator *b_tree_node_begin(struct b_tree_node *node)
|
||||
{
|
||||
b_tree_iterator *it_obj = b_object_create(B_TYPE_TREE_ITERATOR);
|
||||
struct b_tree_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_TREE_ITERATOR);
|
||||
|
||||
it->node = NODE_FIRST_CHILD(node);
|
||||
it->i = 0;
|
||||
it->depth = 0;
|
||||
|
||||
ITERATOR_UNSET_RECURSIVE(it);
|
||||
|
||||
if (!it->node) {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const b_iterator *b_tree_node_cbegin(const struct b_tree_node *node)
|
||||
{
|
||||
return b_tree_node_begin((struct b_tree_node *)node);
|
||||
}
|
||||
|
||||
b_iterator *b_tree_node_begin_recursive(struct b_tree_node *node)
|
||||
{
|
||||
b_tree_iterator *it_obj = b_object_create(B_TYPE_TREE_ITERATOR);
|
||||
struct b_tree_iterator_p *it
|
||||
= b_object_get_private(it_obj, B_TYPE_TREE_ITERATOR);
|
||||
|
||||
it->node = node;
|
||||
it->i = 0;
|
||||
it->depth = 0;
|
||||
|
||||
ITERATOR_SET_RECURSIVE(it);
|
||||
|
||||
if (!it->node) {
|
||||
b_iterator_set_status(it_obj, B_ERR_NO_DATA);
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const b_iterator *b_tree_node_cbegin_recursive(const struct b_tree_node *node)
|
||||
{
|
||||
return b_tree_node_begin_recursive((struct b_tree_node *)node);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void tree_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_tree_p *tree = priv;
|
||||
}
|
||||
|
||||
static void tree_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_tree_p *tree = priv;
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum b_status iterator_move_next(const b_iterator *obj)
|
||||
{
|
||||
struct b_tree_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_TREE_ITERATOR);
|
||||
|
||||
int depth_diff = 0;
|
||||
const struct b_tree_node *next
|
||||
= next_node(it->node, ITERATOR_IS_RECURSIVE(it), &depth_diff);
|
||||
|
||||
if (next) {
|
||||
it->depth += depth_diff;
|
||||
it->i++;
|
||||
} else {
|
||||
it->depth = 0;
|
||||
it->i = 0;
|
||||
}
|
||||
|
||||
it->node = (struct b_tree_node *)next;
|
||||
return (it->node != NULL) ? B_SUCCESS : B_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static enum b_status iterator_erase(b_iterator *obj)
|
||||
{
|
||||
struct b_tree_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_TREE_ITERATOR);
|
||||
|
||||
if (!it->node) {
|
||||
return B_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
struct b_tree_node *parent = NODE_PARENT(it->node);
|
||||
if (!parent) {
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int d = 0;
|
||||
struct b_tree_node *n = it->node;
|
||||
struct b_tree_node *next = NODE_NEXT_SIBLING(n);
|
||||
|
||||
if (!next) {
|
||||
next = NODE_FIRST_CHILD(n);
|
||||
}
|
||||
|
||||
while (!next) {
|
||||
n = NODE_PARENT(n);
|
||||
if (!n) {
|
||||
break;
|
||||
}
|
||||
|
||||
d--;
|
||||
next = NODE_NEXT_SIBLING(n);
|
||||
}
|
||||
|
||||
remove_node(it->node);
|
||||
reparent_children(it->node, parent);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_iterator_value iterator_get_value(b_iterator *obj)
|
||||
{
|
||||
struct b_tree_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_TREE_ITERATOR);
|
||||
|
||||
if (!it->node) {
|
||||
return B_ITERATOR_VALUE_NULL;
|
||||
}
|
||||
|
||||
return B_ITERATOR_VALUE_PTR(it->node);
|
||||
}
|
||||
|
||||
static const b_iterator_value iterator_get_cvalue(const b_iterator *obj)
|
||||
{
|
||||
struct b_tree_iterator_p *it
|
||||
= b_object_get_private(obj, B_TYPE_TREE_ITERATOR);
|
||||
|
||||
if (!it->node) {
|
||||
return B_ITERATOR_VALUE_NULL;
|
||||
}
|
||||
|
||||
return B_ITERATOR_VALUE_CPTR(it->node);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- b_tree DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_tree)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterable, B_TYPE_ITERABLE)
|
||||
B_INTERFACE_ENTRY(it_begin) = b_tree_begin;
|
||||
B_INTERFACE_ENTRY(it_cbegin) = b_tree_cbegin;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterable, B_TYPE_ITERABLE)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_tree)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_tree)
|
||||
B_TYPE_ID(0x8d8fa36b, 0xc515, 0x4803, 0x8124, 0xfd704f01b8ae);
|
||||
B_TYPE_CLASS(b_tree_class);
|
||||
B_TYPE_IMPLEMENTS(B_TYPE_ITERABLE);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_tree_p);
|
||||
B_TYPE_INSTANCE_INIT(tree_init);
|
||||
B_TYPE_INSTANCE_FINI(tree_fini);
|
||||
B_TYPE_DEFINITION_END(b_tree)
|
||||
|
||||
// ---- b_tree_iterator DEFINITION
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_tree_iterator)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_iterator, B_TYPE_ITERATOR)
|
||||
B_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
B_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
B_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
B_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_iterator, B_TYPE_ITERATOR)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_tree_iterator)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_tree_iterator)
|
||||
B_TYPE_ID(0xb896e671, 0x84b2, 0x4892, 0xaf09, 0x407f305f4bf8);
|
||||
B_TYPE_EXTENDS(B_TYPE_ITERATOR);
|
||||
B_TYPE_CLASS(b_tree_iterator_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_tree_iterator_p);
|
||||
B_TYPE_DEFINITION_END(b_tree_iterator)
|
||||
@@ -1,227 +0,0 @@
|
||||
#include <blue/core/stringstream.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <blue/ds/uuid.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_uuid_p {
|
||||
union b_uuid_bytes uuid_bytes;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static b_status uuid_to_cstr(
|
||||
const struct b_uuid_p *uuid, char out[B_UUID_STRING_MAX])
|
||||
{
|
||||
snprintf(
|
||||
out, B_UUID_STRING_MAX,
|
||||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%"
|
||||
"02x%02x",
|
||||
uuid->uuid_bytes.uuid_bytes[0], uuid->uuid_bytes.uuid_bytes[1],
|
||||
uuid->uuid_bytes.uuid_bytes[2], uuid->uuid_bytes.uuid_bytes[3],
|
||||
uuid->uuid_bytes.uuid_bytes[4], uuid->uuid_bytes.uuid_bytes[5],
|
||||
uuid->uuid_bytes.uuid_bytes[6], uuid->uuid_bytes.uuid_bytes[7],
|
||||
uuid->uuid_bytes.uuid_bytes[8], uuid->uuid_bytes.uuid_bytes[9],
|
||||
uuid->uuid_bytes.uuid_bytes[10], uuid->uuid_bytes.uuid_bytes[11],
|
||||
uuid->uuid_bytes.uuid_bytes[12], uuid->uuid_bytes.uuid_bytes[13],
|
||||
uuid->uuid_bytes.uuid_bytes[14], uuid->uuid_bytes.uuid_bytes[15]);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static void uuid_get_bytes(
|
||||
const struct b_uuid_p *uuid, unsigned char bytes[B_UUID_NBYTES])
|
||||
{
|
||||
memcpy(bytes, uuid->uuid_bytes.uuid_bytes, B_UUID_NBYTES);
|
||||
}
|
||||
|
||||
static void uuid_get_uuid_bytes(
|
||||
const struct b_uuid_p *uuid, union b_uuid_bytes *bytes)
|
||||
{
|
||||
memcpy(bytes, &uuid->uuid_bytes, sizeof *bytes);
|
||||
}
|
||||
|
||||
static union b_uuid_bytes *uuid_ptr(struct b_uuid_p *uuid)
|
||||
{
|
||||
return &uuid->uuid_bytes;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_uuid *b_uuid_create_from_bytes(
|
||||
unsigned char u00, unsigned char u01, unsigned char u02,
|
||||
unsigned char u03, unsigned char u04, unsigned char u05,
|
||||
unsigned char u06, unsigned char u07, unsigned char u08,
|
||||
unsigned char u09, unsigned char u10, unsigned char u11,
|
||||
unsigned char u12, unsigned char u13, unsigned char u14, unsigned char u15)
|
||||
{
|
||||
b_uuid *uuid = b_uuid_create();
|
||||
if (!uuid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_uuid_p *p = b_object_get_private(uuid, B_TYPE_UUID);
|
||||
|
||||
p->uuid_bytes.uuid_bytes[0] = u00;
|
||||
p->uuid_bytes.uuid_bytes[1] = u01;
|
||||
p->uuid_bytes.uuid_bytes[2] = u02;
|
||||
p->uuid_bytes.uuid_bytes[3] = u03;
|
||||
p->uuid_bytes.uuid_bytes[4] = u04;
|
||||
p->uuid_bytes.uuid_bytes[5] = u05;
|
||||
p->uuid_bytes.uuid_bytes[6] = u06;
|
||||
p->uuid_bytes.uuid_bytes[7] = u07;
|
||||
p->uuid_bytes.uuid_bytes[8] = u08;
|
||||
p->uuid_bytes.uuid_bytes[9] = u09;
|
||||
p->uuid_bytes.uuid_bytes[10] = u10;
|
||||
p->uuid_bytes.uuid_bytes[11] = u11;
|
||||
p->uuid_bytes.uuid_bytes[12] = u12;
|
||||
p->uuid_bytes.uuid_bytes[13] = u13;
|
||||
p->uuid_bytes.uuid_bytes[14] = u14;
|
||||
p->uuid_bytes.uuid_bytes[15] = u15;
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
b_uuid *b_uuid_create_from_bytev(const unsigned char bytes[B_UUID_NBYTES])
|
||||
{
|
||||
b_uuid *uuid = b_uuid_create();
|
||||
if (!uuid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_uuid_p *p = b_object_get_private(uuid, B_TYPE_UUID);
|
||||
|
||||
memcpy(p->uuid_bytes.uuid_bytes, bytes, B_UUID_NBYTES);
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
b_uuid *b_uuid_create_from_cstr(const char *str)
|
||||
{
|
||||
union b_uuid_bytes bytes;
|
||||
|
||||
bool valid = true;
|
||||
bool is_guid = false;
|
||||
if (*str == '{') {
|
||||
is_guid = true;
|
||||
str++;
|
||||
}
|
||||
|
||||
size_t i, byte = 0;
|
||||
for (i = 0; str[i] && byte < B_UUID_NBYTES;) {
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||||
if (str[i] != '-') {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
char n[3];
|
||||
n[0] = str[i];
|
||||
n[1] = str[i + 1];
|
||||
n[2] = '\0';
|
||||
|
||||
if (!isxdigit(n[0]) || !isxdigit(n[1])) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
char *p;
|
||||
unsigned long v = strtoul(n, &p, 16);
|
||||
bytes.uuid_bytes[byte] = v;
|
||||
|
||||
byte++;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if (str[i] == '}') {
|
||||
if (is_guid) {
|
||||
i++;
|
||||
} else {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (str[i] != '\0' || byte != B_UUID_NBYTES) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return b_uuid_create_from_uuid_bytes(&bytes);
|
||||
}
|
||||
|
||||
b_status b_uuid_to_cstr(const b_uuid *uuid, char out[B_UUID_STRING_MAX])
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_to_cstr, uuid, out);
|
||||
}
|
||||
|
||||
void b_uuid_get_bytes(const b_uuid *uuid, unsigned char bytes[B_UUID_NBYTES])
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_get_bytes, uuid, bytes);
|
||||
}
|
||||
|
||||
void b_uuid_get_uuid_bytes(const b_uuid *uuid, union b_uuid_bytes *bytes)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_UUID, uuid_get_uuid_bytes, uuid, bytes);
|
||||
}
|
||||
|
||||
union b_uuid_bytes *b_uuid_ptr(b_uuid *uuid)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_UUID, uuid_ptr, uuid);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
b_uuid *b_uuid_create_from_uuid_bytes(const union b_uuid_bytes *bytes)
|
||||
{
|
||||
return b_uuid_create_from_bytev(bytes->uuid_bytes);
|
||||
}
|
||||
|
||||
b_uuid *b_uuid_create_from_string(const b_string *string)
|
||||
{
|
||||
return b_uuid_create_from_cstr(b_string_ptr(string));
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void uuid_init(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_uuid_p *uuid = priv;
|
||||
}
|
||||
|
||||
static void uuid_fini(b_object *obj, void *priv)
|
||||
{
|
||||
struct b_uuid_p *uuid = priv;
|
||||
}
|
||||
|
||||
static void uuid_to_string(const b_object *uuid, b_stream *out)
|
||||
{
|
||||
char str[B_UUID_STRING_MAX];
|
||||
b_uuid_to_cstr(uuid, str);
|
||||
b_stream_write_string(out, str, NULL);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_uuid)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = uuid_to_string;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_uuid)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_uuid)
|
||||
B_TYPE_ID(0x17037068, 0x92f7, 0x4582, 0xad1f, 0x0dea43b628de);
|
||||
B_TYPE_CLASS(b_uuid_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_uuid_p);
|
||||
B_TYPE_INSTANCE_INIT(uuid_init);
|
||||
B_TYPE_INSTANCE_FINI(uuid_fini);
|
||||
B_TYPE_DEFINITION_END(b_uuid)
|
||||
@@ -0,0 +1,3 @@
|
||||
include(../cmake/Templates.cmake)
|
||||
|
||||
add_fx_module(NAME cmd DEPENDENCIES core ds term)
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct b_command_arg *b_command_arg_create(void)
|
||||
struct fx_command_arg *fx_command_arg_create(void)
|
||||
{
|
||||
struct b_command_arg *out = malloc(sizeof *out);
|
||||
struct fx_command_arg *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return out;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ struct b_command_arg *b_command_arg_create(void)
|
||||
return out;
|
||||
}
|
||||
|
||||
void b_command_arg_destroy(struct b_command_arg *arg)
|
||||
void fx_command_arg_destroy(struct fx_command_arg *arg)
|
||||
{
|
||||
if (arg->arg_name) {
|
||||
free(arg->arg_name);
|
||||
@@ -37,11 +37,11 @@ void b_command_arg_destroy(struct b_command_arg *arg)
|
||||
free(arg);
|
||||
}
|
||||
|
||||
b_status b_command_arg_set_name(struct b_command_arg *arg, const char *name)
|
||||
fx_status fx_command_arg_set_name(struct fx_command_arg *arg, const char *name)
|
||||
{
|
||||
char *n = b_strdup(name);
|
||||
char *n = fx_strdup(name);
|
||||
if (!n) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (arg->arg_name) {
|
||||
@@ -50,15 +50,15 @@ b_status b_command_arg_set_name(struct b_command_arg *arg, const char *name)
|
||||
}
|
||||
|
||||
arg->arg_name = n;
|
||||
return B_SUCCESS;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_command_arg_set_description(
|
||||
struct b_command_arg *arg, const char *description)
|
||||
fx_status fx_command_arg_set_description(
|
||||
struct fx_command_arg *arg, const char *description)
|
||||
{
|
||||
char *desc = b_strdup(description);
|
||||
char *desc = fx_strdup(description);
|
||||
if (!desc) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (arg->arg_description) {
|
||||
@@ -67,18 +67,18 @@ b_status b_command_arg_set_description(
|
||||
}
|
||||
|
||||
arg->arg_description = desc;
|
||||
return B_SUCCESS;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_command_arg_set_nr_values(
|
||||
struct b_command_arg *arg, enum b_command_arg_value_count nr_values)
|
||||
fx_status fx_command_arg_set_nr_values(
|
||||
struct fx_command_arg *arg, enum fx_command_arg_value_count nr_values)
|
||||
{
|
||||
arg->arg_nr_values = nr_values;
|
||||
return B_SUCCESS;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
b_status b_command_arg_set_allowed_values(
|
||||
struct b_command_arg *arg, const char **allowed_values)
|
||||
fx_status fx_command_arg_set_allowed_values(
|
||||
struct fx_command_arg *arg, const char **allowed_values)
|
||||
{
|
||||
size_t count;
|
||||
for (count = 0; allowed_values[count]; count++)
|
||||
@@ -86,35 +86,35 @@ b_status b_command_arg_set_allowed_values(
|
||||
|
||||
char **values = calloc(count + 1, sizeof *values);
|
||||
if (!values) {
|
||||
return B_ERR_NO_MEMORY;
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
values[i] = b_strdup(allowed_values[i]);
|
||||
values[i] = fx_strdup(allowed_values[i]);
|
||||
if (!values[i]) {
|
||||
/* TODO also free strings in `values` */
|
||||
free(values);
|
||||
return B_ERR_NO_MEMORY;
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
arg->arg_allowed_values = values;
|
||||
return B_SUCCESS;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
void z__b_get_arg_usage_string(struct b_command_arg *arg, bool colour, b_string *out)
|
||||
void z__fx_get_arg_usage_string(struct fx_command_arg *arg, bool colour, fx_string *out)
|
||||
{
|
||||
bool optional = false, multi = false;
|
||||
switch (arg->arg_nr_values) {
|
||||
case B_ARG_0_OR_1_VALUES:
|
||||
case FX_ARG_0_OR_1_VALUES:
|
||||
optional = true;
|
||||
multi = false;
|
||||
break;
|
||||
case B_ARG_0_OR_MORE_VALUES:
|
||||
case FX_ARG_0_OR_MORE_VALUES:
|
||||
optional = true;
|
||||
multi = true;
|
||||
break;
|
||||
case B_ARG_1_OR_MORE_VALUES:
|
||||
case FX_ARG_1_OR_MORE_VALUES:
|
||||
optional = false;
|
||||
multi = true;
|
||||
break;
|
||||
@@ -125,30 +125,30 @@ void z__b_get_arg_usage_string(struct b_command_arg *arg, bool colour, b_string
|
||||
}
|
||||
|
||||
if (optional) {
|
||||
b_string_append_cstrf(
|
||||
fx_string_append_cstrf(
|
||||
out, colour ? F_GREEN "[[%s]" : "[[%s]", arg->arg_name);
|
||||
} else {
|
||||
b_string_append_cstrf(
|
||||
fx_string_append_cstrf(
|
||||
out, colour ? F_GREEN "<%s>" : "<%s>", arg->arg_name);
|
||||
}
|
||||
|
||||
for (int i = 1; i < arg->arg_nr_values; i++) {
|
||||
b_string_append_cstrf(out, " <%s>", arg->arg_name);
|
||||
fx_string_append_cstrf(out, " <%s>", arg->arg_name);
|
||||
}
|
||||
|
||||
if (multi) {
|
||||
b_string_append_cstr(out, "...");
|
||||
fx_string_append_cstr(out, "...");
|
||||
}
|
||||
|
||||
if (colour) {
|
||||
b_string_append_cstr(out, F_RESET);
|
||||
fx_string_append_cstr(out, F_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
void z__b_get_arg_description(struct b_command_arg *arg, b_string *out)
|
||||
void z__fx_get_arg_description(struct fx_command_arg *arg, fx_string *out)
|
||||
{
|
||||
if (arg->arg_description) {
|
||||
b_string_append_cstr(out, arg->arg_description);
|
||||
fx_string_append_cstr(out, arg->arg_description);
|
||||
}
|
||||
|
||||
if (!arg->arg_allowed_values) {
|
||||
@@ -156,19 +156,19 @@ void z__b_get_arg_description(struct b_command_arg *arg, b_string *out)
|
||||
}
|
||||
|
||||
if (arg->arg_description) {
|
||||
b_string_append_cstr(out, " ");
|
||||
fx_string_append_cstr(out, " ");
|
||||
}
|
||||
|
||||
b_string_append_cstr(out, "[[values:");
|
||||
fx_string_append_cstr(out, "[[values:");
|
||||
|
||||
for (size_t i = 0; arg->arg_allowed_values[i]; i++) {
|
||||
if (i > 0) {
|
||||
b_string_append_cstr(out, ",");
|
||||
fx_string_append_cstr(out, ",");
|
||||
}
|
||||
|
||||
b_string_append_cstrf(
|
||||
fx_string_append_cstrf(
|
||||
out, " " F_GREEN "%s" F_RESET, arg->arg_allowed_values[i]);
|
||||
}
|
||||
|
||||
b_string_append_cstr(out, "]");
|
||||
fx_string_append_cstr(out, "]");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,151 @@
|
||||
#ifndef _FX_COMMAND_H_
|
||||
#define _FX_COMMAND_H_
|
||||
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/core/bst.h>
|
||||
#include <fx/core/queue.h>
|
||||
#include <fx/ds/string.h>
|
||||
|
||||
#define F_RED "[bright_red]"
|
||||
#define F_GREEN "[bright_green]"
|
||||
#define F_YELLOW "[bright_yellow]"
|
||||
|
||||
#define F_RED_BOLD "[bright_red,bold]"
|
||||
#define F_GREEN_BOLD "[bright_green,bold]"
|
||||
#define F_YELLOW_BOLD "[bright_yellow,bold]"
|
||||
#define F_RESET "[reset]"
|
||||
|
||||
enum cmd_string_flags {
|
||||
CMD_STR_COLOUR = 0x01u,
|
||||
CMD_STR_DIRECT_USAGE = 0x02u,
|
||||
};
|
||||
|
||||
enum fx_command_usage_entry_type {
|
||||
CMD_USAGE_NONE = 0,
|
||||
CMD_USAGE_ARG,
|
||||
CMD_USAGE_OPT,
|
||||
CMD_USAGE_COMMAND,
|
||||
};
|
||||
|
||||
struct fx_command {
|
||||
unsigned int c_id;
|
||||
unsigned int c_parent_id;
|
||||
struct fx_command *c_parent;
|
||||
enum fx_command_flags c_flags;
|
||||
|
||||
char *c_name;
|
||||
char *c_long_name;
|
||||
char c_short_name;
|
||||
char *c_description;
|
||||
struct fx_queue c_opt;
|
||||
struct fx_queue c_arg;
|
||||
struct fx_queue c_subcommands;
|
||||
struct fx_queue c_usage;
|
||||
|
||||
fx_command_callback c_callback;
|
||||
struct fx_queue_entry c_entry;
|
||||
struct fx_bst_node c_node;
|
||||
};
|
||||
|
||||
struct fx_command_usage_entry {
|
||||
struct fx_queue_entry e_entry;
|
||||
enum fx_command_usage_entry_type e_type;
|
||||
|
||||
union {
|
||||
struct fx_command_option *e_opt;
|
||||
struct fx_command_arg *e_arg;
|
||||
unsigned int e_cmd_id;
|
||||
};
|
||||
};
|
||||
|
||||
struct fx_command_usage {
|
||||
fx_command_usage_flags u_flags;
|
||||
struct fx_queue_entry u_entry;
|
||||
|
||||
struct fx_queue u_parts;
|
||||
};
|
||||
|
||||
struct fx_command_option {
|
||||
unsigned int opt_id;
|
||||
|
||||
char *opt_long_name;
|
||||
char opt_short_name;
|
||||
char *opt_description;
|
||||
|
||||
// fx_command_arg_value_count arg_nr_values;
|
||||
// char **arg_allowed_values;
|
||||
|
||||
struct fx_queue opt_args;
|
||||
struct fx_queue_entry opt_entry;
|
||||
};
|
||||
|
||||
struct fx_command_arg {
|
||||
unsigned int arg_id;
|
||||
char *arg_name;
|
||||
char *arg_description;
|
||||
|
||||
fx_command_arg_value_count arg_nr_values;
|
||||
char **arg_allowed_values;
|
||||
|
||||
struct fx_queue_entry arg_entry;
|
||||
};
|
||||
|
||||
struct fx_arglist_option {
|
||||
unsigned int opt_id;
|
||||
struct fx_bst opt_values;
|
||||
struct fx_bst_node opt_node;
|
||||
};
|
||||
|
||||
struct fx_arglist {
|
||||
size_t list_argc;
|
||||
const char **list_argv;
|
||||
unsigned int list_argv_last_command;
|
||||
struct fx_command *list_command;
|
||||
struct fx_bst list_options;
|
||||
};
|
||||
|
||||
FX_API struct fx_command *fx_command_get_subcommand_with_name(
|
||||
struct fx_command *cmd, const char *name);
|
||||
FX_API struct fx_command *fx_command_get_subcommand_with_long_name(
|
||||
struct fx_command *cmd, const char *long_name);
|
||||
FX_API struct fx_command *fx_command_get_subcommand_with_short_name(
|
||||
struct fx_command *cmd, char short_name);
|
||||
|
||||
FX_API struct fx_command_option *fx_command_get_option_with_long_name(
|
||||
struct fx_command *cmd, const char *long_name);
|
||||
FX_API struct fx_command_option *fx_command_get_option_with_short_name(
|
||||
struct fx_command *cmd, char short_name);
|
||||
FX_API struct fx_command_option *fx_command_get_option_with_id(
|
||||
struct fx_command *cmd, unsigned int id);
|
||||
FX_API struct fx_command_arg *fx_command_get_arg_with_id(
|
||||
struct fx_command *cmd, unsigned int id);
|
||||
|
||||
FX_API struct fx_command_arg *fx_command_option_get_arg_with_id(
|
||||
struct fx_command_option *opt, unsigned int id);
|
||||
|
||||
FX_API struct fx_command_option *fx_command_option_create(void);
|
||||
FX_API void fx_command_option_destroy(struct fx_command_option *opt);
|
||||
|
||||
FX_API struct fx_command_arg *fx_command_arg_create(void);
|
||||
FX_API void fx_command_arg_destroy(struct fx_command_arg *arg);
|
||||
|
||||
FX_API struct fx_arglist *fx_arglist_create(void);
|
||||
FX_API fx_status fx_arglist_parse(
|
||||
struct fx_arglist *args, struct fx_command **cmd, int argc,
|
||||
const char **argv);
|
||||
FX_API void fx_arglist_destroy(struct fx_arglist *args);
|
||||
|
||||
FX_API fx_string *z__fx_command_default_usage_string(
|
||||
struct fx_command *cmd, struct fx_command_option *with_opt,
|
||||
const struct fx_arglist *args);
|
||||
|
||||
FX_API void z__fx_get_arg_usage_string(
|
||||
struct fx_command_arg *arg, bool colour, fx_string *out);
|
||||
FX_API void z__fx_get_arg_description(struct fx_command_arg *arg, fx_string *out);
|
||||
|
||||
FX_API void z__fx_get_option_usage_string(
|
||||
struct fx_command_option *opt, enum cmd_string_flags flags, fx_string *out);
|
||||
FX_API void z__fx_get_option_description(
|
||||
struct fx_command_option *opt, fx_string *out);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,289 @@
|
||||
#ifndef FX_CMD_H_
|
||||
#define FX_CMD_H_
|
||||
|
||||
#include <fx/core/bst.h>
|
||||
#include <fx/core/init.h>
|
||||
#include <fx/core/iterator.h>
|
||||
#include <fx/core/queue.h>
|
||||
#include <fx/ds/array.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define fx_arglist_foreach(it, q) \
|
||||
for (int z__fx_unique_name() = fx_arglist_iterator_begin( \
|
||||
q, FX_COMMAND_INVALID_ID, FX_COMMAND_INVALID_ID, (it)); \
|
||||
fx_arglist_iterator_is_valid(it); fx_arglist_iterator_next(it))
|
||||
|
||||
#define fx_arglist_foreach_filtered(it, q, opt_id, arg_id) \
|
||||
for (int z__fx_unique_name() \
|
||||
= fx_arglist_iterator_begin(q, opt_id, arg_id, (it)); \
|
||||
fx_arglist_iterator_is_valid(it); fx_arglist_iterator_next(it))
|
||||
|
||||
#define fx_arglist_option_foreach(it, q) \
|
||||
for (int z__fx_unique_name() \
|
||||
= fx_arglist_option_iterator_begin(q, FX_COMMAND_INVALID_ID, (it)); \
|
||||
fx_arglist_option_iterator_is_valid(it); \
|
||||
fx_arglist_option_iterator_next(it))
|
||||
|
||||
#define fx_arglist_option_foreach_filtered(it, q, opt_id) \
|
||||
for (int z__fx_unique_name() \
|
||||
= fx_arglist_option_iterator_begin(q, opt_id, (it)); \
|
||||
fx_arglist_option_iterator_is_valid(it); \
|
||||
fx_arglist_option_iterator_next(it))
|
||||
|
||||
#define FX_COMMAND(id, parent_id) \
|
||||
static fx_command *command_##id = NULL; \
|
||||
static void __init_##id( \
|
||||
fx_command *, fx_command_option *, fx_command_arg *, \
|
||||
fx_command_usage *); \
|
||||
FX_INIT(init_##id) \
|
||||
{ \
|
||||
command_##id = fx_command_create(id); \
|
||||
if ((parent_id) != FX_COMMAND_INVALID_ID) { \
|
||||
fx_command_set_parent(command_##id, parent_id); \
|
||||
} \
|
||||
__init_##id(command_##id, NULL, NULL, NULL); \
|
||||
fx_command_register(command_##id); \
|
||||
} \
|
||||
static void __init_##id( \
|
||||
fx_command *this_cmd, fx_command_option *this_opt, \
|
||||
fx_command_arg *this_arg, fx_command_usage *this_usage)
|
||||
|
||||
#define FX_COMMAND_NAME(name) fx_command_set_name(this_cmd, (name))
|
||||
#define FX_COMMAND_LONG_NAME(name) fx_command_set_long_name(this_cmd, (name))
|
||||
#define FX_COMMAND_SHORT_NAME(name) fx_command_set_short_name(this_cmd, (name))
|
||||
#define FX_COMMAND_DESC(desc) fx_command_set_description(this_cmd, (desc))
|
||||
#define FX_COMMAND_FLAGS(flags) fx_command_set_flags(this_cmd, (flags))
|
||||
#define FX_COMMAND_FUNCTION(fn) fx_command_set_callback(this_cmd, (fn))
|
||||
|
||||
#define FX_COMMAND_OPTION(id) \
|
||||
fx_command_option *opt_##id = fx_command_add_option(this_cmd, (id)); \
|
||||
this_opt = opt_##id; \
|
||||
if (this_opt)
|
||||
|
||||
#define FX_COMMAND_OPTION_GEN(id) \
|
||||
fx_command_option *z__fx_unique_name() \
|
||||
= fx_command_add_option(this_cmd, (id)); \
|
||||
this_opt = z__fx_unique_name(); \
|
||||
if (this_opt)
|
||||
|
||||
#define FX_COMMAND_HELP_OPTION() \
|
||||
do { \
|
||||
fx_command_option *opt \
|
||||
= fx_command_add_option(this_cmd, FX_COMMAND_OPTION_HELP); \
|
||||
fx_command_option_set_description(opt, "Show this help message"); \
|
||||
fx_command_option_set_short_name(opt, 'h'); \
|
||||
fx_command_option_set_long_name(opt, "help"); \
|
||||
} while (0)
|
||||
|
||||
#define FX_OPTION_LONG_NAME(name) \
|
||||
fx_command_option_set_long_name(this_opt, (name))
|
||||
|
||||
#define FX_OPTION_SHORT_NAME(name) \
|
||||
fx_command_option_set_short_name(this_opt, (name))
|
||||
|
||||
#define FX_OPTION_DESC(desc) fx_command_option_set_description(this_opt, (desc))
|
||||
|
||||
#define FX_OPTION_ARG(id) \
|
||||
fx_command_arg *arg_##id = fx_command_option_add_arg(this_opt, (id)); \
|
||||
this_arg = arg_##id; \
|
||||
if (this_arg)
|
||||
|
||||
#define FX_COMMAND_ARG(id) \
|
||||
fx_command_arg *arg_##id = fx_command_add_arg(this_cmd, (id)); \
|
||||
this_arg = arg_##id; \
|
||||
if (this_arg)
|
||||
|
||||
#define FX_ARG_NAME(name) fx_command_arg_set_name(this_arg, (name))
|
||||
|
||||
#define FX_ARG_DESC(desc) fx_command_arg_set_description(this_arg, (desc))
|
||||
|
||||
#define FX_ARG_NR_VALUES(nr_values) \
|
||||
fx_command_arg_set_nr_values(this_arg, (nr_values))
|
||||
|
||||
#define FX_ARG_ALLOWED_VALUES(...) \
|
||||
static const char *allowed_values[] = { \
|
||||
__VA_ARGS__, \
|
||||
NULL, \
|
||||
}; \
|
||||
fx_command_arg_set_allowed_values(this_arg, allowed_values)
|
||||
|
||||
#define FX_COMMAND_USAGE() \
|
||||
fx_command_usage *z__fx_unique_name() = fx_command_add_usage(this_cmd); \
|
||||
this_usage = z__fx_unique_name(); \
|
||||
if (this_usage)
|
||||
|
||||
#define FX_COMMAND_USAGE_COMMAND(cmd_id) \
|
||||
fx_command_usage_add_command(this_usage, cmd_id)
|
||||
|
||||
#define FX_COMMAND_USAGE_COMMAND_PLACEHOLDER() \
|
||||
fx_command_usage_add_command(this_usage, FX_COMMAND_INVALID_ID)
|
||||
|
||||
#define FX_COMMAND_USAGE_OPT(opt_id) \
|
||||
fx_command_usage_add_option(this_usage, opt_##opt_id)
|
||||
|
||||
#define FX_COMMAND_USAGE_OPT_PLACEHOLDER() \
|
||||
fx_command_usage_add_option(this_usage, NULL)
|
||||
|
||||
#define FX_COMMAND_USAGE_ARG(opt_id) \
|
||||
fx_command_usage_add_arg(this_usage, arg_##opt_id)
|
||||
|
||||
#define FX_COMMAND_USAGE_ARG_PLACEHOLDER() \
|
||||
fx_command_usage_add_arg(this_usage, NULL)
|
||||
|
||||
#define FX_COMMAND_OPTION_HELP ((uintptr_t)0xF0000001)
|
||||
#define FX_COMMAND_INVALID_ID ((uintptr_t)0xFFFFFFFF)
|
||||
|
||||
typedef enum fx_command_arg_value_count {
|
||||
FX_ARG_0_OR_1_VALUES = -1,
|
||||
FX_ARG_0_OR_MORE_VALUES = -2,
|
||||
FX_ARG_1_OR_MORE_VALUES = -3,
|
||||
} fx_command_arg_value_count;
|
||||
|
||||
typedef enum fx_command_arg_type {
|
||||
FX_COMMAND_ARG_NONE = 0,
|
||||
FX_COMMAND_ARG_STRING,
|
||||
FX_COMMAND_ARG_SIGNED_INT,
|
||||
FX_COMMAND_ARG_UNSIGNED_INT,
|
||||
|
||||
FX_COMMAND_ARG_INT = FX_COMMAND_ARG_SIGNED_INT,
|
||||
} fx_command_arg_type;
|
||||
|
||||
typedef enum fx_command_flags {
|
||||
FX_COMMAND_SHOW_HELP_BY_DEFAULT = 0x01u,
|
||||
} fx_command_flags;
|
||||
|
||||
typedef enum fx_command_usage_flags {
|
||||
FX_COMMAND_USAGE_SHOW_OPTIONS = 0x01u,
|
||||
} fx_command_usage_flags;
|
||||
|
||||
typedef struct fx_arglist_value {
|
||||
unsigned int val_id;
|
||||
fx_command_arg_type val_type;
|
||||
struct fx_bst_node val_node;
|
||||
|
||||
union {
|
||||
char *val_str;
|
||||
long long val_int;
|
||||
unsigned long long val_uint;
|
||||
};
|
||||
} fx_arglist_value;
|
||||
|
||||
typedef struct fx_arglist_iterator {
|
||||
size_t i;
|
||||
|
||||
unsigned int opt_id;
|
||||
struct fx_arglist_value *value;
|
||||
|
||||
fx_bst_node *_opt_it, *_arg_it;
|
||||
unsigned int _opt_filter, _arg_filter;
|
||||
} fx_arglist_iterator;
|
||||
|
||||
typedef struct fx_arglist_option_iterator {
|
||||
size_t i;
|
||||
|
||||
unsigned int opt_id;
|
||||
struct fx_arglist_option *opt;
|
||||
|
||||
fx_bst_node *_opt_it;
|
||||
unsigned int _opt_filter;
|
||||
} fx_arglist_option_iterator;
|
||||
|
||||
typedef struct fx_command fx_command;
|
||||
typedef struct fx_command_option fx_command_option;
|
||||
typedef struct fx_command_arg fx_command_arg;
|
||||
typedef struct fx_command_usage fx_command_usage;
|
||||
typedef struct fx_arglist fx_arglist;
|
||||
typedef struct fx_arglist_option fx_arglist_option;
|
||||
|
||||
typedef int (*fx_command_callback)(
|
||||
const fx_command *, const fx_arglist *, const fx_array *);
|
||||
|
||||
FX_API fx_command *fx_command_create(unsigned int id);
|
||||
FX_API void fx_command_destroy(fx_command *cmd);
|
||||
FX_API fx_status fx_command_register(fx_command *cmd);
|
||||
FX_API int fx_command_dispatch(unsigned int cmd_id, int argc, const char **argv);
|
||||
|
||||
FX_API fx_status fx_command_set_name(fx_command *cmd, const char *name);
|
||||
FX_API fx_status fx_command_set_long_name(fx_command *cmd, const char *name);
|
||||
FX_API fx_status fx_command_set_short_name(fx_command *cmd, char name);
|
||||
FX_API fx_status fx_command_set_flags(fx_command *cmd, fx_command_flags flags);
|
||||
FX_API fx_status fx_command_set_description(fx_command *cmd, const char *description);
|
||||
FX_API fx_status fx_command_set_callback(
|
||||
fx_command *cmd, fx_command_callback callback);
|
||||
FX_API fx_status fx_command_set_parent(fx_command *cmd, unsigned int parent_id);
|
||||
FX_API fx_command_option *fx_command_add_option(fx_command *cmd, int id);
|
||||
FX_API fx_command_arg *fx_command_add_arg(fx_command *cmd, int id);
|
||||
FX_API fx_command_usage *fx_command_add_usage(fx_command *cmd);
|
||||
|
||||
FX_API const fx_command_option *fx_command_get_option(const fx_command *cmd, int id);
|
||||
|
||||
FX_API const char *fx_command_option_get_long_name(const fx_command_option *opt);
|
||||
FX_API char fx_command_option_get_short_name(const fx_command_option *opt);
|
||||
FX_API const char *fx_command_option_get_description(fx_command_option *opt);
|
||||
FX_API fx_status fx_command_option_set_long_name(
|
||||
fx_command_option *opt, const char *name);
|
||||
FX_API fx_status fx_command_option_set_short_name(fx_command_option *opt, char name);
|
||||
FX_API fx_status fx_command_option_set_description(
|
||||
fx_command_option *opt, const char *description);
|
||||
FX_API fx_command_arg *fx_command_option_add_arg(fx_command_option *opt, int id);
|
||||
|
||||
FX_API fx_status fx_command_arg_set_name(fx_command_arg *arg, const char *name);
|
||||
FX_API fx_status fx_command_arg_set_description(
|
||||
fx_command_arg *arg, const char *description);
|
||||
FX_API fx_status fx_command_arg_set_nr_values(
|
||||
fx_command_arg *arg, fx_command_arg_value_count nr_values);
|
||||
FX_API fx_status fx_command_arg_set_allowed_values(
|
||||
fx_command_arg *arg, const char **allowed_values);
|
||||
|
||||
FX_API fx_status fx_command_usage_add_option(
|
||||
fx_command_usage *usage, fx_command_option *opt);
|
||||
FX_API fx_status fx_command_usage_add_arg(
|
||||
fx_command_usage *usage, fx_command_arg *opt);
|
||||
FX_API fx_status fx_command_usage_add_command(
|
||||
fx_command_usage *usage, unsigned int cmd_id);
|
||||
|
||||
FX_API fx_status fx_arglist_get_string(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
unsigned int index, const char **out);
|
||||
FX_API fx_status fx_arglist_get_int(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
unsigned int index, long long *out);
|
||||
FX_API fx_status fx_arglist_get_uint(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
unsigned int index, unsigned long long *out);
|
||||
FX_API fx_status fx_arglist_get_option(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int index,
|
||||
fx_arglist_option **out);
|
||||
FX_API size_t fx_arglist_get_count(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id);
|
||||
|
||||
FX_API fx_status fx_arglist_report_missing_option(
|
||||
const fx_arglist *args, unsigned int opt_id);
|
||||
FX_API fx_status fx_arglist_report_unexpected_arg(
|
||||
const fx_arglist *args, const char *value);
|
||||
FX_API fx_status fx_arglist_report_invalid_arg_value(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
const char *value);
|
||||
FX_API fx_status fx_arglist_report_missing_args(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
size_t nr_supplied);
|
||||
|
||||
FX_API fx_status fx_arglist_option_get_value(
|
||||
const fx_arglist_option *opt, unsigned int arg_id, unsigned int index,
|
||||
fx_arglist_value **out);
|
||||
|
||||
FX_API int fx_arglist_iterator_begin(
|
||||
const fx_arglist *args, unsigned int opt_filter, unsigned int arg_filter,
|
||||
fx_arglist_iterator *it);
|
||||
FX_API bool fx_arglist_iterator_next(fx_arglist_iterator *it);
|
||||
FX_API bool fx_arglist_iterator_is_valid(const fx_arglist_iterator *it);
|
||||
|
||||
FX_API int fx_arglist_option_iterator_begin(
|
||||
const fx_arglist *args, unsigned int opt_filter,
|
||||
fx_arglist_option_iterator *it);
|
||||
FX_API bool fx_arglist_option_iterator_next(fx_arglist_option_iterator *it);
|
||||
FX_API bool fx_arglist_option_iterator_is_valid(
|
||||
const fx_arglist_option_iterator *it);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <fx/cmd.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct fx_command_option *fx_command_option_create(void)
|
||||
{
|
||||
struct fx_command_option *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return out;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void fx_command_option_destroy(struct fx_command_option *opt)
|
||||
{
|
||||
if (opt->opt_long_name) {
|
||||
free(opt->opt_long_name);
|
||||
}
|
||||
|
||||
if (opt->opt_description) {
|
||||
free(opt->opt_description);
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&opt->opt_args);
|
||||
|
||||
while (entry) {
|
||||
struct fx_command_arg *arg
|
||||
= fx_unbox(struct fx_command_arg, entry, arg_entry);
|
||||
|
||||
struct fx_queue_entry *next = fx_queue_next(entry);
|
||||
fx_queue_delete(&opt->opt_args, entry);
|
||||
|
||||
fx_command_arg_destroy(arg);
|
||||
entry = next;
|
||||
}
|
||||
|
||||
free(opt);
|
||||
}
|
||||
|
||||
const char *fx_command_option_get_long_name(const struct fx_command_option *opt)
|
||||
{
|
||||
return opt->opt_long_name;
|
||||
}
|
||||
|
||||
char fx_command_option_get_short_name(const struct fx_command_option *opt)
|
||||
{
|
||||
return opt->opt_short_name;
|
||||
}
|
||||
|
||||
const char *fx_command_option_get_description(struct fx_command_option *opt)
|
||||
{
|
||||
return opt->opt_description;
|
||||
}
|
||||
|
||||
fx_status fx_command_option_set_long_name(
|
||||
struct fx_command_option *opt, const char *name)
|
||||
{
|
||||
char *n = fx_strdup(name);
|
||||
if (!n) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (opt->opt_long_name) {
|
||||
free(opt->opt_long_name);
|
||||
opt->opt_long_name = NULL;
|
||||
}
|
||||
|
||||
opt->opt_long_name = n;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
fx_status fx_command_option_set_short_name(struct fx_command_option *opt, char name)
|
||||
{
|
||||
opt->opt_short_name = name;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
fx_status fx_command_option_set_description(
|
||||
struct fx_command_option *opt, const char *description)
|
||||
{
|
||||
char *desc = fx_strdup(description);
|
||||
if (!desc) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (opt->opt_description) {
|
||||
free(opt->opt_description);
|
||||
opt->opt_description = NULL;
|
||||
}
|
||||
|
||||
opt->opt_description = desc;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
struct fx_command_arg *fx_command_option_add_arg(struct fx_command_option *opt, int id)
|
||||
{
|
||||
struct fx_command_arg *arg = malloc(sizeof *arg);
|
||||
if (!arg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(arg, 0x0, sizeof *arg);
|
||||
|
||||
arg->arg_id = id;
|
||||
|
||||
fx_queue_push_back(&opt->opt_args, &arg->arg_entry);
|
||||
return arg;
|
||||
}
|
||||
|
||||
void z__fx_get_option_description(struct fx_command_option *opt, fx_string *out)
|
||||
{
|
||||
if (opt->opt_description) {
|
||||
fx_string_append_cstr(out, opt->opt_description);
|
||||
}
|
||||
|
||||
size_t nr_args = fx_queue_length(&opt->opt_args);
|
||||
bool close_bracket = false;
|
||||
|
||||
size_t i = 0;
|
||||
struct fx_queue_entry *entry = fx_queue_first(&opt->opt_args);
|
||||
while (entry) {
|
||||
struct fx_command_arg *arg
|
||||
= fx_unbox(struct fx_command_arg, entry, arg_entry);
|
||||
if (!arg || !arg->arg_allowed_values) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
fx_string_append_cstr(out, "; ");
|
||||
} else {
|
||||
fx_string_append_cstr(out, " [[");
|
||||
close_bracket = true;
|
||||
}
|
||||
|
||||
if (nr_args > 1) {
|
||||
fx_string_append_cstrf(
|
||||
out, "values for `%s`:", arg->arg_name);
|
||||
} else {
|
||||
fx_string_append_cstr(out, "values:");
|
||||
}
|
||||
|
||||
for (size_t i = 0; arg->arg_allowed_values[i]; i++) {
|
||||
if (i > 0) {
|
||||
fx_string_append_cstr(out, ",");
|
||||
}
|
||||
|
||||
fx_string_append_cstrf(
|
||||
out, " " F_GREEN "%s" F_RESET,
|
||||
arg->arg_allowed_values[i]);
|
||||
}
|
||||
|
||||
skip:
|
||||
i++;
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
if (close_bracket) {
|
||||
fx_string_append_cstr(out, "]");
|
||||
}
|
||||
}
|
||||
|
||||
void z__fx_get_option_usage_string(
|
||||
struct fx_command_option *opt, enum cmd_string_flags flags, fx_string *out)
|
||||
{
|
||||
if (flags & CMD_STR_DIRECT_USAGE) {
|
||||
fx_string_append_cstr(out, "{");
|
||||
}
|
||||
|
||||
if (opt->opt_short_name) {
|
||||
fx_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? F_GREEN "-%c" F_RESET : "-%c",
|
||||
opt->opt_short_name);
|
||||
}
|
||||
|
||||
if (opt->opt_short_name && opt->opt_long_name) {
|
||||
fx_string_append_cstr(
|
||||
out, (flags & CMD_STR_DIRECT_USAGE) ? "|" : ", ");
|
||||
}
|
||||
|
||||
if (opt->opt_long_name) {
|
||||
fx_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? F_GREEN "--%s" F_RESET : "--%s",
|
||||
opt->opt_long_name);
|
||||
}
|
||||
|
||||
if (flags & CMD_STR_DIRECT_USAGE) {
|
||||
fx_string_append_cstr(out, "}");
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&opt->opt_args);
|
||||
while (entry) {
|
||||
struct fx_command_arg *arg
|
||||
= fx_unbox(struct fx_command_arg, entry, arg_entry);
|
||||
if (!arg) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
bool optional = false, multi = false;
|
||||
switch (arg->arg_nr_values) {
|
||||
case FX_ARG_0_OR_1_VALUES:
|
||||
optional = true;
|
||||
multi = false;
|
||||
break;
|
||||
case FX_ARG_0_OR_MORE_VALUES:
|
||||
optional = true;
|
||||
multi = true;
|
||||
break;
|
||||
case FX_ARG_1_OR_MORE_VALUES:
|
||||
optional = false;
|
||||
multi = true;
|
||||
break;
|
||||
default:
|
||||
optional = false;
|
||||
multi = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (optional) {
|
||||
fx_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? " " F_GREEN "[%s]"
|
||||
: " [%s]",
|
||||
arg->arg_name);
|
||||
} else {
|
||||
fx_string_append_cstrf(
|
||||
out,
|
||||
(flags & CMD_STR_COLOUR) ? " " F_GREEN "<%s>"
|
||||
: " <%s>",
|
||||
arg->arg_name);
|
||||
}
|
||||
|
||||
for (int i = 1; i < arg->arg_nr_values; i++) {
|
||||
fx_string_append_cstrf(out, " <%s>", arg->arg_name);
|
||||
}
|
||||
|
||||
if (multi) {
|
||||
fx_string_append_cstr(out, "...");
|
||||
}
|
||||
|
||||
if (flags & CMD_STR_COLOUR) {
|
||||
fx_string_append_cstr(out, F_RESET);
|
||||
}
|
||||
|
||||
skip:
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
}
|
||||
|
||||
struct fx_command_arg *fx_command_option_get_arg_with_id(
|
||||
struct fx_command_option *opt, unsigned int id)
|
||||
{
|
||||
struct fx_queue_entry *entry = fx_queue_first(&opt->opt_args);
|
||||
|
||||
while (entry) {
|
||||
struct fx_command_arg *arg
|
||||
= fx_unbox(struct fx_command_arg, entry, arg_entry);
|
||||
|
||||
if (arg->arg_id == id) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
#include "command.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fx/core/stringstream.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <fx/term/print.h>
|
||||
#include <stdio.h>
|
||||
|
||||
enum fx_status fx_arglist_report_missing_option(
|
||||
const fx_arglist *args, unsigned int opt_id)
|
||||
{
|
||||
struct fx_command_option *opt = NULL;
|
||||
|
||||
if (opt_id != FX_COMMAND_INVALID_ID) {
|
||||
opt = fx_command_get_option_with_id(args->list_command, opt_id);
|
||||
}
|
||||
|
||||
if (!opt) {
|
||||
return FX_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
fx_string *opt_string = fx_string_create();
|
||||
z__fx_get_option_usage_string(opt, 0, opt_string);
|
||||
|
||||
fx_stringstream *opt_name = fx_stringstream_create();
|
||||
|
||||
int opt_names = 0;
|
||||
if (opt->opt_short_name) {
|
||||
opt_names++;
|
||||
}
|
||||
|
||||
if (opt->opt_long_name) {
|
||||
opt_names++;
|
||||
}
|
||||
|
||||
if (opt_names == 2) {
|
||||
fx_stream_write_fmt(
|
||||
opt_name, NULL, "-%c / --%s", opt->opt_short_name,
|
||||
opt->opt_long_name);
|
||||
} else if (opt->opt_short_name) {
|
||||
fx_stream_write_fmt(opt_name, NULL, "-%c", opt->opt_short_name);
|
||||
} else if (opt->opt_long_name) {
|
||||
fx_stream_write_fmt(opt_name, NULL, "--%s", opt->opt_long_name);
|
||||
}
|
||||
|
||||
fx_err("required option `" F_YELLOW "%s" F_RESET "` was not specified.",
|
||||
fx_stringstream_ptr(opt_name));
|
||||
fx_i("usage: %s", fx_string_get_cstr(opt_string));
|
||||
fx_i("for more information, use `" F_YELLOW "--help" F_RESET "`");
|
||||
|
||||
fx_string_unref(opt_string);
|
||||
fx_stringstream_unref(opt_name);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
enum fx_status fx_arglist_report_unexpected_arg(
|
||||
const fx_arglist *args, const char *value)
|
||||
{
|
||||
fx_string *usage = z__fx_command_default_usage_string(
|
||||
args->list_command, NULL, args);
|
||||
|
||||
fx_err("unexpected argument '" F_YELLOW "%s" F_RESET "' found.", value);
|
||||
fx_i("usage: %s", fx_string_get_cstr(usage));
|
||||
fx_i("for more information, use '" F_YELLOW "--help" F_RESET "'");
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
enum fx_status fx_arglist_report_invalid_arg_value(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
const char *value)
|
||||
{
|
||||
struct fx_command_option *opt = NULL;
|
||||
struct fx_command_arg *arg = NULL;
|
||||
|
||||
if (opt_id != FX_COMMAND_INVALID_ID) {
|
||||
opt = fx_command_get_option_with_id(args->list_command, opt_id);
|
||||
}
|
||||
|
||||
if (arg_id != FX_COMMAND_INVALID_ID) {
|
||||
arg = opt ? fx_command_option_get_arg_with_id(opt, arg_id)
|
||||
: fx_command_get_arg_with_id(args->list_command, arg_id);
|
||||
}
|
||||
|
||||
fx_string *usage = z__fx_command_default_usage_string(
|
||||
args->list_command, opt, args);
|
||||
fx_string *opt_string = fx_string_create();
|
||||
|
||||
if (opt) {
|
||||
z__fx_get_option_usage_string(opt, 0, opt_string);
|
||||
} else {
|
||||
z__fx_get_arg_usage_string(arg, 0, opt_string);
|
||||
}
|
||||
|
||||
fx_err("invalid value '" F_YELLOW "%s" F_RESET "' for '" F_YELLOW
|
||||
"%s" F_RESET "'.",
|
||||
value, fx_string_get_cstr(opt_string));
|
||||
|
||||
if (opt) {
|
||||
fx_i("'" F_YELLOW "%s" F_RESET
|
||||
"' accepts the following values for '" F_YELLOW "%s" F_RESET
|
||||
"':",
|
||||
fx_string_get_cstr(opt_string), arg->arg_name);
|
||||
} else {
|
||||
fx_i("'" F_YELLOW "%s" F_RESET "' accepts the following values:",
|
||||
fx_string_get_cstr(opt_string));
|
||||
}
|
||||
|
||||
for (int i = 0; arg->arg_allowed_values[i]; i++) {
|
||||
fx_printf(
|
||||
" * " F_GREEN "%s" F_RESET "\n",
|
||||
arg->arg_allowed_values[i]);
|
||||
}
|
||||
|
||||
fx_printf("\n");
|
||||
fx_i("usage: %s", fx_string_get_cstr(usage));
|
||||
fx_i("for more information, use '" F_YELLOW "--help" F_RESET);
|
||||
|
||||
fx_string_unref(usage);
|
||||
fx_string_unref(opt_string);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
enum fx_status fx_arglist_report_missing_args(
|
||||
const fx_arglist *args, unsigned int opt_id, unsigned int arg_id,
|
||||
size_t args_supplied)
|
||||
{
|
||||
struct fx_command_option *opt = NULL;
|
||||
struct fx_command_arg *arg = NULL;
|
||||
|
||||
if (opt_id != FX_COMMAND_INVALID_ID) {
|
||||
opt = fx_command_get_option_with_id(args->list_command, opt_id);
|
||||
assert(opt);
|
||||
}
|
||||
|
||||
if (arg_id != FX_COMMAND_INVALID_ID) {
|
||||
arg = opt ? fx_command_option_get_arg_with_id(opt, arg_id)
|
||||
: fx_command_get_arg_with_id(args->list_command, arg_id);
|
||||
assert(arg);
|
||||
}
|
||||
|
||||
fx_string *usage = z__fx_command_default_usage_string(
|
||||
args->list_command, opt, args);
|
||||
fx_string *opt_string = fx_string_create();
|
||||
|
||||
if (opt) {
|
||||
z__fx_get_option_usage_string(opt, 0, opt_string);
|
||||
} else {
|
||||
z__fx_get_arg_usage_string(arg, 0, opt_string);
|
||||
}
|
||||
|
||||
char supplied_arg_str[64];
|
||||
if (args_supplied == 0) {
|
||||
snprintf(
|
||||
supplied_arg_str, sizeof supplied_arg_str,
|
||||
F_RED_BOLD "none" F_RESET " were provided");
|
||||
} else if (args_supplied == 1) {
|
||||
snprintf(
|
||||
supplied_arg_str, sizeof supplied_arg_str,
|
||||
"only " F_YELLOW_BOLD "%zu" F_RESET " was provided",
|
||||
args_supplied);
|
||||
} else {
|
||||
snprintf(
|
||||
supplied_arg_str, sizeof supplied_arg_str,
|
||||
"only " F_YELLOW_BOLD "%zu" F_RESET " were provided",
|
||||
args_supplied);
|
||||
}
|
||||
|
||||
char required_arg_count[64];
|
||||
switch (arg->arg_nr_values) {
|
||||
case FX_ARG_1_OR_MORE_VALUES:
|
||||
snprintf(
|
||||
required_arg_count, sizeof required_arg_count,
|
||||
"one or more");
|
||||
break;
|
||||
default:
|
||||
snprintf(
|
||||
required_arg_count, sizeof required_arg_count, "%d",
|
||||
arg->arg_nr_values);
|
||||
}
|
||||
|
||||
fx_err("argument `" F_YELLOW "%s" F_RESET "` requires " F_GREEN_BOLD
|
||||
"%s" F_RESET " `" F_YELLOW "%s" F_RESET "` value%s, but %s.",
|
||||
fx_string_get_cstr(opt_string), required_arg_count, arg->arg_name,
|
||||
(arg->arg_nr_values == 1) ? "" : "s", supplied_arg_str);
|
||||
fx_i("usage: %s", fx_string_get_cstr(usage));
|
||||
fx_i("for more information, use '" F_YELLOW "--help" F_RESET "'");
|
||||
|
||||
fx_string_unref(usage);
|
||||
fx_string_unref(opt_string);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
include(../cmake/Templates.cmake)
|
||||
|
||||
add_fx_module(NAME ds DEPENDENCIES core)
|
||||
@@ -0,0 +1,528 @@
|
||||
#include <fx/core/iterator.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <fx/ds/array.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_array_p {
|
||||
/* number of items in array */
|
||||
size_t ar_len;
|
||||
/* maximum number of items that can currently be stored in array */
|
||||
size_t ar_cap;
|
||||
fx_object **ar_data;
|
||||
};
|
||||
|
||||
struct fx_array_iterator_p {
|
||||
fx_array *_a;
|
||||
struct fx_array_p *_a_p;
|
||||
|
||||
/** The index of the current value */
|
||||
size_t i;
|
||||
/** The current value */
|
||||
fx_object *value;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static fx_status resize_array(struct fx_array_p *array, size_t new_capacity)
|
||||
{
|
||||
if (array->ar_cap < new_capacity) {
|
||||
void *new_data = realloc(
|
||||
array->ar_data,
|
||||
new_capacity * sizeof(struct fx_dsref *));
|
||||
if (!new_data) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
array->ar_data = new_data;
|
||||
} else {
|
||||
for (size_t i = new_capacity; i < array->ar_len; i++) {
|
||||
fx_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
void *new_data = realloc(
|
||||
array->ar_data,
|
||||
new_capacity * sizeof(struct fx_dsref *));
|
||||
if (!new_data) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
array->ar_data = new_data;
|
||||
}
|
||||
|
||||
array->ar_cap = new_capacity;
|
||||
if (array->ar_len > new_capacity) {
|
||||
array->ar_len = new_capacity;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status array_insert(
|
||||
struct fx_array_p *array,
|
||||
fx_object *value,
|
||||
size_t at)
|
||||
{
|
||||
if (at == FX_NPOS) {
|
||||
at = array->ar_len;
|
||||
}
|
||||
|
||||
if (at > array->ar_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
fx_status status = FX_SUCCESS;
|
||||
|
||||
if (array->ar_len + 1 > array->ar_cap) {
|
||||
status = resize_array(array, array->ar_cap + 8);
|
||||
|
||||
if (status != FX_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
fx_object **src = array->ar_data + at;
|
||||
fx_object **dest = src + 1;
|
||||
size_t move_len = (array->ar_len - at) * sizeof(struct fx_dsref *);
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
array->ar_data[at] = fx_object_ref(value);
|
||||
array->ar_len++;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status array_remove(struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
fx_object **src = array->ar_data + at;
|
||||
fx_object **dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(struct fx_dsref *);
|
||||
|
||||
fx_object_unref(array->ar_data[at]);
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
array->ar_len--;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status array_remove_front(struct fx_array_p *array)
|
||||
{
|
||||
return array_remove(array, 0);
|
||||
}
|
||||
|
||||
static fx_status array_remove_back(struct fx_array_p *array)
|
||||
{
|
||||
return array_remove(array, array->ar_len - 1);
|
||||
}
|
||||
|
||||
static fx_object *array_pop(struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fx_object **src = array->ar_data + at;
|
||||
fx_object **dest = src + 1;
|
||||
size_t move_len = array->ar_len * sizeof(struct fx_dsref *);
|
||||
|
||||
fx_object *out = array->ar_data[at];
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
array->ar_len--;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static fx_object *array_pop_front(struct fx_array_p *array)
|
||||
{
|
||||
return array_pop(array, 0);
|
||||
}
|
||||
|
||||
static fx_object *array_pop_back(struct fx_array_p *array)
|
||||
{
|
||||
return array_pop(array, array->ar_len - 1);
|
||||
}
|
||||
|
||||
static fx_object *array_at(const struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return array->ar_data[at];
|
||||
}
|
||||
|
||||
static fx_object *array_get(struct fx_array_p *array, size_t at)
|
||||
{
|
||||
if (at >= array->ar_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fx_object_ref(array->ar_data[at]);
|
||||
}
|
||||
|
||||
static size_t array_size(const struct fx_array_p *array)
|
||||
{
|
||||
return array->ar_len;
|
||||
}
|
||||
|
||||
static size_t array_capacity(const struct fx_array_p *array)
|
||||
{
|
||||
return array->ar_cap;
|
||||
}
|
||||
|
||||
static void array_clear(struct fx_array_p *array)
|
||||
{
|
||||
if (!array->ar_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
fx_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
memset(array->ar_data, 0x0, array->ar_cap * sizeof(fx_object *));
|
||||
array->ar_len = 0;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_array *fx_array_create_with_values(
|
||||
fx_object *const *values,
|
||||
size_t nr_values)
|
||||
{
|
||||
fx_array *array = fx_array_create();
|
||||
if (!array) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_array_p *p = fx_object_get_private(array, FX_TYPE_ARRAY);
|
||||
|
||||
size_t real_nr_values = 0;
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
if (values[i]) {
|
||||
real_nr_values++;
|
||||
}
|
||||
}
|
||||
|
||||
p->ar_len = real_nr_values;
|
||||
p->ar_cap = real_nr_values;
|
||||
p->ar_data = calloc(real_nr_values, sizeof(struct fx_dsref *));
|
||||
if (!p->ar_data) {
|
||||
fx_array_unref(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < nr_values; i++) {
|
||||
p->ar_data[index++] = fx_object_ref(values[i]);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_insert, array, value, at);
|
||||
}
|
||||
|
||||
fx_status fx_array_remove(fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_remove, array, at);
|
||||
}
|
||||
|
||||
fx_status fx_array_remove_front(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_front, array);
|
||||
}
|
||||
|
||||
fx_status fx_array_remove_back(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_remove_back, array);
|
||||
}
|
||||
|
||||
fx_object *fx_array_pop(fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_pop, array, at);
|
||||
}
|
||||
|
||||
fx_object *fx_array_pop_front(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_front, array);
|
||||
}
|
||||
|
||||
fx_object *fx_array_pop_back(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_pop_back, array);
|
||||
}
|
||||
|
||||
fx_object *fx_array_at(const fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_at, array, at);
|
||||
}
|
||||
|
||||
fx_object *fx_array_get(fx_array *array, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_ARRAY, array_get, array, at);
|
||||
}
|
||||
|
||||
size_t fx_array_size(const fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_size, array);
|
||||
}
|
||||
|
||||
size_t fx_array_capacity(const fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_capacity, array);
|
||||
}
|
||||
|
||||
void fx_array_clear(fx_array *array)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_ARRAY, array_clear, array);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
fx_status fx_array_append(fx_array *array, fx_object *value)
|
||||
{
|
||||
return fx_array_insert(array, value, FX_NPOS);
|
||||
}
|
||||
|
||||
fx_status fx_array_prepend(fx_array *array, fx_object *value)
|
||||
{
|
||||
return fx_array_insert(array, value, 0);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void array_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_array_p *array = priv;
|
||||
}
|
||||
|
||||
static void array_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_array_p *array = priv;
|
||||
|
||||
if (array->ar_data) {
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
fx_object_unref(array->ar_data[i]);
|
||||
}
|
||||
|
||||
free(array->ar_data);
|
||||
array->ar_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void array_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_array_p *array = fx_object_get_private(obj, FX_TYPE_ARRAY);
|
||||
|
||||
if (!array->ar_len) {
|
||||
fx_stream_write_cstr(out, "[]", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(out, "[\n", NULL);
|
||||
|
||||
fx_stream_push_indent(out, 1);
|
||||
size_t len = array_size(array);
|
||||
|
||||
for (size_t i = 0; i < array->ar_len; i++) {
|
||||
fx_object *value = array->ar_data[i];
|
||||
bool is_string = fx_object_is_type(value, FX_TYPE_STRING);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_object_to_string(value, out);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
if (i < len - 1) {
|
||||
fx_stream_write_cstr(out, ",", NULL);
|
||||
}
|
||||
|
||||
fx_stream_write_char(out, '\n');
|
||||
}
|
||||
|
||||
fx_stream_pop_indent(out);
|
||||
fx_stream_write_char(out, ']');
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static fx_iterator *iterable_begin(fx_object *obj)
|
||||
{
|
||||
fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
it->_a = obj;
|
||||
it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY);
|
||||
it->i = 0;
|
||||
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterable_cbegin(const fx_object *obj)
|
||||
{
|
||||
fx_array_iterator *it_obj = fx_object_create(FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
it->_a = (fx_array *)obj;
|
||||
it->_a_p = fx_object_get_private(obj, FX_TYPE_ARRAY);
|
||||
it->i = 0;
|
||||
|
||||
if (it->_a_p->ar_len > 0) {
|
||||
it->value = it->_a_p->ar_data[0];
|
||||
} else {
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
|
||||
if (it->value == NULL || it->i >= array->ar_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
it->value = NULL;
|
||||
} else {
|
||||
it->value = array->ar_data[it->i];
|
||||
}
|
||||
|
||||
return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
if (array->ar_data[it->i] != it->value) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
array_remove(array, it->i);
|
||||
|
||||
if (it->i < array->ar_len) {
|
||||
it->value = array->ar_data[it->i];
|
||||
} else {
|
||||
it->value = NULL;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_PTR(it->value);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(it->value);
|
||||
}
|
||||
|
||||
static enum fx_status iterator_is_valid(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_array_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_ARRAY_ITERATOR);
|
||||
struct fx_array_p *array = it->_a_p;
|
||||
|
||||
if (it->i >= array->ar_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (array->ar_data[it->i] != it->value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (it->value != NULL) ? FX_SUCCESS : FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_array DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = array_to_string;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_array)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_array)
|
||||
FX_TYPE_ID(0xe3c46da1, 0x5f37, 0x4e44, 0xb53b, 0xff5a6200191b);
|
||||
FX_TYPE_CLASS(fx_array_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_array_p);
|
||||
FX_TYPE_INSTANCE_INIT(array_init);
|
||||
FX_TYPE_INSTANCE_FINI(array_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_array)
|
||||
|
||||
// ---- fx_array_iterator DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_array_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_ID(0xe5e9e8b8, 0x14cb, 0x4192, 0x8138, 0xf45238a2ae73);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_array_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_array_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_array_iterator)
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <fx/ds/bitbuffer.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_bitbuffer_p {
|
||||
int x;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void bitbuffer_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_bitbuffer_p *bitbuffer = priv;
|
||||
}
|
||||
|
||||
static void bitbuffer_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_bitbuffer_p *bitbuffer = priv;
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bitbuffer)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_bitbuffer)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_bitbuffer)
|
||||
FX_TYPE_ID(0x628e33da, 0x3109, 0x4a5d, 0x98d5, 0xb0e4cb3ccb65);
|
||||
FX_TYPE_CLASS(fx_bitbuffer_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_bitbuffer_p);
|
||||
FX_TYPE_INSTANCE_INIT(bitbuffer_init);
|
||||
FX_TYPE_INSTANCE_FINI(bitbuffer_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_bitbuffer)
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <blue/core/bitop.h>
|
||||
#include <blue/core/stream.h>
|
||||
#include <blue/ds/bitmap.h>
|
||||
#include <fx/core/bitop.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <fx/ds/bitmap.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BITS_PER_WORD (8 * sizeof(bitmap_word_t))
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
typedef unsigned long bitmap_word_t;
|
||||
|
||||
struct b_bitmap_p {
|
||||
struct fx_bitmap_p {
|
||||
bitmap_word_t *map_words;
|
||||
size_t map_nr_words, map_nr_bits;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static void bitmap_set_bit(struct b_bitmap_p *map, size_t bit)
|
||||
static void bitmap_set_bit(struct fx_bitmap_p *map, size_t bit)
|
||||
{
|
||||
unsigned long index = bit / BITS_PER_WORD;
|
||||
unsigned long offset = (BITS_PER_WORD - bit - 1) & (BITS_PER_WORD - 1);
|
||||
@@ -27,7 +27,7 @@ static void bitmap_set_bit(struct b_bitmap_p *map, size_t bit)
|
||||
map->map_words[index] |= mask;
|
||||
}
|
||||
|
||||
static void bitmap_clear_bit(struct b_bitmap_p *map, size_t bit)
|
||||
static void bitmap_clear_bit(struct fx_bitmap_p *map, size_t bit)
|
||||
{
|
||||
unsigned long index = bit / BITS_PER_WORD;
|
||||
unsigned long offset = bit & (BITS_PER_WORD - 1);
|
||||
@@ -36,25 +36,25 @@ static void bitmap_clear_bit(struct b_bitmap_p *map, size_t bit)
|
||||
map->map_words[index] &= ~mask;
|
||||
}
|
||||
|
||||
static void bitmap_set_range(struct b_bitmap_p *map, size_t first_bit, size_t nbits)
|
||||
static void bitmap_set_range(struct fx_bitmap_p *map, size_t first_bit, size_t nbits)
|
||||
{
|
||||
}
|
||||
|
||||
static void bitmap_clear_range(struct b_bitmap_p *map, size_t first_bit, size_t nbits)
|
||||
static void bitmap_clear_range(struct fx_bitmap_p *map, size_t first_bit, size_t nbits)
|
||||
{
|
||||
}
|
||||
|
||||
static void bitmap_set_all(struct b_bitmap_p *map)
|
||||
static void bitmap_set_all(struct fx_bitmap_p *map)
|
||||
{
|
||||
memset(map->map_words, 0xFF, map->map_nr_words * sizeof(bitmap_word_t));
|
||||
}
|
||||
|
||||
static void bitmap_clear_all(struct b_bitmap_p *map)
|
||||
static void bitmap_clear_all(struct fx_bitmap_p *map)
|
||||
{
|
||||
memset(map->map_words, 0x00, map->map_nr_words * sizeof(bitmap_word_t));
|
||||
}
|
||||
|
||||
static bool bitmap_check_bit(const struct b_bitmap_p *map, size_t bit)
|
||||
static bool bitmap_check_bit(const struct fx_bitmap_p *map, size_t bit)
|
||||
{
|
||||
unsigned long index = bit / BITS_PER_WORD;
|
||||
unsigned long offset = (BITS_PER_WORD - bit - 1) & (BITS_PER_WORD - 1);
|
||||
@@ -63,12 +63,12 @@ static bool bitmap_check_bit(const struct b_bitmap_p *map, size_t bit)
|
||||
return (map->map_words[index] & mask) != 0;
|
||||
}
|
||||
|
||||
static size_t bitmap_count_set_bits(const struct b_bitmap_p *map)
|
||||
static size_t bitmap_count_set_bits(const struct fx_bitmap_p *map)
|
||||
{
|
||||
size_t set_bits = 0;
|
||||
|
||||
for (size_t i = 0; i < map->map_nr_words; i++) {
|
||||
set_bits += b_popcountl(map->map_words[i]);
|
||||
set_bits += fx_popcountl(map->map_words[i]);
|
||||
}
|
||||
|
||||
if (set_bits > map->map_nr_bits) {
|
||||
@@ -78,12 +78,12 @@ static size_t bitmap_count_set_bits(const struct b_bitmap_p *map)
|
||||
return set_bits;
|
||||
}
|
||||
|
||||
static size_t bitmap_count_clear_bits(const struct b_bitmap_p *map)
|
||||
static size_t bitmap_count_clear_bits(const struct fx_bitmap_p *map)
|
||||
{
|
||||
size_t clear_bits = 0;
|
||||
|
||||
for (size_t i = 0; i < map->map_nr_words; i++) {
|
||||
clear_bits += b_popcountl(~map->map_words[i]);
|
||||
clear_bits += fx_popcountl(~map->map_words[i]);
|
||||
}
|
||||
|
||||
if (clear_bits > map->map_nr_bits) {
|
||||
@@ -93,7 +93,7 @@ static size_t bitmap_count_clear_bits(const struct b_bitmap_p *map)
|
||||
return clear_bits;
|
||||
}
|
||||
|
||||
static size_t bitmap_highest_set_bit(const struct b_bitmap_p *map)
|
||||
static size_t bitmap_highest_set_bit(const struct fx_bitmap_p *map)
|
||||
{
|
||||
unsigned long bit_index = 0;
|
||||
bitmap_word_t last_word = 0;
|
||||
@@ -107,13 +107,13 @@ static size_t bitmap_highest_set_bit(const struct b_bitmap_p *map)
|
||||
}
|
||||
|
||||
if (last_word == 0x00) {
|
||||
return B_NPOS;
|
||||
return FX_NPOS;
|
||||
}
|
||||
|
||||
return bit_index + (BITS_PER_WORD - b_ctzl(last_word) - 1);
|
||||
return bit_index + (BITS_PER_WORD - fx_ctzl(last_word) - 1);
|
||||
}
|
||||
|
||||
static size_t bitmap_highest_clear_bit(const struct b_bitmap_p *map)
|
||||
static size_t bitmap_highest_clear_bit(const struct fx_bitmap_p *map)
|
||||
{
|
||||
unsigned long bit_index = 0;
|
||||
bitmap_word_t last_word = ~(bitmap_word_t)0;
|
||||
@@ -126,17 +126,17 @@ static size_t bitmap_highest_clear_bit(const struct b_bitmap_p *map)
|
||||
}
|
||||
|
||||
if (last_word == ~(unsigned long)0) {
|
||||
return B_NPOS;
|
||||
return FX_NPOS;
|
||||
}
|
||||
|
||||
if (last_word == 0) {
|
||||
return bit_index + BITS_PER_WORD - 1;
|
||||
}
|
||||
|
||||
return bit_index + (BITS_PER_WORD - b_ctzl(~last_word)) - 1;
|
||||
return bit_index + (BITS_PER_WORD - fx_ctzl(~last_word)) - 1;
|
||||
}
|
||||
|
||||
static size_t bitmap_lowest_set_bit(const struct b_bitmap_p *map)
|
||||
static size_t bitmap_lowest_set_bit(const struct fx_bitmap_p *map)
|
||||
{
|
||||
unsigned long bit_index = 0;
|
||||
bitmap_word_t last_word = 0;
|
||||
@@ -151,13 +151,13 @@ static size_t bitmap_lowest_set_bit(const struct b_bitmap_p *map)
|
||||
}
|
||||
|
||||
if (last_word == 0x00) {
|
||||
return B_NPOS;
|
||||
return FX_NPOS;
|
||||
}
|
||||
|
||||
return bit_index + b_clzl(last_word);
|
||||
return bit_index + fx_clzl(last_word);
|
||||
}
|
||||
|
||||
static size_t bitmap_lowest_clear_bit(const struct b_bitmap_p *map)
|
||||
static size_t bitmap_lowest_clear_bit(const struct fx_bitmap_p *map)
|
||||
{
|
||||
unsigned long bit_index = 0;
|
||||
bitmap_word_t last_word = 0;
|
||||
@@ -176,116 +176,116 @@ static size_t bitmap_lowest_clear_bit(const struct b_bitmap_p *map)
|
||||
}
|
||||
|
||||
if (last_word == (~(bitmap_word_t)0)) {
|
||||
return B_NPOS;
|
||||
return FX_NPOS;
|
||||
}
|
||||
|
||||
return bit_index + b_clzl(~last_word);
|
||||
return bit_index + fx_clzl(~last_word);
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_bitmap *b_bitmap_create(size_t nr_bits)
|
||||
fx_bitmap *fx_bitmap_create(size_t nr_bits)
|
||||
{
|
||||
b_bitmap *map = b_object_create(B_TYPE_BITMAP);
|
||||
fx_bitmap *map = fx_object_create(FX_TYPE_BITMAP);
|
||||
if (!map) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_bitmap_p *p = b_object_get_private(map, B_TYPE_BITMAP);
|
||||
struct fx_bitmap_p *p = fx_object_get_private(map, FX_TYPE_BITMAP);
|
||||
p->map_nr_bits = nr_bits;
|
||||
p->map_nr_words = BITMAP_WORDS(nr_bits);
|
||||
p->map_words = calloc(p->map_nr_words, sizeof(bitmap_word_t));
|
||||
if (!p->map_words) {
|
||||
b_bitmap_unref(map);
|
||||
fx_bitmap_unref(map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void b_bitmap_set_bit(b_bitmap *map, size_t bit)
|
||||
void fx_bitmap_set_bit(fx_bitmap *map, size_t bit)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_V(B_TYPE_BITMAP, bitmap_set_bit, map, bit);
|
||||
FX_CLASS_DISPATCH_STATIC_V(FX_TYPE_BITMAP, bitmap_set_bit, map, bit);
|
||||
}
|
||||
|
||||
void b_bitmap_clear_bit(b_bitmap *map, size_t bit)
|
||||
void fx_bitmap_clear_bit(fx_bitmap *map, size_t bit)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_V(B_TYPE_BITMAP, bitmap_clear_bit, map, bit);
|
||||
FX_CLASS_DISPATCH_STATIC_V(FX_TYPE_BITMAP, bitmap_clear_bit, map, bit);
|
||||
}
|
||||
|
||||
void b_bitmap_set_range(b_bitmap *map, size_t first_bit, size_t nbits)
|
||||
void fx_bitmap_set_range(fx_bitmap *map, size_t first_bit, size_t nbits)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_V(
|
||||
B_TYPE_BITMAP, bitmap_set_range, map, first_bit, nbits);
|
||||
FX_CLASS_DISPATCH_STATIC_V(
|
||||
FX_TYPE_BITMAP, bitmap_set_range, map, first_bit, nbits);
|
||||
}
|
||||
|
||||
void b_bitmap_clear_range(b_bitmap *map, size_t first_bit, size_t nbits)
|
||||
void fx_bitmap_clear_range(fx_bitmap *map, size_t first_bit, size_t nbits)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_V(
|
||||
B_TYPE_BITMAP, bitmap_clear_range, map, first_bit, nbits);
|
||||
FX_CLASS_DISPATCH_STATIC_V(
|
||||
FX_TYPE_BITMAP, bitmap_clear_range, map, first_bit, nbits);
|
||||
}
|
||||
|
||||
void b_bitmap_set_all(b_bitmap *map)
|
||||
void fx_bitmap_set_all(fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_V0(B_TYPE_BITMAP, bitmap_set_all, map);
|
||||
FX_CLASS_DISPATCH_STATIC_V0(FX_TYPE_BITMAP, bitmap_set_all, map);
|
||||
}
|
||||
|
||||
void b_bitmap_clear_all(b_bitmap *map)
|
||||
void fx_bitmap_clear_all(fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_V0(B_TYPE_BITMAP, bitmap_clear_all, map);
|
||||
FX_CLASS_DISPATCH_STATIC_V0(FX_TYPE_BITMAP, bitmap_clear_all, map);
|
||||
}
|
||||
|
||||
bool b_bitmap_check_bit(const b_bitmap *map, size_t bit)
|
||||
bool fx_bitmap_check_bit(const fx_bitmap *map, size_t bit)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(B_TYPE_BITMAP, bitmap_check_bit, map, bit);
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BITMAP, bitmap_check_bit, map, bit);
|
||||
}
|
||||
|
||||
size_t b_bitmap_count_set_bits(const b_bitmap *map)
|
||||
size_t fx_bitmap_count_set_bits(const fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BITMAP, bitmap_count_set_bits, map);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_count_set_bits, map);
|
||||
}
|
||||
|
||||
size_t b_bitmap_count_clear_bits(const b_bitmap *map)
|
||||
size_t fx_bitmap_count_clear_bits(const fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BITMAP, bitmap_count_clear_bits, map);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_count_clear_bits, map);
|
||||
}
|
||||
|
||||
size_t b_bitmap_highest_set_bit(const b_bitmap *map)
|
||||
size_t fx_bitmap_highest_set_bit(const fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BITMAP, bitmap_highest_set_bit, map);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_highest_set_bit, map);
|
||||
}
|
||||
|
||||
size_t b_bitmap_highest_clear_bit(const b_bitmap *map)
|
||||
size_t fx_bitmap_highest_clear_bit(const fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BITMAP, bitmap_highest_clear_bit, map);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_highest_clear_bit, map);
|
||||
}
|
||||
|
||||
size_t b_bitmap_lowest_set_bit(const b_bitmap *map)
|
||||
size_t fx_bitmap_lowest_set_bit(const fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BITMAP, bitmap_lowest_set_bit, map);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_lowest_set_bit, map);
|
||||
}
|
||||
|
||||
size_t b_bitmap_lowest_clear_bit(const b_bitmap *map)
|
||||
size_t fx_bitmap_lowest_clear_bit(const fx_bitmap *map)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_BITMAP, bitmap_lowest_clear_bit, map);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BITMAP, bitmap_lowest_clear_bit, map);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void bitmap_init(b_object *obj, void *priv)
|
||||
static void bitmap_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct b_bitmap_p *map = priv;
|
||||
struct fx_bitmap_p *map = priv;
|
||||
}
|
||||
|
||||
static void bitmap_fini(b_object *obj, void *priv)
|
||||
static void bitmap_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct b_bitmap_p *map = priv;
|
||||
struct fx_bitmap_p *map = priv;
|
||||
}
|
||||
|
||||
static void bitmap_to_string(const b_object *obj, b_stream *out)
|
||||
static void bitmap_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
const struct b_bitmap_p *map = b_object_get_private(obj, B_TYPE_BITMAP);
|
||||
const struct fx_bitmap_p *map = fx_object_get_private(obj, FX_TYPE_BITMAP);
|
||||
|
||||
unsigned char *bytes = (unsigned char *)map->map_words;
|
||||
size_t nr_bytes = map->map_nr_words * sizeof(bitmap_word_t);
|
||||
@@ -293,7 +293,7 @@ static void bitmap_to_string(const b_object *obj, b_stream *out)
|
||||
|
||||
for (size_t i = 0; i < nr_bytes - 1; i++) {
|
||||
c = bytes[i];
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, "%c%c%c%c%c%c%c%c", c & 0x80 ? '1' : '0',
|
||||
c & 0x40 ? '1' : '0', c & 0x20 ? '1' : '0',
|
||||
c & 0x10 ? '1' : '0', c & 0x08 ? '1' : '0',
|
||||
@@ -307,24 +307,24 @@ static void bitmap_to_string(const b_object *obj, b_stream *out)
|
||||
|
||||
for (size_t i = 0; i < remaining_bits; i++) {
|
||||
|
||||
b_stream_write_fmt(out, NULL, "%c", (c & mask) ? '1' : '0');
|
||||
fx_stream_write_fmt(out, NULL, "%c", (c & mask) ? '1' : '0');
|
||||
}
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_bitmap)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = bitmap_to_string;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_bitmap)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_bitmap)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = bitmap_to_string;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_bitmap)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_bitmap)
|
||||
B_TYPE_ID(0xea115cef, 0x8a63, 0x445f, 0x9474, 0xba9309d5dde8);
|
||||
B_TYPE_CLASS(b_bitmap_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_bitmap_p);
|
||||
B_TYPE_INSTANCE_INIT(bitmap_init);
|
||||
B_TYPE_INSTANCE_FINI(bitmap_fini);
|
||||
B_TYPE_DEFINITION_END(b_bitmap)
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_bitmap)
|
||||
FX_TYPE_ID(0xea115cef, 0x8a63, 0x445f, 0x9474, 0xba9309d5dde8);
|
||||
FX_TYPE_CLASS(fx_bitmap_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_bitmap_p);
|
||||
FX_TYPE_INSTANCE_INIT(bitmap_init);
|
||||
FX_TYPE_INSTANCE_FINI(bitmap_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_bitmap)
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
@@ -0,0 +1,441 @@
|
||||
#include <fx/core/iterator.h>
|
||||
#include <fx/ds/buffer.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_buffer_p {
|
||||
/* number of items in buffer */
|
||||
unsigned int buf_len;
|
||||
/* maximum number of items that can currently be stored in array */
|
||||
unsigned int buf_cap;
|
||||
/* the size of each individual item in the buffer */
|
||||
unsigned int buf_itemsz;
|
||||
void *buf_data;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static fx_status resize_buffer(struct fx_buffer_p *buffer, size_t new_capacity)
|
||||
{
|
||||
if (buffer->buf_cap < new_capacity) {
|
||||
void *new_data = realloc(
|
||||
buffer->buf_data, new_capacity * buffer->buf_itemsz);
|
||||
if (!new_data) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
buffer->buf_data = new_data;
|
||||
} else {
|
||||
void *new_data = realloc(
|
||||
buffer->buf_data, new_capacity * buffer->buf_itemsz);
|
||||
if (!new_data) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
buffer->buf_data = new_data;
|
||||
}
|
||||
|
||||
buffer->buf_cap = new_capacity;
|
||||
if (buffer->buf_len > new_capacity) {
|
||||
buffer->buf_len = new_capacity;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static void *buffer_steal(struct fx_buffer_p *buf)
|
||||
{
|
||||
void *p = buf->buf_data;
|
||||
|
||||
buf->buf_data = NULL;
|
||||
buf->buf_len = 0;
|
||||
buf->buf_cap = 0;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_reserve(struct fx_buffer_p *buf, size_t capacity)
|
||||
{
|
||||
if (buf->buf_cap >= capacity) {
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
return resize_buffer(buf, capacity);
|
||||
}
|
||||
|
||||
static enum fx_status buffer_resize(struct fx_buffer_p *buf, size_t length)
|
||||
{
|
||||
enum fx_status status = resize_buffer(buf, length);
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
buf->buf_len = length;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_insert(
|
||||
struct fx_buffer_p *buffer, const void *p, size_t count, size_t at)
|
||||
{
|
||||
if (at == FX_NPOS) {
|
||||
at = buffer->buf_len;
|
||||
}
|
||||
|
||||
if (at > buffer->buf_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
fx_status status = FX_SUCCESS;
|
||||
|
||||
if (buffer->buf_len + count > buffer->buf_cap) {
|
||||
status = resize_buffer(buffer, buffer->buf_cap + count);
|
||||
|
||||
if (status != FX_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *src
|
||||
= (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
|
||||
unsigned char *dest = src + (count * buffer->buf_itemsz);
|
||||
size_t move_len = (buffer->buf_len - at) * buffer->buf_itemsz;
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
memcpy(src, p, count * buffer->buf_itemsz);
|
||||
|
||||
buffer->buf_len += count;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_remove(struct fx_buffer_p *buffer, size_t at, size_t count)
|
||||
{
|
||||
if (at >= buffer->buf_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
if (at + count >= buffer->buf_len) {
|
||||
count = buffer->buf_len - at;
|
||||
}
|
||||
|
||||
unsigned char *dest = buffer->buf_data + (at * buffer->buf_itemsz);
|
||||
unsigned char *src = dest + (count * buffer->buf_itemsz);
|
||||
size_t move_len = (buffer->buf_len - at - count) * buffer->buf_itemsz;
|
||||
|
||||
memmove(dest, src, move_len);
|
||||
|
||||
buffer->buf_len -= count;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static void *buffer_ptr(const struct fx_buffer_p *buffer)
|
||||
{
|
||||
return buffer->buf_data;
|
||||
}
|
||||
|
||||
static void *buffer_get(const struct fx_buffer_p *buffer, size_t at)
|
||||
{
|
||||
if (at >= buffer->buf_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (unsigned char *)buffer->buf_data + (at * buffer->buf_itemsz);
|
||||
}
|
||||
|
||||
static size_t buffer_size(const struct fx_buffer_p *buffer)
|
||||
{
|
||||
return buffer->buf_len;
|
||||
}
|
||||
|
||||
static size_t buffer_capacity(const struct fx_buffer_p *buffer)
|
||||
{
|
||||
return buffer->buf_cap;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_clear(struct fx_buffer_p *buffer)
|
||||
{
|
||||
buffer->buf_len = 0;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_push_back(
|
||||
struct fx_buffer_p *buf, size_t count, void **p)
|
||||
{
|
||||
enum fx_status status = FX_SUCCESS;
|
||||
|
||||
if (buf->buf_len + count > buf->buf_cap) {
|
||||
status = resize_buffer(buf, buf->buf_len + count);
|
||||
}
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
buf->buf_len += count;
|
||||
*p = buffer_get(buf, buf->buf_len - count);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_push_front(
|
||||
struct fx_buffer_p *buf, size_t count, void **p)
|
||||
{
|
||||
enum fx_status status = FX_SUCCESS;
|
||||
|
||||
if (buf->buf_len + count > buf->buf_cap) {
|
||||
status = resize_buffer(buf, buf->buf_len + count);
|
||||
}
|
||||
|
||||
if (!FX_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
void *src = buf->buf_data;
|
||||
void *dest = fx_buffer_get(buf->buf_data, count);
|
||||
size_t len = count * buf->buf_itemsz;
|
||||
|
||||
memmove(dest, src, len);
|
||||
buf->buf_len += count;
|
||||
|
||||
*p = buffer_get(buf, 0);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_pop_back(struct fx_buffer_p *buf, size_t count)
|
||||
{
|
||||
if (count > buf->buf_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
buf->buf_len -= count;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status buffer_pop_front(struct fx_buffer_p *buf, size_t count)
|
||||
{
|
||||
if (count > buf->buf_len) {
|
||||
return FX_ERR_OUT_OF_BOUNDS;
|
||||
}
|
||||
|
||||
void *src = fx_buffer_get(buf->buf_data, count);
|
||||
void *dest = buf->buf_data;
|
||||
size_t len = (buf->buf_len - count) * buf->buf_itemsz;
|
||||
|
||||
memmove(dest, src, len);
|
||||
buf->buf_len -= count;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static size_t buffer_get_size(const struct fx_buffer_p *buf)
|
||||
{
|
||||
return buf->buf_len;
|
||||
}
|
||||
|
||||
static size_t buffer_get_item_size(const struct fx_buffer_p *buf)
|
||||
{
|
||||
return buf->buf_itemsz;
|
||||
}
|
||||
|
||||
static size_t buffer_get_capacity(const struct fx_buffer_p *buf)
|
||||
{
|
||||
return buf->buf_cap;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_buffer *fx_buffer_create(size_t item_sz)
|
||||
{
|
||||
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
|
||||
|
||||
p->buf_itemsz = item_sz;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
fx_buffer *fx_buffer_create_from_bytes(const void *buf, size_t len)
|
||||
{
|
||||
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
|
||||
|
||||
p->buf_len = len;
|
||||
p->buf_cap = len;
|
||||
p->buf_itemsz = 1;
|
||||
p->buf_data = calloc(len, 1);
|
||||
if (!p->buf_data) {
|
||||
fx_buffer_unref(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(p->buf_data, buf, len);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
fx_buffer *fx_buffer_create_from_array(const void *buf, size_t item_sz, size_t len)
|
||||
{
|
||||
fx_buffer *buffer = fx_object_create(FX_TYPE_BUFFER);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_buffer_p *p = fx_object_get_private(buffer, FX_TYPE_BUFFER);
|
||||
|
||||
p->buf_len = len;
|
||||
p->buf_cap = len;
|
||||
p->buf_itemsz = item_sz;
|
||||
p->buf_data = calloc(len, item_sz);
|
||||
if (!p->buf_data) {
|
||||
fx_buffer_unref(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(p->buf_data, buf, len * item_sz);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void *fx_buffer_steal(fx_buffer *buf)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_steal, buf);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_reserve(fx_buffer *buf, size_t capacity)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_reserve, buf, capacity);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_resize(fx_buffer *buf, size_t length)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_resize, buf, length);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_insert(
|
||||
fx_buffer *buffer, const void *p, size_t count, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_insert, buffer, p, count, at);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_remove(fx_buffer *buffer, size_t at, size_t count)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_remove, buffer, at, count);
|
||||
}
|
||||
|
||||
void *fx_buffer_ptr(const fx_buffer *buffer)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_ptr, buffer);
|
||||
}
|
||||
|
||||
void *fx_buffer_get(const fx_buffer *buffer, size_t at)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_get, buffer, at);
|
||||
}
|
||||
|
||||
size_t fx_buffer_size(const fx_buffer *buffer)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_size, buffer);
|
||||
}
|
||||
|
||||
size_t fx_buffer_capacity(const fx_buffer *buffer)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_capacity, buffer);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_clear(fx_buffer *buffer)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_clear, buffer);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_push_back(fx_buffer *buf, size_t count, void **p)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_push_back, buf, count, p);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_push_front(fx_buffer *buf, size_t count, void **p)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_push_front, buf, count, p);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_pop_back(fx_buffer *buf, size_t count)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_pop_back, buf, count);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_pop_front(fx_buffer *buf, size_t count)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_BUFFER, buffer_pop_front, buf, count);
|
||||
}
|
||||
|
||||
size_t fx_buffer_get_size(const fx_buffer *buf)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_size, buf);
|
||||
}
|
||||
|
||||
size_t fx_buffer_get_item_size(const fx_buffer *buf)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_item_size, buf);
|
||||
}
|
||||
|
||||
size_t fx_buffer_get_capacity(const fx_buffer *buf)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_BUFFER, buffer_get_capacity, buf);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
|
||||
enum fx_status fx_buffer_append(fx_buffer *buffer, const void *p, size_t count)
|
||||
{
|
||||
return fx_buffer_insert(buffer, p, count, FX_NPOS);
|
||||
}
|
||||
|
||||
enum fx_status fx_buffer_prepend(fx_buffer *buffer, const void *p, size_t count)
|
||||
{
|
||||
return fx_buffer_insert(buffer, p, count, 0);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
void buffer_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_buffer_p *buffer = priv;
|
||||
}
|
||||
|
||||
void buffer_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_buffer_p *buffer = priv;
|
||||
|
||||
if (buffer->buf_data) {
|
||||
free(buffer->buf_data);
|
||||
buffer->buf_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_buffer)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_buffer)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_buffer)
|
||||
FX_TYPE_ID(0x323e6858, 0x7a43, 0x4484, 0xa6fb, 0xe3d1e47ae637);
|
||||
FX_TYPE_CLASS(fx_buffer_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_buffer_p);
|
||||
FX_TYPE_INSTANCE_INIT(buffer_init);
|
||||
FX_TYPE_INSTANCE_FINI(buffer_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_buffer)
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <blue/core/stream.h>
|
||||
#include <blue/ds/datetime.h>
|
||||
#include <blue/ds/string.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <fx/ds/datetime.h>
|
||||
#include <fx/ds/string.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct b_datetime_p {
|
||||
struct fx_datetime_p {
|
||||
unsigned int dt_year, dt_month, dt_day;
|
||||
unsigned short dt_hour, dt_min, dt_sec;
|
||||
unsigned int dt_msec;
|
||||
@@ -16,7 +16,7 @@ struct b_datetime_p {
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static bool is_leap_year(const struct b_datetime_p *dt)
|
||||
static bool is_leap_year(const struct fx_datetime_p *dt)
|
||||
{
|
||||
if ((dt->dt_year % 400) == 0) {
|
||||
return true;
|
||||
@@ -29,17 +29,17 @@ static bool is_leap_year(const struct b_datetime_p *dt)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_year_valid(const struct b_datetime_p *dt)
|
||||
static bool is_year_valid(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_year >= 0;
|
||||
}
|
||||
|
||||
static bool is_month_valid(const struct b_datetime_p *dt)
|
||||
static bool is_month_valid(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_month >= 1 && dt->dt_month <= 12;
|
||||
}
|
||||
|
||||
static bool is_day_valid(const struct b_datetime_p *dt)
|
||||
static bool is_day_valid(const struct fx_datetime_p *dt)
|
||||
{
|
||||
if (dt->dt_day < 1) {
|
||||
return false;
|
||||
@@ -66,7 +66,7 @@ static bool is_day_valid(const struct b_datetime_p *dt)
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_time_valid(const struct b_datetime_p *dt)
|
||||
static bool is_time_valid(const struct fx_datetime_p *dt)
|
||||
{
|
||||
if (!(dt->dt_hour >= 0 && dt->dt_hour <= 23)) {
|
||||
return false;
|
||||
@@ -83,7 +83,7 @@ static bool is_time_valid(const struct b_datetime_p *dt)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_zone_valid(const struct b_datetime_p *dt)
|
||||
static bool is_zone_valid(const struct fx_datetime_p *dt)
|
||||
{
|
||||
if (!(dt->dt_zone_offset_hour >= 0 && dt->dt_zone_offset_hour <= 23)) {
|
||||
return false;
|
||||
@@ -96,7 +96,7 @@ static bool is_zone_valid(const struct b_datetime_p *dt)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool validate(const struct b_datetime_p *dt)
|
||||
static bool validate(const struct fx_datetime_p *dt)
|
||||
{
|
||||
if (dt->dt_has_date) {
|
||||
if (!is_year_valid(dt)) {
|
||||
@@ -125,14 +125,14 @@ static bool validate(const struct b_datetime_p *dt)
|
||||
return true;
|
||||
}
|
||||
|
||||
static b_datetime *parse_rfc3339(const char *s)
|
||||
static fx_datetime *parse_rfc3339(const char *s)
|
||||
{
|
||||
b_datetime *d = b_datetime_create();
|
||||
fx_datetime *d = fx_datetime_create();
|
||||
if (!d) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_datetime_p *dt = b_object_get_private(d, B_TYPE_DATETIME);
|
||||
struct fx_datetime_p *dt = fx_object_get_private(d, FX_TYPE_DATETIME);
|
||||
|
||||
size_t len = strlen(s);
|
||||
|
||||
@@ -305,37 +305,37 @@ static b_datetime *parse_rfc3339(const char *s)
|
||||
dt->dt_has_time = has_time;
|
||||
return d;
|
||||
fail:
|
||||
b_datetime_unref(d);
|
||||
fx_datetime_unref(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static enum b_status encode_rfc3339(const struct b_datetime_p *dt, b_stream *out)
|
||||
static enum fx_status encode_rfc3339(const struct fx_datetime_p *dt, fx_stream *out)
|
||||
{
|
||||
if (dt->dt_has_date) {
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, "%04ld-%02ld-%02ld", dt->dt_year,
|
||||
dt->dt_month, dt->dt_day);
|
||||
}
|
||||
|
||||
if (dt->dt_has_date && dt->dt_has_time) {
|
||||
b_stream_write_char(out, 'T');
|
||||
fx_stream_write_char(out, 'T');
|
||||
}
|
||||
|
||||
if (dt->dt_has_time) {
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, "%02ld:%02ld:%02ld", dt->dt_hour, dt->dt_min,
|
||||
dt->dt_sec);
|
||||
|
||||
if (dt->dt_msec > 0) {
|
||||
b_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
|
||||
fx_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
|
||||
}
|
||||
|
||||
if (!dt->dt_localtime) {
|
||||
if (dt->dt_zone_offset_hour == 0
|
||||
&& dt->dt_zone_offset_minute == 0) {
|
||||
b_stream_write_char(out, 'Z');
|
||||
fx_stream_write_char(out, 'Z');
|
||||
} else {
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, "%c%02ld:%02ld",
|
||||
dt->dt_zone_offset_negative ? '-' : '+',
|
||||
dt->dt_zone_offset_hour,
|
||||
@@ -344,14 +344,14 @@ static enum b_status encode_rfc3339(const struct b_datetime_p *dt, b_stream *out
|
||||
}
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static void datetime_to_string(
|
||||
const struct b_datetime_p *dt, b_datetime_format format, b_stream *dest)
|
||||
const struct fx_datetime_p *dt, fx_datetime_format format, fx_stream *dest)
|
||||
{
|
||||
switch (format) {
|
||||
case B_DATETIME_FORMAT_RFC3339:
|
||||
case FX_DATETIME_FORMAT_RFC3339:
|
||||
encode_rfc3339(dt, dest);
|
||||
break;
|
||||
default:
|
||||
@@ -359,79 +359,79 @@ static void datetime_to_string(
|
||||
}
|
||||
}
|
||||
|
||||
static bool datetime_is_localtime(const struct b_datetime_p *dt)
|
||||
static bool datetime_is_localtime(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_localtime;
|
||||
}
|
||||
|
||||
static bool datetime_has_date(const struct b_datetime_p *dt)
|
||||
static bool datetime_has_date(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_has_date;
|
||||
}
|
||||
|
||||
static bool datetime_has_time(const struct b_datetime_p *dt)
|
||||
static bool datetime_has_time(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_has_time;
|
||||
}
|
||||
|
||||
static long datetime_year(const struct b_datetime_p *dt)
|
||||
static long datetime_year(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_year;
|
||||
}
|
||||
|
||||
static long datetime_month(const struct b_datetime_p *dt)
|
||||
static long datetime_month(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_month;
|
||||
}
|
||||
|
||||
static long datetime_day(const struct b_datetime_p *dt)
|
||||
static long datetime_day(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_day;
|
||||
}
|
||||
|
||||
static long datetime_hour(const struct b_datetime_p *dt)
|
||||
static long datetime_hour(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_hour;
|
||||
}
|
||||
|
||||
static long datetime_minute(const struct b_datetime_p *dt)
|
||||
static long datetime_minute(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_min;
|
||||
}
|
||||
|
||||
static long datetime_second(const struct b_datetime_p *dt)
|
||||
static long datetime_second(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_sec;
|
||||
}
|
||||
|
||||
static long datetime_subsecond(const struct b_datetime_p *dt)
|
||||
static long datetime_subsecond(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_msec;
|
||||
}
|
||||
|
||||
static bool datetime_zone_offset_is_negative(const struct b_datetime_p *dt)
|
||||
static bool datetime_zone_offset_is_negative(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_zone_offset_negative;
|
||||
}
|
||||
|
||||
static long datetime_zone_offset_hour(const struct b_datetime_p *dt)
|
||||
static long datetime_zone_offset_hour(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_zone_offset_hour;
|
||||
}
|
||||
|
||||
static long datetime_zone_offset_minute(const struct b_datetime_p *dt)
|
||||
static long datetime_zone_offset_minute(const struct fx_datetime_p *dt)
|
||||
{
|
||||
return dt->dt_zone_offset_minute;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
b_datetime *b_datetime_parse(enum b_datetime_format format, const char *s)
|
||||
fx_datetime *fx_datetime_parse(enum fx_datetime_format format, const char *s)
|
||||
{
|
||||
b_datetime *dt = NULL;
|
||||
fx_datetime *dt = NULL;
|
||||
|
||||
switch (format) {
|
||||
case B_DATETIME_FORMAT_RFC3339:
|
||||
case FX_DATETIME_FORMAT_RFC3339:
|
||||
dt = parse_rfc3339(s);
|
||||
break;
|
||||
default:
|
||||
@@ -442,126 +442,126 @@ b_datetime *b_datetime_parse(enum b_datetime_format format, const char *s)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct b_datetime_p *p = b_object_get_private(dt, B_TYPE_DATETIME);
|
||||
struct fx_datetime_p *p = fx_object_get_private(dt, FX_TYPE_DATETIME);
|
||||
|
||||
if (!validate(p)) {
|
||||
b_datetime_unref(dt);
|
||||
fx_datetime_unref(dt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
void b_datetime_to_string(
|
||||
const b_datetime *dt, b_datetime_format format, b_stream *dest)
|
||||
void fx_datetime_to_string(
|
||||
const fx_datetime *dt, fx_datetime_format format, fx_stream *dest)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC(
|
||||
B_TYPE_DATETIME, datetime_to_string, dt, format, dest);
|
||||
FX_CLASS_DISPATCH_STATIC(
|
||||
FX_TYPE_DATETIME, datetime_to_string, dt, format, dest);
|
||||
}
|
||||
|
||||
bool b_datetime_is_localtime(const b_datetime *dt)
|
||||
bool fx_datetime_is_localtime(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_is_localtime, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_is_localtime, dt);
|
||||
}
|
||||
|
||||
bool b_datetime_has_date(const b_datetime *dt)
|
||||
bool fx_datetime_has_date(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_has_date, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_has_date, dt);
|
||||
}
|
||||
|
||||
bool b_datetime_has_time(const b_datetime *dt)
|
||||
bool fx_datetime_has_time(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_has_time, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_has_time, dt);
|
||||
}
|
||||
|
||||
long b_datetime_year(const b_datetime *dt)
|
||||
long fx_datetime_year(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_year, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_year, dt);
|
||||
}
|
||||
|
||||
long b_datetime_month(const b_datetime *dt)
|
||||
long fx_datetime_month(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_month, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_month, dt);
|
||||
}
|
||||
|
||||
long b_datetime_day(const b_datetime *dt)
|
||||
long fx_datetime_day(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_day, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_day, dt);
|
||||
}
|
||||
|
||||
long b_datetime_hour(const b_datetime *dt)
|
||||
long fx_datetime_hour(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_hour, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_hour, dt);
|
||||
}
|
||||
|
||||
long b_datetime_minute(const b_datetime *dt)
|
||||
long fx_datetime_minute(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_minute, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_minute, dt);
|
||||
}
|
||||
|
||||
long b_datetime_second(const b_datetime *dt)
|
||||
long fx_datetime_second(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_second, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_second, dt);
|
||||
}
|
||||
|
||||
long b_datetime_subsecond(const b_datetime *dt)
|
||||
long fx_datetime_subsecond(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_subsecond, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_subsecond, dt);
|
||||
}
|
||||
|
||||
bool b_datetime_zone_offset_is_negative(const b_datetime *dt)
|
||||
bool fx_datetime_zone_offset_is_negative(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(
|
||||
B_TYPE_DATETIME, datetime_zone_offset_is_negative, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(
|
||||
FX_TYPE_DATETIME, datetime_zone_offset_is_negative, dt);
|
||||
}
|
||||
|
||||
long b_datetime_zone_offset_hour(const b_datetime *dt)
|
||||
long fx_datetime_zone_offset_hour(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_zone_offset_hour, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_zone_offset_hour, dt);
|
||||
}
|
||||
|
||||
long b_datetime_zone_offset_minute(const b_datetime *dt)
|
||||
long fx_datetime_zone_offset_minute(const fx_datetime *dt)
|
||||
{
|
||||
B_CLASS_DISPATCH_STATIC_0(B_TYPE_DATETIME, datetime_zone_offset_minute, dt);
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DATETIME, datetime_zone_offset_minute, dt);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void datetime_init(b_object *obj, void *priv)
|
||||
static void datetime_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct b_datetime_p *dt = priv;
|
||||
struct fx_datetime_p *dt = priv;
|
||||
}
|
||||
|
||||
static void datetime_fini(b_object *obj, void *priv)
|
||||
static void datetime_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct b_datetime_p *dt = priv;
|
||||
struct fx_datetime_p *dt = priv;
|
||||
}
|
||||
|
||||
static void _datetime_to_string(const b_object *obj, b_stream *out)
|
||||
static void _datetime_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct b_datetime_p *dt = b_object_get_private(obj, B_TYPE_DATETIME);
|
||||
struct fx_datetime_p *dt = fx_object_get_private(obj, FX_TYPE_DATETIME);
|
||||
|
||||
if (dt->dt_has_date) {
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, "%04ld-%02ld-%02ld", dt->dt_year,
|
||||
dt->dt_month, dt->dt_day);
|
||||
}
|
||||
|
||||
if (dt->dt_has_date && dt->dt_has_time) {
|
||||
b_stream_write_char(out, ' ');
|
||||
fx_stream_write_char(out, ' ');
|
||||
}
|
||||
|
||||
if (dt->dt_has_time) {
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, "%02ld:%02ld:%02ld", dt->dt_hour, dt->dt_min,
|
||||
dt->dt_sec);
|
||||
|
||||
if (dt->dt_msec > 0) {
|
||||
b_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
|
||||
fx_stream_write_fmt(out, NULL, ".%04ld", dt->dt_msec);
|
||||
}
|
||||
|
||||
if (!dt->dt_localtime) {
|
||||
b_stream_write_fmt(
|
||||
fx_stream_write_fmt(
|
||||
out, NULL, " %c%02ld:%02ld",
|
||||
dt->dt_zone_offset_negative ? '-' : '+',
|
||||
dt->dt_zone_offset_hour,
|
||||
@@ -572,16 +572,16 @@ static void _datetime_to_string(const b_object *obj, b_stream *out)
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
B_TYPE_CLASS_DEFINITION_BEGIN(b_datetime)
|
||||
B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT)
|
||||
B_INTERFACE_ENTRY(to_string) = _datetime_to_string;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT)
|
||||
B_TYPE_CLASS_DEFINITION_END(b_datetime)
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_datetime)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = _datetime_to_string;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_datetime)
|
||||
|
||||
B_TYPE_DEFINITION_BEGIN(b_datetime)
|
||||
B_TYPE_ID(0x06a6030b, 0x1e3c, 0x4be2, 0xbd23, 0xf34f4a8e68be);
|
||||
B_TYPE_CLASS(b_datetime_class);
|
||||
B_TYPE_INSTANCE_PRIVATE(struct b_datetime_p);
|
||||
B_TYPE_INSTANCE_INIT(datetime_init);
|
||||
B_TYPE_INSTANCE_FINI(datetime_fini);
|
||||
B_TYPE_DEFINITION_END(b_datetime)
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_datetime)
|
||||
FX_TYPE_ID(0x06a6030b, 0x1e3c, 0x4be2, 0xbd23, 0xf34f4a8e68be);
|
||||
FX_TYPE_CLASS(fx_datetime_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_datetime_p);
|
||||
FX_TYPE_INSTANCE_INIT(datetime_init);
|
||||
FX_TYPE_INSTANCE_FINI(datetime_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_datetime)
|
||||
@@ -0,0 +1,746 @@
|
||||
#include <fx/core/status.h>
|
||||
#include <fx/core/stream.h>
|
||||
#include <fx/ds/dict.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_dict_bucket_item {
|
||||
fx_queue_entry bi_entry;
|
||||
fx_string *bi_str;
|
||||
fx_object *bi_value;
|
||||
};
|
||||
|
||||
struct fx_dict_bucket {
|
||||
fx_bst_node bk_node;
|
||||
uint64_t bk_hash;
|
||||
fx_queue bk_items;
|
||||
};
|
||||
|
||||
struct fx_dict_p {
|
||||
fx_bst d_buckets;
|
||||
};
|
||||
|
||||
struct fx_dict_iterator_p {
|
||||
size_t i;
|
||||
fx_dict_item item;
|
||||
|
||||
fx_dict *_d;
|
||||
struct fx_dict_p *_d_p;
|
||||
fx_bst_node *_cbn;
|
||||
fx_queue_entry *_cqe;
|
||||
};
|
||||
|
||||
/*** MISC FUNCTIONS ***********************************************************/
|
||||
|
||||
static FX_BST_DEFINE_SIMPLE_GET(
|
||||
struct fx_dict_bucket,
|
||||
uint64_t,
|
||||
bk_node,
|
||||
bk_hash,
|
||||
get_bucket);
|
||||
static FX_BST_DEFINE_SIMPLE_INSERT(
|
||||
struct fx_dict_bucket,
|
||||
bk_node,
|
||||
bk_hash,
|
||||
put_bucket);
|
||||
|
||||
uint64_t fx_cstr_hash(const char *s)
|
||||
{
|
||||
#define FNV1_OFFSET_BASIS 0xcbf29ce484222325
|
||||
#define FNV1_PRIME 0x100000001b3
|
||||
uint64_t hash = FNV1_OFFSET_BASIS;
|
||||
size_t i = 0;
|
||||
|
||||
for (i = 0; s[i]; i++) {
|
||||
hash ^= s[i];
|
||||
hash *= FNV1_PRIME;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static struct fx_dict_bucket *create_bucket(void)
|
||||
{
|
||||
struct fx_dict_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct fx_dict_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct fx_dict_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static fx_status dict_put(
|
||||
struct fx_dict_p *dict,
|
||||
const char *key,
|
||||
fx_object *value)
|
||||
{
|
||||
uint64_t hash = fx_cstr_hash(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&dict->d_buckets, bucket);
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item->bi_str = fx_string_create_from_cstr(key);
|
||||
item->bi_value = fx_object_ref(value);
|
||||
|
||||
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_status dict_put_sk(
|
||||
struct fx_dict_p *dict,
|
||||
const fx_string *key,
|
||||
fx_object *value)
|
||||
{
|
||||
uint64_t hash = fx_string_hash(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&dict->d_buckets, bucket);
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
item->bi_str = fx_string_duplicate(key);
|
||||
item->bi_value = fx_object_ref(value);
|
||||
|
||||
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_object *dict_at(const struct fx_dict_p *dict, const char *key)
|
||||
{
|
||||
uint64_t hash = fx_cstr_hash(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item
|
||||
= fx_unbox(struct fx_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
if (!strcmp(fx_string_get_cstr(item->bi_str), key)) {
|
||||
return item->bi_value;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fx_object *dict_at_sk(const struct fx_dict_p *dict, const fx_string *key)
|
||||
{
|
||||
uint64_t hash = fx_string_hash(key);
|
||||
struct fx_dict_bucket *bucket = get_bucket(&dict->d_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item
|
||||
= fx_unbox(struct fx_dict_bucket_item, entry, bi_entry);
|
||||
|
||||
if (fx_string_compare(item->bi_str, key)) {
|
||||
return item->bi_value;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static fx_object *dict_get(struct fx_dict_p *dict, const char *key)
|
||||
{
|
||||
fx_object *value = dict_at(dict, key);
|
||||
if (value) {
|
||||
fx_object_ref(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static fx_object *dict_get_sk(struct fx_dict_p *dict, const fx_string *key)
|
||||
{
|
||||
fx_object *value = dict_at_sk(dict, key);
|
||||
if (value) {
|
||||
fx_object_ref(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool dict_has_key(const struct fx_dict_p *dict, const char *key)
|
||||
{
|
||||
return dict_at(dict, key) != NULL;
|
||||
}
|
||||
|
||||
static bool dict_has_skey(const struct fx_dict_p *dict, const fx_string *key)
|
||||
{
|
||||
return dict_at_sk(dict, key) != NULL;
|
||||
}
|
||||
|
||||
static size_t dict_get_size(const struct fx_dict_p *dict)
|
||||
{
|
||||
size_t count = 0;
|
||||
#if 0
|
||||
fx_bst_iterator it1;
|
||||
fx_queue_iterator it2;
|
||||
|
||||
fx_bst_foreach (&it1, &dict->d_buckets) {
|
||||
struct fx_dict_bucket *bucket
|
||||
= fx_unbox(struct fx_dict_bucket, it1.node, bk_node);
|
||||
|
||||
fx_queue_foreach (&it2, &bucket->bk_items) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool dict_is_empty(const struct fx_dict_p *dict)
|
||||
{
|
||||
fx_bst_node *first_node = fx_bst_first(&dict->d_buckets);
|
||||
struct fx_dict_bucket *first_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_dict_bucket_item *first_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool get_next_node(
|
||||
struct fx_bst_node *cur_node,
|
||||
struct fx_queue_entry *cur_entry,
|
||||
struct fx_bst_node **out_next_node,
|
||||
struct fx_queue_entry **out_next_entry)
|
||||
{
|
||||
struct fx_dict_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, cur_node, bk_node);
|
||||
if (!cur_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, cur_entry, bi_entry);
|
||||
if (!cur_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_bst_node *next_node = cur_node;
|
||||
struct fx_queue_entry *next_entry = fx_queue_next(cur_entry);
|
||||
if (!next_entry) {
|
||||
next_node = fx_bst_next(cur_node);
|
||||
if (!next_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket *next_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, next_node, bk_node);
|
||||
if (!next_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
next_entry = fx_queue_first(&next_bucket->bk_items);
|
||||
if (!next_entry) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *next_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
|
||||
if (!next_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_next_node = next_node;
|
||||
*out_next_entry = next_entry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static fx_status delete_item(
|
||||
struct fx_dict_p *dict,
|
||||
struct fx_dict_bucket *bucket,
|
||||
struct fx_dict_bucket_item *item)
|
||||
{
|
||||
fx_queue_delete(&bucket->bk_items, &item->bi_entry);
|
||||
free(item);
|
||||
|
||||
if (fx_queue_empty(&bucket->bk_items)) {
|
||||
fx_bst_delete(&dict->d_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
#if 0
|
||||
fx_dict *fx_dict_create_with_items(const fx_dict_item *items)
|
||||
{
|
||||
fx_dict *dict = fx_dict_create();
|
||||
if (!dict) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_dict_p *p = fx_object_get_private(dict, FX_TYPE_DICT);
|
||||
|
||||
for (size_t i = 0; items[i].key; i++) {
|
||||
dict_put(p, items[i].key, items[i].value);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
#endif
|
||||
|
||||
fx_status fx_dict_put(fx_dict *dict, const char *key, fx_object *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_put, dict, key, value);
|
||||
}
|
||||
|
||||
fx_status fx_dict_put_sk(fx_dict *dict, const fx_string *key, fx_object *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_put_sk, dict, key, value);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_at(const fx_dict *dict, const char *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_at, dict, key);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_at_sk(const fx_dict *dict, const fx_string *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_at_sk, dict, key);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_get(fx_dict *dict, const char *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_get, dict, key);
|
||||
}
|
||||
|
||||
fx_object *fx_dict_get_sk(fx_dict *dict, const fx_string *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_get_sk, dict, key);
|
||||
}
|
||||
|
||||
bool fx_dict_has_key(const fx_dict *dict, const char *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_has_key, dict, key);
|
||||
}
|
||||
|
||||
bool fx_dict_has_skey(const fx_dict *dict, const fx_string *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_DICT, dict_has_skey, dict, key);
|
||||
}
|
||||
|
||||
size_t fx_dict_get_size(const fx_dict *dict)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DICT, dict_get_size, dict);
|
||||
}
|
||||
|
||||
bool fx_dict_is_empty(const fx_dict *dict)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_DICT, dict_is_empty, dict);
|
||||
}
|
||||
|
||||
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void dict_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_dict_p *dict = priv;
|
||||
}
|
||||
|
||||
static void dict_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_dict_p *dict = priv;
|
||||
|
||||
struct fx_bst_node *node = fx_bst_first(&dict->d_buckets);
|
||||
while (node) {
|
||||
struct fx_dict_bucket *bucket
|
||||
= fx_unbox(struct fx_dict_bucket, node, bk_node);
|
||||
struct fx_bst_node *next_node = fx_bst_next(node);
|
||||
fx_bst_delete(&dict->d_buckets, node);
|
||||
|
||||
struct fx_queue_entry *entry
|
||||
= fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item = fx_unbox(
|
||||
struct fx_dict_bucket_item,
|
||||
entry,
|
||||
bi_entry);
|
||||
struct fx_queue_entry *next_entry
|
||||
= fx_queue_next(entry);
|
||||
fx_queue_delete(&bucket->bk_items, entry);
|
||||
|
||||
free(item->bi_str);
|
||||
fx_object_unref(item->bi_value);
|
||||
free(item);
|
||||
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
free(bucket);
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
static void dict_to_string(const fx_object *obj, fx_stream *out)
|
||||
{
|
||||
struct fx_dict_p *dict = fx_object_get_private(obj, FX_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(dict)) {
|
||||
fx_stream_write_cstr(out, "{}", NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fx_stream_write_cstr(out, "{\n", NULL);
|
||||
|
||||
fx_stream_push_indent(out, 1);
|
||||
size_t len = dict_get_size(dict);
|
||||
size_t i = 0;
|
||||
|
||||
struct fx_bst_node *node = fx_bst_first(&dict->d_buckets);
|
||||
while (node) {
|
||||
struct fx_dict_bucket *bucket
|
||||
= fx_unbox(struct fx_dict_bucket, node, bk_node);
|
||||
|
||||
struct fx_queue_entry *entry
|
||||
= fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_dict_bucket_item *item = fx_unbox(
|
||||
struct fx_dict_bucket_item,
|
||||
entry,
|
||||
bi_entry);
|
||||
|
||||
fx_object_to_string(item->bi_str, out);
|
||||
fx_stream_write_cstr(out, ": ", NULL);
|
||||
|
||||
bool is_string = fx_object_is_type(
|
||||
item->bi_value,
|
||||
FX_TYPE_STRING);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
fx_object_to_string(item->bi_value, out);
|
||||
|
||||
if (is_string) {
|
||||
fx_stream_write_char(out, '"');
|
||||
}
|
||||
|
||||
if (i < len - 1) {
|
||||
fx_stream_write_cstr(out, ",", NULL);
|
||||
}
|
||||
|
||||
fx_stream_write_char(out, '\n');
|
||||
entry = fx_queue_next(entry);
|
||||
i++;
|
||||
}
|
||||
node = fx_bst_next(node);
|
||||
}
|
||||
|
||||
fx_stream_pop_indent(out);
|
||||
fx_stream_write_char(out, '}');
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static fx_iterator *iterable_begin(fx_dict *dict)
|
||||
{
|
||||
fx_iterator *it_obj = fx_object_create(FX_TYPE_DICT_ITERATOR);
|
||||
if (!it_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
it->i = 0;
|
||||
it->_d = dict;
|
||||
it->_d_p = fx_object_get_private(dict, FX_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(it->_d_p)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_bst_node *first_node = fx_bst_first(&it->_d_p->d_buckets);
|
||||
struct fx_dict_bucket *first_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_dict_bucket_item *first_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
it->item.key = first_item->bi_str;
|
||||
it->item.value = first_item->bi_value;
|
||||
|
||||
it->_d = dict;
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static const fx_iterator *iterable_cbegin(const fx_dict *dict)
|
||||
{
|
||||
fx_iterator *it_obj = fx_object_create(FX_TYPE_DICT_ITERATOR);
|
||||
if (!it_obj) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
it->i = 0;
|
||||
it->_d = (fx_dict *)dict;
|
||||
it->_d_p = fx_object_get_private(dict, FX_TYPE_DICT);
|
||||
|
||||
if (dict_is_empty(it->_d_p)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_bst_node *first_node = fx_bst_first(&it->_d_p->d_buckets);
|
||||
struct fx_dict_bucket *first_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_dict_bucket_item *first_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
it->item.key = first_item->bi_str;
|
||||
it->item.value = first_item->bi_value;
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket_item *next_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
|
||||
|
||||
if (!next_item) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
it->item.key = next_item->bi_str;
|
||||
it->item.value = next_item->bi_value;
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
if ((it->item.key || it->item.value) && !(it->_cbn && it->_cqe)) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!it->item.key || !it->_cqe) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_dict_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_dict_bucket, it->_cbn, bk_node);
|
||||
struct fx_dict_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, it->_cqe, bi_entry);
|
||||
|
||||
struct fx_dict_bucket_item *next_item
|
||||
= fx_unbox(struct fx_dict_bucket_item, next_entry, bi_entry);
|
||||
|
||||
fx_status status = delete_item(it->_d_p, cur_bucket, cur_item);
|
||||
if (FX_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (next_item) {
|
||||
it->item.key = next_item->bi_str;
|
||||
it->item.value = next_item->bi_value;
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
} else {
|
||||
it->item.key = NULL;
|
||||
it->item.value = NULL;
|
||||
|
||||
it->_cbn = NULL;
|
||||
it->_cqe = NULL;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_PTR(&it->item);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_dict_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_DICT_ITERATOR);
|
||||
|
||||
return FX_ITERATOR_VALUE_CPTR(&it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_dict DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_dict)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = dict_to_string;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = iterable_begin;
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = iterable_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_dict)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_dict)
|
||||
FX_TYPE_ID(0xd2af61d9, 0xd0be, 0x4960, 0xbe3f, 0x509749814c10);
|
||||
FX_TYPE_CLASS(fx_dict_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_dict_p);
|
||||
FX_TYPE_INSTANCE_INIT(dict_init);
|
||||
FX_TYPE_INSTANCE_FINI(dict_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_dict)
|
||||
|
||||
// ---- fx_dict_iterator DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_dict_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_dict_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_dict_iterator)
|
||||
FX_TYPE_ID(0x9ea96701, 0x1713, 0x4a3e, 0xbf63, 0xdc856b456f3b);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_dict_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_dict_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_dict_iterator)
|
||||
@@ -0,0 +1,598 @@
|
||||
#include <fx/core/misc.h>
|
||||
#include <fx/core/status.h>
|
||||
#include <fx/ds/hashmap.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define HASH_OFFSET_BASIS 0xcbf29ce484222325
|
||||
#define HASH_PRIME 0x100000001b3
|
||||
|
||||
/*** PRIVATE DATA *************************************************************/
|
||||
|
||||
struct fx_hashmap_bucket_item {
|
||||
struct fx_queue_entry bi_entry;
|
||||
struct fx_hashmap_key bi_key;
|
||||
struct fx_hashmap_value bi_value;
|
||||
};
|
||||
|
||||
struct fx_hashmap_bucket {
|
||||
struct fx_bst_node bk_node;
|
||||
uint64_t bk_hash;
|
||||
struct fx_queue bk_items;
|
||||
};
|
||||
|
||||
struct fx_hashmap_p {
|
||||
size_t h_count;
|
||||
struct fx_bst h_buckets;
|
||||
fx_hashmap_key_destructor h_key_dtor;
|
||||
fx_hashmap_value_destructor h_value_dtor;
|
||||
};
|
||||
|
||||
struct fx_hashmap_iterator_p {
|
||||
size_t i;
|
||||
fx_hashmap_item item;
|
||||
|
||||
fx_hashmap *_h;
|
||||
struct fx_hashmap_p *_h_p;
|
||||
fx_bst_node *_cbn;
|
||||
fx_queue_entry *_cqe;
|
||||
};
|
||||
|
||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||
|
||||
static FX_BST_DEFINE_SIMPLE_GET(
|
||||
struct fx_hashmap_bucket, uint64_t, bk_node, bk_hash, get_bucket);
|
||||
static FX_BST_DEFINE_SIMPLE_INSERT(
|
||||
struct fx_hashmap_bucket, bk_node, bk_hash, put_bucket);
|
||||
|
||||
static uint64_t hash_data(const void *p, size_t size)
|
||||
{
|
||||
const unsigned char *s = p;
|
||||
uint64_t hash = HASH_OFFSET_BASIS;
|
||||
|
||||
for (size_t i = 0; s[i]; i++) {
|
||||
hash *= HASH_PRIME;
|
||||
hash ^= s[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static uint64_t hash_key(const struct fx_hashmap_key *key)
|
||||
{
|
||||
if (key->key_flags & FX_HASHMAP_KEY_F_INTVALUE) {
|
||||
return hash_data(&key->key_data, sizeof key->key_data);
|
||||
} else {
|
||||
return hash_data(key->key_data, key->key_size);
|
||||
}
|
||||
}
|
||||
|
||||
static bool compare_key(
|
||||
const struct fx_hashmap_key *a, const struct fx_hashmap_key *b)
|
||||
{
|
||||
const void *a_data = NULL, *fx_data = NULL;
|
||||
size_t a_len = 0, fx_len = 0;
|
||||
|
||||
if (a->key_flags & FX_HASHMAP_KEY_F_INTVALUE) {
|
||||
a_data = &a->key_data;
|
||||
a_len = sizeof a->key_data;
|
||||
} else {
|
||||
a_data = a->key_data;
|
||||
a_len = a->key_size;
|
||||
}
|
||||
|
||||
if (b->key_flags & FX_HASHMAP_KEY_F_INTVALUE) {
|
||||
fx_data = &b->key_data;
|
||||
fx_len = sizeof b->key_data;
|
||||
} else {
|
||||
fx_data = b->key_data;
|
||||
fx_len = b->key_size;
|
||||
}
|
||||
|
||||
if (a_len != fx_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t cmp_len = a_len;
|
||||
return memcmp(a_data, fx_data, cmp_len) == 0;
|
||||
}
|
||||
|
||||
static bool get_next_node(
|
||||
struct fx_bst_node *cur_node, struct fx_queue_entry *cur_entry,
|
||||
struct fx_bst_node **out_next_node, struct fx_queue_entry **out_next_entry)
|
||||
{
|
||||
struct fx_hashmap_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, cur_node, bk_node);
|
||||
if (!cur_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, cur_entry, bi_entry);
|
||||
if (!cur_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_bst_node *next_node = cur_node;
|
||||
struct fx_queue_entry *next_entry = fx_queue_next(cur_entry);
|
||||
if (!next_entry) {
|
||||
next_node = fx_bst_next(cur_node);
|
||||
if (!next_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket *next_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, next_node, bk_node);
|
||||
if (!next_bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
next_entry = fx_queue_first(&next_bucket->bk_items);
|
||||
if (!next_entry) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *next_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
|
||||
if (!next_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_next_node = next_node;
|
||||
*out_next_entry = next_entry;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct fx_hashmap_bucket *create_bucket(void)
|
||||
{
|
||||
struct fx_hashmap_bucket *bucket = malloc(sizeof *bucket);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bucket, 0x0, sizeof *bucket);
|
||||
return bucket;
|
||||
}
|
||||
|
||||
static struct fx_hashmap_bucket_item *create_bucket_item(void)
|
||||
{
|
||||
struct fx_hashmap_bucket_item *item = malloc(sizeof *item);
|
||||
if (!item) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(item, 0x0, sizeof *item);
|
||||
return item;
|
||||
}
|
||||
|
||||
static fx_status hashmap_put(
|
||||
struct fx_hashmap_p *hashmap, const fx_hashmap_key *key,
|
||||
const fx_hashmap_value *value)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
|
||||
if (!bucket) {
|
||||
bucket = create_bucket();
|
||||
if (!bucket) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
bucket->bk_hash = hash;
|
||||
put_bucket(&hashmap->h_buckets, bucket);
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_hashmap_bucket_item *item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *item = create_bucket_item();
|
||||
if (!item) {
|
||||
return FX_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(&item->bi_key, key, sizeof *key);
|
||||
memcpy(&item->bi_value, value, sizeof *value);
|
||||
|
||||
fx_queue_push_back(&bucket->bk_items, &item->bi_entry);
|
||||
hashmap->h_count++;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct fx_hashmap_value *hashmap_get(
|
||||
const struct fx_hashmap_p *hashmap, const struct fx_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
|
||||
struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_hashmap_bucket_item *item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return &item->bi_value;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hashmap_has_key(
|
||||
const struct fx_hashmap_p *hashmap, const fx_hashmap_key *key)
|
||||
{
|
||||
uint64_t hash = hash_key(key);
|
||||
struct fx_hashmap_bucket *bucket = get_bucket(&hashmap->h_buckets, hash);
|
||||
if (!bucket) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&bucket->bk_items);
|
||||
while (entry) {
|
||||
struct fx_hashmap_bucket_item *item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, entry, bi_entry);
|
||||
|
||||
if (compare_key(&item->bi_key, key)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t hashmap_get_size(const struct fx_hashmap_p *hashmap)
|
||||
{
|
||||
return hashmap->h_count;
|
||||
}
|
||||
|
||||
static bool hashmap_is_empty(const struct fx_hashmap_p *hashmap)
|
||||
{
|
||||
fx_bst_node *first_node = fx_bst_first(&hashmap->h_buckets);
|
||||
struct fx_hashmap_bucket *first_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_hashmap_bucket_item *first_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static fx_status delete_item(
|
||||
struct fx_hashmap_p *hashmap, struct fx_hashmap_bucket *bucket,
|
||||
struct fx_hashmap_bucket_item *item)
|
||||
{
|
||||
fx_queue_delete(&bucket->bk_items, &item->bi_entry);
|
||||
|
||||
if (hashmap->h_key_dtor) {
|
||||
hashmap->h_key_dtor((void *)item->bi_key.key_data);
|
||||
}
|
||||
|
||||
if (hashmap->h_value_dtor) {
|
||||
hashmap->h_value_dtor((void *)item->bi_value.value_data);
|
||||
}
|
||||
|
||||
free(item);
|
||||
|
||||
if (fx_queue_empty(&bucket->bk_items)) {
|
||||
fx_bst_delete(&hashmap->h_buckets, &bucket->bk_node);
|
||||
free(bucket);
|
||||
}
|
||||
|
||||
hashmap->h_count--;
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
/*** PUBLIC FUNCTIONS *********************************************************/
|
||||
|
||||
fx_hashmap *fx_hashmap_create(
|
||||
fx_hashmap_key_destructor key_dtor, fx_hashmap_value_destructor value_dtor)
|
||||
{
|
||||
fx_hashmap *hashmap = fx_object_create(FX_TYPE_HASHMAP);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
fx_hashmap *fx_hashmap_create_with_items(const fx_hashmap_item *items)
|
||||
{
|
||||
fx_hashmap *hashmap = fx_hashmap_create(NULL, NULL);
|
||||
if (!hashmap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct fx_hashmap_p *p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP);
|
||||
|
||||
for (size_t i = 0; items[i].key.key_data && items[i].key.key_size; i++) {
|
||||
hashmap_put(p, &items[i].key, &items[i].value);
|
||||
}
|
||||
|
||||
return hashmap;
|
||||
}
|
||||
|
||||
fx_status fx_hashmap_put(
|
||||
fx_hashmap *hashmap, const fx_hashmap_key *key, const fx_hashmap_value *value)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_put, hashmap, key, value);
|
||||
}
|
||||
|
||||
const struct fx_hashmap_value *fx_hashmap_get(
|
||||
const fx_hashmap *hashmap, const struct fx_hashmap_key *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_get, hashmap, key);
|
||||
}
|
||||
|
||||
bool fx_hashmap_has_key(const fx_hashmap *hashmap, const fx_hashmap_key *key)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC(FX_TYPE_HASHMAP, hashmap_has_key, hashmap, key);
|
||||
}
|
||||
|
||||
size_t fx_hashmap_get_size(const fx_hashmap *hashmap)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_get_size, hashmap);
|
||||
}
|
||||
|
||||
bool fx_hashmap_is_empty(const fx_hashmap *hashmap)
|
||||
{
|
||||
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_HASHMAP, hashmap_is_empty, hashmap);
|
||||
}
|
||||
|
||||
fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap)
|
||||
{
|
||||
fx_hashmap_iterator *it_obj = fx_object_create(FX_TYPE_HASHMAP_ITERATOR);
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(it_obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
it->_h = hashmap;
|
||||
it->_h_p = fx_object_get_private(hashmap, FX_TYPE_HASHMAP);
|
||||
|
||||
it->i = 0;
|
||||
if (fx_hashmap_is_empty(hashmap)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct fx_bst_node *first_node = fx_bst_first(&it->_h_p->h_buckets);
|
||||
struct fx_hashmap_bucket *first_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, first_node, bk_node);
|
||||
if (!first_bucket) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
struct fx_queue_entry *first_entry = fx_queue_first(&first_bucket->bk_items);
|
||||
struct fx_hashmap_bucket_item *first_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, first_entry, bi_entry);
|
||||
if (!first_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
fx_iterator_set_status(it_obj, FX_ERR_NO_DATA);
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
memcpy(&it->item.key, &first_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &first_item->bi_value, sizeof it->item.value);
|
||||
|
||||
it->_cbn = first_node;
|
||||
it->_cqe = first_entry;
|
||||
|
||||
return it_obj;
|
||||
}
|
||||
|
||||
const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap)
|
||||
{
|
||||
return fx_hashmap_begin((fx_hashmap *)hashmap);
|
||||
}
|
||||
|
||||
/*** VIRTUAL FUNCTIONS ********************************************************/
|
||||
|
||||
static void hashmap_init(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_hashmap_p *map = priv;
|
||||
}
|
||||
|
||||
static void hashmap_fini(fx_object *obj, void *priv)
|
||||
{
|
||||
struct fx_hashmap_p *map = priv;
|
||||
|
||||
struct fx_bst_node *node = fx_bst_first(&map->h_buckets);
|
||||
while (node) {
|
||||
struct fx_hashmap_bucket *b
|
||||
= fx_unbox(struct fx_hashmap_bucket, node, bk_node);
|
||||
struct fx_bst_node *next_node = fx_bst_next(node);
|
||||
fx_bst_delete(&map->h_buckets, node);
|
||||
|
||||
struct fx_queue_entry *entry = fx_queue_first(&b->bk_items);
|
||||
while (entry) {
|
||||
struct fx_hashmap_bucket_item *item = fx_unbox(
|
||||
struct fx_hashmap_bucket_item, entry, bi_entry);
|
||||
struct fx_queue_entry *next_entry = fx_queue_next(entry);
|
||||
fx_queue_delete(&b->bk_items, entry);
|
||||
|
||||
if (map->h_key_dtor) {
|
||||
map->h_key_dtor((void *)item->bi_key.key_data);
|
||||
}
|
||||
|
||||
if (map->h_value_dtor) {
|
||||
map->h_value_dtor((void *)item->bi_value.value_data);
|
||||
}
|
||||
|
||||
free(item);
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
free(b);
|
||||
node = next_node;
|
||||
}
|
||||
}
|
||||
|
||||
/*** ITERATOR FUNCTIONS *******************************************************/
|
||||
|
||||
static enum fx_status iterator_move_next(const fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket_item *next_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
if (!next_item) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
it->i++;
|
||||
memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &next_item->bi_value, sizeof it->item.value);
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static enum fx_status iterator_erase(fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
|
||||
if ((it->item.key.key_data || it->item.value.value_data)
|
||||
&& !(it->_cbn && it->_cqe)) {
|
||||
return FX_ERR_BAD_STATE;
|
||||
}
|
||||
|
||||
if (!it->item.key.key_data || !it->_cqe) {
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_bst_node *next_node;
|
||||
struct fx_queue_entry *next_entry;
|
||||
if (!get_next_node(it->_cbn, it->_cqe, &next_node, &next_entry)) {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
return FX_ERR_NO_DATA;
|
||||
}
|
||||
|
||||
struct fx_hashmap_bucket *cur_bucket
|
||||
= fx_unbox(struct fx_hashmap_bucket, it->_cbn, bk_node);
|
||||
struct fx_hashmap_bucket_item *cur_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, it->_cqe, bi_entry);
|
||||
|
||||
struct fx_hashmap_bucket_item *next_item
|
||||
= fx_unbox(struct fx_hashmap_bucket_item, next_entry, bi_entry);
|
||||
|
||||
fx_status status = delete_item(it->_h_p, cur_bucket, cur_item);
|
||||
if (FX_ERR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (next_item) {
|
||||
memcpy(&it->item.key, &next_item->bi_key, sizeof it->item.key);
|
||||
memcpy(&it->item.value, &next_item->bi_value,
|
||||
sizeof it->item.value);
|
||||
|
||||
it->_cbn = next_node;
|
||||
it->_cqe = next_entry;
|
||||
} else {
|
||||
memset(&it->item, 0x0, sizeof it->item);
|
||||
|
||||
it->_cbn = NULL;
|
||||
it->_cqe = NULL;
|
||||
}
|
||||
|
||||
return FX_SUCCESS;
|
||||
}
|
||||
|
||||
static fx_iterator_value iterator_get_value(fx_iterator *obj)
|
||||
{
|
||||
struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
return FX_ITERATOR_VALUE_PTR(&it->item);
|
||||
}
|
||||
|
||||
static const fx_iterator_value iterator_get_cvalue(const fx_iterator *obj)
|
||||
{
|
||||
const struct fx_hashmap_iterator_p *it
|
||||
= fx_object_get_private(obj, FX_TYPE_HASHMAP_ITERATOR);
|
||||
return FX_ITERATOR_VALUE_CPTR(&it->item);
|
||||
}
|
||||
|
||||
/*** CLASS DEFINITION *********************************************************/
|
||||
|
||||
// ---- fx_hashmap DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_INTERFACE_ENTRY(it_begin) = fx_hashmap_begin;
|
||||
FX_INTERFACE_ENTRY(it_cbegin) = fx_hashmap_cbegin;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterable, FX_TYPE_ITERABLE)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_hashmap)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashmap)
|
||||
FX_TYPE_ID(0x7bf5bcd1, 0x1ff3, 0x4e43, 0xbed8, 0x7c74f28348bf);
|
||||
FX_TYPE_CLASS(fx_hashmap_class);
|
||||
FX_TYPE_IMPLEMENTS(FX_TYPE_ITERABLE);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashmap_p);
|
||||
FX_TYPE_INSTANCE_INIT(hashmap_init);
|
||||
FX_TYPE_INSTANCE_FINI(hashmap_fini);
|
||||
FX_TYPE_DEFINITION_END(fx_hashmap)
|
||||
|
||||
// ---- fx_hashmap_iterator DEFINITION
|
||||
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_hashmap_iterator)
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||
|
||||
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_INTERFACE_ENTRY(it_move_next) = iterator_move_next;
|
||||
FX_INTERFACE_ENTRY(it_erase) = iterator_erase;
|
||||
FX_INTERFACE_ENTRY(it_get_value) = iterator_get_value;
|
||||
FX_INTERFACE_ENTRY(it_get_cvalue) = iterator_get_cvalue;
|
||||
FX_TYPE_CLASS_INTERFACE_END(fx_iterator, FX_TYPE_ITERATOR)
|
||||
FX_TYPE_CLASS_DEFINITION_END(fx_hashmap_iterator)
|
||||
|
||||
FX_TYPE_DEFINITION_BEGIN(fx_hashmap_iterator)
|
||||
FX_TYPE_ID(0xd9658456, 0xdd80, 0x419a, 0xb23a, 0xb513013e6431);
|
||||
FX_TYPE_EXTENDS(FX_TYPE_ITERATOR);
|
||||
FX_TYPE_CLASS(fx_hashmap_iterator_class);
|
||||
FX_TYPE_INSTANCE_PRIVATE(struct fx_hashmap_iterator_p);
|
||||
FX_TYPE_DEFINITION_END(fx_hashmap_iterator)
|
||||
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* A heterogeneous array of objects. fx_array only stores references
|
||||
* to the objects that it contains, not the object data itself.
|
||||
*
|
||||
* fx_array stores pointers to objects in a single contiguous array,
|
||||
* but this is an implementation detail that may change in the future.
|
||||
* Users of fx_array should not rely on this being the case.
|
||||
*/
|
||||
#ifndef FX_DS_ARRAY_H_
|
||||
#define FX_DS_ARRAY_H_
|
||||
|
||||
#include <fx/core/iterator.h>
|
||||
#include <fx/core/macros.h>
|
||||
#include <fx/core/misc.h>
|
||||
#include <fx/core/status.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_ARRAY (fx_array_get_type())
|
||||
#define FX_TYPE_ARRAY_ITERATOR (fx_array_iterator_get_type())
|
||||
|
||||
struct fx_array_p;
|
||||
|
||||
FX_DECLARE_TYPE(fx_array);
|
||||
FX_DECLARE_TYPE(fx_array_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_array)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_array)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_array_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_array_iterator)
|
||||
|
||||
FX_API fx_type fx_array_get_type(void);
|
||||
FX_API fx_type fx_array_iterator_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_array, FX_TYPE_ARRAY);
|
||||
|
||||
/**
|
||||
* Creates an fx_array initialised with the contents of the provided
|
||||
* fx_object pointer array. The fx_array will take a reference to each
|
||||
* object specified in `values`, and will increment the reference count.
|
||||
* The order of objects in the new fx_array will be the same as the order
|
||||
* of objects in `values`. Any NULL pointers in the `values` array will
|
||||
* be ignored, and will not result in gaps in the created fx_array.
|
||||
* However, `nr_values` should be large enough to cover the final
|
||||
* non-NULL pointer in `values`, including any NULL pointers in-between.
|
||||
*
|
||||
* @param values The list of object pointers which should make up the
|
||||
* contents of the new fx_array.
|
||||
* @param nr_values The size of the `values` array.
|
||||
* @return A pointer to the new fx_array, or NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_array *fx_array_create_with_values(
|
||||
fx_object *const *values, size_t nr_values);
|
||||
|
||||
/**
|
||||
* Remove all object references from an fx_array, resetting the size of the array to zero.
|
||||
* The reference counts of all objects in the array will be decremented.
|
||||
*
|
||||
* @param array The fx_array to clear.
|
||||
*/
|
||||
FX_API void fx_array_clear(fx_array *array);
|
||||
|
||||
/**
|
||||
* Inserts an object at the end of an fx_array. The reference count of
|
||||
* the object will be incremented.
|
||||
*
|
||||
* @param array The fx_array to append the object to.
|
||||
* @param value The object to append.
|
||||
* @return FX_SUCCESS if the object was appended successfully, or an
|
||||
* error code if an error occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_append(fx_array *array, fx_object *value);
|
||||
|
||||
/**
|
||||
* Inserts an object at the beginning of an fx_array. The reference count
|
||||
* of the object will be incremented. All other objects in the array
|
||||
* will be moved to make space for the object being pre-pended.
|
||||
*
|
||||
* @param array The fx_array to prepend the object to.
|
||||
* @param value The object to prepend.
|
||||
* @return FX_SUCCESS if the object was prepended successfully, or an
|
||||
* error code if an error occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_prepend(fx_array *array, fx_object *value);
|
||||
|
||||
/**
|
||||
* Inserts an object into an fx_array at a given index. The reference
|
||||
* count of the object will be incremented. If the specified index is at
|
||||
* the beginning or mid-way through the array (i.e. not at the end),
|
||||
* some or all of the objects already in the array will be moved to make
|
||||
* space for the object being inserted.
|
||||
*
|
||||
* @param array The fx_array to insert the object into.
|
||||
* @param value The object to insert.
|
||||
* @param at The index to insert the object at. If the index is
|
||||
* `FX_NPOS`, the object will be inserted at the end of the fx_array.
|
||||
* @return FX_SUCCESS if the object was inserted, or a status code
|
||||
* describing any error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_insert(fx_array *array, fx_object *value, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the specified index from an fx_array. The
|
||||
* reference count of the removed object will be decremented. If the
|
||||
* specified index is at the beginning or mid-way through the array
|
||||
* (i.e. not at the end), the remaining objects will be moved to fill
|
||||
* the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @param at The index of the object to be removed.
|
||||
* @return FX_SUCCESS if the object was removed, or a status code
|
||||
* describing any error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_remove(fx_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the beginning of an fx_array. The reference count
|
||||
* of the removed object will be decremented. The remaining objects will be moved
|
||||
* to fill the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return FX_SUCCESS if the object was removed, or a status code describing any error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_remove_front(fx_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the end of an fx_array. The reference count
|
||||
* of the removed object will be decremented.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return FX_SUCCESS if the object was removed, or a status code describing any error that occurred.
|
||||
*/
|
||||
FX_API fx_status fx_array_remove_back(fx_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the specified index of an fx_array, and returns
|
||||
* a pointer to it. The reference count of the removed object will NOT
|
||||
* be decremented. The caller becomes the owner of the array's reference
|
||||
* to the object. If the specified index is at the beginning or mid-way
|
||||
* through the array (i.e. not at the end), the remaining objects will
|
||||
* be moved to fill the empty space created by the object's removal.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @param at The index of the object to be removed.
|
||||
* @return An pointer to the removed object. This pointer is owned by
|
||||
* the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_pop(fx_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Removes the object at the beginning of an fx_array, and returns a
|
||||
* pointer to it. The reference count of the removed object will NOT be
|
||||
* decremented. The caller becomes the owner of the array's reference to
|
||||
* the object. The remaining objects in the fx_array will be moved to
|
||||
* fill the empty space left by the removed object.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return An pointer to the removed object. This pointer is owned by
|
||||
* the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_pop_front(fx_array *array);
|
||||
|
||||
/**
|
||||
* Removes the object at the end of an fx_array, and returns a pointer to it. The
|
||||
* reference count of the removed object will NOT be decremented. The caller
|
||||
* becomes the owner of the array's reference to the object.
|
||||
*
|
||||
* @param array The fx_array to remove the object from.
|
||||
* @return An pointer to the removed object. This pointer is owned by the
|
||||
* caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_pop_back(fx_array *array);
|
||||
|
||||
/**
|
||||
* Returns an unowned pointer to the object at the given index of an fx_array.
|
||||
* The caller does not own the returned pointer, and MUST NOT release it.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @param at The index of the object to return.
|
||||
* @return A pointer to the object at the given index. This pointer is NOT owned
|
||||
* by the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_at(const fx_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Returns an owned pointer to the object at the given index of an
|
||||
* fx_array. The caller owns the returned pointer, and must release it
|
||||
* when they are finished with it.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @param at The index of the object to return.
|
||||
* @return A pointer to the object at the given index. This pointer is
|
||||
* owned by the caller. Returns NULL if an error occurred.
|
||||
*/
|
||||
FX_API fx_object *fx_array_get(fx_array *array, size_t at);
|
||||
|
||||
/**
|
||||
* Returns the number of objects contained in an fx_array.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @return The number of objects contained in the fx_array.
|
||||
*/
|
||||
FX_API size_t fx_array_size(const fx_array *array);
|
||||
|
||||
/**
|
||||
* Returns the current maximum capacity of an fx_array. This represents
|
||||
* the number of objects that can be stored in an fx_array before its
|
||||
* internal buffer would need to be re-sized.
|
||||
*
|
||||
* @param array The fx_array.
|
||||
* @return The maximum capacity of the fx_array.
|
||||
*/
|
||||
FX_API size_t fx_array_capacity(const fx_array *array);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef FX_DS_BITBUFFER_H_
|
||||
#define FX_DS_BITBUFFER_H_
|
||||
|
||||
#include <fx/core/macros.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
FX_DECLARE_TYPE(fx_bitbuffer);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bitbuffer)
|
||||
;
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_bitbuffer);
|
||||
|
||||
FX_API fx_status fx_bitbuffer_put_bit(fx_bitbuffer *buf, int bit);
|
||||
FX_API fx_status fx_bitbuffer_put_bool(fx_bitbuffer *buf, bool b);
|
||||
FX_API fx_status fx_bitbuffer_put_int(
|
||||
fx_bitbuffer *buf, uint64_t v, unsigned int nr_bits);
|
||||
FX_API fx_status fx_bitbuffer_put_bytes(
|
||||
fx_bitbuffer *buf, const void *p, size_t len, size_t bits_per_byte);
|
||||
FX_API fx_status fx_bitbuffer_put_string(
|
||||
fx_bitbuffer *buf, const char *p, size_t len, size_t bits_per_char);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef FX_DS_BITMAP_H_
|
||||
#define FX_DS_BITMAP_H_
|
||||
|
||||
#include <fx/core/macros.h>
|
||||
#include <fx/core/misc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_BITMAP (fx_bitmap_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_bitmap);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_bitmap)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_bitmap)
|
||||
|
||||
FX_API fx_type fx_bitmap_get_type(void);
|
||||
|
||||
FX_API fx_bitmap *fx_bitmap_create(size_t nr_bits);
|
||||
|
||||
FX_API void fx_bitmap_set_bit(fx_bitmap *map, size_t bit);
|
||||
FX_API void fx_bitmap_clear_bit(fx_bitmap *map, size_t bit);
|
||||
FX_API void fx_bitmap_set_range(fx_bitmap *map, size_t first_bit, size_t nbits);
|
||||
FX_API void fx_bitmap_clear_range(fx_bitmap *map, size_t first_bit, size_t nbits);
|
||||
FX_API void fx_bitmap_set_all(fx_bitmap *map);
|
||||
FX_API void fx_bitmap_clear_all(fx_bitmap *map);
|
||||
|
||||
FX_API bool fx_bitmap_check_bit(const fx_bitmap *map, size_t bit);
|
||||
|
||||
FX_API size_t fx_bitmap_count_set_bits(const fx_bitmap *map);
|
||||
FX_API size_t fx_bitmap_count_clear_bits(const fx_bitmap *map);
|
||||
|
||||
FX_API size_t fx_bitmap_highest_set_bit(const fx_bitmap *map);
|
||||
FX_API size_t fx_bitmap_highest_clear_bit(const fx_bitmap *map);
|
||||
FX_API size_t fx_bitmap_lowest_set_bit(const fx_bitmap *map);
|
||||
FX_API size_t fx_bitmap_lowest_clear_bit(const fx_bitmap *map);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef FX_DS_BUFFER_H_
|
||||
#define FX_DS_BUFFER_H_
|
||||
|
||||
#include <fx/core/macros.h>
|
||||
#include <stddef.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_BUFFER (fx_buffer_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_buffer);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_buffer)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_buffer)
|
||||
|
||||
FX_API fx_type fx_buffer_get_type(void);
|
||||
|
||||
FX_API fx_buffer *fx_buffer_create(size_t item_sz);
|
||||
FX_API fx_buffer *fx_buffer_create_from_bytes(const void *p, size_t len);
|
||||
FX_API fx_buffer *fx_buffer_create_from_array(
|
||||
const void *p, size_t item_sz, size_t len);
|
||||
|
||||
FX_API void *fx_buffer_steal(fx_buffer *buf);
|
||||
FX_API fx_status fx_buffer_reserve(fx_buffer *buf, size_t capacity);
|
||||
FX_API fx_status fx_buffer_resize(fx_buffer *buf, size_t length);
|
||||
|
||||
FX_API fx_status fx_buffer_append(fx_buffer *dest, const void *p, size_t count);
|
||||
FX_API fx_status fx_buffer_prepend(fx_buffer *dest, const void *p, size_t count);
|
||||
FX_API fx_status fx_buffer_insert(
|
||||
fx_buffer *dest, const void *p, size_t count, size_t at);
|
||||
FX_API fx_status fx_buffer_remove(fx_buffer *dest, size_t at, size_t count);
|
||||
FX_API fx_status fx_buffer_clear(fx_buffer *buf);
|
||||
|
||||
FX_API fx_status fx_buffer_push_back(fx_buffer *buf, size_t count, void **p);
|
||||
FX_API fx_status fx_buffer_push_front(fx_buffer *buf, size_t count, void **p);
|
||||
|
||||
FX_API fx_status fx_buffer_pop_back(fx_buffer *buf, size_t count);
|
||||
FX_API fx_status fx_buffer_pop_front(fx_buffer *buf, size_t count);
|
||||
|
||||
FX_API size_t fx_buffer_get_size(const fx_buffer *buf);
|
||||
FX_API size_t fx_buffer_get_item_size(const fx_buffer *buf);
|
||||
FX_API size_t fx_buffer_get_capacity(const fx_buffer *buf);
|
||||
|
||||
FX_API void *fx_buffer_ptr(const fx_buffer *buf);
|
||||
FX_API void *fx_buffer_get(const fx_buffer *buf, size_t at);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef FX_DS_DATETIME_H_
|
||||
#define FX_DS_DATETIME_H_
|
||||
|
||||
#include <fx/core/macros.h>
|
||||
#include <fx/core/status.h>
|
||||
#include <ctype.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_DATETIME (fx_datetime_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_datetime);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_datetime)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_datetime)
|
||||
|
||||
typedef enum fx_datetime_format {
|
||||
FX_DATETIME_FORMAT_RFC3339 = 1,
|
||||
} fx_datetime_format;
|
||||
|
||||
FX_API fx_type fx_datetime_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_datetime, FX_TYPE_DATETIME);
|
||||
|
||||
FX_API fx_datetime *fx_datetime_parse(fx_datetime_format format, const char *s);
|
||||
FX_API void fx_datetime_to_string(
|
||||
const fx_datetime *dt, fx_datetime_format format,
|
||||
FX_TYPE_FWDREF(fx_stream) * dest);
|
||||
|
||||
FX_API bool fx_datetime_is_localtime(const fx_datetime *dt);
|
||||
FX_API bool fx_datetime_has_date(const fx_datetime *dt);
|
||||
FX_API bool fx_datetime_has_time(const fx_datetime *dt);
|
||||
|
||||
FX_API long fx_datetime_year(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_month(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_day(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_hour(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_minute(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_second(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_subsecond(const fx_datetime *dt);
|
||||
|
||||
FX_API bool fx_datetime_zone_offset_is_negative(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_zone_offset_hour(const fx_datetime *dt);
|
||||
FX_API long fx_datetime_zone_offset_minute(const fx_datetime *dt);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef FX_DS_DICT_H_
|
||||
#define FX_DS_DICT_H_
|
||||
|
||||
#include <fx/core/bst.h>
|
||||
#include <fx/core/macros.h>
|
||||
#include <fx/core/misc.h>
|
||||
#include <fx/core/queue.h>
|
||||
#include <fx/core/status.h>
|
||||
#include <fx/ds/string.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
#define FX_TYPE_DICT (fx_dict_get_type())
|
||||
#define FX_TYPE_DICT_ITERATOR (fx_dict_iterator_get_type())
|
||||
|
||||
struct fx_dict_p;
|
||||
|
||||
FX_DECLARE_TYPE(fx_dict);
|
||||
FX_DECLARE_TYPE(fx_dict_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_dict)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_dict)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_dict_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_dict_iterator)
|
||||
|
||||
#define FX_DICT_ITEM(k, v) {.key = (k), .value = (v)}
|
||||
#define FX_DICT_ITEM_END {.key = NULL, .value = NULL}
|
||||
|
||||
#define fx_dict_foreach(it, dict) \
|
||||
for (int z__fx_unique_name() = fx_dict_iterator_begin(dict, it); \
|
||||
(it)->key != NULL; fx_dict_iterator_next(it))
|
||||
|
||||
typedef struct fx_dict_item {
|
||||
const fx_string *key;
|
||||
fx_object *value;
|
||||
} fx_dict_item;
|
||||
|
||||
FX_API fx_type fx_dict_get_type(void);
|
||||
FX_API fx_type fx_dict_iterator_get_type(void);
|
||||
|
||||
FX_TYPE_DEFAULT_CONSTRUCTOR(fx_dict, FX_TYPE_DICT);
|
||||
|
||||
#if 0
|
||||
FX_API fx_dict *fx_dict_create_with_items(const fx_dict_item *items);
|
||||
#endif
|
||||
|
||||
FX_API fx_status fx_dict_put(fx_dict *dict, const char *key, fx_object *value);
|
||||
FX_API fx_status fx_dict_put_sk(fx_dict *dict, const fx_string *key, fx_object *value);
|
||||
FX_API fx_object *fx_dict_at(const fx_dict *dict, const char *key);
|
||||
FX_API fx_object *fx_dict_at_sk(const fx_dict *dict, const fx_string *key);
|
||||
FX_API fx_object *fx_dict_get(fx_dict *dict, const char *key);
|
||||
FX_API fx_object *fx_dict_get_sk(fx_dict *dict, const fx_string *key);
|
||||
|
||||
FX_API bool fx_dict_has_key(const fx_dict *dict, const char *key);
|
||||
FX_API bool fx_dict_has_skey(const fx_dict *dict, const fx_string *key);
|
||||
FX_API size_t fx_dict_get_size(const fx_dict *dict);
|
||||
FX_API bool fx_dict_is_empty(const fx_dict *dict);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifndef FX_DS_HASHMAP_H_
|
||||
#define FX_DS_HASHMAP_H_
|
||||
|
||||
#include <fx/core/bst.h>
|
||||
#include <fx/core/macros.h>
|
||||
#include <fx/core/misc.h>
|
||||
#include <fx/core/queue.h>
|
||||
#include <fx/core/status.h>
|
||||
#include <stddef.h>
|
||||
|
||||
FX_DECLS_BEGIN;
|
||||
|
||||
struct fx_hashmap_p;
|
||||
|
||||
#define FX_TYPE_HASHMAP (fx_hashmap_get_type())
|
||||
#define FX_TYPE_HASHMAP_ITERATOR (fx_hashmap_iterator_get_type())
|
||||
|
||||
FX_DECLARE_TYPE(fx_hashmap);
|
||||
FX_DECLARE_TYPE(fx_hashmap_iterator);
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashmap)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_hashmap)
|
||||
|
||||
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_hashmap_iterator)
|
||||
FX_TYPE_CLASS_DECLARATION_END(fx_hashmap_iterator)
|
||||
|
||||
#define FX_HASHMAP_KEY(k, ks) {.key_data = (k), .key_size = (ks)}
|
||||
#define FX_HASHMAP_VALUE(v, vs) {.value_data = (v), .value_size = (vs)}
|
||||
|
||||
#define FX_HASHMAP_ITEM(k, ks, v, vs) \
|
||||
{.key = FX_HASHMAP_KEY(k, ks), .value = FX_HASHMAP_VALUE(v, vs)}
|
||||
|
||||
#define FX_HASHMAP_ITEM_END {.key = {0}, .value = {0}}
|
||||
|
||||
#define fx_hashmap_foreach(it, hashmap) \
|
||||
for (int z__fx_unique_name() = fx_hashmap_iterator_begin(hashmap, it); \
|
||||
(it)->key != NULL; fx_hashmap_iterator_next(it))
|
||||
|
||||
typedef void (*fx_hashmap_key_destructor)(void *);
|
||||
typedef void (*fx_hashmap_value_destructor)(void *);
|
||||
|
||||
typedef enum fx_hashmap_key_flags {
|
||||
FX_HASHMAP_KEY_F_INTVALUE = 0x01u,
|
||||
} fx_hashmap_key_flags;
|
||||
|
||||
typedef struct fx_hashmap_key {
|
||||
fx_hashmap_key_flags key_flags;
|
||||
const void *key_data;
|
||||
size_t key_size;
|
||||
} fx_hashmap_key;
|
||||
|
||||
typedef struct fx_hashmap_value {
|
||||
void *value_data;
|
||||
size_t value_size;
|
||||
} fx_hashmap_value;
|
||||
|
||||
typedef struct fx_hashmap_item {
|
||||
fx_hashmap_key key;
|
||||
fx_hashmap_value value;
|
||||
} fx_hashmap_item;
|
||||
|
||||
FX_API fx_type fx_hashmap_get_type(void);
|
||||
FX_API fx_type fx_hashmap_iterator_get_type(void);
|
||||
|
||||
FX_API fx_hashmap *fx_hashmap_create(
|
||||
fx_hashmap_key_destructor key_dtor, fx_hashmap_value_destructor value_dtor);
|
||||
FX_API fx_hashmap *fx_hashmap_create_with_items(const fx_hashmap_item *items);
|
||||
|
||||
FX_API fx_status fx_hashmap_put(
|
||||
fx_hashmap *hashmap, const fx_hashmap_key *key, const fx_hashmap_value *value);
|
||||
FX_API const fx_hashmap_value *fx_hashmap_get(
|
||||
const fx_hashmap *hashmap, const fx_hashmap_key *key);
|
||||
|
||||
FX_API bool fx_hashmap_has_key(const fx_hashmap *hashmap, const fx_hashmap_key *key);
|
||||
FX_API size_t fx_hashmap_get_size(const fx_hashmap *hashmap);
|
||||
FX_API bool fx_hashmap_is_empty(const fx_hashmap *hashmap);
|
||||
|
||||
FX_API fx_iterator *fx_hashmap_begin(fx_hashmap *hashmap);
|
||||
FX_API const fx_iterator *fx_hashmap_cbegin(const fx_hashmap *hashmap);
|
||||
|
||||
FX_DECLS_END;
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user