summaryrefslogtreecommitdiff
path: root/simclist-1.5
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2025-08-03 19:22:36 +0200
committerAldrik Ramaekers <aldrikboy@gmail.com>2025-08-03 19:22:36 +0200
commit853bbb3752a5fa2f58ef456ffb6e3a552e13cb11 (patch)
treece49a533f82a42a65fa6a4771a7b8fbfe33798cf /simclist-1.5
initial commit
Diffstat (limited to 'simclist-1.5')
-rw-r--r--simclist-1.5/._CMakeLists.txtbin0 -> 229 bytes
-rw-r--r--simclist-1.5/._docbin0 -> 229 bytes
-rw-r--r--simclist-1.5/._examplesbin0 -> 229 bytes
-rw-r--r--simclist-1.5/._perftestbin0 -> 229 bytes
-rw-r--r--simclist-1.5/._regrtestbin0 -> 229 bytes
-rw-r--r--simclist-1.5/._simclist.hbin0 -> 229 bytes
-rw-r--r--simclist-1.5/CMakeLists.txt39
-rw-r--r--simclist-1.5/Changes58
-rw-r--r--simclist-1.5/Doxyfile1252
-rw-r--r--simclist-1.5/README34
-rw-r--r--simclist-1.5/examples/._ex1.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/examples/._ex2.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/examples/._ex3.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/examples/ex1.c28
-rw-r--r--simclist-1.5/examples/ex2.c38
-rw-r--r--simclist-1.5/examples/ex3.c58
-rw-r--r--simclist-1.5/perftest/._README-perftest.txtbin0 -> 229 bytes
-rw-r--r--simclist-1.5/perftest/._ext.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/perftest/._ins.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/perftest/._sort.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/perftest/README-perftest.txt34
-rw-r--r--simclist-1.5/perftest/ext.c31
-rw-r--r--simclist-1.5/perftest/ins.c17
-rw-r--r--simclist-1.5/perftest/sort.c24
-rw-r--r--simclist-1.5/regrtest/._printlist.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/regrtest/._test1.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/regrtest/._test2.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/regrtest/._test3-dump.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/regrtest/._test3-restore.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/regrtest/._test4-seeker.cbin0 -> 229 bytes
-rw-r--r--simclist-1.5/regrtest/printlist.c11
-rw-r--r--simclist-1.5/regrtest/test1.c120
-rw-r--r--simclist-1.5/regrtest/test2.c75
-rw-r--r--simclist-1.5/regrtest/test3-dump.c57
-rw-r--r--simclist-1.5/regrtest/test3-restore.c64
-rw-r--r--simclist-1.5/regrtest/test4-seeker.c53
-rw-r--r--simclist-1.5/simclist.c1483
-rw-r--r--simclist-1.5/simclist.h971
38 files changed, 4447 insertions, 0 deletions
diff --git a/simclist-1.5/._CMakeLists.txt b/simclist-1.5/._CMakeLists.txt
new file mode 100644
index 0000000..03e3d87
--- /dev/null
+++ b/simclist-1.5/._CMakeLists.txt
Binary files differ
diff --git a/simclist-1.5/._doc b/simclist-1.5/._doc
new file mode 100644
index 0000000..c4ae9d7
--- /dev/null
+++ b/simclist-1.5/._doc
Binary files differ
diff --git a/simclist-1.5/._examples b/simclist-1.5/._examples
new file mode 100644
index 0000000..64452ad
--- /dev/null
+++ b/simclist-1.5/._examples
Binary files differ
diff --git a/simclist-1.5/._perftest b/simclist-1.5/._perftest
new file mode 100644
index 0000000..18e30d5
--- /dev/null
+++ b/simclist-1.5/._perftest
Binary files differ
diff --git a/simclist-1.5/._regrtest b/simclist-1.5/._regrtest
new file mode 100644
index 0000000..560655d
--- /dev/null
+++ b/simclist-1.5/._regrtest
Binary files differ
diff --git a/simclist-1.5/._simclist.h b/simclist-1.5/._simclist.h
new file mode 100644
index 0000000..32623c0
--- /dev/null
+++ b/simclist-1.5/._simclist.h
Binary files differ
diff --git a/simclist-1.5/CMakeLists.txt b/simclist-1.5/CMakeLists.txt
new file mode 100644
index 0000000..28f3474
--- /dev/null
+++ b/simclist-1.5/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.6)
+PROJECT(simclist)
+
+# simclist options
+OPTION(SIMCLIST_DEBUG
+ "Build with debug code and debug symbols enabled"
+ OFF)
+OPTION(SIMCLIST_THREADING
+ "Build with simclist threading enable"
+ OFF)
+OPTION(SIMCLIST_NO_DUMPRESTORE
+ "Disable building of dump & restore functionalities"
+ OFF)
+OPTION(SIMCLIST_ALLOW_LOCATIONBASED_HASHES
+ "Allow list_hash() to work exclusively on memory locations"
+ OFF)
+
+# expand selected options
+SET(SIMCCFLAGS "")
+# build with debug?
+IF(SIMCLIST_DEBUG)
+ SET(SIMCCFLAGS "${SIMCCFLAGS} -DSIMCLIST_DEBUG")
+ENDIF(SIMCLIST_DEBUG)
+# build with threading?
+IF(SIMCLIST_THREADING)
+ SET(SIMCCFLAGS "${SIMCCFLAGS} -DSIMCLIST_WITH_THREADS")
+ENDIF(SIMCLIST_THREADING)
+# build without dump/restore functionalities?
+IF(SIMCLIST_NO_DUMPRESTORE)
+ SET(SIMCCFLAGS "${SIMCCFLAGS} -DSIMCLIST_NO_DUMPRESTORE")
+ENDIF(SIMCLIST_NO_DUMPRESTORE)
+IF(SIMCLIST_ALLOW_LOCATIONBASED_HASHES)
+ SET(SIMCCFLAGS "${SIMCCFLAGS} -DSIMCLIST_ALLOW_LOCATIONBASED_HASHES")
+ENDIF(SIMCLIST_ALLOW_LOCATIONBASED_HASHES)
+SET_SOURCE_FILES_PROPERTIES(simclist.c COMPILE_FLAGS "${SIMCCFLAGS}")
+
+# main building stuff
+ADD_LIBRARY(simclist SHARED simclist.c)
+SET(CMAKE_C_FLAGS "-O2 -Wall -std=c99")
diff --git a/simclist-1.5/Changes b/simclist-1.5/Changes
new file mode 100644
index 0000000..06a8e80
--- /dev/null
+++ b/simclist-1.5/Changes
@@ -0,0 +1,58 @@
+* 1.5 Nov 2010
+ - improve performance of list_init() (thanks L. Rousseau)
+ - fix assert() failure up to mid pointer not NULLed on cleared lists (thanks L. Rousseau)
+
+* 1.4.4rc4 Apr 2010
+ - fix compilation warnings on Solaris (thanks Joerg Schilling, Ludovic Rousseau)
+
+* 1.4.4rc3 Mar 2010
+ - fix speculation in list dumping causing possible broken dumps (thanks Richard Krakhofer)
+
+* 1.4.4rc2 Mar 2010
+ - add function list_delete() to delete by element (thanks Ludovic Rousseau)
+
+* 1.4.4rc1 Aug 2009
+ - support compilers without C99 capabilities
+ - change API for list_hash() (and add SIMCLIST_ALLOW_LOCATIONBASED_HASHES)
+
+* 1.4.3 Apr 2009
+ - fix return values of list_empty()
+
+* 1.4.2 Mar 2009
+ - make return values of list_dump_file() and list_restore_file() consistent
+ - allow to disable compilation of dump/restore features to save memory on
+ ultra-constrained devices
+
+* 1.4.1 Jan 2009
+ - define EPROTO for those operating systems that don't define it
+ - SimCList celebrates 2 years and over 2000 downloads <8-D
+
+* 1.4 Dec 2008
+ - interface changes:
+ - _restore*() and _dump*() functions now write length in argument
+ - list_seek() no longer returns a constant reference
+ - decorate with "restrict" qualifiers => now requires C99 support from compiler
+ - minor improvements in documentation
+
+* 1.3.1 Jan 2008
+ - fix portability issue when compiling on some OSes
+
+* 1.3 Nov 2007
+ - support custom element seek
+ - support for dumping/restoring lists on files
+
+* 1.2 Jun 2007
+ - natively support transparent inclusion in C++ apps
+ - use sentinels to improve performance on list traversals
+ - fix list_insert_at that could output inconsistent lists
+ when inserting into even-sized lists in position 0
+
+* 1.1 Apr 2007
+ - use freelists for improving memory allocation performance
+ - fix list_concat() that could output inconsistent lists
+ - new ready-made comparators, metric and hashing functions for
+ the most common types (numeric and strings)
+ - new list_find() function
+
+* 1.0 Jan 2007
+ - first release to public
diff --git a/simclist-1.5/Doxyfile b/simclist-1.5/Doxyfile
new file mode 100644
index 0000000..f82db39
--- /dev/null
+++ b/simclist-1.5/Doxyfile
@@ -0,0 +1,1252 @@
+# Doxyfile 1.5.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a 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 (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = SimCList
+
+# 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 = 1.5
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# 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 = doc/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 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 cause performance problems for the file system.
+
+CREATE_SUBDIRS = YES
+
+# 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.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) 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.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) 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.
+
+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" "the"
+
+ABBREVIATE_BRIEF =
+
+# 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.
+
+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.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then 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.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then 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.
+
+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 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.
+
+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
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_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 behaviour.
+# 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 behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+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.
+
+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.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" 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:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+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.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# 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); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# 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.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) 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.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# 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 and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+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.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When 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 (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) 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.
+
+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 (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+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 (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+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 (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) 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.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# 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 default), 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.
+
+SORT_BY_SCOPE_NAME = 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.
+
+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.
+
+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.
+
+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.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of 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 initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+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.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# 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. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED 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.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = 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)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# 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 stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be 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.
+
+INPUT =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_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 the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# 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.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+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 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.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are 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.
+
+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
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# 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 also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# 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 documentstion.
+
+REFERENCES_LINK_SOURCE = 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 http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) 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.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# 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.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# 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 one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+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. If left blank `html' will be used as the default path.
+
+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). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+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 the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, 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.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = YES
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag 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 (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# 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.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+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. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = pdflatex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = 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.
+
+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, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal 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. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). 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.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# 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.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# 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 very pretty with
+# other RTF readers or editors.
+
+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. If left blank `rtf' will be used as the default path.
+
+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.
+
+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 other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+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. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# 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 is NO.
+
+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.
+
+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. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# 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.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# 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.
+
+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.
+
+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.
+
+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.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+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 (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF 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.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+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.
+
+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.
+
+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
+# 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.
+
+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.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all 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.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that 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.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+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.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# 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.
+
+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, 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)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are 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.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+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.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# 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.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are 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.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are 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.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are 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.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH 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.
+
+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).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# 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 a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# 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).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES 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.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/simclist-1.5/README b/simclist-1.5/README
new file mode 100644
index 0000000..e1d9ec2
--- /dev/null
+++ b/simclist-1.5/README
@@ -0,0 +1,34 @@
+version: 1.5
+website: http://mij.oltrelinux.com/devel/simclist/
+contact: mij <mij@bitchx.it>
+license: BSD revised (see http://www.opensource.org/licenses/bsd-license.php)
+
+
+>> USE / INSTALL
+
+Because of its BSD license, if you use simclist you can simply embed its whole
+source code into your application.
+Otherwise, simclist can be installed as a shared library. For installing
+SimCList as a shared library:
+
+1. enter the package root directory
+2. let cmake (http://cmake.org) produce the Makefile you need (mind the trailing dot)
+ $ cmake .
+3. compile
+ $ make
+
+
+>> CONTENT
+
+- simclist.{c,h} library sources
+- examples/* examples on using the API
+- perftest/* sources for performance tests
+
+
+>> API DOCUMENTATION
+
+Use doxygen to build SimCList's doc. A Doxyfile configuration for doxygen is
+already available in the package.
+This will build HTML documentation, in the English language, in doc/:
+ $ doxygen
+
diff --git a/simclist-1.5/examples/._ex1.c b/simclist-1.5/examples/._ex1.c
new file mode 100644
index 0000000..3a559d8
--- /dev/null
+++ b/simclist-1.5/examples/._ex1.c
Binary files differ
diff --git a/simclist-1.5/examples/._ex2.c b/simclist-1.5/examples/._ex2.c
new file mode 100644
index 0000000..536216c
--- /dev/null
+++ b/simclist-1.5/examples/._ex2.c
Binary files differ
diff --git a/simclist-1.5/examples/._ex3.c b/simclist-1.5/examples/._ex3.c
new file mode 100644
index 0000000..89542cf
--- /dev/null
+++ b/simclist-1.5/examples/._ex3.c
Binary files differ
diff --git a/simclist-1.5/examples/ex1.c b/simclist-1.5/examples/ex1.c
new file mode 100644
index 0000000..13c67c3
--- /dev/null
+++ b/simclist-1.5/examples/ex1.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+
+#include <simclist.h> /* use the SimCList library */
+
+
+int main() {
+ list_t mylist; /* declare a list */
+ int userval;
+
+
+ list_init(& mylist); /* initialize the list */
+
+ printf("Insert your number: ");
+ scanf("%d", & userval);
+
+ list_append(& mylist, & userval); /* add an element to the list */
+
+ printf("The list now holds %u elements.\n", \
+ list_size(& mylist)); /* get the size of the list */
+
+ printf("Your number was: %d\n", \
+ * (int*)list_get_at(& mylist, 0)); /* extract the first element of the list */
+
+ list_destroy(&mylist);
+
+ return 0;
+}
+
diff --git a/simclist-1.5/examples/ex2.c b/simclist-1.5/examples/ex2.c
new file mode 100644
index 0000000..3fc2c5e
--- /dev/null
+++ b/simclist-1.5/examples/ex2.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+
+#include <simclist.h>
+
+int main() {
+ int val;
+ list_t l;
+
+ list_init(&l);
+
+ /* request to store copies, and provide the metric function */
+ list_attributes_copy(&l, list_meter_int32_t, 1);
+
+ printf("Give numbers. Terminate with one negative.\n");
+ scanf("%d", &val);
+ while (val > 0) {
+ list_append(&l, &val);
+ scanf("%d", &val);
+ }
+
+ /* setting the comparator, so the list can sort, find the min, max etc */
+ list_attributes_comparator(&l, list_comparator_int32_t);
+ list_sort(&l, -1); /* sorting the list in descending (-1) order */
+
+ /* printing out the result */
+ printf("Sorted values:\n");
+
+ list_iterator_start(&l); /* starting an iteration "session" */
+ while (list_iterator_hasnext(&l)) { /* tell whether more values available */
+ printf("%d\n", *(int *)list_iterator_next(&l)); /* get the next value */
+ }
+ list_iterator_stop(&l); /* starting the iteration "session" */
+
+ list_destroy(&l);
+
+ return 0;
+}
+
diff --git a/simclist-1.5/examples/ex3.c b/simclist-1.5/examples/ex3.c
new file mode 100644
index 0000000..74d3091
--- /dev/null
+++ b/simclist-1.5/examples/ex3.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+
+#include <simclist.h>
+
+typedef struct {
+ int x, y;
+} point2D;
+
+typedef struct {
+ point2D a, b, c, d;
+} rectangle; /* custom data type to store in list */
+
+/* this function returns the size of elements */
+size_t mymeter(const void *el) {
+ /* every element has the constant size of a rectangle structure */
+ return sizeof(rectangle);
+}
+
+/*
+ * compare rectangles by area
+ *
+ * this function compares two elements:
+ * <0: a greater than b
+ * 0: a equivalent to b
+ * >0: b greater than a
+ */
+int mycomparator(const void *a, const void *b) {
+ /* compare areas */
+ const rectangle *A = (rectangle *) a;
+ const rectangle *B = (rectangle *) b;
+ unsigned int areaA, areaB;
+ areaA = ((A->c.y - A->b.y) * (A->b.x - A->a.x));
+ areaB = ((B->c.y - B->b.y) * (B->b.x - B->a.x));
+ return (areaA < areaB) - (areaA > areaB);
+}
+
+int main() {
+ rectangle rect;
+ list_t l;
+
+ list_init(&l);
+
+ /* setting the custom spanning function */
+ list_attributes_copy(&l, mymeter, 1);
+
+ /* acquire rectangles and insert in list ... */
+
+ /* setting the custom area comparator */
+ list_attributes_comparator(&l, mycomparator);
+ list_sort(&l, -1); /* sorting by area (descending) */
+
+ /* [display list ...] */
+
+ list_destroy(&l);
+
+ return 0;
+}
+
diff --git a/simclist-1.5/perftest/._README-perftest.txt b/simclist-1.5/perftest/._README-perftest.txt
new file mode 100644
index 0000000..fd67f74
--- /dev/null
+++ b/simclist-1.5/perftest/._README-perftest.txt
Binary files differ
diff --git a/simclist-1.5/perftest/._ext.c b/simclist-1.5/perftest/._ext.c
new file mode 100644
index 0000000..70f73dd
--- /dev/null
+++ b/simclist-1.5/perftest/._ext.c
Binary files differ
diff --git a/simclist-1.5/perftest/._ins.c b/simclist-1.5/perftest/._ins.c
new file mode 100644
index 0000000..17ab7f1
--- /dev/null
+++ b/simclist-1.5/perftest/._ins.c
Binary files differ
diff --git a/simclist-1.5/perftest/._sort.c b/simclist-1.5/perftest/._sort.c
new file mode 100644
index 0000000..168e05d
--- /dev/null
+++ b/simclist-1.5/perftest/._sort.c
Binary files differ
diff --git a/simclist-1.5/perftest/README-perftest.txt b/simclist-1.5/perftest/README-perftest.txt
new file mode 100644
index 0000000..127e51a
--- /dev/null
+++ b/simclist-1.5/perftest/README-perftest.txt
@@ -0,0 +1,34 @@
+SimCList performance test cases
+
+===== ins.c
+insert 10 000 000 (ten million) elements into a list, with element autocopy
+disabled.
+Compile:
+ gcc -O2 -I.. -std=c99 -o ins ins.c ../simclist.c
+Use:
+ time ./ins
+
+
+===== ext.c
+insert 1 000 000 (one million) elements with element autocopy, then extracts 1
+000 elements at random position (from a Uniform(0, list_size) probability
+density function).
+Compile:
+ gcc -O2 -I.. -std=c99 -o ext ext.c ../simclist.c
+Use:
+ time ./ext
+
+
+===== sort.c
+insert 1 000 000 elements with autocopy, then sorting.
+
+Compile:
+ # for testing the default setup
+ gcc -O2 -I.. -std=c99 -o sort sort.c ../simclist.c
+ # for testing with threading enabled
+ gcc -DSIMCLIST_WITH_THREADS -O2 -I.. -std=c99 -o sort sort.c ../simclist.c
+Use:
+ # generate data to insert into the list
+ # e.g. for ((i = 0; i<1000000; i++)); do echo $RANDOM; done >randdata.txt
+ time ./sort < randdata.txt
+
diff --git a/simclist-1.5/perftest/ext.c b/simclist-1.5/perftest/ext.c
new file mode 100644
index 0000000..8288b84
--- /dev/null
+++ b/simclist-1.5/perftest/ext.c
@@ -0,0 +1,31 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <simclist.h>
+
+#define NELS 1000000
+
+size_t szelem(const void *el) {
+ return sizeof(int);
+}
+
+int main() {
+ list_t l;
+ int i;
+
+ srandom(time(NULL));
+
+ list_init(&l);
+ list_attributes_copy(&l, szelem, 1);
+
+ for (i = 0; i < NELS; i++) {
+ list_append(&l, &i);
+ }
+
+ for (i = 0; i < 1000; i++) {
+ list_get_at(&l, random()%NELS);
+ }
+
+ return 0;
+}
diff --git a/simclist-1.5/perftest/ins.c b/simclist-1.5/perftest/ins.c
new file mode 100644
index 0000000..e7d1c19
--- /dev/null
+++ b/simclist-1.5/perftest/ins.c
@@ -0,0 +1,17 @@
+
+#include <stdio.h>
+#include <simclist.h>
+
+#define NELS 10000000
+
+int main() {
+ list_t l;
+ int i;
+
+ list_init(&l);
+ for (i = 0; i < NELS; i++) {
+ list_append(&l, &i);
+ }
+
+ return 0;
+}
diff --git a/simclist-1.5/perftest/sort.c b/simclist-1.5/perftest/sort.c
new file mode 100644
index 0000000..171c8d7
--- /dev/null
+++ b/simclist-1.5/perftest/sort.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <simclist.h>
+
+#define BUFLEN 20
+
+int main() {
+ list_t l;
+ unsigned int i;
+ char buf[BUFLEN];
+
+ list_init(&l);
+ list_attributes_copy(&l, list_meter_int32_t, 1);
+ list_attributes_comparator(&l, list_comparator_int32_t);
+
+ while (fgets(buf, BUFLEN, stdin) != NULL) {
+ i = atoi(buf);
+ list_append(&l, &i);
+ }
+
+ list_sort(&l, 1);
+
+ return 0;
+}
diff --git a/simclist-1.5/regrtest/._printlist.c b/simclist-1.5/regrtest/._printlist.c
new file mode 100644
index 0000000..041f2c1
--- /dev/null
+++ b/simclist-1.5/regrtest/._printlist.c
Binary files differ
diff --git a/simclist-1.5/regrtest/._test1.c b/simclist-1.5/regrtest/._test1.c
new file mode 100644
index 0000000..95f06ce
--- /dev/null
+++ b/simclist-1.5/regrtest/._test1.c
Binary files differ
diff --git a/simclist-1.5/regrtest/._test2.c b/simclist-1.5/regrtest/._test2.c
new file mode 100644
index 0000000..0866fd9
--- /dev/null
+++ b/simclist-1.5/regrtest/._test2.c
Binary files differ
diff --git a/simclist-1.5/regrtest/._test3-dump.c b/simclist-1.5/regrtest/._test3-dump.c
new file mode 100644
index 0000000..d6eacff
--- /dev/null
+++ b/simclist-1.5/regrtest/._test3-dump.c
Binary files differ
diff --git a/simclist-1.5/regrtest/._test3-restore.c b/simclist-1.5/regrtest/._test3-restore.c
new file mode 100644
index 0000000..b97c3f5
--- /dev/null
+++ b/simclist-1.5/regrtest/._test3-restore.c
Binary files differ
diff --git a/simclist-1.5/regrtest/._test4-seeker.c b/simclist-1.5/regrtest/._test4-seeker.c
new file mode 100644
index 0000000..02a536f
--- /dev/null
+++ b/simclist-1.5/regrtest/._test4-seeker.c
Binary files differ
diff --git a/simclist-1.5/regrtest/printlist.c b/simclist-1.5/regrtest/printlist.c
new file mode 100644
index 0000000..bb4d0c7
--- /dev/null
+++ b/simclist-1.5/regrtest/printlist.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+
+void printlist(list_t *l) {
+ int i;
+
+ for (i = 0; i < list_size(l); i++) {
+ printf ("> %d\n", *(int *)list_get_at(l, i));
+ }
+}
+
diff --git a/simclist-1.5/regrtest/test1.c b/simclist-1.5/regrtest/test1.c
new file mode 100644
index 0000000..3b93056
--- /dev/null
+++ b/simclist-1.5/regrtest/test1.c
@@ -0,0 +1,120 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+#include "../simclist.h"
+
+#include "printlist.c"
+
+#define N 250
+
+#undef NDEBUG
+
+int main() {
+ list_t tl, tl2, tl3;
+ unsigned int pos;
+ int el, el2, i;
+ list_hash_t lhash1, lhash2;
+
+
+ list_init(&tl);
+ assert(list_size(&tl) == 0);
+
+ printf("1\n");
+
+ lhash1 = list_hash(&tl);
+
+ /* attributes */
+ list_attributes_copy(&tl, list_meter_int32_t, 1);
+ list_attributes_comparator(&tl, list_comparator_int32_t);
+ list_attributes_hash_computer(&tl, list_hashcomputer_int32_t);
+
+ /* insertion */
+ srandom(time(NULL));
+ printf("Inserting at: ");
+ for (i = 0; i < N; i++) {
+ pos = random() % (list_size(&tl) + 1);
+ printf("%u ", pos);
+ list_insert_at(&tl, &i, pos);
+ }
+ printf("\nDone.\n");
+ assert(list_size(&tl) == N);
+
+ /* min/max */
+ printf("2\n");
+ assert(*(int *)list_get_max(&tl) == N-1);
+ printf("3\n");
+ assert(*(int *)list_get_min(&tl) == 0);
+ printf("4\n");
+
+ /* incorrect deletion */
+ assert(list_insert_at(&tl, &el, N+1) < 0);
+ printf("5\n");
+ assert(list_delete_at(&tl, N) < 0);
+ printf("6\n");
+ assert(list_delete_range(&tl, 0, N+1) < 0);
+ printf("7\n");
+ assert(list_delete_range(&tl, N, N/2) < 0);
+
+ /* hashes */
+ printf("8\n");
+ lhash2 = list_hash(&tl);
+ assert(lhash2 != lhash1);
+
+ /* find and contains */
+ printf("9\n");
+ el = N-1;
+ assert(list_contains(&tl, &el));
+
+ /* sorting */
+ printf("10\n");
+ list_sort(&tl, 1);
+
+ /* iteration sessions */
+ el2 = el = -1;
+ list_iterator_start(&tl);
+ while (list_iterator_hasnext(&tl)) {
+ el2 = *(int *)list_iterator_next(&tl);
+ if (el > el2)
+ break;
+ el = el2;
+ }
+ list_iterator_stop(&tl);
+ assert(el2 == N-1);
+
+ /* legal deletion */
+ printf("11\n");
+ list_delete_range(&tl, 0, N/2);
+ assert(list_size(&tl) == (N-1)/2);
+ assert(*(int *)list_get_at(&tl, 0) == (N/2 +1));
+
+ /* concatenation, and hashes */
+ printf("12\n");
+ lhash1 = list_hash(&tl);
+ assert(lhash1 != lhash2);
+
+ printf("13\n");
+ list_init(&tl2); /* tl2 empty */
+ list_concat(&tl, &tl2, &tl3);
+ list_attributes_hash_computer(&tl3, list_hashcomputer_int32_t);
+ assert(list_hash(&tl) == list_hash(&tl3));
+
+ printf("14\n");
+ list_destroy(&tl3);
+ list_concat(&tl2, &tl, &tl3);
+ list_attributes_hash_computer(&tl3, list_hashcomputer_int32_t);
+ assert(list_hash(&tl) == list_hash(&tl3));
+
+ printf("15\n");
+ list_delete_range(&tl3, 1, list_size(&tl3)-2);
+ el = 123;
+ list_append(&tl3, &el);
+ assert(list_size(&tl3) == 3 && list_find(&tl3, &el) == (list_size(&tl3)-1));
+
+
+ list_destroy(&tl);
+
+ printf("==========\nAll tests passed.\n");
+ return 0;
+}
+
diff --git a/simclist-1.5/regrtest/test2.c b/simclist-1.5/regrtest/test2.c
new file mode 100644
index 0000000..a92c114
--- /dev/null
+++ b/simclist-1.5/regrtest/test2.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+#include "../simclist.h"
+
+#include "printlist.c"
+
+#define N 250
+
+int main() {
+ list_t l;
+ int i, j, newpos, els[N];
+
+ srandom(time(NULL));
+ list_init(&l);
+
+ list_attributes_copy(&l, list_meter_int32_t, 1);
+ list_attributes_comparator(&l, list_comparator_int32_t);
+
+ /* insert N zeros */
+ printf("Test 1: head insertions ... ");
+ fflush(stdout);
+ j = 0;
+ for (i = 0; i < N; i++) {
+ list_insert_at(&l, &j, 0);
+ assert((int)list_size(&l) == i+1);
+ }
+ //list_clear(&l);
+ printf("passed.\n");
+
+ /* generate an unsorted list of values from 0 to N */
+ printf("Test 2: random insertions and deletions ... ");
+ fflush(stdout);
+ els[0] = 0;
+ for (i = 1; i < N; i++) {
+ els[i] = i;
+ newpos = random() % (i + 1);
+ j = els[newpos];
+ els[newpos] = i;
+ els[i] = j;
+ }
+
+ for (i = 0; i < N; i++) {
+ list_insert_at(&l, & els[i], els[i]);
+ assert(*(int *)list_get_at(&l, els[i]) == els[i]);
+ assert(*(int *)list_get_at(&l, els[i]+1) == 0);
+ list_delete_range(&l, els[i]+1, els[i]+1);
+ }
+ printf("passed.\n");
+
+ printf("Test 3: positioning (The Revenge) ... ");
+ fflush(stdout);
+ for (i = 0; i < N; i++) {
+ assert(*(int *)list_get_at(&l, i) == i);
+ }
+ printf("passed.\n");
+
+
+ printf("Test 4: sorting ... ");
+ fflush(stdout);
+ assert(list_sort(&l, -1) == 0);
+ for (i = 0; i < N; i++) {
+ assert(*(int *)list_get_at(&l, i) == N-1-i);
+ }
+ printf("passed.\n");
+
+ list_destroy(&l);
+
+ printf("==========\nAll tests passed.\n");
+
+ return 0;
+}
+
diff --git a/simclist-1.5/regrtest/test3-dump.c b/simclist-1.5/regrtest/test3-dump.c
new file mode 100644
index 0000000..667b119
--- /dev/null
+++ b/simclist-1.5/regrtest/test3-dump.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "../simclist.h"
+
+#define N 123
+
+#define hton64(x) (\
+ htons(1) == 1 ? \
+ (uint64_t)x /* big endian */ \
+ : /* little endian */ \
+ ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \
+ (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \
+ )
+
+
+size_t meter(const void *el) {
+ return sizeof(unsigned long long int);
+}
+
+void *elserial(const void *el, uint32_t *len) {
+ unsigned long long *x;
+
+ *len = sizeof(unsigned long long);
+ x = malloc(*len);
+ *x = hton64(*(unsigned long long *)el);
+
+ return x;
+}
+
+int main() {
+ list_t l;
+ unsigned long long int data;
+
+ list_init(& l);
+ list_attributes_copy(&l, meter, 1);
+ list_attributes_serializer(&l, elserial);
+
+ for (data = 1; data < N; data++) {
+ list_append(& l, & data);
+ }
+ if (list_dump_file(&l, "mylistdump.simc") == 0 && errno != 0) {
+ printf("fuck off\n");
+ }
+
+ list_destroy(& l);
+
+ return 0;
+}
+
diff --git a/simclist-1.5/regrtest/test3-restore.c b/simclist-1.5/regrtest/test3-restore.c
new file mode 100644
index 0000000..6e143f6
--- /dev/null
+++ b/simclist-1.5/regrtest/test3-restore.c
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "../simclist.h"
+
+#define N 123
+
+#define hton64(x) (\
+ htons(1) == 1 ? \
+ (uint64_t)x /* big endian */ \
+ : /* little endian */ \
+ ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \
+ (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \
+ )
+
+
+void *elunserial(const void *el, uint32_t *len) {
+ unsigned long long *x;
+
+ *len = sizeof(unsigned long long);
+ x = malloc(*len);
+ *x = hton64(*(unsigned long long *)el);
+
+ return x;
+}
+
+int main() {
+ list_t l;
+ unsigned long long int data, val;
+ unsigned int mem;
+
+ list_init(& l);
+ list_attributes_unserializer(&l, elunserial);
+
+ mem = list_restore_file(&l, "mylistdump.simc");
+ if (mem == 0 && errno != 0) {
+ perror("open");
+ printf("fuck off\n");
+ } else {
+ printf("Restored successfully:\n");
+ printf("N els: %u\nmemread: %u\n", list_size(&l), mem);
+ for (data = 1; data < N; data++) {
+ val = *(unsigned long long *)list_get_at(&l, (unsigned int)data-1);
+ if (data != val) {
+ printf("Wrong data. Pos %llu, expected %llu, got %llu\n", data-1, data, val);
+ return 0;
+ }
+ printf("%lld ", val);
+ }
+ printf("\n");
+ }
+
+ list_destroy(& l);
+
+ return 0;
+}
+
diff --git a/simclist-1.5/regrtest/test4-seeker.c b/simclist-1.5/regrtest/test4-seeker.c
new file mode 100644
index 0000000..4b4b64a
--- /dev/null
+++ b/simclist-1.5/regrtest/test4-seeker.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h> /* for srandom() */
+#include "../simclist.h"
+
+#define N 100000
+#define LEN 12
+
+struct foo_s {
+ int a, b;
+ char c[LEN];
+};
+
+int seeker(const void *el, const void *indicator) {
+ if (((struct foo_s *)el)->a == *(int *)indicator)
+ return 1;
+ return 0;
+}
+
+size_t mymeter(const void *el) {
+ return (sizeof(struct foo_s));
+}
+
+int main() {
+ list_t l;
+ struct foo_s el;
+ int i, j;
+
+ list_init(& l);
+ list_attributes_seeker(&l, seeker);
+ list_attributes_copy(&l, mymeter, 1);
+
+ for (i = 0; i < N; i++) {
+ el.a = i;
+ el.b = 3*i;
+ snprintf(el.c, LEN, "%d-%d", el.a, el.b);
+ list_insert_at(& l, & el, i);
+ }
+
+ srandom(time(NULL));
+
+ for (i = 0; i < N/4; i++) {
+ j = random() % list_size(&l);
+ el = *(struct foo_s *)list_seek(&l, &j);
+ if (el.a != j) {
+ printf("KO: %d retrieved %d\n", j, el.a);
+ return 1;
+ }
+ }
+
+ list_destroy(& l);
+ return 0;
+}
diff --git a/simclist-1.5/simclist.c b/simclist-1.5/simclist.c
new file mode 100644
index 0000000..edae4bb
--- /dev/null
+++ b/simclist-1.5/simclist.c
@@ -0,0 +1,1483 @@
+/*
+ * Copyright (c) 2007,2008,2009,2010 Mij <mij@bitchx.it>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*
+ * SimCList library. See http://mij.oltrelinux.com/devel/simclist
+ */
+
+/* SimCList implementation, version 1.5 */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h> /* for setting errno */
+#include <sys/types.h>
+//#include <sys/uio.h> /* for READ_ERRCHECK() and write() */
+#include <fcntl.h> /* for open() etc */
+//#include <arpa/inet.h> /* for htons() */
+//#include <unistd.h>
+#include <time.h> /* for time() for random seed */
+//#include <sys/time.h> /* for gettimeofday() */
+//#include <sys/stat.h> /* for open()'s access modes S_IRUSR etc */
+#include <limits.h>
+#include <stdint.h>
+
+
+/* work around lack of inttypes.h support in broken Microsoft Visual Studio compilers */
+#if !defined(WIN32) || !defined(_MSC_VER)
+# include <inttypes.h> /* (u)int*_t */
+#else
+# include <basetsd.h>
+typedef UINT8 uint8_t;
+typedef UINT16 uint16_t;
+typedef ULONG32 uint32_t;
+typedef UINT64 uint64_t;
+typedef INT8 int8_t;
+typedef INT16 int16_t;
+typedef LONG32 int32_t;
+typedef INT64 int64_t;
+#endif
+
+
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+/* convert 64bit integers from host to network format */
+#define hton64(x) (\
+ htons(1) == 1 ? \
+ (uint64_t)x /* big endian */ \
+ : /* little endian */ \
+ ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \
+ (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+ (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+ (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
+ (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
+ (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+ (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+ (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \
+ )
+
+/* convert 64bit integers from network to host format */
+#define ntoh64(x) (hton64(x))
+#endif
+
+/* some OSes don't have EPROTO (eg OpenBSD) */
+#ifndef EPROTO
+#define EPROTO EIO
+#endif
+
+/* disable asserts */
+#ifndef SIMCLIST_DEBUG
+#define NDEBUG
+#endif
+
+#include <assert.h>
+
+#ifdef SIMCLIST_WITH_THREADS
+/* limit (approx) to the number of threads running
+ * for threaded operations. Only meant when
+ * SIMCLIST_WITH_THREADS is defined */
+#define SIMCLIST_MAXTHREADS 2
+#endif
+
+/*
+ * how many elems to keep as spare. During a deletion, an element
+ * can be saved in a "free-list", not free()d immediately. When
+ * latter insertions are performed, spare elems can be used instead
+ * of malloc()ing new elems.
+ *
+ * about this param, some values for appending
+ * 10 million elems into an empty list:
+ * (#, time[sec], gain[%], gain/no[%])
+ * 0 2,164 0,00 0,00 <-- feature disabled
+ * 1 1,815 34,9 34,9
+ * 2 1,446 71,8 35,9 <-- MAX gain/no
+ * 3 1,347 81,7 27,23
+ * 5 1,213 95,1 19,02
+ * 8 1,064 110,0 13,75
+ * 10 1,015 114,9 11,49 <-- MAX gain w/ likely sol
+ * 15 1,019 114,5 7,63
+ * 25 0,985 117,9 4,72
+ * 50 1,088 107,6 2,15
+ * 75 1,016 114,8 1,53
+ * 100 0,988 117,6 1,18
+ * 150 1,022 114,2 0,76
+ * 200 0,939 122,5 0,61 <-- MIN time
+ */
+#ifndef SIMCLIST_MAX_SPARE_ELEMS
+#define SIMCLIST_MAX_SPARE_ELEMS 5
+#endif
+
+
+#ifdef SIMCLIST_WITH_THREADS
+#include <pthread.h>
+#endif
+
+#include "simclist.h"
+
+
+/* minumum number of elements for sorting with quicksort instead of insertion */
+#define SIMCLIST_MINQUICKSORTELS 24
+
+
+/* list dump declarations */
+#define SIMCLIST_DUMPFORMAT_VERSION 1 /* (short integer) version of fileformat managed by _dump* and _restore* functions */
+
+#define SIMCLIST_DUMPFORMAT_HEADERLEN 30 /* length of the header */
+
+/* header for a list dump */
+struct list_dump_header_s {
+ uint16_t ver; /* version */
+ int64_t timestamp; /* dump timestamp */
+ int32_t rndterm; /* random value terminator -- terminates the data sequence */
+
+ uint32_t totlistlen; /* sum of every element' size, bytes */
+ uint32_t numels; /* number of elements */
+ uint32_t elemlen; /* bytes length of an element, for constant-size lists, <= 0 otherwise */
+ int32_t listhash; /* hash of the list at the time of dumping, or 0 if to be ignored */
+};
+
+
+
+/* deletes tmp from list, with care wrt its position (head, tail, middle) */
+static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos);
+
+/* set default values for initialized lists */
+static int list_attributes_setdefaults(list_t *restrict l);
+
+#ifndef NDEBUG
+/* check whether the list internal REPresentation is valid -- Costs O(n) */
+static int list_repOk(const list_t *restrict l);
+
+/* check whether the list attribute set is valid -- Costs O(1) */
+static int list_attrOk(const list_t *restrict l);
+#endif
+
+/* do not inline, this is recursive */
+static void list_sort_quicksort(list_t *restrict l, int versus,
+ unsigned int first, struct list_entry_s *fel,
+ unsigned int last, struct list_entry_s *lel);
+
+static inline void list_sort_selectionsort(list_t *restrict l, int versus,
+ unsigned int first, struct list_entry_s *fel,
+ unsigned int last, struct list_entry_s *lel);
+
+static void *list_get_minmax(const list_t *restrict l, int versus);
+
+static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart);
+
+/* write() decorated with error checking logic */
+#define WRITE_ERRCHECK(fd, msgbuf, msglen) do { \
+ if (write(fd, msgbuf, msglen) < 0) return -1; \
+ } while (0);
+/* READ_ERRCHECK() decorated with error checking logic */
+#define READ_ERRCHECK(fd, msgbuf, msglen) do { \
+ if (read(fd, msgbuf, msglen) != msglen) { \
+ /*errno = EPROTO;*/ \
+ return -1; \
+ } \
+ } while (0);
+
+/*
+ * Random Number Generator
+ *
+ * The user is expected to seed the RNG (ie call srand()) if
+ * SIMCLIST_SYSTEM_RNG is defined.
+ *
+ * Otherwise, a self-contained RNG based on LCG is used; see
+ * http://en.wikipedia.org/wiki/Linear_congruential_generator .
+ *
+ * Facts pro local RNG:
+ * 1. no need for the user to call srand() on his own
+ * 2. very fast, possibly faster than OS
+ * 3. avoid interference with user's RNG
+ *
+ * Facts pro system RNG:
+ * 1. may be more accurate (irrelevant for SimCList randno purposes)
+ * 2. why reinvent the wheel
+ *
+ * Default to local RNG for user's ease of use.
+ */
+
+#ifdef SIMCLIST_SYSTEM_RNG
+/* keep track whether we initialized already (non-0) or not (0) */
+static unsigned random_seed = 0;
+
+/* use local RNG */
+static inline void seed_random() {
+ if (random_seed == 0)
+ random_seed = (unsigned)getpid() ^ (unsigned)time(NULL);
+}
+
+static inline long get_random() {
+ random_seed = (1664525 * random_seed + 1013904223);
+ return random_seed;
+}
+
+#else
+/* use OS's random generator */
+# define seed_random()
+# define get_random() (rand())
+#endif
+
+
+/* list initialization */
+int list_init(list_t *restrict l) {
+ if (l == NULL) return -1;
+
+ seed_random();
+
+ l->numels = 0;
+
+ /* head/tail sentinels and mid pointer */
+ l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+ l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+ l->head_sentinel->next = l->tail_sentinel;
+ l->tail_sentinel->prev = l->head_sentinel;
+ l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
+ l->head_sentinel->data = l->tail_sentinel->data = NULL;
+
+ /* iteration attributes */
+ l->iter_active = 0;
+ l->iter_pos = 0;
+ l->iter_curentry = NULL;
+
+ /* free-list attributes */
+ l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
+ l->spareelsnum = 0;
+
+#ifdef SIMCLIST_WITH_THREADS
+ l->threadcount = 0;
+#endif
+
+ list_attributes_setdefaults(l);
+
+ assert(list_repOk(l));
+ assert(list_attrOk(l));
+
+ return 0;
+}
+
+void list_destroy(list_t *restrict l) {
+ unsigned int i;
+
+ list_clear(l);
+ for (i = 0; i < l->spareelsnum; i++) {
+ free(l->spareels[i]);
+ }
+ free(l->spareels);
+ free(l->head_sentinel);
+ free(l->tail_sentinel);
+}
+
+int list_attributes_setdefaults(list_t *restrict l) {
+ l->attrs.comparator = NULL;
+ l->attrs.seeker = NULL;
+
+ /* also free() element data when removing and element from the list */
+ l->attrs.meter = NULL;
+ l->attrs.copy_data = 0;
+
+ l->attrs.hasher = NULL;
+
+ /* serializer/unserializer */
+ l->attrs.serializer = NULL;
+ l->attrs.unserializer = NULL;
+
+ assert(list_attrOk(l));
+
+ return 0;
+}
+
+/* setting list properties */
+int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun) {
+ if (l == NULL) return -1;
+
+ l->attrs.comparator = comparator_fun;
+
+ assert(list_attrOk(l));
+
+ return 0;
+}
+
+int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun) {
+ if (l == NULL) return -1;
+
+ l->attrs.seeker = seeker_fun;
+ assert(list_attrOk(l));
+
+ return 0;
+}
+
+int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data) {
+ if (l == NULL || (metric_fun == NULL && copy_data != 0)) return -1;
+
+ l->attrs.meter = metric_fun;
+ l->attrs.copy_data = copy_data;
+
+ assert(list_attrOk(l));
+
+ return 0;
+}
+
+int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun) {
+ if (l == NULL) return -1;
+
+ l->attrs.hasher = hash_computer_fun;
+ assert(list_attrOk(l));
+ return 0;
+}
+
+int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun) {
+ if (l == NULL) return -1;
+
+ l->attrs.serializer = serializer_fun;
+ assert(list_attrOk(l));
+ return 0;
+}
+
+int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun) {
+ if (l == NULL) return -1;
+
+ l->attrs.unserializer = unserializer_fun;
+ assert(list_attrOk(l));
+ return 0;
+}
+
+int list_append(list_t *restrict l, const void *data) {
+ return list_insert_at(l, data, l->numels);
+}
+
+int list_prepend(list_t *restrict l, const void *data) {
+ return list_insert_at(l, data, 0);
+}
+
+void *list_fetch(list_t *restrict l) {
+ return list_extract_at(l, 0);
+}
+
+void *list_get_at(const list_t *restrict l, unsigned int pos) {
+ struct list_entry_s *tmp;
+
+ tmp = list_findpos(l, pos);
+
+ return (tmp != NULL ? tmp->data : NULL);
+}
+
+void *list_get_max(const list_t *restrict l) {
+ return list_get_minmax(l, +1);
+}
+
+void *list_get_min(const list_t *restrict l) {
+ return list_get_minmax(l, -1);
+}
+
+/* REQUIRES {list->numels >= 1}
+ * return the min (versus < 0) or max value (v > 0) in l */
+static void *list_get_minmax(const list_t *restrict l, int versus) {
+ void *curminmax;
+ struct list_entry_s *s;
+
+ if (l->attrs.comparator == NULL || l->numels == 0)
+ return NULL;
+
+ curminmax = l->head_sentinel->next->data;
+ for (s = l->head_sentinel->next->next; s != l->tail_sentinel; s = s->next) {
+ if (l->attrs.comparator(curminmax, s->data) * versus > 0)
+ curminmax = s->data;
+ }
+
+ return curminmax;
+}
+
+/* set tmp to point to element at index posstart in l */
+static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) {
+ struct list_entry_s *ptr;
+ float x;
+ int i;
+
+ /* accept 1 slot overflow for fetching head and tail sentinels */
+ if (posstart < -1 || posstart > (int)l->numels) return NULL;
+
+ x = (float)(posstart+1) / l->numels;
+ if (x <= 0.25) {
+ /* first quarter: get to posstart from head */
+ for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++);
+ } else if (x < 0.5) {
+ /* second quarter: get to posstart from mid */
+ for (i = (l->numels-1)/2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--);
+ } else if (x <= 0.75) {
+ /* third quarter: get to posstart from mid */
+ for (i = (l->numels-1)/2, ptr = l->mid; i < posstart; ptr = ptr->next, i++);
+ } else {
+ /* fourth quarter: get to posstart from tail */
+ for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--);
+ }
+
+ return ptr;
+}
+
+void *list_extract_at(list_t *restrict l, unsigned int pos) {
+ struct list_entry_s *tmp;
+ void *data;
+
+ if (l->iter_active || pos >= l->numels) return NULL;
+
+ tmp = list_findpos(l, pos);
+ data = tmp->data;
+
+ tmp->data = NULL; /* save data from list_drop_elem() free() */
+ list_drop_elem(l, tmp, pos);
+ l->numels--;
+
+ assert(list_repOk(l));
+
+ return data;
+}
+
+int list_insert_at(list_t *restrict l, const void *data, unsigned int pos) {
+ struct list_entry_s *lent, *succ, *prec;
+
+ if (l->iter_active || pos > l->numels) return -1;
+
+ /* this code optimizes malloc() with a free-list */
+ if (l->spareelsnum > 0) {
+ lent = l->spareels[l->spareelsnum-1];
+ l->spareelsnum--;
+ } else {
+ lent = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+ if (lent == NULL)
+ return -1;
+ }
+
+ if (l->attrs.copy_data) {
+ /* make room for user' data (has to be copied) */
+ size_t datalen = l->attrs.meter(data);
+ lent->data = (struct list_entry_s *)malloc(datalen);
+ memcpy(lent->data, data, datalen);
+ } else {
+ lent->data = (void*)data;
+ }
+
+ /* actually append element */
+ prec = list_findpos(l, pos-1);
+ succ = prec->next;
+
+ prec->next = lent;
+ lent->prev = prec;
+ lent->next = succ;
+ succ->prev = lent;
+
+ l->numels++;
+
+ /* fix mid pointer */
+ if (l->numels == 1) { /* first element, set pointer */
+ l->mid = lent;
+ } else if (l->numels % 2) { /* now odd */
+ if (pos >= (l->numels-1)/2) l->mid = l->mid->next;
+ } else { /* now even */
+ if (pos <= (l->numels-1)/2) l->mid = l->mid->prev;
+ }
+
+ assert(list_repOk(l));
+
+ return 1;
+}
+
+int list_delete(list_t *restrict l, const void *data) {
+ int pos, r;
+
+ pos = list_locate(l, data);
+ if (pos < 0)
+ return -1;
+
+ r = list_delete_at(l, pos);
+ if (r < 0)
+ return -1;
+
+ assert(list_repOk(l));
+
+ return 0;
+}
+
+int list_delete_at(list_t *restrict l, unsigned int pos) {
+ struct list_entry_s *delendo;
+
+
+ if (l->iter_active || pos >= l->numels) return -1;
+
+ delendo = list_findpos(l, pos);
+
+ list_drop_elem(l, delendo, pos);
+
+ l->numels--;
+
+
+ assert(list_repOk(l));
+
+ return 0;
+}
+
+int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend) {
+ struct list_entry_s *lastvalid, *tmp, *tmp2;
+ unsigned int i;
+ int movedx;
+ unsigned int numdel, midposafter;
+
+ if (l->iter_active || posend < posstart || posend >= l->numels) return -1;
+
+ tmp = list_findpos(l, posstart); /* first el to be deleted */
+ lastvalid = tmp->prev; /* last valid element */
+
+ numdel = posend - posstart + 1;
+ midposafter = (l->numels-1-numdel)/2;
+
+ midposafter = midposafter < posstart ? midposafter : midposafter+numdel;
+ movedx = midposafter - (l->numels-1)/2;
+
+ if (movedx > 0) { /* move right */
+ for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->next, i++);
+ } else { /* move left */
+ movedx = -movedx;
+ for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->prev, i++);
+ }
+
+ assert(posstart == 0 || lastvalid != l->head_sentinel);
+ i = posstart;
+ if (l->attrs.copy_data) {
+ /* also free element data */
+ for (; i <= posend; i++) {
+ tmp2 = tmp;
+ tmp = tmp->next;
+ if (tmp2->data != NULL) free(tmp2->data);
+ if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
+ l->spareels[l->spareelsnum++] = tmp2;
+ } else {
+ free(tmp2);
+ }
+ }
+ } else {
+ /* only free containers */
+ for (; i <= posend; i++) {
+ tmp2 = tmp;
+ tmp = tmp->next;
+ if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
+ l->spareels[l->spareelsnum++] = tmp2;
+ } else {
+ free(tmp2);
+ }
+ }
+ }
+ assert(i == posend+1 && (posend != l->numels || tmp == l->tail_sentinel));
+
+ lastvalid->next = tmp;
+ tmp->prev = lastvalid;
+
+ l->numels -= posend - posstart + 1;
+
+ assert(list_repOk(l));
+
+ return 0;
+}
+
+int list_clear(list_t *restrict l) {
+ struct list_entry_s *s;
+
+ if (l->iter_active) return -1;
+
+ if (l->attrs.copy_data) { /* also free user data */
+ /* spare a loop conditional with two loops: spareing elems and freeing elems */
+ for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) {
+ /* move elements as spares as long as there is room */
+ if (s->data != NULL) free(s->data);
+ l->spareels[l->spareelsnum++] = s;
+ }
+ while (s != l->tail_sentinel) {
+ /* free the remaining elems */
+ if (s->data != NULL) free(s->data);
+ s = s->next;
+ free(s->prev);
+ }
+ l->head_sentinel->next = l->tail_sentinel;
+ l->tail_sentinel->prev = l->head_sentinel;
+ } else { /* only free element containers */
+ /* spare a loop conditional with two loops: spareing elems and freeing elems */
+ for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) {
+ /* move elements as spares as long as there is room */
+ l->spareels[l->spareelsnum++] = s;
+ }
+ while (s != l->tail_sentinel) {
+ /* free the remaining elems */
+ s = s->next;
+ free(s->prev);
+ }
+ l->head_sentinel->next = l->tail_sentinel;
+ l->tail_sentinel->prev = l->head_sentinel;
+ }
+ l->numels = 0;
+ l->mid = NULL;
+
+ assert(list_repOk(l));
+
+ return 0;
+}
+
+unsigned int list_size(const list_t *restrict l) {
+ return l->numels;
+}
+
+int list_empty(const list_t *restrict l) {
+ return (l->numels == 0);
+}
+
+int list_locate(const list_t *restrict l, const void *data) {
+ struct list_entry_s *el;
+ int pos = 0;
+
+ if (l->attrs.comparator != NULL) {
+ /* use comparator */
+ for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) {
+ if (l->attrs.comparator(data, el->data) == 0) break;
+ }
+ } else {
+ /* compare references */
+ for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) {
+ if (el->data == data) break;
+ }
+ }
+ if (el == l->tail_sentinel) return -1;
+
+ return pos;
+}
+
+void *list_seek(list_t *restrict l, const void *indicator) {
+ const struct list_entry_s *iter;
+
+ if (l->attrs.seeker == NULL) return NULL;
+
+ for (iter = l->head_sentinel->next; iter != l->tail_sentinel; iter = iter->next) {
+ if (l->attrs.seeker(iter->data, indicator) != 0) return iter->data;
+ }
+
+ return NULL;
+}
+
+int list_contains(const list_t *restrict l, const void *data) {
+ return (list_locate(l, data) >= 0);
+}
+
+int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest) {
+ struct list_entry_s *el, *srcel;
+ unsigned int cnt;
+ int err;
+
+
+ if (l1 == NULL || l2 == NULL || dest == NULL || l1 == dest || l2 == dest)
+ return -1;
+
+ list_init(dest);
+
+ dest->numels = l1->numels + l2->numels;
+ if (dest->numels == 0)
+ return 0;
+
+ /* copy list1 */
+ srcel = l1->head_sentinel->next;
+ el = dest->head_sentinel;
+ while (srcel != l1->tail_sentinel) {
+ el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+ el->next->prev = el;
+ el = el->next;
+ el->data = srcel->data;
+ srcel = srcel->next;
+ }
+ dest->mid = el; /* approximate position (adjust later) */
+ /* copy list 2 */
+ srcel = l2->head_sentinel->next;
+ while (srcel != l2->tail_sentinel) {
+ el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+ el->next->prev = el;
+ el = el->next;
+ el->data = srcel->data;
+ srcel = srcel->next;
+ }
+ el->next = dest->tail_sentinel;
+ dest->tail_sentinel->prev = el;
+
+ /* fix mid pointer */
+ err = l2->numels - l1->numels;
+ if ((err+1)/2 > 0) { /* correct pos RIGHT (err-1)/2 moves */
+ err = (err+1)/2;
+ for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->next;
+ } else if (err/2 < 0) { /* correct pos LEFT (err/2)-1 moves */
+ err = -err/2;
+ for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->prev;
+ }
+
+ assert(!(list_repOk(l1) && list_repOk(l2)) || list_repOk(dest));
+
+ return 0;
+}
+
+int list_sort(list_t *restrict l, int versus) {
+ if (l->iter_active || l->attrs.comparator == NULL) /* cannot modify list in the middle of an iteration */
+ return -1;
+
+ if (l->numels <= 1)
+ return 0;
+ list_sort_quicksort(l, versus, 0, l->head_sentinel->next, l->numels-1, l->tail_sentinel->prev);
+ assert(list_repOk(l));
+ return 0;
+}
+
+#ifdef SIMCLIST_WITH_THREADS
+struct list_sort_wrappedparams {
+ list_t *restrict l;
+ int versus;
+ unsigned int first, last;
+ struct list_entry_s *fel, *lel;
+};
+
+static void *list_sort_quicksort_threadwrapper(void *wrapped_params) {
+ struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)wrapped_params;
+ list_sort_quicksort(wp->l, wp->versus, wp->first, wp->fel, wp->last, wp->lel);
+ free(wp);
+ pthread_exit(NULL);
+ return NULL;
+}
+#endif
+
+static inline void list_sort_selectionsort(list_t *restrict l, int versus,
+ unsigned int first, struct list_entry_s *fel,
+ unsigned int last, struct list_entry_s *lel) {
+ struct list_entry_s *cursor, *toswap, *firstunsorted;
+ void *tmpdata;
+
+ if (last <= first) /* <= 1-element lists are always sorted */
+ return;
+
+ for (firstunsorted = fel; firstunsorted != lel; firstunsorted = firstunsorted->next) {
+ /* find min or max in the remainder of the list */
+ for (toswap = firstunsorted, cursor = firstunsorted->next; cursor != lel->next; cursor = cursor->next)
+ if (l->attrs.comparator(toswap->data, cursor->data) * -versus > 0) toswap = cursor;
+ if (toswap != firstunsorted) { /* swap firstunsorted with toswap */
+ tmpdata = firstunsorted->data;
+ firstunsorted->data = toswap->data;
+ toswap->data = tmpdata;
+ }
+ }
+}
+
+static void list_sort_quicksort(list_t *restrict l, int versus,
+ unsigned int first, struct list_entry_s *fel,
+ unsigned int last, struct list_entry_s *lel) {
+ unsigned int pivotid;
+ unsigned int i;
+ register struct list_entry_s *pivot;
+ struct list_entry_s *left, *right;
+ void *tmpdata;
+#ifdef SIMCLIST_WITH_THREADS
+ pthread_t tid;
+ int traised;
+#endif
+
+
+ if (last <= first) /* <= 1-element lists are always sorted */
+ return;
+
+ if (last - first+1 <= SIMCLIST_MINQUICKSORTELS) {
+ list_sort_selectionsort(l, versus, first, fel, last, lel);
+ return;
+ }
+
+ /* base of iteration: one element list */
+ if (! (last > first)) return;
+
+ pivotid = (get_random() % (last - first + 1));
+ /* pivotid = (last - first + 1) / 2; */
+
+ /* find pivot */
+ if (pivotid < (last - first + 1)/2) {
+ for (i = 0, pivot = fel; i < pivotid; pivot = pivot->next, i++);
+ } else {
+ for (i = last - first, pivot = lel; i > pivotid; pivot = pivot->prev, i--);
+ }
+
+ /* smaller PIVOT bigger */
+ left = fel;
+ right = lel;
+ /* iterate --- left ---> PIV <--- right --- */
+ while (left != pivot && right != pivot) {
+ for (; left != pivot && (l->attrs.comparator(left->data, pivot->data) * -versus <= 0); left = left->next);
+ /* left points to a smaller element, or to pivot */
+ for (; right != pivot && (l->attrs.comparator(right->data, pivot->data) * -versus >= 0); right = right->prev);
+ /* right points to a bigger element, or to pivot */
+ if (left != pivot && right != pivot) {
+ /* swap, then move iterators */
+ tmpdata = left->data;
+ left->data = right->data;
+ right->data = tmpdata;
+
+ left = left->next;
+ right = right->prev;
+ }
+ }
+
+ /* now either left points to pivot (end run), or right */
+ if (right == pivot) { /* left part longer */
+ while (left != pivot) {
+ if (l->attrs.comparator(left->data, pivot->data) * -versus > 0) {
+ tmpdata = left->data;
+ left->data = pivot->prev->data;
+ pivot->prev->data = pivot->data;
+ pivot->data = tmpdata;
+ pivot = pivot->prev;
+ pivotid--;
+ if (pivot == left) break;
+ } else {
+ left = left->next;
+ }
+ }
+ } else { /* right part longer */
+ while (right != pivot) {
+ if (l->attrs.comparator(right->data, pivot->data) * -versus < 0) {
+ /* move current right before pivot */
+ tmpdata = right->data;
+ right->data = pivot->next->data;
+ pivot->next->data = pivot->data;
+ pivot->data = tmpdata;
+ pivot = pivot->next;
+ pivotid++;
+ if (pivot == right) break;
+ } else {
+ right = right->prev;
+ }
+ }
+ }
+
+ /* sort sublists A and B : |---A---| pivot |---B---| */
+
+#ifdef SIMCLIST_WITH_THREADS
+ traised = 0;
+ if (pivotid > 0) {
+ /* prepare wrapped args, then start thread */
+ if (l->threadcount < SIMCLIST_MAXTHREADS-1) {
+ struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)malloc(sizeof(struct list_sort_wrappedparams));
+ l->threadcount++;
+ traised = 1;
+ wp->l = l;
+ wp->versus = versus;
+ wp->first = first;
+ wp->fel = fel;
+ wp->last = first+pivotid-1;
+ wp->lel = pivot->prev;
+ if (pthread_create(&tid, NULL, list_sort_quicksort_threadwrapper, wp) != 0) {
+ free(wp);
+ traised = 0;
+ list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
+ }
+ } else {
+ list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
+ }
+ }
+ if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel);
+ if (traised) {
+ pthread_join(tid, (void **)NULL);
+ l->threadcount--;
+ }
+#else
+ if (pivotid > 0) list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
+ if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel);
+#endif
+}
+
+int list_iterator_start(list_t *restrict l) {
+ if (l->iter_active) return 0;
+ l->iter_pos = 0;
+ l->iter_active = 1;
+ l->iter_curentry = l->head_sentinel->next;
+ return 1;
+}
+
+void *list_iterator_next(list_t *restrict l) {
+ void *toret;
+
+ if (! l->iter_active) return NULL;
+
+ toret = l->iter_curentry->data;
+ l->iter_curentry = l->iter_curentry->next;
+ l->iter_pos++;
+
+ return toret;
+}
+
+int list_iterator_hasnext(const list_t *restrict l) {
+ if (! l->iter_active) return 0;
+ return (l->iter_pos < l->numels);
+}
+
+int list_iterator_stop(list_t *restrict l) {
+ if (! l->iter_active) return 0;
+ l->iter_pos = 0;
+ l->iter_active = 0;
+ return 1;
+}
+
+int list_hash(const list_t *restrict l, list_hash_t *restrict hash) {
+ struct list_entry_s *x;
+ list_hash_t tmphash;
+
+ assert(hash != NULL);
+
+ tmphash = l->numels * 2 + 100;
+ if (l->attrs.hasher == NULL) {
+#ifdef SIMCLIST_ALLOW_LOCATIONBASED_HASHES
+ /* ENABLE WITH CARE !! */
+#warning "Memlocation-based hash is consistent only for testing modification in the same program run."
+ int i;
+
+ /* only use element references */
+ for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+ for (i = 0; i < sizeof(x->data); i++) {
+ tmphash += (tmphash ^ (uintptr_t)x->data);
+ }
+ tmphash += tmphash % l->numels;
+ }
+#else
+ return -1;
+#endif
+ } else {
+ /* hash each element with the user-given function */
+ for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+ tmphash += tmphash ^ l->attrs.hasher(x->data);
+ tmphash +=* hash % l->numels;
+ }
+ }
+
+ *hash = tmphash;
+
+ return 0;
+}
+
+#define SIMCLIST_NO_DUMPRESTORE
+#ifndef SIMCLIST_NO_DUMPRESTORE
+int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info) {
+ int32_t terminator_head, terminator_tail;
+ uint32_t elemlen;
+ off_t hop;
+
+
+ /* version */
+ READ_ERRCHECK(fd, & info->version, sizeof(info->version));
+ info->version = ntohs(info->version);
+ if (info->version > SIMCLIST_DUMPFORMAT_VERSION) {
+ errno = EILSEQ;
+ return -1;
+ }
+
+ /* timestamp */
+ READ_ERRCHECK(fd, & info->timestamp, sizeof(info->timestamp));
+ info->timestamp = hton64(info->timestamp);
+
+ /* list terminator (to check thereafter) */
+ READ_ERRCHECK(fd, & terminator_head, sizeof(terminator_head));
+ terminator_head = ntohl(terminator_head);
+
+ /* list size */
+ READ_ERRCHECK(fd, & info->list_size, sizeof(info->list_size));
+ info->list_size = ntohl(info->list_size);
+
+ /* number of elements */
+ READ_ERRCHECK(fd, & info->list_numels, sizeof(info->list_numels));
+ info->list_numels = ntohl(info->list_numels);
+
+ /* length of each element (for checking for consistency) */
+ READ_ERRCHECK(fd, & elemlen, sizeof(elemlen));
+ elemlen = ntohl(elemlen);
+
+ /* list hash */
+ READ_ERRCHECK(fd, & info->list_hash, sizeof(info->list_hash));
+ info->list_hash = ntohl(info->list_hash);
+
+ /* check consistency */
+ if (elemlen > 0) {
+ /* constant length, hop by size only */
+ hop = info->list_size;
+ } else {
+ /* non-constant length, hop by size + all element length blocks */
+ hop = info->list_size + elemlen*info->list_numels;
+ }
+ if (lseek(fd, hop, SEEK_CUR) == -1) {
+ return -1;
+ }
+
+ /* read the trailing value and compare with terminator_head */
+ READ_ERRCHECK(fd, & terminator_tail, sizeof(terminator_tail));
+ terminator_tail = ntohl(terminator_tail);
+
+ if (terminator_head == terminator_tail)
+ info->consistent = 1;
+ else
+ info->consistent = 0;
+
+ return 0;
+}
+
+int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info) {
+ int fd, ret;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd < 0) return -1;
+
+ ret = list_dump_getinfo_filedescriptor(fd, info);
+ close(fd);
+
+ return ret;
+}
+
+int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len) {
+ struct list_entry_s *x;
+ void *ser_buf;
+ uint32_t bufsize;
+ struct timeval timeofday;
+ struct list_dump_header_s header;
+
+ if (l->attrs.meter == NULL && l->attrs.serializer == NULL) {
+ errno = ENOTTY;
+ return -1;
+ }
+
+ /**** DUMP FORMAT ****
+
+ [ ver timestamp | totlen numels elemlen hash | DATA ]
+
+ where DATA can be:
+ @ for constant-size list (element size is constant; elemlen > 0)
+ [ elem elem ... elem ]
+ @ for other lists (element size dictated by element_meter each time; elemlen <= 0)
+ [ size elem size elem ... size elem ]
+
+ all integers are encoded in NETWORK BYTE FORMAT
+ *****/
+
+
+ /* prepare HEADER */
+ /* version */
+ header.ver = htons( SIMCLIST_DUMPFORMAT_VERSION );
+
+ /* timestamp */
+ gettimeofday(&timeofday, NULL);
+ header.timestamp = (int64_t)timeofday.tv_sec * 1000000 + (int64_t)timeofday.tv_usec;
+ header.timestamp = hton64(header.timestamp);
+
+ header.rndterm = htonl((int32_t)get_random());
+
+ /* total list size is postprocessed afterwards */
+
+ /* number of elements */
+ header.numels = htonl(l->numels);
+
+ /* include an hash, if possible */
+ if (l->attrs.hasher != NULL) {
+ if (htonl(list_hash(l, & header.listhash)) != 0) {
+ /* could not compute list hash! */
+ return -1;
+ }
+ } else {
+ header.listhash = htonl(0);
+ }
+
+ header.totlistlen = header.elemlen = 0;
+
+ /* leave room for the header at the beginning of the file */
+ if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) {
+ /* errno set by lseek() */
+ return -1;
+ }
+
+ /* write CONTENT */
+ if (l->numels > 0) {
+ /* SPECULATE that the list has constant element size */
+
+ if (l->attrs.serializer != NULL) { /* user user-specified serializer */
+ /* get preliminary length of serialized element in header.elemlen */
+ ser_buf = l->attrs.serializer(l->head_sentinel->next->data, & header.elemlen);
+ free(ser_buf);
+ /* request custom serialization of each element */
+ for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+ ser_buf = l->attrs.serializer(x->data, &bufsize);
+ header.totlistlen += bufsize;
+ if (header.elemlen != 0) { /* continue on speculation */
+ if (header.elemlen != bufsize) {
+ free(ser_buf);
+ /* constant element length speculation broken! */
+ header.elemlen = 0;
+ header.totlistlen = 0;
+ x = l->head_sentinel;
+ if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) {
+ /* errno set by lseek() */
+ return -1;
+ }
+ /* restart from the beginning */
+ continue;
+ }
+ /* speculation confirmed */
+ WRITE_ERRCHECK(fd, ser_buf, bufsize);
+ } else { /* speculation found broken */
+ WRITE_ERRCHECK(fd, & bufsize, sizeof(size_t));
+ WRITE_ERRCHECK(fd, ser_buf, bufsize);
+ }
+ free(ser_buf);
+ }
+ } else if (l->attrs.meter != NULL) {
+ header.elemlen = (uint32_t)l->attrs.meter(l->head_sentinel->next->data);
+
+ /* serialize the element straight from its data */
+ for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+ bufsize = l->attrs.meter(x->data);
+ header.totlistlen += bufsize;
+ if (header.elemlen != 0) {
+ if (header.elemlen != bufsize) {
+ /* constant element length speculation broken! */
+ header.elemlen = 0;
+ header.totlistlen = 0;
+ x = l->head_sentinel;
+ /* restart from the beginning */
+ continue;
+ }
+ WRITE_ERRCHECK(fd, x->data, bufsize);
+ } else {
+ WRITE_ERRCHECK(fd, &bufsize, sizeof(size_t));
+ WRITE_ERRCHECK(fd, x->data, bufsize);
+ }
+ }
+ }
+ /* adjust endianness */
+ header.elemlen = htonl(header.elemlen);
+ header.totlistlen = htonl(header.totlistlen);
+ }
+
+ /* write random terminator */
+ WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* list terminator */
+
+
+ /* write header */
+ lseek(fd, 0, SEEK_SET);
+
+ WRITE_ERRCHECK(fd, & header.ver, sizeof(header.ver)); /* version */
+ WRITE_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp)); /* timestamp */
+ WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* random terminator */
+
+ WRITE_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen)); /* total length of elements */
+ WRITE_ERRCHECK(fd, & header.numels, sizeof(header.numels)); /* number of elements */
+ WRITE_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen)); /* size of each element, or 0 for independent */
+ WRITE_ERRCHECK(fd, & header.listhash, sizeof(header.listhash)); /* list hash, or 0 for "ignore" */
+
+
+ /* possibly store total written length in "len" */
+ if (len != NULL) {
+ *len = sizeof(header) + ntohl(header.totlistlen);
+ }
+
+ return 0;
+}
+
+int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len) {
+ struct list_dump_header_s header;
+ unsigned long cnt;
+ void *buf;
+ uint32_t elsize, totreadlen, totmemorylen;
+
+ memset(& header, 0, sizeof(header));
+
+ /* read header */
+
+ /* version */
+ READ_ERRCHECK(fd, &header.ver, sizeof(header.ver));
+ header.ver = ntohs(header.ver);
+ if (header.ver != SIMCLIST_DUMPFORMAT_VERSION) {
+ errno = EILSEQ;
+ return -1;
+ }
+
+ /* timestamp */
+ READ_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp));
+
+ /* list terminator */
+ READ_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm));
+
+ header.rndterm = ntohl(header.rndterm);
+
+ /* total list size */
+ READ_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen));
+ header.totlistlen = ntohl(header.totlistlen);
+
+ /* number of elements */
+ READ_ERRCHECK(fd, & header.numels, sizeof(header.numels));
+ header.numels = ntohl(header.numels);
+
+ /* length of every element, or '0' = variable */
+ READ_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen));
+ header.elemlen = ntohl(header.elemlen);
+
+ /* list hash, or 0 = 'ignore' */
+ READ_ERRCHECK(fd, & header.listhash, sizeof(header.listhash));
+ header.listhash = ntohl(header.listhash);
+
+
+ /* read content */
+ totreadlen = totmemorylen = 0;
+ if (header.elemlen > 0) {
+ /* elements have constant size = header.elemlen */
+ if (l->attrs.unserializer != NULL) {
+ /* use unserializer */
+ buf = malloc(header.elemlen);
+ for (cnt = 0; cnt < header.numels; cnt++) {
+ READ_ERRCHECK(fd, buf, header.elemlen);
+ list_append(l, l->attrs.unserializer(buf, & elsize));
+ totmemorylen += elsize;
+ }
+ } else {
+ /* copy verbatim into memory */
+ for (cnt = 0; cnt < header.numels; cnt++) {
+ buf = malloc(header.elemlen);
+ READ_ERRCHECK(fd, buf, header.elemlen);
+ list_append(l, buf);
+ }
+ totmemorylen = header.numels * header.elemlen;
+ }
+ totreadlen = header.numels * header.elemlen;
+ } else {
+ /* elements have variable size. Each element is preceded by its size */
+ if (l->attrs.unserializer != NULL) {
+ /* use unserializer */
+ for (cnt = 0; cnt < header.numels; cnt++) {
+ READ_ERRCHECK(fd, & elsize, sizeof(elsize));
+ buf = malloc((size_t)elsize);
+ READ_ERRCHECK(fd, buf, elsize);
+ totreadlen += elsize;
+ list_append(l, l->attrs.unserializer(buf, & elsize));
+ totmemorylen += elsize;
+ }
+ } else {
+ /* copy verbatim into memory */
+ for (cnt = 0; cnt < header.numels; cnt++) {
+ READ_ERRCHECK(fd, & elsize, sizeof(elsize));
+ buf = malloc(elsize);
+ READ_ERRCHECK(fd, buf, elsize);
+ totreadlen += elsize;
+ list_append(l, buf);
+ }
+ totmemorylen = totreadlen;
+ }
+ }
+
+ READ_ERRCHECK(fd, &elsize, sizeof(elsize)); /* read list terminator */
+ elsize = ntohl(elsize);
+
+ /* possibly verify the list consistency */
+ /* wrt hash */
+ /* don't do that
+ if (header.listhash != 0 && header.listhash != list_hash(l)) {
+ errno = ECANCELED;
+ return -1;
+ }
+ */
+
+ /* wrt header */
+ if (totreadlen != header.totlistlen && (int32_t)elsize == header.rndterm) {
+ errno = EPROTO;
+ return -1;
+ }
+
+ /* wrt file */
+ if (lseek(fd, 0, SEEK_CUR) != lseek(fd, 0, SEEK_END)) {
+ errno = EPROTO;
+ return -1;
+ }
+
+ if (len != NULL) {
+ *len = totmemorylen;
+ }
+
+ return 0;
+}
+
+int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len) {
+ int fd;
+ size_t sizetoret;
+
+ fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0) return -1;
+
+ sizetoret = list_dump_filedescriptor(l, fd, len);
+ close(fd);
+
+ return sizetoret;
+}
+
+int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *restrict len) {
+ int fd;
+ size_t totdata;
+
+ fd = open(filename, O_RDONLY, 0);
+ if (fd < 0) return -1;
+
+ totdata = list_restore_filedescriptor(l, fd, len);
+ close(fd);
+
+ return totdata;
+}
+#endif /* ifndef SIMCLIST_NO_DUMPRESTORE */
+
+
+static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos) {
+ if (tmp == NULL) return -1;
+
+ /* fix mid pointer. This is wrt the PRE situation */
+ if (l->numels % 2) { /* now odd */
+ /* sort out the base case by hand */
+ if (l->numels == 1) l->mid = NULL;
+ else if (pos >= l->numels/2) l->mid = l->mid->prev;
+ } else { /* now even */
+ if (pos < l->numels/2) l->mid = l->mid->next;
+ }
+
+ tmp->prev->next = tmp->next;
+ tmp->next->prev = tmp->prev;
+
+ /* free what's to be freed */
+ if (l->attrs.copy_data && tmp->data != NULL)
+ free(tmp->data);
+
+ if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
+ l->spareels[l->spareelsnum++] = tmp;
+ } else {
+ free(tmp);
+ }
+
+ return 0;
+}
+
+/* ready-made comparators and meters */
+#define SIMCLIST_NUMBER_COMPARATOR(type) int list_comparator_##type(const void *a, const void *b) { return( *(type *)a < *(type *)b) - (*(type *)a > *(type *)b); }
+
+SIMCLIST_NUMBER_COMPARATOR(int8_t)
+SIMCLIST_NUMBER_COMPARATOR(int16_t)
+SIMCLIST_NUMBER_COMPARATOR(int32_t)
+SIMCLIST_NUMBER_COMPARATOR(int64_t)
+
+SIMCLIST_NUMBER_COMPARATOR(uint8_t)
+SIMCLIST_NUMBER_COMPARATOR(uint16_t)
+SIMCLIST_NUMBER_COMPARATOR(uint32_t)
+SIMCLIST_NUMBER_COMPARATOR(uint64_t)
+
+SIMCLIST_NUMBER_COMPARATOR(float)
+SIMCLIST_NUMBER_COMPARATOR(double)
+
+int list_comparator_string(const void *a, const void *b) { return strcmp((const char *)b, (const char *)a); }
+
+/* ready-made metric functions */
+#define SIMCLIST_METER(type) size_t list_meter_##type(const void *el) { if (el) { /* kill compiler whinge */ } return sizeof(type); }
+
+SIMCLIST_METER(int8_t)
+SIMCLIST_METER(int16_t)
+SIMCLIST_METER(int32_t)
+SIMCLIST_METER(int64_t)
+
+SIMCLIST_METER(uint8_t)
+SIMCLIST_METER(uint16_t)
+SIMCLIST_METER(uint32_t)
+SIMCLIST_METER(uint64_t)
+
+SIMCLIST_METER(float)
+SIMCLIST_METER(double)
+
+size_t list_meter_string(const void *el) { return strlen((const char *)el) + 1; }
+
+/* ready-made hashing functions */
+#define SIMCLIST_HASHCOMPUTER(type) list_hash_t list_hashcomputer_##type(const void *el) { return (list_hash_t)(*(type *)el); }
+
+SIMCLIST_HASHCOMPUTER(int8_t)
+SIMCLIST_HASHCOMPUTER(int16_t)
+SIMCLIST_HASHCOMPUTER(int32_t)
+SIMCLIST_HASHCOMPUTER(int64_t)
+
+SIMCLIST_HASHCOMPUTER(uint8_t)
+SIMCLIST_HASHCOMPUTER(uint16_t)
+SIMCLIST_HASHCOMPUTER(uint32_t)
+SIMCLIST_HASHCOMPUTER(uint64_t)
+
+SIMCLIST_HASHCOMPUTER(float)
+SIMCLIST_HASHCOMPUTER(double)
+
+list_hash_t list_hashcomputer_string(const void *el) {
+ size_t l;
+ list_hash_t hash = 123;
+ const char *str = (const char *)el;
+ char plus;
+
+ for (l = 0; str[l] != '\0'; l++) {
+ if (l) plus = hash ^ str[l];
+ else plus = hash ^ (str[l] - str[0]);
+ hash += (plus << (CHAR_BIT * (l % sizeof(list_hash_t))));
+ }
+
+ return hash;
+}
+
+
+#ifndef NDEBUG
+static int list_repOk(const list_t *restrict l) {
+ int ok, i;
+ struct list_entry_s *s;
+
+ ok = (l != NULL) && (
+ /* head/tail checks */
+ (l->head_sentinel != NULL && l->tail_sentinel != NULL) &&
+ (l->head_sentinel != l->tail_sentinel) && (l->head_sentinel->prev == NULL && l->tail_sentinel->next == NULL) &&
+ /* empty list */
+ (l->numels > 0 || (l->mid == NULL && l->head_sentinel->next == l->tail_sentinel && l->tail_sentinel->prev == l->head_sentinel)) &&
+ /* spare elements checks */
+ l->spareelsnum <= SIMCLIST_MAX_SPARE_ELEMS
+ );
+
+ if (!ok) return 0;
+
+ if (l->numels >= 1) {
+ /* correct referencing */
+ for (i = -1, s = l->head_sentinel; i < (int)(l->numels-1)/2 && s->next != NULL; i++, s = s->next) {
+ if (s->next->prev != s) break;
+ }
+ ok = (i == (int)(l->numels-1)/2 && l->mid == s);
+ if (!ok) return 0;
+ for (; s->next != NULL; i++, s = s->next) {
+ if (s->next->prev != s) break;
+ }
+ ok = (i == (int)l->numels && s == l->tail_sentinel);
+ }
+
+ return ok;
+}
+
+static int list_attrOk(const list_t *restrict l) {
+ int ok;
+
+ ok = (l->attrs.copy_data == 0 || l->attrs.meter != NULL);
+ return ok;
+}
+
+#endif
+
diff --git a/simclist-1.5/simclist.h b/simclist-1.5/simclist.h
new file mode 100644
index 0000000..55bdf4b
--- /dev/null
+++ b/simclist-1.5/simclist.h
@@ -0,0 +1,971 @@
+/*
+ * Copyright (c) 2007,2008 Mij <mij@bitchx.it>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*
+ * SimCList library. See http://mij.oltrelinux.com/devel/simclist
+ */
+
+
+#ifndef SIMCLIST_H
+#define SIMCLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/types.h>
+
+/* Be friend of both C90 and C99 compilers */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+ /* "inline" and "restrict" are keywords */
+#else
+# define inline /* inline */
+# define restrict /* restrict */
+#endif
+
+
+/**
+ * Type representing list hashes.
+ *
+ * This is a signed integer value.
+ */
+typedef int32_t list_hash_t;
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+typedef struct {
+ uint16_t version; /* dump version */
+ int64_t timestamp; /* when the list has been dumped, microseconds from UNIX epoch */
+ uint32_t list_size;
+ uint32_t list_numels;
+ list_hash_t list_hash; /* hash of the list when dumped, or 0 if invalid */
+ uint32_t dumpsize;
+ int consistent; /* 1 if the dump is verified complete/consistent; 0 otherwise */
+} list_dump_info_t;
+#endif
+
+/**
+ * a comparator of elements.
+ *
+ * A comparator of elements is a function that:
+ * -# receives two references to elements a and b
+ * -# returns {<0, 0, >0} if (a > b), (a == b), (a < b) respectively
+ *
+ * It is responsability of the function to handle possible NULL values.
+ */
+typedef int (*element_comparator)(const void *a, const void *b);
+
+/**
+ * a seeker of elements.
+ *
+ * An element seeker is a function that:
+ * -# receives a reference to an element el
+ * -# receives a reference to some indicator data
+ * -# returns non-0 if the element matches the indicator, 0 otherwise
+ *
+ * It is responsability of the function to handle possible NULL values in any
+ * argument.
+ */
+typedef int (*element_seeker)(const void *el, const void *indicator);
+
+/**
+ * an element lenght meter.
+ *
+ * An element meter is a function that:
+ * -# receives the reference to an element el
+ * -# returns its size in bytes
+ *
+ * It is responsability of the function to handle possible NULL values.
+ */
+typedef size_t (*element_meter)(const void *el);
+
+/**
+ * a function computing the hash of elements.
+ *
+ * An hash computing function is a function that:
+ * -# receives the reference to an element el
+ * -# returns a hash value for el
+ *
+ * It is responsability of the function to handle possible NULL values.
+ */
+typedef list_hash_t (*element_hash_computer)(const void *el);
+
+/**
+ * a function for serializing an element.
+ *
+ * A serializer function is one that gets a reference to an element,
+ * and returns a reference to a buffer that contains its serialization
+ * along with the length of this buffer.
+ * It is responsability of the function to handle possible NULL values,
+ * returning a NULL buffer and a 0 buffer length.
+ *
+ * These functions have 3 goals:
+ * -# "freeze" and "flatten" the memory representation of the element
+ * -# provide a portable (wrt byte order, or type size) representation of the element, if the dump can be used on different sw/hw combinations
+ * -# possibly extract a compressed representation of the element
+ *
+ * @param el reference to the element data
+ * @param serialize_buffer reference to fill with the length of the buffer
+ * @return reference to the buffer with the serialized data
+ */
+typedef void *(*element_serializer)(const void *restrict el, uint32_t *restrict serializ_len);
+
+/**
+ * a function for un-serializing an element.
+ *
+ * An unserializer function accomplishes the inverse operation of the
+ * serializer function. An unserializer function is one that gets a
+ * serialized representation of an element and turns it backe to the original
+ * element. The serialized representation is passed as a reference to a buffer
+ * with its data, and the function allocates and returns the buffer containing
+ * the original element, and it sets the length of this buffer into the
+ * integer passed by reference.
+ *
+ * @param data reference to the buffer with the serialized representation of the element
+ * @param data_len reference to the location where to store the length of the data in the buffer returned
+ * @return reference to a buffer with the original, unserialized representation of the element
+ */
+typedef void *(*element_unserializer)(const void *restrict data, uint32_t *restrict data_len);
+
+/* [private-use] list entry -- olds actual user datum */
+struct list_entry_s {
+ void *data;
+
+ /* doubly-linked list service references */
+ struct list_entry_s *next;
+ struct list_entry_s *prev;
+};
+
+/* [private-use] list attributes */
+struct list_attributes_s {
+ /* user-set routine for comparing list elements */
+ element_comparator comparator;
+ /* user-set routing for seeking elements */
+ element_seeker seeker;
+ /* user-set routine for determining the length of an element */
+ element_meter meter;
+ int copy_data;
+ /* user-set routine for computing the hash of an element */
+ element_hash_computer hasher;
+ /* user-set routine for serializing an element */
+ element_serializer serializer;
+ /* user-set routine for unserializing an element */
+ element_unserializer unserializer;
+};
+
+/** list object */
+typedef struct {
+ struct list_entry_s *head_sentinel;
+ struct list_entry_s *tail_sentinel;
+ struct list_entry_s *mid;
+
+ unsigned int numels;
+
+ /* array of spare elements */
+ struct list_entry_s **spareels;
+ unsigned int spareelsnum;
+
+#ifdef SIMCLIST_WITH_THREADS
+ /* how many threads are currently running */
+ unsigned int threadcount;
+#endif
+
+ /* service variables for list iteration */
+ int iter_active;
+ unsigned int iter_pos;
+ struct list_entry_s *iter_curentry;
+
+ /* list attributes */
+ struct list_attributes_s attrs;
+} list_t;
+
+/**
+ * initialize a list object for use.
+ *
+ * @param l must point to a user-provided memory location
+ * @return 0 for success. -1 for failure
+ */
+int list_init(list_t *restrict l);
+
+/**
+ * completely remove the list from memory.
+ *
+ * This function is the inverse of list_init(). It is meant to be called when
+ * the list is no longer going to be used. Elements and possible memory taken
+ * for internal use are freed.
+ *
+ * @param l list to destroy
+ */
+void list_destroy(list_t *restrict l);
+
+/**
+ * set the comparator function for list elements.
+ *
+ * Comparator functions are used for searching and sorting. If NULL is passed
+ * as reference to the function, the comparator is disabled.
+ *
+ * @param l list to operate
+ * @param comparator_fun pointer to the actual comparator function
+ * @return 0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_comparator()
+ */
+int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun);
+
+/**
+ * set a seeker function for list elements.
+ *
+ * Seeker functions are used for finding elements. If NULL is passed as reference
+ * to the function, the seeker is disabled.
+ *
+ * @param l list to operate
+ * @param seeker_fun pointer to the actual seeker function
+ * @return 0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_seeker()
+ */
+int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun);
+
+/**
+ * require to free element data when list entry is removed (default: don't free).
+ *
+ * [ advanced preference ]
+ *
+ * By default, when an element is removed from the list, it disappears from
+ * the list by its actual data is not free()d. With this option, every
+ * deletion causes element data to be freed.
+ *
+ * It is responsability of this function to correctly handle NULL values, if
+ * NULL elements are inserted into the list.
+ *
+ * @param l list to operate
+ * @param metric_fun pointer to the actual metric function
+ * @param copy_data 0: do not free element data (default); non-0: do free
+ * @return 0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_meter()
+ * @see list_meter_int8_t()
+ * @see list_meter_int16_t()
+ * @see list_meter_int32_t()
+ * @see list_meter_int64_t()
+ * @see list_meter_uint8_t()
+ * @see list_meter_uint16_t()
+ * @see list_meter_uint32_t()
+ * @see list_meter_uint64_t()
+ * @see list_meter_float()
+ * @see list_meter_double()
+ * @see list_meter_string()
+ */
+int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data);
+
+/**
+ * set the element hash computing function for the list elements.
+ *
+ * [ advanced preference ]
+ *
+ * An hash can be requested depicting the list status at a given time. An hash
+ * only depends on the elements and their order. By default, the hash of an
+ * element is only computed on its reference. With this function, the user can
+ * set a custom function computing the hash of an element. If such function is
+ * provided, the list_hash() function automatically computes the list hash using
+ * the custom function instead of simply referring to element references.
+ *
+ * @param l list to operate
+ * @param hash_computer_fun pointer to the actual hash computing function
+ * @return 0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_hash_computer()
+ */
+int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun);
+
+/**
+ * set the element serializer function for the list elements.
+ *
+ * [ advanced preference ]
+ *
+ * Serialize functions are used for dumping the list to some persistent
+ * storage. The serializer function is called for each element; it is passed
+ * a reference to the element and a reference to a size_t object. It will
+ * provide (and return) the buffer with the serialization of the element and
+ * fill the size_t object with the length of this serialization data.
+ *
+ * @param l list to operate
+ * @param serializer_fun pointer to the actual serializer function
+ * @return 0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_serializer()
+ * @see list_dump_filedescriptor()
+ * @see list_restore_filedescriptor()
+ */
+int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun);
+
+/**
+ * set the element unserializer function for the list elements.
+ *
+ * [ advanced preference ]
+ *
+ * Unserialize functions are used for restoring the list from some persistent
+ * storage. The unserializer function is called for each element segment read
+ * from the storage; it is passed the segment and a reference to an integer.
+ * It shall allocate and return a buffer compiled with the resumed memory
+ * representation of the element, and set the integer value to the length of
+ * this buffer.
+ *
+ * @param l list to operate
+ * @param unserializer_fun pointer to the actual unserializer function
+ * @return 0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_unserializer()
+ * @see list_dump_filedescriptor()
+ * @see list_restore_filedescriptor()
+ */
+int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun);
+
+/**
+ * append data at the end of the list.
+ *
+ * This function is useful for adding elements with a FIFO/queue policy.
+ *
+ * @param l list to operate
+ * @param data pointer to user data to append
+ *
+ * @return 1 for success. < 0 for failure
+ */
+int list_append(list_t *restrict l, const void *data);
+
+/**
+ * insert data in the head of the list.
+ *
+ * This function is useful for adding elements with a LIFO/Stack policy.
+ *
+ * @param l list to operate
+ * @param data pointer to user data to append
+ *
+ * @return 1 for success. < 0 for failure
+ */
+int list_prepend(list_t *restrict l, const void *restrict data);
+
+/**
+ * extract the element in the top of the list.
+ *
+ * This function is for using a list with a FIFO/queue policy.
+ *
+ * @param l list to operate
+ * @return reference to user datum, or NULL on errors
+ */
+void *list_fetch(list_t *restrict l);
+
+/**
+ * retrieve an element at a given position.
+ *
+ * @param l list to operate
+ * @param pos [0,size-1] position index of the element wanted
+ * @return reference to user datum, or NULL on errors
+ */
+void *list_get_at(const list_t *restrict l, unsigned int pos);
+
+/**
+ * return the maximum element of the list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Returns the maximum element with respect to the comparator function output.
+ *
+ * @see list_attributes_comparator()
+ *
+ * @param l list to operate
+ * @return the reference to the element, or NULL
+ */
+void *list_get_max(const list_t *restrict l);
+
+/**
+ * return the minimum element of the list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Returns the minimum element with respect to the comparator function output.
+ *
+ * @see list_attributes_comparator()
+ *
+ * @param l list to operate
+ * @return the reference to the element, or NULL
+ */
+void *list_get_min(const list_t *restrict l);
+
+/**
+ * retrieve and remove from list an element at a given position.
+ *
+ * @param l list to operate
+ * @param pos [0,size-1] position index of the element wanted
+ * @return reference to user datum, or NULL on errors
+ */
+void *list_extract_at(list_t *restrict l, unsigned int pos);
+
+/**
+ * insert an element at a given position.
+ *
+ * @param l list to operate
+ * @param data reference to data to be inserted
+ * @param pos [0,size-1] position index to insert the element at
+ * @return positive value on success. Negative on failure
+ */
+int list_insert_at(list_t *restrict l, const void *data, unsigned int pos);
+
+/**
+ * expunge the first found given element from the list.
+ *
+ * Inspects the given list looking for the given element; if the element
+ * is found, it is removed. Only the first occurence is removed.
+ * If a comparator function was not set, elements are compared by reference.
+ * Otherwise, the comparator is used to match the element.
+ *
+ * @param l list to operate
+ * @param data reference of the element to search for
+ * @return 0 on success. Negative value on failure
+ *
+ * @see list_attributes_comparator()
+ * @see list_delete_at()
+ */
+int list_delete(list_t *restrict l, const void *data);
+
+/**
+ * expunge an element at a given position from the list.
+ *
+ * @param l list to operate
+ * @param pos [0,size-1] position index of the element to be deleted
+ * @return 0 on success. Negative value on failure
+ */
+int list_delete_at(list_t *restrict l, unsigned int pos);
+
+/**
+ * expunge an array of elements from the list, given their position range.
+ *
+ * @param l list to operate
+ * @param posstart [0,size-1] position index of the first element to be deleted
+ * @param posend [posstart,size-1] position of the last element to be deleted
+ * @return the number of elements successfully removed
+ */
+int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend);
+
+/**
+ * clear all the elements off of the list.
+ *
+ * The element datums will not be freed.
+ *
+ * @see list_delete_range()
+ * @see list_size()
+ *
+ * @param l list to operate
+ * @return the number of elements in the list before cleaning
+ */
+int list_clear(list_t *restrict l);
+
+/**
+ * inspect the number of elements in the list.
+ *
+ * @param l list to operate
+ * @return number of elements currently held by the list
+ */
+unsigned int list_size(const list_t *restrict l);
+
+/**
+ * inspect whether the list is empty.
+ *
+ * @param l list to operate
+ * @return 0 iff the list is not empty
+ *
+ * @see list_size()
+ */
+int list_empty(const list_t *restrict l);
+
+/**
+ * find the position of an element in a list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Inspects the given list looking for the given element; if the element
+ * is found, its position into the list is returned.
+ * Elements are inspected comparing references if a comparator has not been
+ * set. Otherwise, the comparator is used to find the element.
+ *
+ * @param l list to operate
+ * @param data reference of the element to search for
+ * @return position of element in the list, or <0 if not found
+ *
+ * @see list_attributes_comparator()
+ * @see list_get_at()
+ */
+int list_locate(const list_t *restrict l, const void *data);
+
+/**
+ * returns an element given an indicator.
+ *
+ * @warning Requires a seeker function to be set for the list.
+ *
+ * Inspect the given list looking with the seeker if an element matches
+ * an indicator. If such element is found, the reference to the element
+ * is returned.
+ *
+ * @param l list to operate
+ * @param indicator indicator data to pass to the seeker along with elements
+ * @return reference to the element accepted by the seeker, or NULL if none found
+ */
+void *list_seek(list_t *restrict l, const void *indicator);
+
+/**
+ * inspect whether some data is member of the list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * By default, a per-reference comparison is accomplished. That is,
+ * the data is in list if any element of the list points to the same
+ * location of data.
+ * A "semantic" comparison is accomplished, otherwise, if a comparator
+ * function has been set previously, with list_attributes_comparator();
+ * in which case, the given data reference is believed to be in list iff
+ * comparator_fun(elementdata, userdata) == 0 for any element in the list.
+ *
+ * @param l list to operate
+ * @param data reference to the data to search
+ * @return 0 iff the list does not contain data as an element
+ *
+ * @see list_attributes_comparator()
+ */
+int list_contains(const list_t *restrict l, const void *data);
+
+/**
+ * concatenate two lists
+ *
+ * Concatenates one list with another, and stores the result into a
+ * user-provided list object, which must be different from both the
+ * lists to concatenate. Attributes from the original lists are not
+ * cloned.
+ * The destination list referred is threated as virgin room: if it
+ * is an existing list containing elements, memory leaks will happen.
+ * It is OK to specify the same list twice as source, for "doubling"
+ * it in the destination.
+ *
+ * @param l1 base list
+ * @param l2 list to append to the base
+ * @param dest reference to the destination list
+ * @return 0 for success, -1 for errors
+ */
+int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest);
+
+/**
+ * sort list elements.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Sorts the list in ascending or descending order as specified by the versus
+ * flag. The algorithm chooses autonomously what algorithm is best suited for
+ * sorting the list wrt its current status.
+ *
+ * @param l list to operate
+ * @param versus positive: order small to big; negative: order big to small
+ * @return 0: sorting went OK non-0: errors happened
+ *
+ * @see list_attributes_comparator()
+ */
+int list_sort(list_t *restrict l, int versus);
+
+/**
+ * start an iteration session.
+ *
+ * This function prepares the list to be iterated.
+ *
+ * @param l list to operate
+ * @return 0 if the list cannot be currently iterated. >0 otherwise
+ *
+ * @see list_iterator_stop()
+ */
+int list_iterator_start(list_t *restrict l);
+
+/**
+ * return the next element in the iteration session.
+ *
+ * @param l list to operate
+ * @return element datum, or NULL on errors
+ */
+void *list_iterator_next(list_t *restrict l);
+
+/**
+ * inspect whether more elements are available in the iteration session.
+ *
+ * @param l list to operate
+ * @return 0 iff no more elements are available.
+ */
+int list_iterator_hasnext(const list_t *restrict l);
+
+/**
+ * end an iteration session.
+ *
+ * @param l list to operate
+ * @return 0 iff the iteration session cannot be stopped
+ */
+int list_iterator_stop(list_t *restrict l);
+
+/**
+ * return the hash of the current status of the list.
+ *
+ * @param l list to operate
+ * @param hash where the resulting hash is put
+ *
+ * @return 0 for success; <0 for failure
+ */
+int list_hash(const list_t *restrict l, list_hash_t *restrict hash);
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+/**
+ * get meta informations on a list dump on filedescriptor.
+ *
+ * [ advanced function ]
+ *
+ * Extracts the meta information from a SimCList dump located in a file
+ * descriptor. The file descriptor must be open and positioned at the
+ * beginning of the SimCList dump block.
+ *
+ * @param fd file descriptor to get metadata from
+ * @param info reference to a dump metainformation structure to fill
+ * @return 0 for success; <0 for failure
+ *
+ * @see list_dump_filedescriptor()
+ */
+int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info);
+
+/**
+ * get meta informations on a list dump on file.
+ *
+ * [ advanced function ]
+ *
+ * Extracts the meta information from a SimCList dump located in a file.
+ *
+ * @param filename filename of the file to fetch from
+ * @param info reference to a dump metainformation structure to fill
+ * @return 0 for success; <0 for failure
+ *
+ * @see list_dump_filedescriptor()
+ */
+int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info);
+
+/**
+ * dump the list into an open, writable file descriptor.
+ *
+ * This function "dumps" the list to a persistent storage so it can be
+ * preserved across process terminations.
+ * When called, the file descriptor must be open for writing and positioned
+ * where the serialized data must begin. It writes its serialization of the
+ * list in a form which is portable across different architectures. Dump can
+ * be safely performed on stream-only (non seekable) descriptors. The file
+ * descriptor is not closed at the end of the operations.
+ *
+ * To use dump functions, either of these conditions must be satisfied:
+ * -# a metric function has been specified with list_attributes_copy()
+ * -# a serializer function has been specified with list_attributes_serializer()
+ *
+ * If a metric function has been specified, each element of the list is dumped
+ * as-is from memory, copying it from its pointer for its length down to the
+ * file descriptor. This might have impacts on portability of the dump to
+ * different architectures.
+ *
+ * If a serializer function has been specified, its result for each element is
+ * dumped to the file descriptor.
+ *
+ *
+ * @param l list to operate
+ * @param fd file descriptor to write to
+ * @param len location to store the resulting length of the dump (bytes), or NULL
+ *
+ * @return 0 if successful; -1 otherwise
+ *
+ * @see element_serializer()
+ * @see list_attributes_copy()
+ * @see list_attributes_serializer()
+ */
+int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len);
+
+/**
+ * dump the list to a file name.
+ *
+ * This function creates a filename and dumps the current content of the list
+ * to it. If the file exists it is overwritten. The number of bytes written to
+ * the file can be returned in a specified argument.
+ *
+ * @param l list to operate
+ * @param filename filename to write to
+ * @param len location to store the resulting length of the dump (bytes), or NULL
+ *
+ * @return 0 if successful; -1 otherwise
+ *
+ * @see list_attributes_copy()
+ * @see element_serializer()
+ * @see list_attributes_serializer()
+ * @see list_dump_filedescriptor()
+ * @see list_restore_file()
+ *
+ * This function stores a representation of the list
+ */
+int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len);
+
+/**
+ * restore the list from an open, readable file descriptor to memory.
+ *
+ * This function is the "inverse" of list_dump_filedescriptor(). It restores
+ * the list content from a (open, read-ready) file descriptor to memory. An
+ * unserializer might be needed to restore elements from the persistent
+ * representation back into memory-consistent format. List attributes can not
+ * be restored and must be set manually.
+ *
+ * @see list_dump_filedescriptor()
+ * @see list_attributes_serializer()
+ * @see list_attributes_unserializer()
+ *
+ * @param l list to restore to
+ * @param fd file descriptor to read from.
+ * @param len location to store the length of the dump read (bytes), or NULL
+ * @return 0 if successful; -1 otherwise
+ */
+int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len);
+
+/**
+ * restore the list from a file name.
+ *
+ * This function restores the content of a list from a file into memory. It is
+ * the inverse of list_dump_file().
+ *
+ * @see element_unserializer()
+ * @see list_attributes_unserializer()
+ * @see list_dump_file()
+ * @see list_restore_filedescriptor()
+ *
+ * @param l list to restore to
+ * @param filename filename to read data from
+ * @param len location to store the length of the dump read (bytes), or NULL
+ * @return 0 if successful; -1 otherwise
+ */
+int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *len);
+#endif
+
+/* ready-made comparators, meters and hash computers */
+ /* comparator functions */
+/**
+ * ready-made comparator for int8_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int8_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for int16_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int16_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for int32_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int32_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for int64_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int64_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint8_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint8_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint16_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint16_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint32_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint32_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint64_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint64_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for float elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_float(const void *a, const void *b);
+
+/**
+ * ready-made comparator for double elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_double(const void *a, const void *b);
+
+/**
+ * ready-made comparator for string elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_string(const void *a, const void *b);
+
+ /* metric functions */
+/**
+ * ready-made metric function for int8_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int8_t(const void *el);
+
+/**
+ * ready-made metric function for int16_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int16_t(const void *el);
+
+/**
+ * ready-made metric function for int32_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int32_t(const void *el);
+
+/**
+ * ready-made metric function for int64_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int64_t(const void *el);
+
+/**
+ * ready-made metric function for uint8_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint8_t(const void *el);
+
+/**
+ * ready-made metric function for uint16_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint16_t(const void *el);
+
+/**
+ * ready-made metric function for uint32_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint32_t(const void *el);
+
+/**
+ * ready-made metric function for uint64_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint64_t(const void *el);
+
+/**
+ * ready-made metric function for float elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_float(const void *el);
+
+/**
+ * ready-made metric function for double elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_double(const void *el);
+
+/**
+ * ready-made metric function for string elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_string(const void *el);
+
+ /* hash functions */
+/**
+ * ready-made hash function for int8_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int8_t(const void *el);
+
+/**
+ * ready-made hash function for int16_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int16_t(const void *el);
+
+/**
+ * ready-made hash function for int32_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int32_t(const void *el);
+
+/**
+ * ready-made hash function for int64_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int64_t(const void *el);
+
+/**
+ * ready-made hash function for uint8_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint8_t(const void *el);
+
+/**
+ * ready-made hash function for uint16_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint16_t(const void *el);
+
+/**
+ * ready-made hash function for uint32_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint32_t(const void *el);
+
+/**
+ * ready-made hash function for uint64_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint64_t(const void *el);
+
+/**
+ * ready-made hash function for float elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_float(const void *el);
+
+/**
+ * ready-made hash function for double elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_double(const void *el);
+
+/**
+ * ready-made hash function for string elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_string(const void *el);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+