diff options
| author | Mikhail Romanko <me@blankhex.com> | 2024-06-03 22:11:05 +0300 |
|---|---|---|
| committer | Mikhail Romanko <me@blankhex.com> | 2024-06-03 22:11:05 +0300 |
| commit | 79874622a28c081abe155dc01860ddba746abd3b (patch) | |
| tree | 9dea56ea33951b7c851b534eb6f9d1ff1e1dcfe8 | |
| parent | fdbabab0e04fac2b5a84ea8e8088cd4767034a45 (diff) | |
| download | bhlib-old-79874622a28c081abe155dc01860ddba746abd3b.tar.gz | |
Add documentation, expand error handling, implement file and buffer io
37 files changed, 5529 insertions, 984 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 07b23f0..c84cd4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,9 @@ include(CTest) enable_testing() # Set library code -set(BHLIB_SOURCE +set(BH_SOURCE src/algo.c + src/buffer.c src/hashmap.c src/queue.c src/thread.c @@ -32,9 +33,10 @@ set(BHLIB_SOURCE src/deflate.c ) -set(BHLIB_HEADER +set(BH_HEADER include/bh/bh.h include/bh/platform.h + include/bh/buffer.h include/bh/algo.h include/bh/hashmap.h include/bh/queue.h @@ -43,7 +45,7 @@ set(BHLIB_HEADER include/bh/deflate.h ) -set(BHLIB_INCLUDE_DIRS +set(BH_INCLUDE_DIRS include ${PROJECT_BINARY_DIR}/include ) @@ -52,45 +54,58 @@ set(BHLIB_INCLUDE_DIRS # Determine platform if(WIN32) message(STATUS "Platform - Win32") + set(BH_PLATFORM_WIN TRUE) + + # Add platform dependent files + list(APPEND BH_SOURCE + src/file_win.c + ) # Check multithreading support - check_symbol_exists(_beginthread process.h BHLIB_USE_WINTHREAD) - if(BHLIB_USE_WINTHREAD) + check_symbol_exists(_beginthread process.h BH_USE_WINTHREAD) + if(BH_USE_WINTHREAD) message(STATUS "Multithreading enabled") - list(APPEND BHLIB_SOURCE + list(APPEND BH_SOURCE src/thread_win.c ) else() message(STATUS "Multithreading disabled") - list(APPEND BHLIB_SOURCE + list(APPEND BH_SOURCE src/thread_null.c ) endif() - if(BHLIB_NO_WINXP) + if(BH_NO_WINXP) add_definitions(-D_WIN32_WINNT=_WIN32_WINNT_VISTA -DWINVER=_WIN32_WINNT_VISTA) endif() elseif(UNIX) message(STATUS "Platform: Unix (Linux/BSD/MacOS X)") + set(BH_PLATFORM_POSIX TRUE) + + # Add platform dependent files + list(APPEND BH_SOURCE + src/file_posix.c + ) # Check multithreading support - check_include_file(pthread.h BHLIB_USE_PTHREAD) - if(BHLIB_USE_PTHREAD) + check_include_file(pthread.h BH_USE_PTHREAD) + if(BH_USE_PTHREAD) message(STATUS "Multithreading enabled") - list(APPEND BHLIB_SOURCE + list(APPEND BH_SOURCE src/thread_posix.c ) else() message(STATUS "Multithreading disabled") - list(APPEND BHLIB_SOURCE + list(APPEND BH_SOURCE src/thread_null.c ) endif() else() message(STATUS "Platform: Unknown") message(STATUS "Multithreading disabled") - list(APPEND BHLIB_SOURCE + list(APPEND BH_SOURCE src/thread_null.c + src/file_null.c ) endif() @@ -98,8 +113,8 @@ endif() configure_file(include/bh/config.in include/bh/config.h) # Library -add_library(bhlib STATIC ${BHLIB_SOURCE} ${BHLIB_HEADER}) -target_include_directories(bhlib PUBLIC ${BHLIB_INCLUDE_DIRS}) +add_library(bhlib STATIC ${BH_SOURCE} ${BH_HEADER}) +target_include_directories(bhlib PUBLIC ${BH_INCLUDE_DIRS}) # Runtime definition add_executable(main diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 0000000..0c19e87 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,2737 @@ +# Doxyfile 1.9.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = bhlib + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = YES + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = YES + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.l \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using JavaScript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. +# +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: YES. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. +# The default value is: YES. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. See also the chapter Grouping +# in the manual. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag UML_LOOK is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, +# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, +# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate +# files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. +# The default value is: YES. + +DOT_CLEANUP = YES diff --git a/include/bh/algo.h b/include/bh/algo.h index b859b1f..32a1583 100644 --- a/include/bh/algo.h +++ b/include/bh/algo.h @@ -1,154 +1,63 @@ -#ifndef BHLIB_ALGO_H -#define BHLIB_ALGO_H +#ifndef BH_ALGO_H +#define BH_ALGO_H #include "bh.h" -/** - * @brief Swap two elements. - * - * @param lhs Pointer to the first element - * @param rhs Pointer to the second element - * @param size Element size - */ -void bh_swap(void *lhs, - void *rhs, +void bh_swap(void *dest, + void *src, size_t size); -/** - * @brief Partition the array. - * - * @param pivot Pointer to the pivot element - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - * - * @return The return value is the pointer to the first element of the second - * partition. - * - * @warning Pivot element can be a part of the partitioned array. - */ void *bh_partition(void *pivot, void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Sort the array. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - */ void bh_sort(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Sort the array using insert sort. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - */ void bh_sort_insert(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Sort the array using shell sort. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - */ void bh_sort_shell(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Sort the array using intro sort. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - */ void bh_sort_intro(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Sort the array using heap sort. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - */ void bh_sort_heap(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Make heap from the array. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - * - * @sa bh_heap_remove, bh_heap_insert - */ void bh_heap_make(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Remove element from the heap. - * - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - * - * @warning Removed element is placed at the end of the array - * - * @sa bh_heap_make, bh_heap_remove - */ void bh_heap_remove(void *array, size_t size, size_t element, bh_equal_cb_t equal); -/** - * @brief Insert element to the heap. - * - * @param value Pointer to the inserted value (optional) - * @param array Pointer to the array - * @param size Array size - * @param element Element size - * @param equal Equal/compare function - * - * @warning If value is not passed, function assumes inserted element - * is already placed at the end of the array. - * - * @sa bh_heap_make, bh_heap_remove - */ void bh_heap_insert(void *value, void *array, size_t size, size_t element, bh_equal_cb_t equal); -#endif /* BHLIB_ALGO_H */ +void bh_heap_replace(void *value, + void *array, + size_t size, + size_t element, + bh_equal_cb_t equal); + +#endif /* BH_ALGO_H */ diff --git a/include/bh/bh.h b/include/bh/bh.h index f761518..277728e 100644 --- a/include/bh/bh.h +++ b/include/bh/bh.h @@ -1,25 +1,34 @@ -#ifndef BHLIB_H -#define BHLIB_H +#ifndef BH_H +#define BH_H #include <bh/config.h> #include <stddef.h> #include "platform.h" -#define BH_INT_TO_PTR(x) \ +#define BH_INT_TO_PTR(x) \ ((void *)((bh_intptr_t)(x))) -#define BH_UINT_TO_PTR(x) \ +#define BH_UINT_TO_PTR(x) \ ((void *)((bh_uintptr_t)(x))) -#define BH_PTR_TO_INT(x) \ +#define BH_PTR_TO_INT(x) \ ((bh_intptr_t)(x)) -#define BH_PTR_TO_UINT(x) \ +#define BH_PTR_TO_UINT(x) \ ((bh_uintptr_t)(x)) +#define BH_OK 0x0000 +#define BH_ERROR 0x0001 +#define BH_OOM 0x0002 +#define BH_INVALID 0x0003 +#define BH_NO_IMPL 0x0004 +#define BH_FOUND 0x0005 +#define BH_NOT_FOUND 0x0006 +#define BH_TIMEOUT 0x0007 + typedef int (*bh_equal_cb_t)(const void *, const void *); typedef size_t (*bh_hash_cb_t)(const void *); -#endif /* BHLIB_H */ +#endif /* BH_H */ diff --git a/include/bh/buffer.h b/include/bh/buffer.h new file mode 100644 index 0000000..35c89cc --- /dev/null +++ b/include/bh/buffer.h @@ -0,0 +1,91 @@ +#ifndef BH_BUFFER_H +#define BH_BUFFER_H + +#include "io.h" + +typedef struct bh_buffer_s bh_buffer_t; + +bh_buffer_t *bh_buffer_new(void); + +void bh_buffer_free(bh_buffer_t *buffer); + +const char *bh_buffer_data(bh_buffer_t *buffer); + +void bh_buffer_set_data(bh_buffer_t *buffer, + const char *data, + size_t size); + +size_t bh_buffer_capacity(bh_buffer_t *buffer); + +int bh_buffer_reserve(bh_buffer_t *buffer, + size_t size); + +int bh_buffer_open_base(bh_buffer_t *buffer, + int mode); + +void bh_buffer_close_base(bh_buffer_t *buffer); + +int bh_buffer_is_open_base(bh_buffer_t *buffer); + +size_t bh_buffer_read_base(bh_buffer_t *buffer, + char *data, + size_t size); + +size_t bh_buffer_write_base(bh_buffer_t *buffer, + const char *data, + size_t size); + +void bh_buffer_flush_base(bh_buffer_t *buffer); + +int bh_buffer_seek_base(bh_buffer_t *buffer, + bh_off_t pos, + int dir); + +bh_off_t bh_buffer_size_base(bh_buffer_t *buffer); + +bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer); + +bh_off_t bh_buffer_available_base(bh_buffer_t *buffer); + +void bh_buffer_clear_base(bh_buffer_t *buffer); + +#define bh_buffer_open(buffer, mode) \ + bh_io_open((bh_io_t *)(buffer), (mode)) + +#define bh_buffer_close(buffer) \ + bh_io_close((bh_io_t *)(buffer)) + +#define bh_buffer_is_open(buffer) \ + bh_io_is_open((bh_io_t *)(buffer)) + +#define bh_buffer_read(buffer, data, size) \ + bh_io_read((bh_io_t *)(buffer), (data), (size)) + +#define bh_buffer_write(buffer, data, size) \ + bh_io_write((bh_io_t *)(buffer), (data), (size)) + +#define bh_buffer_flush(buffer) \ + bh_io_flush((bh_io_t *)(buffer)) + +#define bh_buffer_seek(buffer, pos, dir) \ + bh_io_seek((bh_io_t *)(buffer), (pos), (dir)) + +#define bh_buffer_size(buffer) \ + bh_io_size((bh_io_t *)(buffer)) + +#define bh_buffer_tell(buffer) \ + bh_io_tell((bh_io_t *)(buffer)) + +#define bh_buffer_available(buffer) \ + bh_io_available((bh_io_t *)(buffer)) + +#define bh_buffer_clear(buffer) \ + bh_io_clear((bh_io_t *)(buffer)) + +#define bh_buffer_error(buffer) \ + bh_io_error((bh_io_t *)(buffer)) + +#define bh_buffer_eof(buffer) \ + bh_io_eof((bh_io_t *)(buffer)) + +#endif /* BH_BUFFER_H */ diff --git a/include/bh/config.in b/include/bh/config.in index 21dea6e..5820781 100644 --- a/include/bh/config.in +++ b/include/bh/config.in @@ -1,8 +1,10 @@ -#ifndef BHLIB_CONFIG_H -#define BHLIB_CONFIG_H +#ifndef BH_CONFIG_H +#define BH_CONFIG_H -#cmakedefine BHLIB_USE_WINTHREAD -#cmakedefine BHLIB_USE_PTHREAD -#cmakedefine BHLIB_NO_WINXP +#cmakedefine BH_USE_WINTHREAD +#cmakedefine BH_USE_PTHREAD +#cmakedefine BH_NO_WINXP +#cmakedefine BH_PLATFORM_POSIX +#cmakedefine BH_PLATFORM_WIN -#endif /* BHLIB_CONFIG_H */ +#endif /* BH_CONFIG_H */ diff --git a/include/bh/deflate.h b/include/bh/deflate.h index 6b0696b..7d9eaba 100644 --- a/include/bh/deflate.h +++ b/include/bh/deflate.h @@ -1,5 +1,5 @@ -#ifndef BHLIB_DEFLATE_H -#define BHLIB_DEFLATE_H +#ifndef BH_DEFLATE_H +#define BH_DEFLATE_H -#endif /* BHLIB_DEFLATE_H */ +#endif /* BH_DEFLATE_H */ diff --git a/include/bh/file.h b/include/bh/file.h index 7718c80..3410f74 100644 --- a/include/bh/file.h +++ b/include/bh/file.h @@ -1,37 +1,80 @@ -#ifndef BHLIB_FILE_H -#define BHLIB_FILE_H +#ifndef BH_FILE_H +#define BH_FILE_H #include "io.h" typedef struct bh_file_s bh_file_t; -bh_file_t *bh_file_new(const char *path, - const char *mode); - +bh_file_t *bh_file_new(const char *path); + void bh_file_free(bh_file_t *file); -size_t bh_file_read(bh_file_t *file, - char *buffer, - size_t size); +int bh_file_open_base(bh_file_t *file, + int mode); + +void bh_file_close_base(bh_file_t *file); + +int bh_file_is_open_base(bh_file_t *file); + +size_t bh_file_read_base(bh_file_t *file, + char *data, + size_t size); + +size_t bh_file_write_base(bh_file_t *file, + const char *data, + size_t size); + +void bh_file_flush_base(bh_file_t *file); + +int bh_file_seek_base(bh_file_t *file, + bh_off_t pos, + int dir); + +bh_off_t bh_file_size_base(bh_file_t *file); + +bh_off_t bh_file_tell_base(bh_file_t *file); + +bh_off_t bh_file_available_base(bh_file_t *file); + +void bh_file_clear_base(bh_file_t *file); + +#define bh_file_open(file, mode) \ + bh_io_open((bh_io_t *)(file), (mode)) + +#define bh_file_close(file) \ + bh_io_close((bh_io_t *)(file)) + +#define bh_file_is_open(file) \ + bh_io_is_open((bh_io_t *)(file)) + +#define bh_file_read(file, data, size) \ + bh_io_read((bh_io_t *)(file), (data), (size)) + +#define bh_file_write(file, data, size) \ + bh_io_write((bh_io_t *)(file), (data), (size)) -size_t bh_file_write(bh_file_t *file, - const char *buffer, - size_t size); +#define bh_file_flush(file) \ + bh_io_flush((bh_io_t *)(file)) -void bh_file_flush(bh_file_t *file); +#define bh_file_seek(file, pos, dir) \ + bh_io_seek((bh_io_t *)(file), (pos), (dir)) -void bh_file_seek(bh_file_t *file, - bh_off_t pos, - int dir); +#define bh_file_size(file) \ + bh_io_size((bh_io_t *)(file)) -bh_off_t bh_file_tell(bh_file_t *file); +#define bh_file_tell(file) \ + bh_io_tell((bh_io_t *)(file)) -bh_off_t bh_file_available(bh_file_t *file); +#define bh_file_available(file) \ + bh_io_available((bh_io_t *)(file)) -int bh_file_error(bh_file_t *file); +#define bh_file_clear(file) \ + bh_io_clear((bh_io_t *)(file)) -int bh_file_eof(bh_file_t *file); +#define bh_file_error(file) \ + bh_io_error((bh_io_t *)(file)) -void bh_file_clear(bh_file_t *file); +#define bh_file_eof(file) \ + bh_io_eof((bh_io_t *)(file)) -#endif /* BHLIB_FILE_H */ +#endif /* BH_FILE_H */ diff --git a/include/bh/hashmap.h b/include/bh/hashmap.h index 6e8634e..e57c03d 100644 --- a/include/bh/hashmap.h +++ b/include/bh/hashmap.h @@ -1,231 +1,53 @@ -#ifndef BHLIB_HASHMAP_H -#define BHLIB_HASHMAP_H +#ifndef BH_HASHMAP_H +#define BH_HASHMAP_H #include "bh.h" typedef struct bh_hashmap_s bh_hashmap_t; -/** - * @brief Create new hashmap object. - * - * @param equal Function used for comparing keys - * @param hash Function used to calculate hash value of the key - * - * @return If the function succeeds, the return value is a pointer to the new - * hashmap object. - * @return If the function fails, the return value is NULL. - * - * @sa bh_hashmap_free, bh_hashmap_reserve, bh_hashmap_insert - */ bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal, bh_hash_cb_t hash); -/** - * @brief Free hashmap object. - * - * @param hashmap Valid pointer to the hashmap object. - * - * @sa bh_hashmap_clear - */ void bh_hashmap_free(bh_hashmap_t *hashmap); -/** - * @brief Clear the hashmap. - * - * @param hashmap Valid pointer to the hashmap object. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_hashmap_remove - */ void bh_hashmap_clear(bh_hashmap_t *hashmap); -/** - * @brief Reserve space for the specified amount of elements. - * - * @param hashmap Valid pointer to the hashmap object. - * @param size The amount of elements. - * - * @return If the function succeeds, the return value is zero. - * @return If the function fails, the return value is non-zero. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_hashmap_capacity, bh_hashmap_insert - */ int bh_hashmap_reserve(bh_hashmap_t *hashmap, size_t size); -/** - * @brief Insert key/value into the hashmap. - * - * @param hashmap Valid pointer to the hashmap object. - * @param key Key - * @param value Value - * - * @return If the function succeeds, the return value is zero. - * @return If the function fails, the return value is non-zero. - * - * @warning Inserted element is owned by the caller of the function. - * @warning Calling this function will invalidate iterators. - * - * @sa bh_hashmap_remove, bh_hashmap_at - */ int bh_hashmap_insert(bh_hashmap_t *hashmap, void *key, void *value); -/** - * @brief Remove element from the hashmap. - * - * @param hashmap Valid pointer to the hashmap object. - * @param key Key. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_hashmap_insert, bh_hashmap_at - */ void bh_hashmap_remove(bh_hashmap_t *hashmap, void *key); -/** - * @brief Return element value by the key from the hashmap. - * - * @param hashmap Valid pointer to the hashmap. - * @param key Key. - * @param exists Optional pointer to the exists flag. - * - * @return If the function succeeds, the return value is a valid pointer to - * the element value. - * @return If the function fails, the return value is NULL. - * - * @sa bh_hashmap_empty, bh_hashmap_insert - */ void *bh_hashmap_at(bh_hashmap_t *hashmap, void *key, int *exists); -/** - * @brief Check if the hashmap is empty. - * - * @param hashmap Valid pointer to the hashmap object. - * - * @return The return value is non-zero if the hashmap is empty, otherwise - * zero. - * - * @sa bh_hashmap_size - */ int bh_hashmap_empty(bh_hashmap_t *hashmap); -/** - * @brief Return hashmap size. - * - * @param hashmap Valid pointer to the hashmap object. - * - * @return The return value is current hashmap size. - * - * @sa bh_hashmap_empty, bh_hashmap_capacity - */ size_t bh_hashmap_size(bh_hashmap_t *hashmap); -/** - * @brief Return hashmap capacity. - * - * @param hashmap Valid pointer to the hashmap object. - * - * @return The return value is current hashmap capacity. - * - * @sa bh_hashmap_reserve, bh_hashmap_size - */ size_t bh_hashmap_capacity(bh_hashmap_t *hashmap); -/** - * @brief Return hashmap load factor. - * - * @param hashmap Valid pointer to the hashmap object. - * - * @return The return value is current hashmap load factor. - * - * @sa bh_hashmap_set_factor, bh_hashmap_capacity - */ float bh_hashmap_factor(bh_hashmap_t *hashmap); -/** - * @brief Set hashmap load factor. - * - * @param hashmap Valid pointer to the hashmap object. - * @param factor Load factor. - * - * @sa bh_hashmap_factor - */ void bh_hashmap_set_factor(bh_hashmap_t *hashmap, float factor); -/** - * @brief Return iterator for the element by the key. - * - * @param hashmap Valid pointer to the hashmap object. - * @param key Key - * - * @return The return value is the valid iterator for the element in the - * hashmap. - * @return The return value is the NULL iterator if there is no element with - * specified key. - * - * @sa bh_hashmap_iter_key, bh_hashmap_iter_value - */ void *bh_hashmap_iter_at(bh_hashmap_t *hashmap, void *key); -/** - * @brief Return iterator for the next element in the hashmap. - * - * @param hashmap Valid pointer to the hashmap object. - * @param iter Valid or NULL iterator. - * - * @return The return value is the valid iterator for the next element in the - * hashmap. - * @return The return value is the NULL iterator if there is no more elements - * in the hashmap. - * - * @sa bh_hashmap_iter_key, bh_hashmap_iter_value - */ void *bh_hashmap_iter_next(bh_hashmap_t *hashmap, void *iter); -/** - * @brief Remove element from the hashmap by the iterator. - * - * @param hashmap Valid pointer to the hashmap object. - * @param key Valid iterator. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_hashmap_insert, bh_hashmap_at - */ void bh_hashmap_iter_remove(bh_hashmap_t *hashmap, void *iter); -/** - * @brief Return pointer to the element's key. - * - * @param iter Valid iterator. - * - * @return The return value is the stored element key. - * - * @sa bh_hashmap_iter_value, bh_hashmap_iter_next - */ void *bh_hashmap_iter_key(void *iter); -/** - * @brief Return pointer to the element's value. - * - * @param iter Valid iterator. - * - * @return The return value is the stored element value. - * - * @sa bh_hashmap_iter_key, bh_hashmap_iter_next - */ void *bh_hashmap_iter_value(void *iter); -#endif /* BHLIB_HASHMAP_H */ +#endif /* BH_HASHMAP_H */ diff --git a/include/bh/internal/buffer.h b/include/bh/internal/buffer.h new file mode 100644 index 0000000..ab033b6 --- /dev/null +++ b/include/bh/internal/buffer.h @@ -0,0 +1,20 @@ +#ifndef BH_INTERNAL_BUFFER_H +#define BH_INTERNAL_BUFFER_H + +#include <bh/buffer.h> + +struct bh_buffer_s +{ + bh_io_t base; + char *data; + size_t capacity; + size_t size; + size_t at; + int mode; +}; + +int bh_buffer_init(bh_buffer_t *buffer); + +void bh_buffer_destroy(bh_buffer_t *buffer); + +#endif /* BH_INTERNAL_BUFFER_H */ diff --git a/include/bh/internal/file.h b/include/bh/internal/file.h new file mode 100644 index 0000000..f23cf29 --- /dev/null +++ b/include/bh/internal/file.h @@ -0,0 +1,20 @@ +#ifndef BH_INTERNAL_FILE_H +#define BH_INTERNAL_FILE_H + +#include "io.h" +#include <bh/file.h> + +#if defined(BH_PLATFORM_POSIX) +#include "file_posix.h" +#elif defined(BH_PLATFORM_WIN) +#include "file_win.h" +#else +#include "file_null.h" +#endif + +int bh_file_init(bh_file_t *file, + const char *path); + +void bh_file_destroy(bh_file_t *file); + +#endif /* BH_INTERNAL_FILE_H */ diff --git a/include/bh/internal/file_null.h b/include/bh/internal/file_null.h new file mode 100644 index 0000000..dd5338b --- /dev/null +++ b/include/bh/internal/file_null.h @@ -0,0 +1,4 @@ +struct bh_file_s +{ + bh_io_t base; +}; diff --git a/include/bh/internal/file_posix.h b/include/bh/internal/file_posix.h index e69de29..e041e61 100644 --- a/include/bh/internal/file_posix.h +++ b/include/bh/internal/file_posix.h @@ -0,0 +1,9 @@ +#include <unistd.h> + +struct bh_file_s +{ + bh_io_t base; + char *path; + int mode; + int handle; +};
\ No newline at end of file diff --git a/include/bh/internal/file_win.h b/include/bh/internal/file_win.h index e69de29..026d239 100644 --- a/include/bh/internal/file_win.h +++ b/include/bh/internal/file_win.h @@ -0,0 +1,9 @@ +#include <windows.h> + +struct bh_file_s +{ + bh_io_t base; + char *path; + int mode; + HANDLE handle; +};
\ No newline at end of file diff --git a/include/bh/internal/hashmap.h b/include/bh/internal/hashmap.h index 8d62c16..416611d 100644 --- a/include/bh/internal/hashmap.h +++ b/include/bh/internal/hashmap.h @@ -1,5 +1,5 @@ -#ifndef BHLIB_INTERNAL_HASHMAP_H -#define BHLIB_INTERNAL_HASHMAP_H +#ifndef BH_INTERNAL_HASHMAP_H +#define BH_INTERNAL_HASHMAP_H #include <bh/hashmap.h> @@ -27,4 +27,4 @@ void bh_hashmap_init(bh_hashmap_t *hashmap, void bh_hashmap_destroy(bh_hashmap_t *hashmap); -#endif /* BHLIB_INTERNAL_HASHMAP_H */ +#endif /* BH_INTERNAL_HASHMAP_H */ diff --git a/include/bh/internal/io.h b/include/bh/internal/io.h index 6a1f7ed..988982c 100644 --- a/include/bh/internal/io.h +++ b/include/bh/internal/io.h @@ -1,12 +1,12 @@ -#ifndef BHLIB_INTERNAL_IO_H -#define BHLIB_INTERNAL_IO_H +#ifndef BH_INTERNAL_IO_H +#define BH_INTERNAL_IO_H #include <bh/io.h> void bh_io_init(bh_io_t *io, - bh_io_table_t *table); + const bh_io_table_t *table); void bh_io_destroy(bh_io_t *io); -#endif /* BHLIB_INTERNAL_IO_H */ +#endif /* BH_INTERNAL_IO_H */ diff --git a/include/bh/internal/queue.h b/include/bh/internal/queue.h index 13a6cad..fd3d8e8 100644 --- a/include/bh/internal/queue.h +++ b/include/bh/internal/queue.h @@ -1,5 +1,5 @@ -#ifndef BHLIB_INTERNAL_QUEUE_H -#define BHLIB_INTERNAL_QUEUE_H +#ifndef BH_INTERNAL_QUEUE_H +#define BH_INTERNAL_QUEUE_H #include <bh/queue.h> @@ -12,24 +12,8 @@ struct bh_queue_s size_t capacity; }; -/** - * @internal - * @brief Initialize embedded queue object. - * - * @param queue Valid pointer to the queue object. - * - * @sa bh_queue_destroy - */ void bh_queue_init(bh_queue_t *queue); -/** - * @internal - * @brief Destroy embedded queue object. - * - * @param queue Valid pointer to the queue object. - * - * @sa bh_queue_init - */ void bh_queue_destroy(bh_queue_t *queue); -#endif /* BHLIB_INTERNAL_QUEUE_H */ +#endif /* BH_INTERNAL_QUEUE_H */ diff --git a/include/bh/internal/thread.h b/include/bh/internal/thread.h index fe2a9c8..34e2f76 100644 --- a/include/bh/internal/thread.h +++ b/include/bh/internal/thread.h @@ -1,14 +1,14 @@ -#ifndef BHLIB_INTERNAL_THREAD_H -#define BHLIB_INTERNAL_THREAD_H +#ifndef BH_INTERNAL_THREAD_H +#define BH_INTERNAL_THREAD_H #include <bh/thread.h> #include "queue.h" -#define BH_THREAD_DONE (1 << 8) +#define BH_THREAD_DONE 0x0100 -#if defined(BHLIB_USE_PTHREAD) +#if defined(BH_USE_PTHREAD) #include "thread_posix.h" -#elif defined(BHLIB_USE_WINTHREAD) +#elif defined(BH_USE_WINTHREAD) #include "thread_win.h" #else #include "thread_null.h" @@ -42,4 +42,4 @@ void bh_task_destroy(bh_task_t *task); void bh_thread_pool_worker(void *arg); -#endif /* BHLIB_INTERNAL_THREAD_H */ +#endif /* BH_INTERNAL_THREAD_H */ diff --git a/include/bh/internal/thread_win.h b/include/bh/internal/thread_win.h index 57150f0..46365c8 100644 --- a/include/bh/internal/thread_win.h +++ b/include/bh/internal/thread_win.h @@ -50,7 +50,7 @@ int bh_thread_init_base(bh_thread_t *thread, int bh_mutex_init(bh_mutex_t *mutex); void bh_mutex_destroy(bh_mutex_t *mutex); -int bh_semaphore_init(bh_semaphore_t *semaphore, +int bh_semaphore_init(bh_semaphore_t *semaphore, int count); void bh_semaphore_destroy(bh_semaphore_t *semaphore); diff --git a/include/bh/io.h b/include/bh/io.h index cdf442a..b5510f3 100644 --- a/include/bh/io.h +++ b/include/bh/io.h @@ -1,10 +1,24 @@ -#ifndef BHLIB_IO_H -#define BHLIB_IO_H +#ifndef BH_IO_H +#define BH_IO_H #include "bh.h" -#define BH_IO_ERROR (1 << 0) -#define BH_IO_EOF (1 << 1) +#define BH_IO_ERROR 0x0001 +#define BH_IO_EOF 0x0002 + +#define BH_IO_READ 0x0001 +#define BH_IO_WRITE 0x0002 +#define BH_IO_READ_WRITE (BH_IO_READ | BH_IO_WRITE) +#define BH_IO_OPEN 0x0000 +#define BH_IO_CREATE 0x0100 +#define BH_IO_APPEND 0x0200 +#define BH_IO_TRUNCATE 0x0300 +#define BH_IO_MASK 0xFF00 + + +#define BH_IO_SET 0x0000 +#define BH_IO_CURRENT 0x0001 +#define BH_IO_END 0x0002 #define BH_IO_CAST(x) \ ((bh_io_t *)(x)) @@ -13,6 +27,13 @@ struct bh_io_s; typedef struct bh_io_table_s { + int (*open)(struct bh_io_s *io, + int mode); + + void (*close)(struct bh_io_s *io); + + int (*is_open)(struct bh_io_s *io); + size_t (*read)(struct bh_io_s *io, char *data, size_t size); @@ -23,9 +44,11 @@ typedef struct bh_io_table_s void (*flush)(struct bh_io_s *io); - void (*seek)(struct bh_io_s *io, - bh_off_t offset, - int dir); + int (*seek)(struct bh_io_s *io, + bh_off_t offset, + int dir); + + bh_off_t (*size)(struct bh_io_s *io); bh_off_t (*tell)(struct bh_io_s *io); @@ -38,145 +61,49 @@ typedef struct bh_io_table_s typedef struct bh_io_s { - bh_io_table_t *table; + const bh_io_table_t *table; int flags; } bh_io_t; -/** - * @brief Create new IO object. - * - * @param table Valid pointer to the IO table. - * @param size Size of the IO object. - * - * @return If the function succeeds, the return value is a pointer to the - * new, semi-initalized, IO object. - * @return If the function fails, the return value is NULL. - * - * @warning This function should be used in context of implementing child - * IO objects (files, sockets, streaming compression, etc). - * - * @sa bh_io_free - */ bh_io_t *bh_io_new(bh_io_table_t *table, size_t size); -/** - * @brief Free IO object. - * - * @param io Valid pointer to the IO object. - */ void bh_io_free(bh_io_t *io); -/** - * @brief Read data from IO. - * - * @param io Valid pointer to the IO object. - * @param data Valid pointer to the buffer. - * @param size Size of the buffer. - * - * @return If the function succeeds, the return value is the amount - * of bytes read from the IO object. - * @return If the function fails, the return value is zero and error - * flag is set. - * - * @sa bh_io_write, bh_io_eof, bh_io_error - */ +int bh_io_open(bh_io_t *io, + int mode); + +void bh_io_close(bh_io_t *io); + +int bh_io_is_open(bh_io_t *io); + size_t bh_io_read(bh_io_t *io, char *data, size_t size); -/** - * @brief Write data to IO. - * - * @param io Valid pointer to the IO object. - * @param data Valid pointer to the buffer. - * @param size Size of the buffer. - * - * @return If the function succeeds, the return value is the amount - * of bytes written to the IO object. - * @return If the function fails, the return value is zero and error - * flag is set. - * - * @sa bh_io_read, bh_io_error, bh_io_flush - */ + size_t bh_io_write(bh_io_t *io, const char* data, size_t size); -/** - * @brief Writes any uncommited changes (if possible). - * - * @param io Valid pointer to the IO object. - */ void bh_io_flush(bh_io_t *io); -/** - * @brief Seeks IO object to the specified position (if possible). - * - * @param io Valid pointer to the IO object. - * @param offset Position - * @param dir Direction - * - * @sa bh_io_tell - */ -void bh_io_seek(bh_io_t *io, - bh_off_t offset, - int dir); -/** - * @brief Return current position in IO. - * - * @param io Valid pointer to the IO object. - * - * @return If the function succeeds, the return value is current - * position in the IO. - * @return If the function fails, the return value is -1. - * - * @sa bh_io_seek - */ +int bh_io_seek(bh_io_t *io, + bh_off_t offset, + int dir); + +bh_off_t bh_io_size(bh_io_t *io); + bh_off_t bh_io_tell(bh_io_t *io); -/** - * @brief Return available bytes in the IO. - * - * @param io Valid pointer to the IO object. - * - * @return If the function succeeds, the return value is the amount - * of the available bytes for reading. - * @return If the function fails, the return value is zero. - */ + bh_off_t bh_io_available(bh_io_t *io); -/** - * @brief Return error flag of the IO. - * - * @param io Valid pointer to the IO object. - * - * @return The return value is error flag. - * - * @sa bh_io_eof, bh_io_clear - */ int bh_io_error(bh_io_t *io); -/** - * @brief Return end-of-file flag of the IO. - * - * @param io Valid pointer to the IO object. - * - * @return The return value is end-of-file flag. - * - * @sa bh_io_error, bh_io_clear - */ int bh_io_eof(bh_io_t *io); -/** - * @brief Crear IO object state. - * - * @param io Valid pointer to the IO object. - * - * @sa bh_io_error, bh_io_eof - */ void bh_io_clear(bh_io_t *io); - -#endif /* BHLIB_IO_H */ +#endif /* BH_IO_H */ diff --git a/include/bh/platform.h b/include/bh/platform.h index c48149c..59d9051 100644 --- a/include/bh/platform.h +++ b/include/bh/platform.h @@ -1,5 +1,5 @@ -#ifndef BHLIB_PLATFORM_H -#define BHLIB_PLATFORM_H +#ifndef BH_PLATFORM_H +#define BH_PLATFORM_H #include <stddef.h> @@ -43,4 +43,4 @@ typedef unsigned __int32 bh_uintptr_t; typedef bh_int64_t bh_off_t; -#endif /* BHLIB_PLATFORM_H */ +#endif /* BH_PLATFORM_H */ diff --git a/include/bh/queue.h b/include/bh/queue.h index d25af65..2baf1b6 100644 --- a/include/bh/queue.h +++ b/include/bh/queue.h @@ -5,152 +5,31 @@ typedef struct bh_queue_s bh_queue_t; -/** - * @brief Create new queue object. - * - * @return If the function succeeds, the return value is a pointer to the new - * queue object. - * @return If the function fails, the return value is NULL. - * - * @sa bh_queue_free, bh_queue_reserve, bh_queue_insert - */ bh_queue_t *bh_queue_new(void); -/** - * @brief Free queue object. - * - * @param queue Valid pointer to the queue object. - * - * @sa bh_queue_clear - */ void bh_queue_free(bh_queue_t *queue); -/** - * @brief Clear the queue. - * - * @param queue Valid pointer to the queue object. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_queue_remove - */ void bh_queue_clear(bh_queue_t *queue); -/** - * @brief Reserve space for the specified amount of elements. - * - * @param queue Valid pointer to the queue object. - * @param size The amount of elements. - * - * @return If the function succeeds, the return value is zero. - * @return If the function fails, the return value is non-zero. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_queue_capacity, bh_queue_insert - */ int bh_queue_reserve(bh_queue_t *queue, size_t size); -/** - * @brief Insert element at the end of the queue. - * - * @param queue Valid pointer to the queue object. - * @param value Element. - * - * @return If the function succeeds, the return value is zero. - * @return If the function fails, the return value is non-zero. - * - * @warning Inserted element is owned by the caller of the function. - * @warning Calling this function will invalidate iterators. - * - * @sa bh_queue_remove, bh_queue_front - */ int bh_queue_insert(bh_queue_t *queue, void *value); -/** - * @brief Remove element from the front of the queue. - * - * @param queue Valid pointer to the queue object. - * - * @warning Calling this function will invalidate iterators. - * - * @sa bh_queue_insert, bh_queue_front - */ void bh_queue_remove(bh_queue_t *queue); -/** - * @brief Return element from the front of the queue. - * - * @param queue Valid pointer to the queue object. - * - * @return If the function succeeds, the return value is a valid pointer to - * the element. - * @return If the function fails, the return value is NULL. - * - * @sa bh_queue_empty, bh_queue_insert - */ void *bh_queue_front(bh_queue_t *queue); -/** - * @brief Check if the queue is empty. - * - * @param queue Valid pointer to the queue object. - * - * @return The return value is non-zero if the queue is empty, otherwise zero. - * - * @sa bh_queue_size - */ int bh_queue_empty(bh_queue_t *queue); -/** - * @brief Return queue size. - * - * @param queue Valid pointer to the queue object. - * - * @return The return value is current queue size. - * - * @sa bh_queue_empty, bh_queue_capacity - */ size_t bh_queue_size(bh_queue_t *queue); -/** - * @brief Return queue capacity. - * - * @param queue Valid pointer to the queue object. - * - * @return The return value is current queue capacity. - * - * @sa bh_queue_reserve, bh_queue_size - */ size_t bh_queue_capacity(bh_queue_t *queue); -/** - * @brief Return iterator for the next element in the queue. - * - * @param queue Valid pointer to the queue object. - * @param iter Valid or NULL iterator. - * - * @return The return value is the valid iterator for the next element in the - * queue. - * @return The return value is the NULL iterator if there is no more elements - * in the queue. - * - * @sa bh_queue_iter_value - */ void *bh_queue_iter_next(bh_queue_t *queue, void *iter); -/** - * @brief Return pointer to the element's value. - * - * @param iter Valid iterator. - * - * @return The return value is the stored element. - * - * @sa bh_queue_iter_next - */ void *bh_queue_iter_value(void *iter); #endif /* BH_QUEUE_H */ diff --git a/include/bh/thread.h b/include/bh/thread.h index cfc02e8..22bdf30 100644 --- a/include/bh/thread.h +++ b/include/bh/thread.h @@ -1,9 +1,9 @@ -#ifndef BHLIB_THREAD_H -#define BHLIB_THREAD_H +#ifndef BH_THREAD_H +#define BH_THREAD_H #include "bh.h" -#define BH_THREAD_CLEANUP (1 << 0) +#define BH_THREAD_CLEANUP 0x0001 typedef void (*bh_thread_cb_t)(void *); typedef struct bh_thread_s bh_thread_t; @@ -13,12 +13,12 @@ typedef struct bh_cond_s bh_cond_t; typedef struct bh_task_s bh_task_t; typedef struct bh_thread_pool_s bh_thread_pool_t; -#if defined(BHLIB_USE_PTHREAD) +#if defined(BH_USE_PTHREAD) bh_thread_t *bh_thread_new(bh_task_t *task); bh_thread_pool_t *bh_thread_pool_new(size_t size); -#elif defined(BHLIB_USE_WINTHREAD) +#elif defined(BH_USE_WINTHREAD) #include <windows.h> #include <process.h> @@ -47,250 +47,65 @@ bh_thread_pool_t *bh_thread_pool_new_base(size_t size, #endif -/** - * @brief Create new task - * - * @param func Function - * @param data Function data - * @param flags Task flags - * - * @return Pointer to the new task - * - * @sa bh_task_free, bh_task_reuse, bh_task_done - */ bh_task_t *bh_task_new(void (*func)(void *), void *data, int flags); -/** - * @brief Free the task. - * - * @param task Pointer to the task - */ void bh_task_free(bh_task_t *task); -/** - * @brief Reuse task. - * - * @param task Pointer to the task - * @param func Function - * @param data Data - * - * @sa bh_task_free, bh_task_done - */ void bh_task_reuse(bh_task_t *task, void (*func)(void *), void *data); -/** - * @brief Check if task is done. - * - * @param task Pointer to the task - * - * @return The return value is boolean flag, indicating if the task is done. - */ int bh_task_done(bh_task_t *task); -/** - * @function bh_thread_new - * - * @brief Create new thread. - * - * @param task Thread task - * - * @return Pointer to thread - * - * @sa bh_thread_join, bh_thread_detach - */ - -/** - * @function bh_thread_pool_new - * @brief Create new thread pool. - * - * @param pool Pointer to the thread pool - * @param size Amount of threads - * - * @return Pointer to thread pool - * - * @sa bh_thread_pool_add, bh_thread_pool_join, bh_thread_pool_free - */ - -/** - * @brief Join thread. - * - * @param thread Pointer to the thread - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_thread_detach - */ int bh_thread_join(bh_thread_t *thread); -/** - * @brief Detach thread. - * - * @param thread Pointer to the thread - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_thread_join - */ int bh_thread_detach(bh_thread_t *thread); -/** - * @brief Create mutex. - * - * @return Pointer to the mutex - * - * @sa bh_mutex_lock, bh_mutex_try_lock, bh_mutex_destroy - */ bh_mutex_t *bh_mutex_new(void); -/** - * @brief Free mutex. - * - * @param mutex Pointer ot the mutex - */ void bh_mutex_free(bh_mutex_t *mutex); -/** - * @brief Lock mutex. - * - * @param mutex Pointer to the mutex - * - * @return 0 on success, non-zero otherwise - * - * @note Locking already locked mutex will block thread until mutex is - * released - * - * @sa bh_mutex_try_lock, bh_mutex_unlock - */ int bh_mutex_lock(bh_mutex_t *mutex); -/** - * @brief Try to lock mutex. - * - * @param mutex Pointer to the mutex - * - * @return 0 on success, positive value if mutex is locked, negative value on - * error - * - * @sa bh_mutex_lock, bh_mutex_unlock - */ int bh_mutex_try_lock(bh_mutex_t *mutex); -/** - * @brief Unlock mutex. - * - * @param mutex Pointer to the mutex - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_mutex_lock, bh_mutex_try_lock - */ int bh_mutex_unlock(bh_mutex_t *mutex); bh_semaphore_t *bh_semaphore_new(int count); + void bh_semaphore_free(bh_semaphore_t *semaphore); + int bh_semaphore_post(bh_semaphore_t *semaphore); + int bh_semaphore_wait(bh_semaphore_t *semaphore); + int bh_semaphore_wait_for(bh_semaphore_t *semaphore, unsigned long timeout); + int bh_semaphore_try_wait(bh_semaphore_t *semaphore); -/** - * @brief Create condition variable. - * - * @return Pointer to the condition variable - */ bh_cond_t *bh_cond_new(void); -/** - * @brief Destroy condition variable. - * - * @param cond Pointer to the conditional variable - */ void bh_cond_free(bh_cond_t *cond); -/** - * @brief Block on conditional variable. - * - * @param cond Pointer to the condition variable - * @param mutex Pointer to the mutex - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_cond_wait_for, bh_cond_signal, bh_cond_broadcast - */ int bh_cond_wait(bh_cond_t *cond, bh_mutex_t *mutex); -/** - * @brief Block on conditional variable for a period of the time. - * - * @param cond Pointer to the conditional variable - * @param mutex Pointer to the mutex - * @param timeout Timeout in miliseconds - * - * @return 0 on success, positive value on timeout, negative on error - * - * @sa bh_cond_wait, bh_cond_signal, bh_cond_broadcast - */ int bh_cond_wait_for(bh_cond_t *cond, bh_mutex_t *mutex, unsigned long timeout); -/** - * @brief Unblock (notify) thread. - * - * @param cond Pointer to the condition variable - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_cond_broadcast, bh_cond_wait, bh_cond_wait_for - */ int bh_cond_signal(bh_cond_t *cond); -/** - * @brief Unblock all threads. - * - * @param cond Pointer to the conditional variable - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_cond_signal, bh_cond_wait, bh_cond_wait_for - */ int bh_cond_broadcast(bh_cond_t *cond); -/** - * @brief Submit task to the thread pool. - * - * @param pool Pointer to the thread pool - * @param func Task function - * @param data Task data - * - * @return 0 on success, non-zero otherwise - * - * @sa bh_thread_pool_join - */ int bh_thread_pool_add(bh_thread_pool_t *pool, bh_task_t *task); -/** - * @brief Wait until all tasks are finished. - * - * @param pool Pointer to the thread pool - * @return 0 on success, non-zero otherwise - * - * @sa bh_thread_pool_add - */ int bh_thread_pool_wait(bh_thread_pool_t *pool); -/** - * @brief Destroy thread pool. - * - * @param pool Pointer to the thread pool - */ void bh_thread_pool_free(bh_thread_pool_t *pool); -#endif /* BHLIB_THREAD_H */ +#endif /* BH_THREAD_H */ @@ -1,6 +1,8 @@ #include <bh/queue.h> #include <bh/hashmap.h> #include <bh/thread.h> +#include <bh/file.h> +#include <bh/buffer.h> #include <stdio.h> #include <stdint.h> @@ -50,7 +52,7 @@ void factor_task(void *arg) //printf("Factor: %d\n", factor(42)); //fflush(stdout); volatile int i = factor(16); - + //printf("Factor: %d\n", factor(15)); } @@ -61,7 +63,7 @@ void bar() bh_thread_pool_t *pool; bh_task_t *task; size_t i; - + bh_uint64_t start, end; //printf("Pool create\n"); @@ -75,9 +77,9 @@ void bar() //printf("Prepare\n"); //fflush(stdout); - + start = __rdtsc(); - + for (i = 0; i < 128 * 1024; i++) { //printf("Task create\n"); @@ -85,26 +87,173 @@ void bar() task = bh_task_new(factor_task, NULL, BH_THREAD_CLEANUP); bh_thread_pool_add(pool, task); } - + //system("pause"); bh_thread_pool_wait(pool); end = __rdtsc(); bh_thread_pool_free(pool); - - - + + + printf("Elapsed: %llu\n", end - start); //system("pause"); } +int fib(int x) +{ + static int memory[128] = {0}; + int result; + + if (x < 128 && memory[x] != 0) + return memory[x]; + + if (x <= 1) + return 1; + + + result = fib(x - 1) + fib(x - 2); + + if (x < 128) + memory[x] = result; + + return result; +} + +#include <string.h> + +char* itoa (unsigned long long value, char str[], int radix) +{ + char buf [66]; + char* dest = buf + sizeof(buf); + int sign = 0; + + if (value == 0) { + memcpy (str, "0", 2); + return str; + } + + if (radix < 0) { + radix = -radix; + if ( (long long) value < 0) { + value = -value; + sign = 1; + } + } + + *--dest = '\0'; + + switch (radix) + { + case 16: + while (value) { + * --dest = '0' + (value & 0xF); + if (*dest > '9') *dest += 'A' - '9' - 1; + value >>= 4; + } + break; + case 10: + while (value) { + *--dest = '0' + (value % 10); + value /= 10; + } + break; + + case 8: + while (value) { + *--dest = '0' + (value & 7); + value >>= 3; + } + break; + + case 2: + while (value) { + *--dest = '0' + (value & 1); + value >>= 1; + } + break; + + default: // The slow version, but universal + while (value) { + *--dest = '0' + (value % radix); + if (*dest > '9') *dest += 'A' - '9' - 1; + value /= radix; + } + break; + } + + if (sign) *--dest = '-'; + + memcpy (str, dest, buf +sizeof(buf) - dest); + return str; +} + +void test_api(bh_io_t *io) +{ + int i; + + for (i = 0; i < 128; i++) + { + char str[65]; + + itoa(i, str, 10); + bh_io_write(io, str, strlen(str)); + bh_io_write(io, " ", 1); + itoa(fib(i), str, 10); + bh_io_write(io, str, strlen(str)); + bh_io_write(io, "\n", 1); + } +} + +void test(void) +{ + bh_file_t *file = bh_file_new("log.txt"); + + if (!file) + return; + + if (bh_file_open(file, BH_IO_APPEND | BH_IO_WRITE)) + { + printf("File not opened?"); + bh_file_free(file); + return; + } + + bh_file_write(file, "Hello, world!\n", 14); + test_api((bh_io_t *)file); + bh_file_free(file); +} + +void ddump() +{ + bh_buffer_t *buffer; + bh_file_t *file; + + buffer = bh_buffer_new(); + bh_buffer_open(buffer, BH_IO_WRITE); + + bh_buffer_write(buffer, "Hello, world!", 13); + bh_buffer_close(buffer); + + file = bh_file_new("debug.txt"); + bh_file_open(file, BH_IO_WRITE | BH_IO_TRUNCATE); + bh_file_write(file, bh_buffer_data(buffer), bh_buffer_size(buffer)); + + bh_file_free(file); + bh_buffer_free(buffer); +} + int main() { bh_queue_t *queue; void *iter; size_t i, j; + ddump(); + return 0; + //foo(); + test(); printf("Thread?\n"); fflush(stdout); @@ -1,34 +1,72 @@ #include <bh/algo.h> #include <string.h> -#include <stdio.h> -void bh_swap(void *lhs, - void *rhs, +/** + * \defgroup algo Algorithms + * + * Common algorithms (search, swap, heap, etc) + * \{ + */ + +/** + * Swaps \a size bytes between the object pointed to by \a src and object + * pointed to by \a dest. + * + * If the objects overlap, the behavior is undefined. + * + * If either \a src or \a dest is an invalid or null pointer, the behavior is + * undefined. + * + * \param dest Pointer to the memory location to swap to + * \param src Pointer to the memory location to swap from + * \param size Number of bytes to swap + */ +void bh_swap(void *dest, + void *src, size_t size) { int tmp; - /* Swap values in int sized chunks */ + /* Swap bytes in int-sized chunks */ while (size >= sizeof(tmp)) { - memmove(&tmp, lhs, sizeof(tmp)); - memmove(lhs, rhs, sizeof(tmp)); - memmove(rhs, &tmp, sizeof(tmp)); + memmove(&tmp, dest, sizeof(tmp)); + memmove(dest, src, sizeof(tmp)); + memmove(src, &tmp, sizeof(tmp)); - lhs = (char *)lhs + sizeof(tmp); - rhs = (char *)rhs + sizeof(tmp); + dest = (char *)dest + sizeof(tmp); + src = (char *)src + sizeof(tmp); size -= sizeof(tmp); } - /* Swap the rest */ + /* Swap the remaining size */ if (size) { - memmove(&tmp, lhs, size); - memmove(lhs, rhs, size); - memmove(rhs, &tmp, size); + memmove(&tmp, dest, size); + memmove(dest, src, size); + memmove(src, &tmp, size); } } +/** + * Partitions the \a array of \a size elements of \a element bytes, relative to + * the specified \a pivot element. Function pointed by \a equal is used for + * comparison. + * + * If the \a pivot element is part of the partitioned \a array, function will + * behaive the same way, as if \a pivot element wasn't part of the array. + * + * If \a equal indicates two elements as equivalent, their order in the + * resulting partitioned array is unspecified. + * + * \param pivot Pointer to the pivot element + * \param array Pointer to the array to partition + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + * + * \return Pointer to the first element of the second partition. + */ void *bh_partition(void *pivot, void *array, size_t size, @@ -74,6 +112,17 @@ void *bh_partition(void *pivot, return j + element; } +/** + * Sorts the \a array of \a size elements of \a element bytes. Function pointed + * by \a equal is used for comparision. + * + * This sorting does not make any gurantees about time or space complexity. + * + * \param array Pointer to the array to sort + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + */ void bh_sort(void *array, size_t size, size_t element, @@ -83,6 +132,23 @@ void bh_sort(void *array, bh_sort_intro(array, size, element, equal); } + +/** + * Sorts the \a array of \a size elements of \a element bytes with insertion + * sort. Function pointed by \a equal is used for comparision. + * + * This sorting has following time complexity: + * - best case O(n) + * - average case O(n^2) + * - worst case O(n^2) + * + * This sorting has O(1) space complexity. + * + * \param array Pointer to the array to sort + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + */ void bh_sort_insert(void *array, size_t size, size_t element, @@ -109,6 +175,20 @@ void bh_sort_insert(void *array, } +/** + * Sorts the \a array of \a size elements of \a element bytes with shell sort. + * Function pointed by \a equal is used for comparision. + * + * This sorting has the O(n log n) best cast time complexity. Average and worst + * cases are implementation dependant. + * + * This sorting has O(1) space complexity. + * + * \param array Pointer to the array to sort + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + */ void bh_sort_shell(void *array, size_t size, size_t element, @@ -118,7 +198,7 @@ void bh_sort_shell(void *array, const size_t *gap; size_t i, j; - /* Shell sort with A102549 sequence*/ + /* Shell sort with A102549 sequence */ for (gap = gaps; gap < gaps + sizeof(gaps) / sizeof(*gaps); gap++) { for (i = *gap; i < size; i++) @@ -201,6 +281,22 @@ static void bh_sort_intro_r(void *array, } } +/** + * Sorts the \a array of \a size elements of \a element bytes with insertion + * sort. Function pointed by \a equal is used for comparision. + * + * This sorting has following time complexity: + * - best case O(n log n) + * - average case O(n log n) + * - worst case O(n log n) + * + * This sorting has O(log n) space complexity. + * + * \param array Pointer to the array to sort + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + */ void bh_sort_intro(void *array, size_t size, size_t element, @@ -221,6 +317,22 @@ void bh_sort_intro(void *array, bh_sort_intro_r(array, size, element, equal, depth); } +/** + * Sorts the \a array of \a size elements of \a element bytes with insertion + * sort. Function pointed by \a equal is used for comparision. + * + * This sorting has following time complexity: + * - best case O(n) + * - average case O(n log n) + * - worst case O(n log n) + * + * This sorting has O(1) space complexity. + * + * \param array Pointer to the array to sort + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + */ void bh_sort_heap(void *array, size_t size, size_t element, @@ -232,7 +344,15 @@ void bh_sort_heap(void *array, bh_heap_remove(array, size--, element, equal); } - +/** + * Heapifes the \a array of \a size elements of \a element bytes. Function + * pointed by \a equal is used for comparision. + * + * \param array Pointer to the array to heapify + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparision function + */ void bh_heap_make(void *array, size_t size, size_t element, @@ -279,6 +399,15 @@ void bh_heap_make(void *array, } } +/** + * Removes top element from heapified \a array of \a size elements of \a + * elements bytes. Function pointed by \a equal is used for comparasion. + * + * \param array Pointer to the array to remove element from + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparasion function + */ void bh_heap_remove(void *array, size_t size, size_t element, @@ -323,6 +452,16 @@ void bh_heap_remove(void *array, } } +/** + * Inserts new element into heapified \a array of \a size elements of \a + * elements bytes. Function pointed by \a equal is used for comparasion. + * + * \param value Pointer to the value to be inserted + * \param array Pointer to the array to remove element from + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparasion function + */ void bh_heap_insert(void *value, void *array, size_t size, @@ -358,3 +497,64 @@ void bh_heap_insert(void *value, break; } } + +/** + * Replaces top element of the heapified \a array of \a size elements of \a + * elements bytes. Function pointed by \a equal is used for comparasion. + * + * This function is equal to two consecutive operations of remove and insert. + * + * \param value Pointer to the value to be inserted + * \param array Pointer to the array to remove element from + * \param size Number of elements in the array + * \param element Size of each element in the array in bytes + * \param equal Comparasion function + */ +void bh_heap_replace(void *value, + void *array, + size_t size, + size_t element, + bh_equal_cb_t equal) +{ + char *start, *end, *current, *left, *right; + + if (size <= 1) + return; + + /* Calculate start, end and children pointers */ + start = (char *)array; + end = start + size * element; + current = start; + left = start + (current - start) * 2 + element; + right = left + element; + + /* Copy supplied element to the first (top) position */ + memmove(current, value, element); + + /* Iterate until we reach the end */ + while (left < end) + { + char *biggest; + + /* Determine biggest child */ + biggest = left; + if (right < end && equal(left, right) < 0) + biggest = right; + + /* Compare biggest child with current */ + if (equal(current, biggest) < 0) + { + /* Swap content and recalculate children pointers */ + bh_swap(current, biggest, element); + current = biggest; + left = start + (current - start) * 2 + element; + right = left + element; + } + else + break; + } +} + +/** + * \} + */
\ No newline at end of file diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..c66c6ae --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,278 @@ +#include <bh/internal/buffer.h> +#include <stdlib.h> +#include <string.h> + +static const bh_io_table_t bh_buffer_table = { + (int (*)(struct bh_io_s *, int)) bh_buffer_open_base, + (void (*)(struct bh_io_s *)) bh_buffer_close_base, + (int (*)(struct bh_io_s *)) bh_buffer_is_open_base, + (size_t (*)(struct bh_io_s *, char *, size_t)) bh_buffer_read_base, + (size_t (*)(struct bh_io_s *, const char *, size_t)) bh_buffer_write_base, + (void (*)(struct bh_io_s *)) bh_buffer_flush_base, + (int (*)(struct bh_io_s *, bh_off_t, int)) bh_buffer_seek_base, + (bh_off_t (*)(struct bh_io_s *)) bh_buffer_size_base, + (bh_off_t (*)(struct bh_io_s *)) bh_buffer_tell_base, + (bh_off_t (*)(struct bh_io_s *)) bh_buffer_available_base, + (void (*)(struct bh_io_s *)) bh_buffer_clear_base, + (void (*)(struct bh_io_s *)) bh_buffer_destroy +}; + +bh_buffer_t *bh_buffer_new(void) +{ + bh_buffer_t *result; + + /* Allocate and initialize buffer structure */ + result = malloc(sizeof(*result)); + if (result && bh_buffer_init(result)) + { + /* Something went wrong - free allocated memory */ + free(result); + result = NULL; + } + + return result; +} + +void bh_buffer_free(bh_buffer_t *buffer) +{ + bh_buffer_destroy(buffer); + free(buffer); +} + +int bh_buffer_init(bh_buffer_t *buffer) +{ + bh_io_init(&buffer->base, &bh_buffer_table); + + buffer->data = NULL; + buffer->capacity = 0; + buffer->size = 0; + buffer->at = 0; + buffer->mode = 0; + + return BH_OK; +} + +void bh_buffer_destroy(bh_buffer_t *buffer) +{ + bh_buffer_close(buffer); + if (buffer->data) + free(buffer->data); +} + +const char *bh_buffer_data(bh_buffer_t *buffer) +{ + return buffer->data; +} + +void bh_buffer_set_data(bh_buffer_t *buffer, + const char *data, + size_t size) +{ + buffer->size = 0; + bh_buffer_write_base(buffer, data, size); +} + +size_t bh_buffer_capacity(bh_buffer_t *buffer) +{ + return buffer->capacity; +} + +int bh_buffer_reserve(bh_buffer_t *buffer, + size_t size) +{ + char *data = NULL; + + /* New capacity can't be less then current buffer size */ + if (size < buffer->size) + size = buffer->size; + + /* Prevent same size reallocation */ + if (buffer->capacity == size) + return BH_OK; + + /* Allocate new memory for the buffer */ + if (size) + { + data = malloc(size); + if (!data) + return BH_OOM; + + /* Copy data */ + if (buffer->size) + memmove(data, buffer->data, buffer->size); + } + + /* Free previosly allocated memory */ + if (buffer->data) + free(buffer->data); + + /* Update buffer fields */ + buffer->data = data; + buffer->capacity = size; + + return BH_OK; +} + +int bh_buffer_open_base(bh_buffer_t *buffer, + int mode) +{ + /* Check if buffer is already open */ + if (buffer->mode != 0) + return BH_OK; + + /* Update buffer mode field */ + buffer->mode = mode; + + /* Determine open mode */ + switch (mode & BH_IO_MASK) + { + case BH_IO_OPEN: + case BH_IO_CREATE: + case BH_IO_APPEND: + break; + + case BH_IO_TRUNCATE: + buffer->size = 0; + break; + + default: + return BH_NO_IMPL; + } + + return BH_OK; +} + +void bh_buffer_close_base(bh_buffer_t *buffer) +{ + buffer->mode = 0; +} + +int bh_buffer_is_open_base(bh_buffer_t *buffer) +{ + return buffer->mode != 0; +} + +size_t bh_buffer_read_base(bh_buffer_t *buffer, + char *data, + size_t size) +{ + /* Check if buffer openned in read mode */ + if (!(buffer->mode & BH_IO_READ)) + { + buffer->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Calculate maximum available size for reading */ + if (size > buffer->size - buffer->at) + size = buffer->size - buffer->at; + + /* Perform reading */ + if (size) + { + memmove(data, buffer->data + buffer->at, size); + buffer->at += size; + } + + /* Check for end of file */ + if (!size) + buffer->base.flags |= BH_IO_EOF; + else + buffer->base.flags &= ~BH_IO_EOF; + + return size; +} + +size_t bh_buffer_write_base(bh_buffer_t *buffer, + const char *data, + size_t size) +{ + size_t capacity = 0; + + /* Check if buffer is openned in write mode */ + if (!(buffer->mode & BH_IO_WRITE)) + { + buffer->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Adjust at position */ + if ((buffer->mode & BH_IO_MASK) == BH_IO_APPEND) + buffer->at = buffer->size; + + /* Calculate required capacity and check for overflow */ + capacity = buffer->at + size; + if (capacity < size) + { + buffer->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Try to grow buffer */ + if (buffer->capacity < capacity) + bh_buffer_reserve(buffer, capacity); + + /* Calculate maximum write size */ + if (size > buffer->capacity - buffer->at) + size = buffer->capacity - buffer->at; + + /* Perform writing */ + if (size) + { + memmove(buffer->data + buffer->at, data, size); + buffer->at += size; + buffer->size += size; + } + + /* Check for end of file */ + if (!size) + buffer->base.flags |= BH_IO_EOF; + else + buffer->base.flags &= ~BH_IO_EOF; + + return size; +} + +void bh_buffer_flush_base(bh_buffer_t *buffer) +{ + (void)buffer; +} + +int bh_buffer_seek_base(bh_buffer_t *buffer, + bh_off_t pos, + int dir) +{ + switch (dir) + { + case BH_IO_SET: buffer->at = pos; break; + case BH_IO_CURRENT: buffer->at += pos; break; + case BH_IO_END: buffer->at = buffer->size - pos; break; + default: return BH_NO_IMPL; + } + + if (buffer->at > buffer->size) + buffer->at = buffer->size; + + return BH_OK; +} + +bh_off_t bh_buffer_size_base(bh_buffer_t *buffer) +{ + return buffer->size; +} + +bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer) +{ + return buffer->at; +} + +bh_off_t bh_buffer_available_base(bh_buffer_t *buffer) +{ + return buffer->size - buffer->at; +} + +void bh_buffer_clear_base(bh_buffer_t *buffer) +{ + buffer->base.flags &= ~BH_IO_ERROR; +} + diff --git a/src/file_null.c b/src/file_null.c new file mode 100644 index 0000000..75684d8 --- /dev/null +++ b/src/file_null.c @@ -0,0 +1,275 @@ +#include <bh/internal/file.h> + +/** + * \defgroup file File IO + * + * File input/output API + * \{ + */ + +/** + * Creates new file object with specified \a path to file. + * + * \param path Path to the file + * + * \return On success, returns new file object. + * \return On failure, returns null pointer. + */ +bh_file_t *bh_file_new(const char *path) +{ + (void)path; + return NULL; +} + +/** + * Frees the \a file object. + * + * Before freeing the file object, this function ensures that underlying file + * was closed. + * + * \param file Pointer to the file object + */ +void bh_file_free(bh_file_t *file) +{ + (void)file; +} + +/** + * Initializes the \a file object with specified \a path to file. + * + * \param file Pointer to the file object + * \param path Path to the file + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ +int bh_file_init(bh_file_t *file, + const char *path) +{ + (void)file; + (void)path; + return BH_NO_IMPL; +} + +/** + * Destroyes the \a file object. + * + * Before destroying the file object, this function ensures that underlying + * file was closed. + * + * \param file Pointer to the file object + */ +void bh_file_destroy(bh_file_t *file) +{ + (void)file; +} + +/** + * Opens the \a file object for specified \a mode of operation. + * + * \param file Pointer to the file object + * \param mode Bitmask determining access mode + * + * \return On success, returns zero. + * \return On failure, returns error code. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +int bh_file_open_base(bh_file_t *file, + int mode) +{ + (void)file; + (void)mode; + return BH_NO_IMPL; +} + +/** + * Closes the \a file object. + * + * \param file Pointer to the file object + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +void bh_file_close_base(bh_file_t *file) +{ + (void)file; +} + +/** + * Checks if the \a file is open. + * + * \param file Pointer to the file object + * + * \return If file object is open - returns non-zero. + * \return If file object is closed - returns zero. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +int bh_file_is_open_base(bh_file_t *file) +{ + (void)file; + return 0; +} + +/** + * Reads up to \a size amount of bytes from the \a file object into memory + * buffer pointed by \a data pointer. + * + * \param file Pointer to the file object + * \param data Pointer to the memory buffer + * \param size Maximum number of bytes to be read + * + * \return On success, returns number of bytes successfuly read. + * \return On failure, returns zero. + * + * \note To check for end-of-file or error see bh_io_eof and bh_io_error. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +size_t bh_file_read_base(bh_file_t *file, + char *data, + size_t size) +{ + (void)file; + (void)data; + (void)size; + return 0; +} + +/** + * Writes up to \a size amount of bytes to the \a file object from memory + * buffer pointed by \a data pointer. + * + * \param file Pointer to the file object + * \param data Pointer to the memory buffer + * \param size Maximum number of bytes to be read + * + * \return On success, returns number of bytes successfuly written. + * \return On failure, returns zero. + * + * \note To check for error see bh_io_error. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +size_t bh_file_write_base(bh_file_t *file, + const char *data, + size_t size) +{ + (void)file; + (void)data; + (void)size; + return 0; +} + +/** + * Synchronizes the \a file object (if possible). + * + * In most cases, this function causes any unwritten/buffered data to be + * written. + * + * \param file Pointer to the file object + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +void bh_file_flush_base(bh_file_t *file) +{ + (void)file; +} + +/** + * Seeks the \a file object in the specified direction \a dir and \a offset + * (if possible). + * + * \param file Pointer to the file object + * \param offset Number of bytes to seek in specified direciton + * \param dir Seeking direction + * + * \return On success, returns zero. + * \return On failure, returns error code. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +int bh_file_seek_base(bh_file_t *file, + bh_off_t off, + int dir) +{ + (void)file; + (void)off; + (void)dir; + return BH_NO_IMPL; +} + +/** + * Returns total size of the \a file object (if possible) + * + * \param file Pointer to the file object + * + * \return On success, returns total size of the file object. + * \return On failure, returns -1. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +bh_off_t bh_file_size_base(bh_file_t *file) +{ + (void)file; + return -1; +} + +/** + * Returns current position in the \a file object (if possible). + * + * \param file Pointer to the io object + * + * \return On success, returns current position in the file object. + * \return On failure, returns -1. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +bh_off_t bh_file_tell_base(bh_file_t *file) +{ + (void)file; + return -1; +} + +/** + * Returns available number of bytes to be read from the \a file object. + * + * \param file Pointer to the file object + * + * \return On success, returns number of available bytes to be read. + * \return On failure, returns zero. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +bh_off_t bh_file_available_base(bh_file_t *file) +{ + (void)file; + return 0; +} + +/** + * Clears error of the \a file object. + * + * \param file Pointer to the file object + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ +void bh_file_clear_base(bh_file_t *file) +{ + (void)file; +} + +/** + * \} + */ diff --git a/src/file_posix.c b/src/file_posix.c index e69de29..0ffbf5e 100644 --- a/src/file_posix.c +++ b/src/file_posix.c @@ -0,0 +1,253 @@ +#include <bh/internal/file.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +static const bh_io_table_t bh_file_table = { + (int (*)(struct bh_io_s *, int)) bh_file_open_base, + (void (*)(struct bh_io_s *)) bh_file_close_base, + (int (*)(struct bh_io_s *)) bh_file_is_open_base, + (size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base, + (size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base, + (void (*)(struct bh_io_s *)) bh_file_flush_base, + (int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base, + (bh_off_t (*)(struct bh_io_s *)) bh_file_size_base, + (bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base, + (bh_off_t (*)(struct bh_io_s *)) bh_file_available_base, + (void (*)(struct bh_io_s *)) bh_file_clear_base, + (void (*)(struct bh_io_s *)) bh_file_destroy +}; + +bh_file_t *bh_file_new(const char *path) +{ + bh_file_t *result; + + /* Allocate and initialize file structure */ + result = malloc(sizeof(*result)); + if (result && bh_file_init(result, path)) + { + /* Something went wrong - free allocated memory */ + free(result); + result = NULL; + } + + return result; +} + +void bh_file_free(bh_file_t *file) +{ + bh_file_destroy(file); + free(file); +} + +int bh_file_init(bh_file_t *file, + const char *path) +{ + /* Ensure that path is not empty */ + if (!path) + return BH_INVALID; + + /* Initialize base io object */ + bh_io_init(&file->base, &bh_file_table); + + /* Initialize file io object */ + file->handle = -1; + file->mode = 0; + file->path = strdup(path); + + return BH_OK; +} + +void bh_file_destroy(bh_file_t *file) +{ + /* Close the file */ + bh_file_close(file); + free(file->path); +} + +int bh_file_open_base(bh_file_t *file, + int mode) +{ + /* Set open mode for 0666 permisions */ + mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + int open_flags = 0; + + /* Check if file is already opened */ + if (file->handle != -1) + return BH_OK; + + /* Determine read/write flags */ + if (mode & BH_IO_READ_WRITE) + open_flags |= O_RDWR; + else if (mode & BH_IO_READ) + open_flags |= O_RDONLY; + else if (mode & BH_IO_WRITE) + open_flags |= O_WRONLY; + else + return BH_INVALID; + + /* Determine open mode */ + switch (mode & BH_IO_MASK) + { + case BH_IO_OPEN: break; + case BH_IO_CREATE: open_flags |= O_CREAT | O_EXCL; break; + case BH_IO_APPEND: open_flags |= O_CREAT | O_APPEND; break; + case BH_IO_TRUNCATE: open_flags |= O_CREAT | O_TRUNC; break; + + default: + return BH_NO_IMPL; + } + + /* Open file */ + file->handle = open(file->path, open_flags, open_mode); + + /* Check for errors */ + if (file->handle == -1) + return BH_ERROR; + + return BH_OK; +} + +void bh_file_close_base(bh_file_t *file) +{ + /* Close file if it's open */ + if (file->handle != -1) + close(file->handle); + + /* Set handle to invalid value */ + file->handle = -1; +} + +int bh_file_is_open_base(bh_file_t *file) +{ + /* If handle is not -1 - then file is open */ + return file->handle != -1; +} + +size_t bh_file_read_base(bh_file_t *file, + char *data, + size_t size) +{ + ssize_t readed; + + /* Check if file is open */ + if (file->handle == -1) + { + /* Error occured - set error bit */ + file->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Read data from file */ + readed = read(file->handle, data, size); + if (readed < 0) + { + /* Error occured - set error bit */ + file->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Check for end of file */ + if (!readed) + file->base.flags |= BH_IO_EOF; + else + file->base.flags &= ~BH_IO_EOF; + + /* Return number of readed bytes */ + return readed; +} + +size_t bh_file_write_base(bh_file_t *file, + const char *data, + size_t size) +{ + ssize_t written; + + /* Check if file is open */ + if (file->handle == -1) + { + /* Error occured - set error bit */ + file->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Write data to file */ + written = write(file->handle, data, size); + if (written < 0) + { + /* Error occured - set error bit */ + file->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Check for end of file */ + if (!written) + file->base.flags |= BH_IO_EOF; + else + file->base.flags &= ~BH_IO_EOF; + + /* Return number of written bytes */ + return written; +} + +void bh_file_flush_base(bh_file_t *file) +{ + /* Check if file is open */ + if (file->handle == -1) + return; + + /* Signal OS to flush data from the internal buffers */ + fsync(file->handle); +} + +int bh_file_seek_base(bh_file_t *file, + bh_off_t pos, + int dir) +{ + /* Check if file is open */ + if (file->handle == -1) + return BH_ERROR; + + /* Seek to desired location */ + if (lseek(file->handle, pos, dir) == -1); + return BH_ERROR; + + return BH_OK; +} + +bh_off_t bh_file_size_base(bh_file_t *file) +{ + struct stat sb; + + /* Check if file is open */ + if (file->handle == -1) + return -1; + + /* Get file size from the OS */ + if (fstat(file->handle, &sb)) + return -1; + + return sb.st_size; +} + +bh_off_t bh_file_tell_base(bh_file_t *file) +{ + /* Check if file is open */ + if (file->handle == -1) + return -1; + + /* Get current file position */ + return lseek(file->handle, 0, SEEK_CUR); +} + +bh_off_t bh_file_available_base(bh_file_t *file) +{ + /* Get available bytes for reading */ + return bh_file_size_base(file) - bh_file_tell_base(file); +} + +void bh_file_clear_base(bh_file_t *file) +{ + file->base.flags &= ~BH_IO_ERROR; +} diff --git a/src/file_win.c b/src/file_win.c index e69de29..e31e0de 100644 --- a/src/file_win.c +++ b/src/file_win.c @@ -0,0 +1,195 @@ +#include <bh/internal/file.h> + +static const bh_io_table_t bh_file_table = { + (int (*)(struct bh_io_s *, int)) bh_file_open_base, + (void (*)(struct bh_io_s *)) bh_file_close_base, + (int (*)(struct bh_io_s *)) bh_file_is_open_base, + (size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base, + (size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base, + (void (*)(struct bh_io_s *)) bh_file_flush_base, + (int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base, + (bh_off_t (*)(struct bh_io_s *)) bh_file_size_base, + (bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base, + (bh_off_t (*)(struct bh_io_s *)) bh_file_available_base, + (void (*)(struct bh_io_s *)) bh_file_clear_base, + (void (*)(struct bh_io_s *)) bh_file_destroy +}; + +bh_file_t *bh_file_new(const char *path) +{ + bh_file_t *result; + + result = malloc(sizeof(*result)); + if (result && bh_file_init(result, path)) + { + free(result); + result = NULL; + } + + return result; +} + +void bh_file_free(bh_file_t *file) +{ + bh_file_destroy(file); + free(file); +} + +int bh_file_init(bh_file_t *file, + const char *path) +{ + if (!path) + return BH_INVALID; + + file->handle = INVALID_HANDLE_VALUE; + file->mode = 0; + file->path = strdup(path); + file->base.table = &bh_file_table; + + return BH_OK; +} + +int bh_file_open_base(bh_file_t *file, + int mode) +{ + DWORD access = 0, how = 0; + + if (mode & BH_IO_READ) + access |= GENERIC_READ; + if (mode & BH_IO_WRITE) + access |= GENERIC_WRITE; + + switch (mode & BH_IO_MASK) + { + case BH_IO_OPEN: how = OPEN_EXISTING; break; + case BH_IO_CREATE: how = CREATE_ALWAYS; break; + case BH_IO_APPEND: how = OPEN_ALWAYS; break; + + default: + case BH_IO_TRUNCATE: + return BH_NO_IMPL; + } + + file->mode = mode; + file->handle = CreateFileA(file->path, access, FILE_SHARE_READ, NULL, how, FILE_ATTRIBUTE_NORMAL, NULL); + + if (file->handle == INVALID_HANDLE_VALUE) + { + /* Error handling */ + switch (GetLastError()) + { + case ERROR_FILE_EXISTS: return BH_FOUND; + case ERROR_FILE_NOT_FOUND: return BH_NOT_FOUND; + default: return BH_ERROR; + } + } + + return BH_OK; +} + +void bh_file_close_base(bh_file_t *file) +{ + if (file->handle != INVALID_HANDLE_VALUE) + CloseHandle(file->handle); + + file->handle = INVALID_HANDLE_VALUE; +} + +int bh_file_is_open_base(bh_file_t *file) +{ + return file->handle != INVALID_HANDLE_VALUE; +} + +void bh_file_destroy(bh_file_t *file) +{ + bh_file_close(file); + free(file->path); +} + +size_t bh_file_read_base(bh_file_t *file, + char *data, + size_t size) +{ + DWORD readed; + + if (!ReadFile(file->handle, data, (DWORD)size, &readed, NULL)) + { + file->base.flags |= BH_IO_ERROR; + return 0; + } + + if (!readed) + file->base.flags |= BH_IO_EOF; + else + file->base.flags &= ~BH_IO_EOF; + + return readed; +} + +size_t bh_file_write_base(bh_file_t *file, + const char *data, + size_t size) +{ + DWORD written; + + if ((file->mode & BH_IO_MASK) == BH_IO_APPEND) + bh_file_seek(file, 0, BH_IO_END); + + if (!WriteFile(file->handle, data, (DWORD)size, &written, NULL)) + { + file->base.flags |= BH_IO_ERROR; + return 0; + } + + if (!written) + file->base.flags |= BH_IO_EOF; + else + file->base.flags &= ~BH_IO_EOF; + + return written; +} + +void bh_file_flush_base(bh_file_t *file) +{ + FlushFileBuffers(file->handle); +} + +int bh_file_seek_base(bh_file_t *file, + bh_off_t pos, + int dir) +{ + LARGE_INTEGER position; + + position.QuadPart = pos; + if (SetFilePointerEx(file->handle, position, NULL, dir)) + return BH_OK; + + return BH_ERROR; +} + +bh_off_t bh_file_size_base(bh_file_t *file) +{ + return -1; +} + +bh_off_t bh_file_tell_base(bh_file_t *file) +{ + LARGE_INTEGER dummy, position; + + dummy.QuadPart = 0; + + if (SetFilePointerEx(file->handle, dummy, &position, BH_IO_CURRENT)) + return position.QuadPart; + + return -1; +} + +bh_off_t bh_file_available_base(bh_file_t *file) +{ + return 0; +} + +void bh_file_clear_base(bh_file_t *file) +{ + file->base.flags &= ~BH_IO_ERROR; +} diff --git a/src/hashmap.c b/src/hashmap.c index c9fb315..256644a 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -2,6 +2,22 @@ #include <stdlib.h> #include <string.h> +/** + * \defgroup hashmap Hashmap + * + * Data stucture for storing pointers in the hashmap. + * \{ + */ + +/** + * Creates the new hashmap object. + * + * \param equal Comparision function + * \param hash Key hash function + * + * \return On success, returns the pointer to the new hashmap object. + * \return On failure, returns a null pointer. + */ bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal, bh_hash_cb_t hash) { @@ -14,12 +30,26 @@ bh_hashmap_t *bh_hashmap_new(bh_equal_cb_t equal, return result; } +/** + * Frees the \a hashmap object. + * + * \param hashmap Pointer to the hashmap object to be freed + */ void bh_hashmap_free(bh_hashmap_t *hashmap) { bh_hashmap_destroy(hashmap); free(hashmap); } +/** + * Initializes the \a hashmap object. + * + * \warning This is an internal function. + * + * \param hashmap Pointer to the hashmap object to be initialized + * \param equal Comparision function + * \param hash Key hash function + */ void bh_hashmap_init(bh_hashmap_t *hashmap, bh_equal_cb_t equal, bh_hash_cb_t hash) @@ -30,6 +60,13 @@ void bh_hashmap_init(bh_hashmap_t *hashmap, hashmap->hash = hash; } +/** + * Destroys the \a hashmap object. + * + * \warning This is an internal function. + * + * \param hashmap Pointer to the hashmap object to be destroied + */ void bh_hashmap_destroy(bh_hashmap_t *hashmap) { if (hashmap->capacity) @@ -39,6 +76,11 @@ void bh_hashmap_destroy(bh_hashmap_t *hashmap) } } +/** + * Clears the \a hashmap object. + * + * \param hashmap Pointer to the hashmap object to be cleared + */ void bh_hashmap_clear(bh_hashmap_t *hashmap) { if (hashmap->capacity) @@ -46,8 +88,24 @@ void bh_hashmap_clear(bh_hashmap_t *hashmap) hashmap->size = 0; } +/** + * Reserves the space for \a size elements in the \a hashmap. + * + * This function can both expand and shrink the available space in \a hashmap. + * This function takes into account current hashmap load factor. + * + * \param hashmap Pointer to the hashmap object to be resized in terms of + * capacity + * \param size New capacity of the hashmap + * + * \note Calling this function will invalidate iterators. + * \note Actual hashmap capacity can be bigger then requested. + * + * \return On success, returns zero value. + * \return On failure, returns error code. + */ int bh_hashmap_reserve(bh_hashmap_t *hashmap, - size_t size) + size_t size) { bh_hashmap_t other; size_t capacity, max_capacity, threshold; @@ -78,7 +136,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap, /* Capacity can't be bigger than max capacity and overflow */ if (capacity > max_capacity || capacity < 16) - return -1; + return BH_OOM; } } else @@ -93,7 +151,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap, /* Prevent same size reallocation */ if (capacity == hashmap->capacity) - return 0; + return BH_OK; /* Initialize new hashmap */ bh_hashmap_init(&other, hashmap->equal, hashmap->hash); @@ -105,7 +163,6 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap, /* Allocate new memory for the hashmap */ other.data = malloc(sizeof(*other.data) * capacity); - other.psls = malloc(sizeof(size_t) * capacity); other.threshold = threshold; other.capacity = capacity; @@ -117,7 +174,7 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap, free(other.data); if (other.psls) free(other.psls); - return -1; + return BH_OOM; } /* Reset probe sequence lengths */ @@ -140,9 +197,22 @@ int bh_hashmap_reserve(bh_hashmap_t *hashmap, /* Swap hashmaps */ bh_hashmap_destroy(hashmap); *hashmap = other; - return 0; + return BH_OK; } +/** + * Inserts the pair of \a key and \a value into the \a hashmap. This function + * allows duplicates to be inserted. + * + * \param hashmap Pointer to the hashmap object + * \param key Key to be inserted + * \param value Value to be inserted + * + * \note Calling this function will invalidate iterators. + * + * \return On success, returns zero value. + * \return On failure, returns error code. + */ int bh_hashmap_insert(bh_hashmap_t *hashmap, void *key, void *value) @@ -154,7 +224,7 @@ int bh_hashmap_insert(bh_hashmap_t *hashmap, if (hashmap->size + 1 > hashmap->threshold) if (bh_hashmap_reserve(hashmap, hashmap->size + 1)) if (hashmap->size >= hashmap->capacity) - return -1; + return BH_OOM; /* Prepare inserted data and set PSL to 1 */ item.key = key; @@ -187,9 +257,19 @@ int bh_hashmap_insert(bh_hashmap_t *hashmap, hashmap->psls[bucket] = psl; hashmap->size++; - return 0; + return BH_OK; } +/** + * Removes value from the \a hashmap by \a key. + * + * \param hashmap Pointer to the hashmap object + * \param key Key value + * + * \note Calling this function will invalidate iterators. + * \note If hashmap contains several key-value pairs with the same key, only + * one pair will be removed. + */ void bh_hashmap_remove(bh_hashmap_t *hashmap, void *key) { @@ -200,6 +280,19 @@ void bh_hashmap_remove(bh_hashmap_t *hashmap, bh_hashmap_iter_remove(hashmap, iter); } +/** + * Returns the value from the \a hashmap by the specified \a key. + * + * If the \a exists is not null pointer, the value will be stored to indicated, + * whether the \a key exists in the hashmap or not. + * + * \param hashmap Pointer to the hashmap object + * \param key Key value + * \param exists Pointer to the exists flag variable (optional) + * + * \return On success, returns value. + * \return On failure, return null pointer. + */ void *bh_hashmap_at(bh_hashmap_t *hashmap, void *key, int *exists) @@ -221,36 +314,87 @@ void *bh_hashmap_at(bh_hashmap_t *hashmap, return NULL; } +/** + * Checks if the \a hashmap is empty. + * + * \param hashmap Pointer to the hashmap object + * + * \return If hashmap is empty, returns non-zero value + * \return If hashmap is not empty, returns zero value + */ int bh_hashmap_empty(bh_hashmap_t *hashmap) { return !hashmap->size; } +/** + * Returns the size of the \a hashmap. + * + * \param hashmap Pointer to the hashmap object + * + * \return Returns the size of the hashmap. + */ size_t bh_hashmap_size(bh_hashmap_t *hashmap) { return hashmap->size; } +/** + * Returns the capacity of the \a hashmap. + * + * \param hashmap Pointer to the hashmap object + * + * \return Returns the capacity of the hashmap. + */ size_t bh_hashmap_capacity(bh_hashmap_t *hashmap) { return hashmap->capacity; } +/** + * Returns the load factor of the \a hashmap. + * + * \param hashmap Pointer to the hashmap object + * + * \return Returns the load factor of the hashmap. + */ float bh_hashmap_factor(bh_hashmap_t *hashmap) { return hashmap->factor; } +/** + * Sets the load \a factor of the \a hashmap. + * + * \param hashmap Pointer to the hashmap object + * \param factor Load factor value + * + * \note New load factor will be applied on the next reserve/insert operation. + */ void bh_hashmap_set_factor(bh_hashmap_t *hashmap, float factor) { + /* Limit the factor value to [0.15, 1.0] */ factor = (factor > 1.0f) ? (1.0f) : (factor); factor = (factor < 0.15f) ? (0.15f) : (factor); + /* Calculate new threshold value */ hashmap->factor = factor; hashmap->threshold = hashmap->capacity * factor; } +/** + * Returns the iterator to the element in the \a hashmap with specified \a key. + * + * \param hashmap Pointer to the hashmap object + * \param iter Opaque iterator value + * + * \return On success, returns iterator value. + * \return On failure, returns null pointer. + * + * \note If hashmap contains several key-value pairs with the same key, only + * iterator to the one of the pairs will returned. + */ void *bh_hashmap_iter_at(bh_hashmap_t *hashmap, void *key) { @@ -278,6 +422,19 @@ void *bh_hashmap_iter_at(bh_hashmap_t *hashmap, return NULL; } +/** + * Returns the iterator to the next element in the \a hashmap. + * + * \param hashmap Pointer to the hashmap object + * \param iter Opaque iterator value + * + * \return If the \a iter doesn't point to the last element of the hashmap, + * returns next iterator value. + * \return If the \a iter point to the last element of the hashmap, returns + * null pointer. + * \return If the \a iter is the null pointer, returns iterator to the + * first element of the hashmap. + */ void *bh_hashmap_iter_next(bh_hashmap_t *hashmap, void *iter) { @@ -302,6 +459,14 @@ void *bh_hashmap_iter_next(bh_hashmap_t *hashmap, } } +/** + * Removes value from the \a hashmap by iterator \a iter. + * + * \param hashmap Pointer to the hashmap object + * \param iter Iterator value + * + * \note Calling this function will invalidate iterators. + */ void bh_hashmap_iter_remove(bh_hashmap_t *hashmap, void *iter) { @@ -332,12 +497,30 @@ void bh_hashmap_iter_remove(bh_hashmap_t *hashmap, hashmap->psls[bucket] = 0; } +/** + * Returns the key, pointed by the hashmap iterator \a iter. + * + * \param iter Opaque iterator value + * + * \return Returns key, pointed by iterator. + */ void *bh_hashmap_iter_key(void *iter) { return ((bh_hashmap_node_t *)iter)->key; } +/** + * Returns the value, pointed by the hashmap iterator \a iter. + * + * \param iter Opaque iterator value + * + * \return Returns value, pointed by iterator. + */ void *bh_hashmap_iter_value(void *iter) { return ((bh_hashmap_node_t *)iter)->value; } + +/** + * \} + */ @@ -1,6 +1,25 @@ #include <bh/internal/io.h> #include <stdlib.h> +/** + * \defgroup io Input/Output + * + * Input/output device abstraction layer. + * \{ + */ + +/** + * Creates the new io object with specified \a table and \a size. + * + * \param table Pointer to the io table + * \param size Size of the io object + * + * \return On success, returns new semi-initialized io object. + * \return On failure, returns null pointer. + * + * \warning This function should be used in context of implementing child + * io objects (files, sockets, streaming compression, etc). + */ bh_io_t *bh_io_new(bh_io_table_t *table, size_t size) { @@ -13,24 +32,91 @@ bh_io_t *bh_io_new(bh_io_table_t *table, return result; } +/** + * Frees the \a io object. + * + * \param io Pointer to the io object to be freed + */ void bh_io_free(bh_io_t *io) { bh_io_destroy(io); free(io); } +/** + * Initializes the \a io object with specified \a table. + * + * \param io Pointer to the io object to be initialized + * \param table Pointer to the io table + */ void bh_io_init(bh_io_t *io, - bh_io_table_t *table) + const bh_io_table_t *table) { io->table = table; io->flags = 0; } +/** + * Destroys the \a io object. + * + * \param io Pointer to the io object to be destroyed + */ void bh_io_destroy(bh_io_t *io) { io->table->destroy(io); } +/** + * Opens the \a io object for specified \a mode of operation. + * + * \param io Pointer to the io object + * \param mode Bitmask determining access mode + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ +int bh_io_open(bh_io_t *io, + int mode) +{ + return io->table->open(io, mode); +} + +/** + * Closes the \a io object. + * + * \param io Pointer to the io object + */ +void bh_io_close(bh_io_t *io) +{ + io->table->close(io); +} + +/** + * Checks if the \a io is open. + * + * \param io Pointer to the io object + * + * \return If io object is open - returns non-zero. + * \return If io object is closed - returns zero. + */ +int bh_io_is_open(bh_io_t *io) +{ + return io->table->is_open(io); +} + +/** + * Reads up to \a size amount of bytes from the \a io object into memory buffer + * pointed by \a data pointer. + * + * \param io Pointer to the io object + * \param data Pointer to the memory buffer + * \param size Maximum number of bytes to be read + * + * \return On success, returns number of bytes successfuly read. + * \return On failure, returns zero. + * + * \note To check for end-of-file or error see bh_io_eof and bh_io_error. + */ size_t bh_io_read(bh_io_t *io, char *data, size_t size) @@ -38,6 +124,19 @@ size_t bh_io_read(bh_io_t *io, return io->table->read(io, data, size); } +/** + * Writes up to \a size amount of bytes to the \a io object from memory buffer + * pointed by \a data pointer. + * + * \param io Pointer to the io object + * \param data Pointer to the memory buffer + * \param size Maximum number of bytes to be read + * + * \return On success, returns number of bytes successfuly written. + * \return On failure, returns zero. + * + * \note To check for error see bh_io_error. + */ size_t bh_io_write(bh_io_t *io, const char* data, size_t size) @@ -45,39 +144,112 @@ size_t bh_io_write(bh_io_t *io, return io->table->write(io, data, size); } +/** + * Synchronizes the \a io object (if possible). + * + * In most cases, this function causes any unwritten/buffered data to be + * written. + * + * \param io Pointer to the io object + */ void bh_io_flush(bh_io_t *io) { io->table->flush(io); } -void bh_io_seek(bh_io_t *io, - bh_off_t offset, - int dir) +/** + * Seeks the \a io object in the specified direction \a dir and \a offset (if + * possible). + * + * \param io Pointer to the io object + * \param offset Number of bytes to seek in specified direciton + * \param dir Seeking direction + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ +int bh_io_seek(bh_io_t *io, + bh_off_t offset, + int dir) { - io->table->seek(io, offset, dir); + return io->table->seek(io, offset, dir); } +/** + * Returns total size of the \a io object (if possible) + * + * \param io Pointer to the io object + * + * \return On success, returns total size of the io object. + * \return On failure, returns -1. + */ +bh_off_t bh_io_size(bh_io_t *io) +{ + return io->table->size(io); +} + +/** + * Returns current position in the \a io object (if possible). + * + * \param io Pointer to the io object + * + * \return On success, returns current position in the io object. + * \return On failure, returns -1. + */ bh_off_t bh_io_tell(bh_io_t *io) { return io->table->tell(io); } +/** + * Returns available number of bytes to be read from the \a io object. + * + * \param io Pointer to the io object + * + * \return On success, returns number of available bytes to be read. + * \return On failure, returns zero. + */ bh_off_t bh_io_available(bh_io_t *io) { return io->table->available(io); } +/** + * Checks error flag of the \a io object. + * + * \param io Pointer to the io object + * + * \return If error flag is set, returns non-zero. + * \return If error flag is not set, returns zero. + */ int bh_io_error(bh_io_t *io) { - return (io->flags & BH_IO_ERROR) > 0; + return (io->flags & BH_IO_ERROR) != 0; } +/** + * Checks end-of-file flag of the \a io object. + * + * \param io Pointer to the io object + * + * \return If end-of-file flag is set, returns non-zero. + * \return If end-of-file flag is not set, returns zero. + */ int bh_io_eof(bh_io_t *io) { - return (io->flags & BH_IO_EOF) > 0; + return (io->flags & BH_IO_EOF) != 0; } +/** + * Clears error of the \a io object. + * + * \param io Pointer to the io object + */ void bh_io_clear(bh_io_t *io) { io->table->clear(io); } + +/** + * \} + */ diff --git a/src/queue.c b/src/queue.c index 8d48401..e991769 100644 --- a/src/queue.c +++ b/src/queue.c @@ -2,6 +2,19 @@ #include <stdlib.h> #include <string.h> +/** + * \defgroup queue Queue + * + * Data stucture for storing pointers in queue. + * \{ + */ + +/** + * Creates the new queue object. + * + * \return On success, returns the pointer to the new queue object. + * \return On failure, returns a null pointer. + */ bh_queue_t *bh_queue_new(void) { bh_queue_t *result; @@ -13,23 +26,47 @@ bh_queue_t *bh_queue_new(void) return result; } +/** + * Frees the \a queue object. + * + * \param queue Pointer to the queue object to be freed + */ void bh_queue_free(bh_queue_t *queue) { bh_queue_destroy(queue); free(queue); } +/** + * Initializes the \a queue object. + * + * \warning This is an internal function. + * + * \param queue Pointer to the queue object to be initialized + */ void bh_queue_init(bh_queue_t *queue) { memset(queue, 0, sizeof(*queue)); } +/** + * Destroys the \a queue object. + * + * \warning This is an internal function. + * + * \param queue Pointer to the queue object to be destroyed + */ void bh_queue_destroy(bh_queue_t *queue) { if (queue->capacity) free(queue->data); } +/** + * Clears the \a queue object. + * + * \param queue Pointer to the queue object to be cleared + */ void bh_queue_clear(bh_queue_t *queue) { queue->head = 0; @@ -37,6 +74,20 @@ void bh_queue_clear(bh_queue_t *queue) queue->size = 0; } +/** + * Reserves the space for \a size elements in the \a queue. + * + * This function can both expand and shrink the available space in \a queue. + * + * \param queue Pointer to the queue object to be resized in terms of capacity + * \param size New capacity of the queue + * + * \note Calling this function will invalidate iterators. + * \note Actual hashmap capacity can be bigger then requested. + * + * \return On success, returns zero value. + * \return On failure, returns error code. + */ int bh_queue_reserve(bh_queue_t *queue, size_t size) { @@ -48,11 +99,11 @@ int bh_queue_reserve(bh_queue_t *queue, /* New capacity should not exceed maximum capacity */ if (size > ((size_t)-1) / sizeof(void *)) - return -1; + return BH_OOM; /* Prevent same size memory reallocation */ if (size == queue->capacity) - return 0; + return BH_OK; /* Prepare new empty queue */ bh_queue_init(&other); @@ -64,7 +115,7 @@ int bh_queue_reserve(bh_queue_t *queue, other.data = malloc(size * sizeof(void *)); other.capacity = size; if (!other.data) - return -1; + return BH_OOM; /* Iterate over old queue and insert data into new queue */ iter = bh_queue_iter_next(queue, NULL); @@ -81,9 +132,20 @@ int bh_queue_reserve(bh_queue_t *queue, /* Copy queue information */ *queue = other; - return 0; + return BH_OK; } +/** + * Inserts the \a value into the \a queue. + * + * \param queue Pointer to the queue object + * \param value Value to be inserted + * + * \note Calling this function will invalidate iterators. + * + * \return On success, returns zero value. + * \return On failure, returns error code. + */ int bh_queue_insert(bh_queue_t *queue, void *value) { @@ -95,7 +157,7 @@ int bh_queue_insert(bh_queue_t *queue, /* Check potential size overflow and reserve capacity */ capacity = (queue->capacity) ? (queue->capacity * 2) : (16); if (capacity < queue->capacity || bh_queue_reserve(queue, capacity)) - return -1; + return BH_OOM; } /* Increase queue size and advance tail index */ @@ -104,9 +166,16 @@ int bh_queue_insert(bh_queue_t *queue, if (++queue->tail >= queue->capacity) queue->tail = 0; - return 0; + return BH_OK; } +/** + * Removes front value from the \a queue. + * + * \param queue Pointer to the queue object + * + * \note Calling this function will invalidate iterators. + */ void bh_queue_remove(bh_queue_t *queue) { /* Do nothing if queue is empty */ @@ -119,6 +188,14 @@ void bh_queue_remove(bh_queue_t *queue) queue->head = 0; } +/** + * Returns front value from the \a queue. + * + * \param queue Pointer to the queue object + * + * \return On success, returns front value from the queue. + * \return On failure, returns null pointer. + */ void *bh_queue_front(bh_queue_t *queue) { /* Do nothing if queue is empty */ @@ -129,21 +206,56 @@ void *bh_queue_front(bh_queue_t *queue) return queue->data[queue->head]; } +/** + * Checks if the \a queue is empty. + * + * \param queue Pointer to the queue object + * + * \return If queue is empty, returns non-zero value + * \return If queue is not empty, returns zero value + */ int bh_queue_empty(bh_queue_t *queue) { return !queue->size; } +/** + * Returns the size of the \a queue. + * + * \param queue Pointer to the queue object + * + * \return Returns the size of the queue. + */ size_t bh_queue_size(bh_queue_t *queue) { return queue->size; } +/** + * Returns the capacity of the \a queue. + * + * \param queue Pointer to the queue object + * + * \return Returns the capacity of the queue. + */ size_t bh_queue_capacity(bh_queue_t *queue) { return queue->capacity; } +/** + * Returns the iterator to the next element in the \a queue. + * + * \param queue Pointer to the queue object + * \param iter Opaque iterator value + * + * \return If the \a iter doesn't point to the last element of the queue, + * returns next iterator value. + * \return If the \a iter point to the last element of the queue, returns + * null pointer. + * \return If the \a iter is the null pointer, returns iterator to the + * first element of the queue. + */ void *bh_queue_iter_next(bh_queue_t *queue, void *iter) { @@ -170,7 +282,18 @@ void *bh_queue_iter_next(bh_queue_t *queue, return element; } +/** + * Returns the value, pointed by the queue iterator \a iter. + * + * \param iter Opaque iterator value + * + * \return Returns value, pointed by iterator. + */ void *bh_queue_iter_value(void *iter) { return *(void **)iter; } + +/** + * \} + */ diff --git a/src/thread.c b/src/thread.c index 84bc2c0..2744387 100644 --- a/src/thread.c +++ b/src/thread.c @@ -1,6 +1,27 @@ #include <bh/internal/thread.h> #include <stdlib.h> +/** + * \defgroup thread Multithreading + * + * Multithreading API + * \{ + */ + +/** + * Creates new task object with specified function \a func, \a data and \a + * flags. + * + * If the \a flags contain BH_THREAD_CLEANUP, upon successful completion task + * will be automaticly destroyed. + * + * \param func Task's function + * \param data Task's data + * \param flags Task's flags + * + * \return On success, returns new task object. + * \return On failure, returns null pointer. + */ bh_task_t *bh_task_new(void (*func)(void *), void *data, int flags) @@ -14,12 +35,31 @@ bh_task_t *bh_task_new(void (*func)(void *), return result; } +/** + * Frees the \a task object. + * + * \param task Pointer to the task object. + */ void bh_task_free(bh_task_t *task) { bh_task_destroy(task); free(task); } +/** + * Initializes the \a task object with specified function \a func, \a data and + * \a flags. + * + * If the \a flags contain BH_THREAD_CLEANUP, upon successful completion task + * will be automaticly destroyed. + * + * \warning This is an internal function. + * + * \param task Pointer to the task object + * \param func Task's function + * \param data Task's data + * \param flags Task's flags + */ void bh_task_init(bh_task_t *task, void (*func)(void *), void *data, @@ -30,24 +70,53 @@ void bh_task_init(bh_task_t *task, task->flags = flags; } +/** + * Destroyes the \a task object. + * + * \warning This is an internal function. + * + * \param task Pointer to the task object + */ void bh_task_destroy(bh_task_t *task) { (void)task; } +/** + * Reuses the \a task object for different purpose. + * + * \param task Pointer to the task object + * \param func New task's function + * \param data New task's data + */ void bh_task_reuse(bh_task_t *task, void (*func)(void *), void *data) { + /* If the task is done - reinitilize it with new data */ if (task->flags & BH_THREAD_DONE) bh_task_init(task, func, data, task->flags & ~(BH_THREAD_DONE)); } +/** + * Checks if the \a task is done. + * + * \param task Pointer to the task object + * + * \return If the task is done, returns non-zero. + * \return If the task is not done, returns zero. + */ int bh_task_done(bh_task_t *task) { return (task->flags & BH_THREAD_DONE) != 0; } +/** + * Creates the mutex object. + * + * \return On success, returns new mutex object. + * \return On failure, returns null pointer. + */ bh_mutex_t *bh_mutex_new(void) { bh_mutex_t *result; @@ -62,32 +131,58 @@ bh_mutex_t *bh_mutex_new(void) return result; } +/** + * Frees the \a mutex object. + * + * \param mutex Pointer to the mutex object + */ void bh_mutex_free(bh_mutex_t *mutex) { bh_mutex_destroy(mutex); free(mutex); } +/** + * Creates the semaphore object with initial \a count value. + * + * \param count Initial semaphore value + * + * \return On success, returns new semaphore object. + * \return On failure, returns null pointer. + * + * \note Guranteed maximum \a count value is 32767. + */ bh_semaphore_t *bh_semaphore_new(int count) { bh_semaphore_t *result; - + result = malloc(sizeof(*result)); if (result && bh_semaphore_init(result, count)) { free(result); result = NULL; } - + return result; } +/** + * Frees the \a semaphore object. + * + * \param semaphore Pointer to the semaphore object + */ void bh_semaphore_free(bh_semaphore_t *semaphore) { bh_semaphore_destroy(semaphore); free(semaphore); } +/** + * Creates the condition variable object. + * + * \return On success, returns new condition variable object. + * \return On failure, returns null pointer. + */ bh_cond_t *bh_cond_new(void) { bh_cond_t *result; @@ -102,12 +197,26 @@ bh_cond_t *bh_cond_new(void) return result; } +/** + * Frees the condition variable object \a cond. + * + * \param cond Pointer to the condition variable object + */ void bh_cond_free(bh_cond_t *cond) { bh_cond_destroy(cond); free(cond); } +/** + * Adds \a task to the thread \a pool. + * + * \param pool Pointer to the thread pool object + * \param task Pointer to the task object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_thread_pool_add(bh_thread_pool_t *pool, bh_task_t *task) { @@ -119,16 +228,24 @@ int bh_thread_pool_add(bh_thread_pool_t *pool, if (bh_queue_insert(&pool->tasks, task)) { bh_mutex_unlock(&pool->lock); - return -1; + return BH_ERROR; } /* Signal new job */ bh_mutex_unlock(&pool->lock); bh_cond_signal(&pool->new_task); - return 0; + return BH_OK; } +/** + * Waits unitl all task in thread \a pool are complete. + * + * \param pool Pointer to the thread pool. + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_thread_pool_wait(bh_thread_pool_t *pool) { /* Lock and check if there is jobs in the queue */ @@ -160,9 +277,16 @@ int bh_thread_pool_wait(bh_thread_pool_t *pool) /* Unlock */ bh_mutex_unlock(&pool->lock); - return 0; + return BH_OK; } +/** + * Destroyes the thread \a pool object. + * + * \warning This is an internal function. + * + * \param pool Pointer to the thread pool object + */ void bh_thread_pool_destroy(bh_thread_pool_t *pool) { size_t i; @@ -195,12 +319,21 @@ void bh_thread_pool_destroy(bh_thread_pool_t *pool) bh_mutex_destroy(&pool->lock); } +/** + * Frees the thread \a pool object. + * + * \param pool Pointer to the thread pool object + */ void bh_thread_pool_free(bh_thread_pool_t *pool) { bh_thread_pool_destroy(pool); free(pool); } +/** + * \warning This is an internal function. + * \warning Do not use this function directly! + */ void bh_thread_pool_worker(void *arg) { bh_thread_pool_t *pool; @@ -210,26 +343,31 @@ void bh_thread_pool_worker(void *arg) { bh_task_t *task; + /* Wait unitl there is a task or shutdown signal */ bh_mutex_lock(&pool->lock); while (!pool->shutdown && bh_queue_empty(&pool->tasks)) bh_cond_wait(&pool->new_task, &pool->lock); + /* If its shutdown signal - exit the loop */ if (pool->shutdown) { bh_mutex_unlock(&pool->lock); break; } + /* Fetch task from the front of the queue, increase active counter */ task = bh_queue_front(&pool->tasks); bh_queue_remove(&pool->tasks); pool->active++; bh_mutex_unlock(&pool->lock); + /* Do the task, mark as done, and if required - free it */ task->func(task->data); task->flags |= BH_THREAD_DONE; if (task->flags & BH_THREAD_CLEANUP) bh_task_free(task); + /* Decrease active counter and broadcast that we are done */ bh_mutex_lock(&pool->lock); pool->active--; @@ -237,3 +375,7 @@ void bh_thread_pool_worker(void *arg) bh_cond_broadcast(&pool->done_task); } } + +/** + * \} + */
\ No newline at end of file diff --git a/src/thread_null.c b/src/thread_null.c index af73fd6..25d8a88 100644 --- a/src/thread_null.c +++ b/src/thread_null.c @@ -1,116 +1,300 @@ #include <bh/internal/thread.h> -int bh_thread_init(bh_thread_t *thread, - bh_task_t *task) +/** + * \ingroup thread + * \{ + */ + +/** + * Creates the thread object with the given \a task. + * + * \warning This function can be implemented either as a macro or as a function. + * + * \param task Pointer to the task object + * + * \return On success, returns the pointer to the new queue object. + * \return On failure, returns a null pointer. + */ +bh_thread_t *bh_thread_new(bh_task_t *task) { - (void)thread; (void)task; - return -1; + return NULL; } -bh_thread_t *bh_thread_new(bh_task_t *task) +/** + * Initializes the \a thread object with the given \a task. + * + * \warning This is an internal function. + * \warning This function can be implemented either as a macro or as a function. + * + * \param thread Pointer to the thread object + * \param task Pointer to the task object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ +int bh_thread_init(bh_thread_t *thread, + bh_task_t *task) { + (void)thread; (void)task; - return NULL; + return BH_NO_IMPL; } +/** + * Joins the \a thread. + * + * If thread was created with bh_thread_new, this function also frees the \a + * thread object. + * + * \param thread Pointer to the thread object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_thread_join(bh_thread_t *thread) { (void)thread; - return -1; + return BH_NO_IMPL; } +/** + * Detaches the \a thread. + * + * If thread was created with bh_thread_new, this function also frees the \a + * thread object. + * + * \param thread Pointer to the thread object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_thread_detach(bh_thread_t *thread) { (void)thread; - return -1; + return BH_NO_IMPL; } +/** + * Initializes the \a mutex object. + * + * \warning This is an internal function. + * + * \param mutex Pointer to the mutex object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_mutex_init(bh_mutex_t *mutex) { (void)mutex; - return -1; + return BH_NO_IMPL; } +/** + * Destroyes the \a mutex object. + * + * \param mutex Pointer to the mutex object + * + * \warning This is an internal function. + */ void bh_mutex_destroy(bh_mutex_t *mutex) { (void)mutex; } +/** + * Locks the \a mutex object. + * + * \param mutex Pointer to the mutex object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_mutex_lock(bh_mutex_t *mutex) { (void)mutex; - return -1; + return BH_NO_IMPL; } +/** + * Tries to lock the \a mutex object. + * + * \param mutex Pointer to the mutex object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_mutex_try_lock(bh_mutex_t *mutex) { (void)mutex; - return -1; + return BH_NO_IMPL; } +/** + * Unlocks the \a mutex object. + * + * \param mutex Pointer to the mutex object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_mutex_unlock(bh_mutex_t *mutex) { (void)mutex; - return -1; + return BH_NO_IMPL; } +/** + * Initilizes the \a semaphore object with specified \a count value. + * + * \warning This is an internal function. + * + * \param semaphore Pointer to the semaphore object + * \param count Initial semaphore value + * + * \return On success, returns zero. + * \return On failure, returns error code. + * + * \note Guranteed maximum \a count value is 32767. + */ int bh_semaphore_init(bh_semaphore_t *semaphore, int count) { (void)semaphore; (void)count; - return -1; + return BH_NO_IMPL; } +/** + * Destroyes the \a semaphore object. + * + * \warning This is an internal function. + * + * \param semaphore Pointer to the semaphore object + */ void bh_semaphore_destroy(bh_semaphore_t *semaphore) { (void)semaphore; } +/** + * Posts (increases value of) the \a semaphore. + * + * \param semaphore Pointer to the semaphore object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_semaphore_post(bh_semaphore_t *semaphore) { (void)semaphore; - return -1; + return BH_NO_IMPL; } +/** + * Waits (decreases value of) the \a semaphore. + * + * \param semaphore Pointer to the semaphore object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_semaphore_wait(bh_semaphore_t *semaphore) { (void)semaphore; - return -1; + return BH_NO_IMPL; } +/** + * Waits (decreases value of) the \a semaphore for the specified \a timeout + * amount of milliseconds. + * + * \param semaphore Pointer to the semaphore object + * \param timeout Number of milliseconds to wait for + * + * \return On success, returns zero. + * \return On failure or timeout, returns error code. + */ int bh_semaphore_wait_for(bh_semaphore_t *semaphore, unsigned long timeout) { (void)semaphore; - return -1; + return BH_NO_IMPL; } +/** + * Tries to waits (decrease value of) the \a semaphore. + * + * \param semaphore Pointer to the semaphore object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_semaphore_try_wait(bh_semaphore_t *semaphore) { (void)semaphore; - return -1; + return BH_NO_IMPL; } +/** + * Initializes the condition variable object \a cond. + * + * \warning This is an internal function. + * + * \param cond Pointer to the condition variable + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_cond_init(bh_cond_t *cond) { (void)cond; - return -1; + return BH_NO_IMPL; } +/** + * Destroyes the condition variable object \a cond. + * + * \param cond Pointer to the condition variable object + * + * \return On success, returns zero. + * \return On failure, returns error code. + * + * \warning This is an internal function. + */ void bh_cond_destroy(bh_cond_t *cond) { (void)cond; } +/** + * Waits on the condition variable \a cond with specified \a mutex. + * + * \param cond Pointer to the condition variable object + * \param mutex Pointer to the mutex object + * + * \return On success, returns zero. + * \return ON failure, returns error code. + */ int bh_cond_wait(bh_cond_t *cond, bh_mutex_t *mutex) { (void)cond; (void)mutex; - return -1; + return BH_NO_IMPL; } +/** + * Waits on the condition variable \a cond with specified \a mutex for the + * specified \a timeout amount of milliseconds. + * + * \param cond Pointer to the condition variable object + * \param mutex Pointer to the mutex object + * \param timeout Number of milliseconds to wait for + * + * \return On success, returns zero. + * \return On failure or timeout, returns error code. + */ int bh_cond_wait_for(bh_cond_t *cond, bh_mutex_t *mutex, unsigned long timeout) @@ -118,33 +302,71 @@ int bh_cond_wait_for(bh_cond_t *cond, (void)cond; (void)mutex; (void)timeout; - return -1; + return BH_NO_IMPL; } +/** + * Signals (notifies) one waiting thread on the condition variable \a cond. + * + * \param cond Pointer to the condition variable object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_cond_signal(bh_cond_t *cond) { (void)cond; - return -1; + return BH_NO_IMPL; } +/** + * Signals (notifies) all waiting threads on the condition variable \a cond. + * + * \param cond Pointer to the condition variable object + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ int bh_cond_broadcast(bh_cond_t *cond) { (void)cond; - return -1; + return BH_NO_IMPL; } -int bh_thread_pool_init(bh_thread_pool_t *pool, - size_t size) +/** + * Creates the thread pool object with specified \a size amount of threads. + * + * \param size Number of threads in the thread pool + * + * \return On success, returns pointer to the new thread pool object. + * \return On failure, returns null pointer. + */ +bh_thread_pool_t *bh_thread_pool_new(size_t size) { - (void)pool; (void)size; - return -1; + return NULL; } -bh_thread_pool_t *bh_thread_pool_new(size_t size) +/** + * Initilizes the thread \a pool object with specified \a size amount of + * threads. + * + * \warning This is an internal function. + * + * \param pool Pointer to the thread pool object + * \param size Number of threads in the thread pool + * + * \return On success, returns zero. + * \return On failure, returns error code. + */ +int bh_thread_pool_init(bh_thread_pool_t *pool, + size_t size) { + (void)pool; (void)size; - return NULL; + return BH_NO_IMPL; } - +/** + * \} + */
\ No newline at end of file diff --git a/src/thread_posix.c b/src/thread_posix.c index 21ca2be..2898644 100644 --- a/src/thread_posix.c +++ b/src/thread_posix.c @@ -5,9 +5,9 @@ static void *bh_thread_run(void *arg) { bh_task_t *task; - task = (bh_task_t *)arg; + /* Do the task, mark as done, and if required free it */ task->func(task->data); task->flags |= BH_THREAD_DONE; @@ -21,21 +21,25 @@ int bh_thread_init(bh_thread_t *thread, bh_task_t *task) { thread->allocated = 0; - return pthread_create(&thread->handle, NULL, bh_thread_run, task); + if (pthread_create(&thread->handle, NULL, bh_thread_run, task)) + return BH_ERROR; + + return BH_OK; } bh_thread_t *bh_thread_new(bh_task_t *task) { bh_thread_t *result; + /* Allocate thread object */ result = malloc(sizeof(*result)); - if (result && bh_thread_init(result, task)) { free(result); result = NULL; } + /* Mark thread as allocated for deallocation in join/detach */ if (result) result->allocated = 1; @@ -44,27 +48,35 @@ bh_thread_t *bh_thread_new(bh_task_t *task) int bh_thread_join(bh_thread_t *thread) { - int result = pthread_join(thread->handle, NULL); + /* Join the thread */ + if (pthread_join(thread->handle, NULL)) + return BH_ERROR; + /* If thread is allocated, deallocate it */ if (thread->allocated) free(thread); - return result; + return BH_OK; } int bh_thread_detach(bh_thread_t *thread) { - int result = pthread_detach(thread->handle); + /* Detach the thread */ + if (pthread_detach(thread->handle)) + return BH_ERROR; + /* If thread is allocated, deallocate it */ if (thread->allocated) free(thread); - return result; + return BH_OK; } int bh_mutex_init(bh_mutex_t *mutex) { - return pthread_mutex_init(&mutex->handle, NULL); + if (pthread_mutex_init(&mutex->handle, NULL)) + return BH_ERROR; + return BH_OK; } void bh_mutex_destroy(bh_mutex_t *mutex) @@ -74,22 +86,30 @@ void bh_mutex_destroy(bh_mutex_t *mutex) int bh_mutex_lock(bh_mutex_t *mutex) { - return pthread_mutex_lock(&mutex->handle); + if (pthread_mutex_lock(&mutex->handle)) + return BH_ERROR; + return BH_OK; } int bh_mutex_try_lock(bh_mutex_t *mutex) { - return pthread_mutex_trylock(&mutex->handle); + if (pthread_mutex_trylock(&mutex->handle)) + return BH_ERROR; + return BH_OK; } int bh_mutex_unlock(bh_mutex_t *mutex) { - return pthread_mutex_unlock(&mutex->handle); + if (pthread_mutex_unlock(&mutex->handle)) + return BH_ERROR; + return BH_OK; } int bh_semaphore_init(bh_semaphore_t *semaphore, int count) { - return sem_init(&semaphore->handle, 0, count); + if (sem_init(&semaphore->handle, 0, count)) + return BH_ERROR; + return BH_OK; } void bh_semaphore_destroy(bh_semaphore_t *semaphore) @@ -99,12 +119,16 @@ void bh_semaphore_destroy(bh_semaphore_t *semaphore) int bh_semaphore_post(bh_semaphore_t *semaphore) { - return sem_post(&semaphore->handle); + if (sem_post(&semaphore->handle)) + return BH_ERROR; + return BH_OK; } int bh_semaphore_wait(bh_semaphore_t *semaphore) { - return sem_wait(&semaphore->handle); + if (sem_wait(&semaphore->handle)) + return BH_ERROR; + return BH_OK; } int bh_semaphore_wait_for(bh_semaphore_t *semaphore, @@ -115,17 +139,23 @@ int bh_semaphore_wait_for(bh_semaphore_t *semaphore, ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000; - return sem_timedwait(&semaphore->handle, &ts); + if (sem_timedwait(&semaphore->handle, &ts)) + return BH_TIMEOUT; + return BH_OK; } int bh_semaphore_try_wait(bh_semaphore_t *semaphore) { - return sem_trywait(&semaphore->handle); + if (sem_trywait(&semaphore->handle)) + return BH_ERROR; + return BH_OK; } int bh_cond_init(bh_cond_t *cond) { - return pthread_cond_init(&cond->handle, NULL); + if (pthread_cond_init(&cond->handle, NULL)) + return BH_ERROR; + return BH_OK; } void bh_cond_destroy(bh_cond_t *cond) @@ -136,7 +166,9 @@ void bh_cond_destroy(bh_cond_t *cond) int bh_cond_wait(bh_cond_t *cond, bh_mutex_t *mutex) { - return pthread_cond_wait(&cond->handle, &mutex->handle); + if (pthread_cond_wait(&cond->handle, &mutex->handle)) + return BH_ERROR; + return BH_OK; } int bh_cond_wait_for(bh_cond_t *cond, @@ -148,17 +180,23 @@ int bh_cond_wait_for(bh_cond_t *cond, ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000; - return pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts); + if (pthread_cond_timedwait(&cond->handle, &mutex->handle, &ts)) + return BH_TIMEOUT; + return BH_OK; } int bh_cond_signal(bh_cond_t *cond) { - return pthread_cond_signal(&cond->handle); + if (pthread_cond_signal(&cond->handle)) + return BH_ERROR; + return BH_OK; } int bh_cond_broadcast(bh_cond_t *cond) { - return pthread_cond_broadcast(&cond->handle); + if (pthread_cond_broadcast(&cond->handle)) + return BH_ERROR; + return BH_OK; } int bh_thread_pool_init(bh_thread_pool_t *pool, @@ -215,7 +253,7 @@ int bh_thread_pool_init(bh_thread_pool_t *pool, } } - return 0; + return BH_OK; queue_fail: free(pool->threads); @@ -230,7 +268,7 @@ task_fail: bh_mutex_destroy(&pool->lock); lock_fail: - return -1; + return BH_ERROR; } bh_thread_pool_t *bh_thread_pool_new(size_t size) diff --git a/src/thread_win.c b/src/thread_win.c index 098e7dd..bb14774 100644 --- a/src/thread_win.c +++ b/src/thread_win.c @@ -3,16 +3,19 @@ static unsigned __stdcall bh_thread_run(void *arg) { bh_thread_data_t data; - + + /* Fetch thread data, store it on stack and free from heap */ data = *(bh_thread_data_t *)arg; free(arg); - + + /* Do the task, mark as done, and if required free it */ data.task->func(data.task->data); data.task->flags |= BH_THREAD_DONE; if (data.task->flags & BH_THREAD_CLEANUP) bh_task_free(data.task); - + + /* Call thread specific end function (deallocate TLS) */ data.end(0); return 0; } @@ -23,24 +26,28 @@ int bh_thread_init_base(bh_thread_t *thread, bh_thread_end_cb_t end) { bh_thread_data_t *data; - + + /* Allocate thread specific data */ data = malloc(sizeof(*data)); if (!data) - return -1; - + return BH_OOM; + + /* Setup thread specific data */ data->task = task; data->end = end; - + + /* Create and setup thread (relative to the callers libc) */ thread->allocated = 0; thread->handle = (HANDLE)_beginthreadex(NULL, 0, bh_thread_run, data, 0, NULL); - + + /* Check for errors */ if (!thread->handle) { free(data); - return -1; + return BH_ERROR; } - - return 0; + + return BH_OK; } bh_thread_t *bh_thread_new_base(bh_task_t *task, @@ -48,46 +55,53 @@ bh_thread_t *bh_thread_new_base(bh_task_t *task, bh_thread_end_cb_t end) { bh_thread_t *result; - + + /* Allocate thread object */ result = malloc(sizeof(*result)); if (result && !bh_thread_init_base(result, task, begin, end)) { free(result); result = NULL; } - + + /* Mark thread as allocated for deallocation in join/detach */ if (result) result->allocated = 1; - + return result; } int bh_thread_join(bh_thread_t *thread) { + /* Join the thread */ WaitForSingleObject(thread->handle, INFINITE); CloseHandle(thread->handle); - + + /* If thread is allocated, deallocate it */ if (thread->allocated) free(thread); - - return 0; + + return BH_OK; } int bh_thread_detach(bh_thread_t *thread) { + /* Detach from thread */ CloseHandle(thread->handle); - + + /* If thread is allocated, deallocate it */ if (thread->allocated) free(thread); - - return 0; + + return BH_OK; } int bh_mutex_init(bh_mutex_t *mutex) { + /* TODO: Is this spincount needed or sane? */ if (!InitializeCriticalSectionAndSpinCount(&mutex->handle, 0x400)) - return -1; - return 0; + return BH_ERROR; + return BH_OK; } void bh_mutex_destroy(bh_mutex_t *mutex) @@ -98,29 +112,30 @@ void bh_mutex_destroy(bh_mutex_t *mutex) int bh_mutex_lock(bh_mutex_t *mutex) { EnterCriticalSection(&mutex->handle); - return 0; + return BH_OK; } int bh_mutex_try_lock(bh_mutex_t *mutex) { if (!TryEnterCriticalSection(&mutex->handle)) - return -1; - return 0; + return BH_ERROR; + return BH_OK; } int bh_mutex_unlock(bh_mutex_t *mutex) { LeaveCriticalSection(&mutex->handle); - return 0; + return BH_OK; } int bh_semaphore_init(bh_semaphore_t *semaphore, int count) { + /* Create semaphore with max value of 32767 (to match POSIX) */ semaphore->handle = CreateSemaphore(NULL, count, 0x7FFF, NULL); if (!semaphore->handle) - return -1; - - return 0; + return BH_ERROR; + + return BH_OK; } void bh_semaphore_destroy(bh_semaphore_t *semaphore) @@ -131,37 +146,38 @@ void bh_semaphore_destroy(bh_semaphore_t *semaphore) int bh_semaphore_post(bh_semaphore_t *semaphore) { if (!ReleaseSemaphore(semaphore->handle, 1, NULL)) - return -1; - return 0; + return BH_ERROR; + return BH_OK; } int bh_semaphore_wait(bh_semaphore_t *semaphore) { if (WaitForSingleObject(semaphore->handle, INFINITE)) - return -1; - return 0; + return BH_ERROR; + return BH_OK; } int bh_semaphore_wait_for(bh_semaphore_t *semaphore, unsigned long timeout) { + /* FIXME: Check if we timed out or errored out */ if (WaitForSingleObject(semaphore->handle, timeout)) - return -1; - return 0; + return BH_TIMEOUT; + return BH_ERROR; } int bh_semaphore_try_wait(bh_semaphore_t *semaphore) { if (WaitForSingleObject(semaphore->handle, 0)) - return -1; - return 0; + return BH_ERROR; + return BH_OK; } #if WINVER >= _WIN32_WINNT_VISTA int bh_cond_init(bh_cond_t *cond) { InitializeConditionVariable(&cond->handle); - return 0; + return BH_OK; } void bh_cond_destroy(bh_cond_t *cond) @@ -179,43 +195,46 @@ int bh_cond_wait_for(bh_cond_t *cond, bh_mutex_t *mutex, unsigned long timeout) { + /* FIXME: Check if we timed out or errored out */ if (!SleepConditionVariableCS(&cond->handle, &mutex->handle, timeout)) - return -1; - return 0; + return BH_TIMEOUT; + return BH_OK; } int bh_cond_signal(bh_cond_t *cond) { WakeConditionVariable(&cond->handle); - return 0; + return BH_OK; } int bh_cond_broadcast(bh_cond_t *cond) { WakeAllConditionVariable(&cond->handle); - return 0; + return BH_OK; } #else /* Condition variable implementation based on BeOS article * http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html - */ + * + * Slow, but correct implementation of CVs. + */ int bh_cond_init(bh_cond_t *cond) { if (bh_mutex_init(&cond->lock)) - return -1; - + return BH_ERROR; + if (bh_semaphore_init(&cond->wait, 0)) { bh_mutex_destroy(&cond->lock); - return -1; + return BH_ERROR; } - + if (bh_semaphore_init(&cond->done, 0)) { bh_semaphore_destroy(&cond->wait); bh_mutex_destroy(&cond->lock); - return -1; + return BH_ERROR; } cond->waiting = 0; cond->signals = 0; @@ -234,27 +253,27 @@ int bh_cond_wait(bh_cond_t *cond, bh_mutex_t *mutex) { int retval; - + bh_mutex_lock(&cond->lock); cond->waiting++; bh_mutex_unlock(&cond->lock); bh_mutex_unlock(mutex); - + retval = bh_semaphore_wait(&cond->wait); - + bh_mutex_lock(&cond->lock); if (cond->signals > 0) { if (retval) bh_semaphore_wait(&cond->wait); - + bh_semaphore_post(&cond->done); cond->signals--; } cond->waiting--; - bh_mutex_unlock(&cond->lock); + bh_mutex_unlock(&cond->lock); bh_mutex_lock(mutex); - + return retval; } @@ -263,70 +282,70 @@ int bh_cond_wait_for(bh_cond_t *cond, unsigned long timeout) { int retval; - + bh_mutex_lock(&cond->lock); cond->waiting++; bh_mutex_unlock(&cond->lock); bh_mutex_unlock(mutex); - + retval = bh_semaphore_wait_for(&cond->wait, timeout); - + bh_mutex_lock(&cond->lock); if (cond->signals > 0) { if (retval) bh_semaphore_wait(&cond->wait); - + bh_semaphore_post(&cond->done); cond->signals--; } cond->waiting--; - bh_mutex_unlock(&cond->lock); + bh_mutex_unlock(&cond->lock); bh_mutex_lock(mutex); - + return retval; } int bh_cond_signal(bh_cond_t *cond) { bh_mutex_lock(&cond->lock); - + if (cond->waiting > cond->signals) { cond->signals++; - + bh_semaphore_post(&cond->wait); bh_mutex_unlock(&cond->lock); bh_semaphore_wait(&cond->done); } else bh_mutex_unlock(&cond->lock); - - return 0; + + return BH_OK; } int bh_cond_broadcast(bh_cond_t *cond) { int i, waiting; - + bh_mutex_lock(&cond->lock); if (cond->waiting > cond->signals) { waiting = cond->waiting - cond->signals; cond->signals = cond->waiting; - + for (i = 0; i < waiting; i++) bh_semaphore_post(&cond->wait); - + bh_mutex_unlock(&cond->lock); - + for (i = 0; i < waiting; i++) bh_semaphore_wait(&cond->done); } else bh_mutex_unlock(&cond->lock); - - return 0; + + return BH_OK; } #endif @@ -386,7 +405,7 @@ int bh_thread_pool_init_base(bh_thread_pool_t *pool, } } - return 0; + return BH_OK; queue_fail: free(pool->threads); @@ -401,7 +420,7 @@ task_fail: bh_mutex_destroy(&pool->lock); lock_fail: - return -1; + return BH_ERROR; } bh_thread_pool_t *bh_thread_pool_new_base(size_t size, @@ -409,6 +428,7 @@ bh_thread_pool_t *bh_thread_pool_new_base(size_t size, bh_thread_end_cb_t end) { bh_thread_pool_t *result; + result = malloc(sizeof(*result)); if (result && bh_thread_pool_init_base(result, size, begin, end)) { diff --git a/unit/include/bh/unit.h b/unit/include/bh/unit.h index 62c0d87..f245d03 100644 --- a/unit/include/bh/unit.h +++ b/unit/include/bh/unit.h @@ -1,5 +1,5 @@ -#ifndef BHLIB_UNIT_H -#define BHLIB_UNIT_H +#ifndef BH_UNIT_H +#define BH_UNIT_H #include <stdio.h> @@ -21,4 +21,4 @@ typedef int (*bh_unit_cb_t)(void); void bh_unit_add(const char *name, bh_unit_cb_t func); int bh_unit_run(void); -#endif /* BHLIB_UNIT_H */ +#endif /* BH_UNIT_H */ |
