commit 745e06d1af99f5efbdf8e5a7dc701c05742a193f Author: Danny Robson Date: Mon May 23 17:18:52 2011 +1000 initial import from waif diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..094c4537 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +/aclocal.m4 +/autom4te.cache/ +/compile +/config.* +/configure +/depcomp +.deps/ +.dirstamp +/Doxyfile +/install-sh +/json.cpp +/libgim-*.tar.* +.libs +/libtool +/ltmain.sh +Makefile +Makefile.in +/missing +/stamp-h1 +/version.cpp diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100644 index 00000000..02bf2f34 --- /dev/null +++ b/Doxyfile.in @@ -0,0 +1,1510 @@ +# Doxyfile 1.5.8 + +# 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 +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE_NAME@ + +# 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 = @PACKAGE_VERSION@ + +# 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 = @top_builddir@/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 = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# 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 regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default 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 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 = 4 + +# 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 = NO + +# 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 + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# 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 you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +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 + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# 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 = NO + +# 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 this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = 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 = YES + +# 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_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = 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 + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and 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 = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# 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 = @top_srcdir@/src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard 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 *.f90 + +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 = YES + +# 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 = @top_srcdir@/m4 @top_srcdir@/lib + +# 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 EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# 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 , where +# is the value of the INPUT_FILTER tag, and 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 +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# 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 documentation. + +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 HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# 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 compiled 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 CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# 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 + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# 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 = NO + +# 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 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, 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. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NONE + +# 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 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# 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 = YES + +# 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 = latex + +# 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 = YES + +# 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 = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# 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 + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +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 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# 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 options 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 DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +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 + +#--------------------------------------------------------------------------- +# Options 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/Makefile.am b/Makefile.am new file mode 100644 index 00000000..32049414 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,53 @@ +AUTOMAKE_OPTIONS = dist-bzip2 dist-xz foreign +ACLOCAL_AMFLAGS = -I m4 + +AM_CXXFLAGS = $(BOOST_CFLAGS) $(BOOST_FILESYSTEM_CFLAGS) $(COMMON_CXXFLAGS) +AM_LDFLAGS = $(BOOST_LIB) $(BOOST_FILESYSTEM_LIB) $(COMMON_LDFLAGS) + +SUBDIRS = test + +UTIL_INCLUDE = \ + annotations.hpp \ + backtrace.hpp \ + debug.hpp \ + except.hpp \ + float.hpp \ + io.hpp \ + json.hpp \ + maths.hpp \ + matrix.hpp \ + nocopy.hpp \ + range.hpp \ + region.hpp \ + stream.hpp \ + types.hpp \ + vector.hpp \ + version.hpp + +UTIL_FILES = \ + backtrace.cpp \ + debug.cpp \ + except.cpp \ + float.cpp \ + io.cpp \ + json.cpp \ + maths.cpp \ + matrix.cpp \ + range.cpp \ + region.cpp \ + stream.cpp \ + types.cpp \ + vector.cpp \ + version.cpp + +CLEANFILES = json.cpp version.cpp +EXTRA_DIST = json.cpp.rl version.cpp.rl + +RAGELFLAGS = -F1 +SUFFIXES = .cpp .cpp.rl +.cpp.rl.cpp: + $(RAGEL) $(RAGELFLAGS) -C $< -o $(builddir)/$@ + +lib_LTLIBRARIES = libutil.la +libutil_la_SOURCES = $(UTIL_INCLUDE) $(UTIL_FILES) +libutil_la_CXXFLAGS = -fPIC $(COMMON_CXXFLAGS) diff --git a/annotations.hpp b/annotations.hpp new file mode 100644 index 00000000..5f80b5e3 --- /dev/null +++ b/annotations.hpp @@ -0,0 +1,37 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + + +#ifndef __ANNOTATIONS_HPP +#define __ANNOTATIONS_HPP + +// Don't use the name 'noreturn' as it interferes with other headers which +// may use __attribute__((noreturn)) explicitly. +#define terminal __attribute__ ((noreturn)) +#define nonnull __attribute__ ((nonnull)) + +#define mustuse __attribute__ ((warn_unused_result)) + +#define pure __attribute__ ((pure)) + +#define likely(X) (__builtin_expect((X), 1)) +#define unlikely(X) (__builtin_expect((X), 0)) + +#endif // __ANNOTATIONS_HPP + diff --git a/backtrace.cpp b/backtrace.cpp new file mode 100644 index 00000000..06d2cff1 --- /dev/null +++ b/backtrace.cpp @@ -0,0 +1,36 @@ +#include "backtrace.hpp" + +#include "debug.hpp" + +#include +#include +#include +#include + +using namespace std; + + +debug::backtrace::backtrace (void): + m_frames (DEFAULT_DEPTH) { + + int final; + while ((final = ::backtrace (&m_frames[0], m_frames.size ())) == m_frames.size ()) + m_frames.resize (m_frames.size () * 2); + + check_hard (final > 0); + m_frames.resize ((unsigned)final); +} + + +ostream& +operator <<(ostream &os, const debug::backtrace &rhs) { + const auto frames = rhs.frames (); + + typedef unique_ptr unique_str; + unique_str names (backtrace_symbols (&frames[0], frames.size ()), std::free); + + for (unsigned int i = 0; i < frames.size (); ++i) + os << frames[i] << "\t" << names[i] << "\n"; + + return os; +} diff --git a/backtrace.hpp b/backtrace.hpp new file mode 100644 index 00000000..e818993d --- /dev/null +++ b/backtrace.hpp @@ -0,0 +1,22 @@ + +#include +#include +#include + +namespace debug { + class backtrace { + protected: + static const unsigned int DEFAULT_DEPTH = 16; + std::vector m_frames; + + public: + backtrace (void); + + const decltype(m_frames)& frames(void) const + { return m_frames; } + }; +} + +std::ostream& +operator <<(std::ostream&, const debug::backtrace&); + diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..7975ff30 --- /dev/null +++ b/configure.ac @@ -0,0 +1,96 @@ +AC_INIT([libgim], [0.1.0], [danny@nerdcruft.net]) + +AC_CANONICAL_TARGET + +## We remove CXXFLAGS as autotools inserts them /AFTER/ our own CXXFLAGS, +## thus overriding any variables that both set (specifically we're concerned +## about optimisation flags). +CXXFLAGS="" +AC_PROG_CXX +AC_LANG([C++]) +AC_PROG_LIBTOOL +AM_PROG_CC_C_O + +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE +AM_CONFIG_HEADER(config.h) + + +## +## Warnings +WARNING_FLAGS="" + +AS_COMPILER_FLAG([-Wall], [WARNING_FLAGS="$WARNING_FLAGS -Wall"]) +AS_COMPILER_FLAG([-Wextra], [WARNING_FLAGS="$WARNING_FLAGS -Wextra"]) +AS_COMPILER_FLAG([-Wno-parentheses], [WARNING_FLAGS="$WARNING_FLAGS -Wno-parentheses"]) + +AS_COMPILER_FLAG([-Wpointer-arith], [WARNING_FLAGS="$WARNING_FLAGS -Wpointer-arith"]) +AS_COMPILER_FLAG([-Wcast-qual], [WARNING_FLAGS="$WARNING_FLAGS -Wcast-qual"]) +AS_COMPILER_FLAG([-Wcast-align], [WARNING_FLAGS="$WARNING_FLAGS -Wcast-align"]) + +AS_COMPILER_FLAG([-Wsign-compare], [WARNING_FLAGS="$WARNING_FLAGS -Wsign-compare"]) +AS_COMPILER_FLAG([-Wsign-conversion], [WARNING_FLAGS="$WARNING_FLAGS -Wsign-conversion"]) +AS_COMPILER_FLAG([-Wtype-limits], [WARNING_FLAGS="$WARNING_FLAGS -Wtype-limits"]) +AS_COMPILER_FLAG([-Wfloat-equal], [WARNING_FLAGS="$WARNING_FLAGS -Wfloat-equal"]) + +#AS_COMPILER_FLAG([-Wswitch-default], [COMMON_CFLAGS="$COMMON_CFLAGS -Wswitch-default"]) +AS_COMPILER_FLAG([-Wswitch-enum], [COMMON_CFLAGS="$COMMON_CFLAGS -Wswitch-enum"]) + +AS_COMPILER_FLAG([-Wunsafe-loop-optimizations], + [WARNING_FLAGS="$WARNING_FLAGS -Wunsafe-loop-optimizations"]) + +AS_COMPILER_FLAG([-Wunused-parameter], [WARNING_FLAGS="$WARNING_FLAGS -Wunused-parameter"]) +AS_COMPILER_FLAG([-Wunused-but-set-variable], [WARNING_FLAGS="$WARNING_FLAGS -Wunused-parameter"]) +AS_COMPILER_FLAG([-Wshadow], [WARNING_FLAGS="$WARNING_FLAGS -Wshadow"]) +AS_COMPILER_FLAG([-Wredundant-decls], [WARNING_FLAGS="$WARNING_FLAGS -Wredundant-decls"]) + +AS_COMPILER_FLAG([-pedantic], [COMMON_CFLAGS="$COMMON_CFLAGS -pedantic"]) + +## +## Compilation +AS_COMPILER_FLAG([-fno-common ], [COMMON_CFLAGS="$COMMON_CFLAGS -fno-common "]) +AS_COMPILER_FLAG([-fno-nonansi-builtins], + [COMMON_CFLAGS="$COMMON_CFLAGS -fno-nonansi-builtins"]) +AS_COMPILER_FLAG([-fno-rtti], [COMMON_CFLAGS="$COMMON_CFLAGS -fno-rtti"]) + +AS_COMPILER_FLAG([-ggdb], [COMMON_CFLAGS="$COMMON_CFLAGS -ggdb"]) + +## +## Compiler features +AC_C_CONST +AC_C_RESTRICT +AC_C_INLINE + +## +## stdlib features +AC_FUNC_MMAP + + +## +## Documentation + +## +## Required packages +CHECK_RAGEL + +AX_BOOST_BASE +AX_BOOST_FILESYSTEM +AX_BOOST_SYSTEM + +## Optional packages + +## Output + +COMMON_CXXFLAGS="-O0 -g -std=c++0x -include config.h $WARNING_FLAGS $COMMON_CFLAGS" +COMMON_CFLAGS="-O0 -g -std=c99 -include config.h $WARNING_FLAGS $COMMON_CFLAGS" +COMMON_LDFLAGS="" + +AC_SUBST(COMMON_CFLAGS) +AC_SUBST(COMMON_CXXFLAGS) + +AC_OUTPUT([ + Doxyfile + Makefile + test/Makefile +]) diff --git a/debug.cpp b/debug.cpp new file mode 100644 index 00000000..fc4ea079 --- /dev/null +++ b/debug.cpp @@ -0,0 +1,68 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#include "debug.hpp" +#include "backtrace.hpp" + +#include +#include + +using namespace std; + + +void +panic (const std::string& what) { + breakpoint (); + cerr << "PANIC: " << what << "\n" << debug::backtrace () << endl; + abort (); +} + + +void +panic (void) + { panic ("NFI"); } + + +void +breakpoint (void) { + if (getenv ("DEBUG")) { +#if defined (__x86_64) + __asm__ ("int $3;"); +#else + raise (SIGINT); +#endif + } +} + + +void +not_implemented (void) + { panic ("Function not implemented"); } + + +void +unreachable (void) { + panic ("Unreachable code executed"); +} + + +void +unreachable (const std::string& what) { + panic (" Unreachable code executed: " + what); +} diff --git a/debug.hpp b/debug.hpp new file mode 100644 index 00000000..6a97adad --- /dev/null +++ b/debug.hpp @@ -0,0 +1,132 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __DEBUG_HPP +#define __DEBUG_HPP + + +#include "annotations.hpp" + +#include +#include +#include + +#define verify_soft(C, COND) ({ \ + const auto value = (C); \ + check_soft(value COND); \ + value; \ +}) + + +#define verify_hard(C, COND) ({ \ + const auto value = (C); \ + check_hard(value COND); \ + value; \ +}) + + +#define _check_meta(C, SUCCESS, FAILURE) do { \ + const auto value = (C); \ + if (unlikely (!value)) { \ + std::cerr << PACKAGE << ": " \ + << __FILE__ << ":" \ + << __LINE__ << ": " \ + << __FUNCTION__ \ + << ". Assertion '" << #C \ + << "' failed with: " << value << std::endl; \ + \ + { FAILURE } \ + } else { \ + { SUCCESS } \ + } \ +} while (0) + + +#define check_hard(C) _check_meta((C), { ; }, { panic (); }) +#define check_soft(C) _check_meta((C), { ; }, { ; }) + + +#define check_eq(A,B) do { \ + const auto __a = (A); \ + const auto __b = (B); \ + _check_meta (almost_equal (__a, __b), \ + { ; }, \ + { \ + std::ostringstream os; \ + os << "expected equality.\n" \ + << #A << '(' << __a << ")" \ + << "\n != \n" \ + << #B << '(' << __b << ")"; \ + panic (os.str ()); \ + }); \ +} while (0) + + +#define check_neq(A,B) do { \ + const auto __a = (A); \ + const auto __b = (B); \ + _check_meta (!almost_equal (__a, __b), \ + { ; }, \ + { \ + std::ostringstream os; \ + os << "unexepected equality.\n" \ + << __a << "\n ==\n" << __b; \ + panic (os.str ()); \ + }); \ +} while (0) + + +#define check_throws(E,C) do { \ + bool caught = false; \ + \ + try \ + { C; } \ + catch (E) \ + { caught = true; } \ + \ + if (unlikely (!caught)) \ + panic ("expected exception: " #E); \ +} while (0) + +#define check(C) check_hard(C) + + +class panic_error { + protected: + std::string m_what; + + public: + panic_error (const std::string &_what): + m_what (_what) + { ; } +}; + + +void panic (const std::string&) terminal; +void panic (void) terminal; + + +void not_implemented (void) terminal; +void unreachable (void) terminal; +void unreachable (const std::string&) terminal; + + +void breakpoint (void); + +#endif // __DEBUG_HPP diff --git a/except.cpp b/except.cpp new file mode 100644 index 00000000..06dbd5c2 --- /dev/null +++ b/except.cpp @@ -0,0 +1,37 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#include "except.hpp" + +#include +#include + +using namespace std; + + +errno_error::errno_error (int _errno): + runtime_error (strerror (_errno)), + id (_errno) +{ ; } + + +errno_error::errno_error (): + runtime_error (strerror (errno)), + id (errno) +{ ; } diff --git a/except.hpp b/except.hpp new file mode 100644 index 00000000..4afc0029 --- /dev/null +++ b/except.hpp @@ -0,0 +1,51 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + + +#ifndef __EXCEPT_HPP +#define __EXCEPT_HPP + +#include + + +class input_error : public std::runtime_error { + public: + input_error (const std::string &_what): + runtime_error (_what) + { ; } +}; + + +class unavailable_error : public std::runtime_error { + public: + unavailable_error (const std::string &_what): + runtime_error (_what) + { ; } +}; + + +class errno_error : public std::runtime_error { + public: + int id; + errno_error (int _errno); + errno_error (); +}; + + +#endif diff --git a/float.cpp b/float.cpp new file mode 100644 index 00000000..4e0e529a --- /dev/null +++ b/float.cpp @@ -0,0 +1,85 @@ +#include "float.hpp" + +#include + +using namespace std; + + +/* Constructors */ + +template +ieee_float::ieee_float (void) +{ ; } + + +template +ieee_float::ieee_float (floating_t _floating): + m_floating (_floating) +{ ; } + + +template +ieee_float::ieee_float (const ieee_float &rhs): + m_bits (rhs.m_bits) +{ ; } + + +/* Classifiers */ + +template +bool +ieee_float::is_zero (void) const { + return m_components.exponent == 0 && + m_components.significand == 0; +} + +template +bool +ieee_float::is_subnormal (void) const { + return m_components.exponent == 0 && + m_components.significand != 0; +} + +template +bool +ieee_float::is_inifinity (void) const { + return m_components.exponent == (1 << EXPONENT_BITS) - 1 && + m_components.significand == 0; +} + +template +bool +ieee_float::is_nan (void) const { + return m_components.exponent == (1 << EXPONENT_BITS) - 1 && + m_components.significand != 0; +} + +template +bool +ieee_float::operator==(floating_t _floating) const { + // TODO: This method really shouldn't be generated if there's no + // representative native floating point type. But I'm sick of + // C++'s template bullshit for tonight. + check_hard (bits_type::has_floating); + + return m_bits == *(const uint_t*)&_floating; +} + + +#include + + +template +bool +ieee_float::almost_equal (floating_t a, + floating_t b) { + static const double epsilon = 0.001; + + return fabs(a - b) <= epsilon * std::fabs (a) || + fabs(a - b) <= epsilon * std::fabs (b); +} + + +template class ieee_float< 5, 10>; // ieee_half +template class ieee_float< 8, 23>; // ieee_single; +template class ieee_float<11, 52>; // ieee_double; diff --git a/float.hpp b/float.hpp new file mode 100644 index 00000000..935c58ec --- /dev/null +++ b/float.hpp @@ -0,0 +1,66 @@ +#ifndef __FLOAT_HPP +#define __FLOAT_HPP + +#include "types.hpp" +#include "debug.hpp" + + +template +class ieee_float { + public: + static const unsigned int EXPONENT_BITS = EXPONENT; + static const unsigned int SIGNIFICAND_BITS = SIGNIFICAND; + static const unsigned int TOTAL_BITS = 1 + EXPONENT + SIGNIFICAND; + + static const unsigned int BIAS = (1 << (EXPONENT - 1)) - 1; + + typedef typename bits_type::uint uint_t; + typedef typename bits_type::floating floating_t; + + protected: + union { + uint_t m_bits; + floating_t m_floating; + + struct { + uint_t sign : 1; + uint_t exponent : EXPONENT; + uint_t significand : SIGNIFICAND; + } m_components; + }; + + public: + ieee_float (void); + ieee_float (floating_t _floating); + ieee_float (const ieee_float &rhs); + + static unsigned int bias (void) + { return BIAS; } + + void set_bits (uint_t _bits) { m_bits = _bits; } + uint_t bits (void) const { return m_bits; } + + bool negative (void) const { return m_components.sign; } + void negate (void) { m_components.sign ^= m_components.sign; } + + bool is_zero (void) const; + bool is_subnormal (void) const; + bool is_inifinity (void) const; + bool is_nan (void) const; + bool operator== (floating_t) const; + + static bool almost_equal (floating_t, floating_t); +}; + + +typedef ieee_float< 5, 10> ieee_half; +typedef ieee_float< 8, 23> ieee_single; +typedef ieee_float<11, 52> ieee_double; + + +static_assert (sizeof(ieee_half ) == 2, "ieee_half must be 2 bytes"); +static_assert (sizeof(ieee_single ) == 4, "ieee_single must be 4 bytes"); +static_assert (sizeof(ieee_double ) == 8, "ieee_double must be 8 bytes"); + + +#endif // __FLOAT_HPP diff --git a/io.cpp b/io.cpp new file mode 100644 index 00000000..62125508 --- /dev/null +++ b/io.cpp @@ -0,0 +1,87 @@ +#include "io.hpp" + +#include "debug.hpp" +#include "except.hpp" + +#include +#include +#include +#include +#include +#include + + +using namespace std; + + +fd_ref::fd_ref (int _fd): + m_fd (_fd) +{ + if (m_fd < 0) + throw invalid_argument ("invalid file descriptor"); +} + + +fd_ref::~fd_ref () { + check (m_fd >= 0); + close (m_fd); +} + + +fd_ref::operator int (void) const + { return m_fd; } + + +mapped_file::mapped_file (const char *_path): + m_fd (open (_path, O_RDONLY)) +{ load_fd (); } + + +mapped_file::mapped_file (const std::string &_path): + m_fd (open (_path.c_str (), O_RDONLY)) +{ load_fd (); } + + +mapped_file::mapped_file (const boost::filesystem::path &_path): + m_fd (open (_path.native ().c_str (), O_RDONLY)) +{ load_fd (); } + + +mapped_file::~mapped_file () { + check (m_data != NULL); + munmap (m_data, m_size); +} + + +void +mapped_file::load_fd (void) { + struct stat meta; + if (fstat (m_fd, &meta) < 0) + throw errno_error (); + + m_size = (size_t)meta.st_size; + m_data = (uint8_t *)mmap (NULL, m_size, PROT_READ, MAP_PRIVATE, m_fd, 0); + if (m_data == MAP_FAILED) + throw errno_error (); +} + + +size_t +mapped_file::size (void) const { + check (m_size > 0); + check (m_data != NULL); + + return m_size; +} + + +const uint8_t* +mapped_file::data (void) const { + check (m_size > 0); + check (m_data != NULL); + + return m_data; +} + + + diff --git a/io.hpp b/io.hpp new file mode 100644 index 00000000..d6cc3882 --- /dev/null +++ b/io.hpp @@ -0,0 +1,82 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __UTIL_IO_HPP +#define __UTIL_IO_HPP + +#include +#include +#include +#include + + +enum access_t { + ACCESS_READ = 1 << 0, + ACCESS_WRITE = 1 << 1, + ACCESS_READWRITE = ACCESS_READ | ACCESS_WRITE +}; + + +struct FILE_destructor { + void operator ()(FILE *f) { fclose (f); } +}; + +typedef std::unique_ptr FILE_ref; + + +struct fd_destructor { + void operator ()(int fd) { close (fd); } +}; + +struct fd_ref { + public: + int m_fd; + + + fd_ref (int _fd); + ~fd_ref (); + + operator int (void) const; +}; + + +class mapped_file { + protected: + fd_ref m_fd; + uint8_t *m_data; + size_t m_size; + + void load_fd (void); + + public: + mapped_file (const char *path); + mapped_file (const std::string &path); + mapped_file (const boost::filesystem::path &path); + + mapped_file (const mapped_file &rhs); + mapped_file& operator =(const mapped_file &rhs); + + ~mapped_file (); + + const uint8_t* data (void) const; + size_t size (void) const; +}; + + +#endif diff --git a/json.cpp.rl b/json.cpp.rl new file mode 100644 index 00000000..6bb045de --- /dev/null +++ b/json.cpp.rl @@ -0,0 +1,448 @@ +#include "json.hpp" +#include "maths.hpp" +#include "io.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +using namespace std; + +/* + * Parsing + */ + +struct parse_context { + parse_context(json::node *_root): + root (_root), + value (NULL), + key (NULL), + start (NULL), + stop (NULL) + { ; } + + json::node *root, + *value, + *key; + const char *start, + *stop; +}; + + +%%{ + machine json; + + ## Record whether parsing was successful for future use + action success + { __success = true; } + + action failure { + __success = false; + /*std::cerr << std::endl + << "Failure on: '" << fc << "' in level " << top << " at " << fpc - p + << std::endl; + */ + } + + + action new_object { nodestack.push_back (parse_context(new json::object)); } + action new_array { nodestack.push_back (parse_context(new json::array)); } + + action new_object_value { + assert (nodestack.back ().root->is_object ()); + assert (nodestack.back ().key); + assert (nodestack.back ().value); + + if (!nodestack.back ().key->is_string ()) + throw error ("object keys must be strings"); + + json::object *object = (json::object *)nodestack.back ().root; + object->insert (nodestack.back ().key->to_string (), + nodestack.back ().value); + nodestack.back ().key = NULL; + nodestack.back ().value = NULL; + } + + action new_array_value { + assert (nodestack.back ().root->is_array ()); + assert (nodestack.back ().value); + + json::array *array = (json::array *)nodestack.back ().root; + array->insert (nodestack.back ().value); + nodestack.back ().value = NULL; + } + + action new_string { + assert (!nodestack.empty ()); + assert (!nodestack.back ().value); + + std::string value (std::string (nodestack.back ().start, + nodestack.back ().stop)); + nodestack.back ().value = new json::string(value); + } + + action new_boolean { + assert (!nodestack.empty ()); + assert (!nodestack.back ().value); + + throw error ("unable to parse boolean"); + } + + action new_number { + assert (!nodestack.empty ()); + assert (!nodestack.back ().value); + + errno = 0; + double value = strtod (nodestack.back ().start, NULL); + if (errno) + throw error ("unable to parse number"); + nodestack.back ().value = new json::number (value); + } + + action new_null { + assert (!nodestack.empty ()); + assert (!nodestack.back ().value); + + nodestack.back().value = new json::null (); + } + + action new_object_key { + assert (!nodestack.empty ()); + assert (nodestack.back ().root->is_object ()); + assert (nodestack.back ().value); + assert (!nodestack.back ().key); + + nodestack.back ().key = nodestack.back ().value; + nodestack.back ().value = NULL; + } + + prepush { + fsmstack.push_back (0); + } + + postpop { + fsmstack.pop_back (); + __root = nodestack.back ().root; + if (nodestack.size () > 1) + (nodestack.rbegin () + 1)->value = nodestack.back ().root; + nodestack.pop_back (); + } + + variable stack fsmstack; + + alphtype char; + + ## numerical + exp = [eE]('-' | '+')? digit+; + frac = '.' digit+; + int = '-'? [1-9]? digit+; + + number = int ( frac + | exp + | frac exp)?; + + ## textual + char = + any - (cntrl | '\"' | '\\') + | '\\\"' + | '\\\\' + | '\\/' + | '\\b' + | '\\f' + | '\\n' + | '\\r' + | '\\t' + | '\\u' xdigit{4}; + + string = ('"' + char* >{ nodestack.back ().start = fpc; } + %{ nodestack.back ().stop = fpc; }) + '"' + @new_string; + + ## other + boolean = + 'true' @{ nodestack.back ().value = new json::boolean ( true); } + | 'false' @{ nodestack.back ().value = new json::boolean (false); }; + + ## components + object = '{' @{ fhold; fcall _object; } '}'; + array = '[' @{ fhold; fcall _array; } ']'; + + value = + string + | boolean + | number >{ nodestack.back ().start = fpc; } %{ nodestack.back ().stop = fpc; } %new_number + | object + | array + | 'null' %new_null; + + ## compound data types + _array := ('[' @new_array + space* ((value %new_array_value space* ',' space*)* value %new_array_value space*)? + ']') + $!failure + @{ fhold; fret; }; + + pair = string %new_object_key space* ':' space* value %new_object_value; + _object := ('{' @new_object + space* ((pair space* ',' space*)* pair space*)? + '}') + $!failure + @{ fhold; fret; }; + + json := (space* object space*) + $!failure + %success + >{ __success = false; }; + + write data; +}%% + + +/* + * Node + */ + +namespace json { + json::node * + parse (const boost::filesystem::path &path) { + mapped_file file(path); + return parse ((const char *)file.data (), + (const char *)file.data () + file.size ()); + } + + + node * + parse (const char *start, + const char *stop) { + bool __success = true; + json::node *__root = NULL; + int cs, top = 0; + deque fsmstack; + deque nodestack; + + const char *p = start, + *pe = stop, + *eof = stop; + + %%write init; + %%write exec; + + if (!__success) + throw error ("unable to parse json"); + + //__root->print (cout) << endl; + assert (*__root == *__root); + return __root; + } + + + node* + parse (const char *start) + { return parse (start, start + strlen (start)); } +} + + +const json::object& +json::node::to_object (void) const + { throw error ("node is not an object"); } + + +const json::array& +json::node::to_array (void) const + { throw error ("node is not an array"); } + + +const json::string& +json::node::to_string (void) const + { throw error ("node is not a string"); } + + +const json::number& +json::node::to_number (void) const + { throw error ("node is not a number"); } + + +const json::boolean& +json::node::to_boolean (void) const + { throw error ("node is not a boolean"); } + + +bool +json::node::operator!=(const node &rhs) const + { return !(*this == rhs); } + + +/* + * Object + */ + +json::object::~object () { + for (auto i = m_values.begin (); i != m_values.end (); ++i) + delete i->second; +} + + +bool +json::object::operator ==(const json::object &rhs) const { + for (auto i = rhs.m_values.begin (), j = m_values.begin (); + i != rhs.m_values.end () && j != m_values.end (); + ++i, ++j) + { + if (i->first != j->first) + return false; + if ((*i->second) != (*j->second)) + return false; + } + + return true; +} + + +void +json::object::insert (const std::string _key, json::node* value) + { m_values[_key] = value; } + + +const json::node& +json::object::operator[](const std::string &key) const { + auto value = m_values.find (key); + if (value == m_values.end ()) { + ostringstream ss; + ss << "no key: " << key; + throw json::error (ss.str()); + } + + return *value->second; +} + + +std::ostream& +json::object::print (std::ostream &os) const { + os << "{"; + + for (auto i = m_values.begin (); i != m_values.end ();) { + os << '"' << i->first << "\" : " << *i->second; + + if (++i != m_values.end ()) + os << ",\n"; + } + + os << "}"; + return os; +} + + +/* + * Array + */ + +json::array::~array() { + for (auto i = m_values.begin(); i != m_values.end (); ++i) + delete *i; +} + + +void +json::array::insert (json::node *_value) + { m_values.push_back (_value); } + + +bool +json::array::operator ==(const json::array &rhs) const { + for (auto i = rhs.m_values.begin (), j = m_values.begin (); + i != rhs.m_values.end () && j != m_values.end (); + ++i, ++j) + { if ((**i) != (**j)) return false; } + + return true; +} + + +std::ostream& +json::array::print (std::ostream &os) const { + os << "[ "; + + for (auto i = m_values.begin (); i != m_values.end (); ++i) { + os << (*i)->print (os); + + if (i != m_values.end () - 1) + os << ", "; + } + + os << "]"; + return os; +} + + +/* + * String + */ + +std::ostream& +json::string::print (std::ostream &os) const { + os << '"' << m_value << '"'; + return os; +} + + +bool +json::string::operator ==(const json::string &rhs) const + { return rhs.m_value == m_value; } + + +/* + * Number + */ + +std::ostream& +json::number::print (std::ostream &os) const { + os << '"' << m_value << '"'; + return os; +} + + +bool +json::number::operator ==(const json::number &rhs) const + { return almost_equal (rhs.m_value, m_value); } + + +/* + * Boolean + */ + +std::ostream& +json::boolean::print (std::ostream &os) const { + os << '"' << (m_value ? "true" : "false") << '"'; + return os; +} + +bool +json::boolean::operator ==(const json::boolean &rhs) const + { return rhs.m_value == m_value; } + + +/* + * Null + */ + +std::ostream& +json::null::print (std::ostream &os) const { + os << "null"; + return os; +} + +ostream& +operator <<(ostream &os, const json::node &n) + { return n.print (os); } diff --git a/json.hpp b/json.hpp new file mode 100644 index 00000000..f27487ca --- /dev/null +++ b/json.hpp @@ -0,0 +1,209 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __UTIL_JSON_HPP +#define __UTIL_JSON_HPP + +#include +#include +#include +#include + +#include + + +namespace json { + class node; + class object; + class array; + class string; + class number; + class boolean; + class null; + + extern node* parse (const boost::filesystem::path &path); + extern node* parse (const char *start, const char *stop); + extern node* parse (const char *start); + + class node { + public: + virtual ~node () { ; } + + virtual const object& to_object (void) const; + virtual const array& to_array (void) const; + virtual const string& to_string (void) const; + virtual const number& to_number (void) const; + virtual const boolean& to_boolean (void) const; + + virtual bool is_object (void) const { return false; } + virtual bool is_array (void) const { return false; } + virtual bool is_string (void) const { return false; } + virtual bool is_number (void) const { return false; } + virtual bool is_boolean (void) const { return false; } + virtual bool is_null (void) const { return false; } + + virtual bool operator==(const node &rhs) const = 0; + virtual bool operator!=(const node &rhs) const; + virtual bool operator==(const object &) const { return false; } + virtual bool operator==(const array &) const { return false; } + virtual bool operator==(const string &) const { return false; } + virtual bool operator==(const number &) const { return false; } + virtual bool operator==(const boolean &) const { return false; } + virtual bool operator==(const null &) const { return false; } + + virtual std::ostream& print (std::ostream &os) const = 0; + + }; + + + class object : public node { + protected: + std::map m_values; + + public: + object () { ; } + virtual ~object (); + + virtual const object& to_object (void) const { return *this; } + virtual bool is_object (void) const { return true; } + virtual bool operator==(const object &rhs) const; + virtual bool operator==(const node &rhs) const + { return rhs == *this; } + + virtual void insert (const std::string _key, node* value); + virtual const node& operator[](const std::string &key) const; + + virtual std::ostream& print (std::ostream &os) const; + + }; + + + class array : public node { + protected: + std::vector m_values; + + typedef std::vector::iterator array_iterator; + typedef std::vector::const_iterator const_array_iterator; + + public: + virtual ~array(); + + virtual const array& to_array (void) const { return *this; } + virtual bool is_array (void) const { return true; } + virtual bool operator==(const array &rhs) const; + virtual bool operator==(const node &rhs) const + { return rhs == *this; } + + virtual size_t size (void) const + { return m_values.size (); } + virtual node& operator [](unsigned int idx) + { return *m_values[idx]; } + virtual const node& operator [](unsigned int idx) const + { return *m_values[idx]; } + + virtual const_array_iterator begin (void) const { return m_values.begin (); } + virtual const_array_iterator end (void) const { return m_values.end (); } + + virtual void insert (json::node *_value); + + virtual std::ostream& print (std::ostream &os) const; + }; + + + class string : public node { + protected: + std::string m_value; + + public: + string (const std::string &_value): m_value (_value) { ; } + string (const char *_value): m_value (_value) { ; } + + virtual const string& to_string (void) const { return *this; } + virtual bool is_string (void) const { return true; } + virtual bool operator==(const string &rhs) const; + virtual bool operator==(const node &rhs) const + { return rhs == *this; } + + operator const std::string&(void) const { return m_value; } + + virtual std::ostream& print (std::ostream &os) const; + }; + + + class number : public node { + protected: + double m_value; + + public: + number (double _value): m_value (_value) { ; } + number (int _value): m_value (_value) { ; } + + virtual const number& to_number (void) const { return *this; } + virtual bool is_number (void) const { return true; } + virtual bool operator==(const number &rhs) const; + virtual bool operator==(const node &rhs) const + { return rhs == *this; } + + operator double(void) const { return m_value; } + + virtual std::ostream& print (std::ostream &os) const; + }; + + + class boolean : public node { + protected: + bool m_value; + + public: + boolean (bool _value): m_value (_value) { ; } + + virtual const boolean& to_boolean (void) const { return *this; } + virtual bool is_boolean (void) const { return true; } + virtual bool operator==(const boolean &rhs) const; + virtual bool operator==(const node &rhs) const + { return rhs == *this; } + + virtual std::ostream& print (std::ostream &os) const; + }; + + + class null : public node { + public: + virtual bool is_null (void) const { return true; } + virtual std::ostream& print (std::ostream &os) const; + virtual bool operator==(const null&) const { return true; } + virtual bool operator==(const node &rhs) const + { return rhs == *this; } + }; + + + class error : public std::runtime_error { + public: + error (const std::string &_what): + std::runtime_error (_what) + { ; } + }; +} + + +std::ostream& +operator <<(std::ostream &os, const json::node &n); + +#endif + diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 00000000..0f4126cd --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1 @@ +*.m4 diff --git a/m4/as_compiler_flag.m4 b/m4/as_compiler_flag.m4 new file mode 100644 index 00000000..882a4c7f --- /dev/null +++ b/m4/as_compiler_flag.m4 @@ -0,0 +1,64 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef +dnl Tim-Philipp Müller + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + +dnl AS_CXX_COMPILER_FLAG(CPPFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CPPFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_CXX_COMPILER_FLAG], +[ + AC_REQUIRE([AC_PROG_CXX]) + + AC_MSG_CHECKING([to see if c++ compiler understands $1]) + + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $1" + + AC_LANG_PUSH(C++) + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CPPFLAGS="$save_CPPFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + + AC_LANG_POP(C++) + + AC_MSG_RESULT([$flag_ok]) +]) + diff --git a/m4/ragel.m4 b/m4/ragel.m4 new file mode 100644 index 00000000..8b9b9139 --- /dev/null +++ b/m4/ragel.m4 @@ -0,0 +1,43 @@ +dnl Check for presence of the Ragel State Machine generator. +dnl +dnl This macro checks for the presence of the ragel tool in the system, +dnl and whether the ragel tool is absolutely needed for a complete +dnl build. +dnl +dnl To check for the need for Ragel, you have to provide the relative +dnl path of a source file generated through Ragel: if the file is +dnl present in the source tree, a missing ragel command will not cause +dnl the configure to abort. + +AC_DEFUN([_RAGEL_VARS], [ + AC_ARG_VAR([RAGEL], [Ragel generator command]) + AC_ARG_VAR([RAGELFLAGS], [Ragel generator flags]) +]) + +AC_DEFUN([CHECK_RAGEL], [ + AC_REQUIRE([_RAGEL_VARS]) + AC_CHECK_PROG([RAGEL], [ragel], [ragel], [no]) + + dnl We set RAGEL to false so that it would execute the "false" + dnl command if needed. + AS_IF([test x"$RAGEL" = x"no"], [RAGEL=false]) + + dnl Only test the need if not found + AS_IF([test x"$RAGEL" = x"false"], [ + AC_MSG_CHECKING([whether we need ragel to regenerate sources]) + AS_IF([test -a ${srcdir}/$1], [ragel_needed=no], [ragel_needed=yes]) + AC_MSG_RESULT([$ragel_needed]) + + AS_IF([test x"$ragel_needed" = x"yes"], + [AC_MSG_ERROR([dnl +You need Ragel to build from GIT checkouts. +You can find Ragel at http://www.complang.org/ragel/dnl + ])]) + ]) +]) + +AC_DEFUN([CHECK_RAGEL_AM], [ + CHECK_RAGEL([$1]) + + AM_CONDITIONAL([HAVE_RAGEL], [test x"$RAGEL" != x"false"]) +]) diff --git a/maths.cpp b/maths.cpp new file mode 100644 index 00000000..be5f08b0 --- /dev/null +++ b/maths.cpp @@ -0,0 +1,56 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#include "maths.hpp" + +#include "float.hpp" + +#include + + +template +T +pow2 (T value) +{ return value * value; } + +template double pow2(double); +template int pow2( int); + + +template +double +rootsquare (T a, T b) +{ return sqrt (pow2 (a) + pow2 (b)); } + +template double rootsquare (double, double); +template double rootsquare ( int, int); + + +template <> +bool +almost_equal (float a, float b) + { return ieee_single::almost_equal (a, b); } + + +template <> +bool +almost_equal (double a, double b) + { return ieee_double::almost_equal (a, b); } + + diff --git a/maths.hpp b/maths.hpp new file mode 100644 index 00000000..b9e9686a --- /dev/null +++ b/maths.hpp @@ -0,0 +1,92 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __MATHS_HPP +#define __MATHS_HPP + + +template +T +pow2 (T value); + + +template +double +rootsquare (T a, T b); + + +/** + * Check if two floating point numbers are approximately equal. Returns true + * if the difference is less than a percentage of each individual value. + * + * @e maximum percentage difference for equal values + */ + +template +bool +almost_equal (T a, T b) + { return a == b; } + + +template +bool +almost_equal (Ta a, Tb b) { + return almost_equal (static_cast(a), + static_cast(b)); +} + + +template <> +bool +almost_equal (float a, float b); + + +template <> +bool +almost_equal (double a, double b); + + +/// Variadic minimum +template +const T& +min (const T &a) + { return a ; } + + +template +const T& +min (const T &a , const T &b , const Args &...args ) + { return min ( b < a ? b : a, args...); } + + +/// Variadic maximum +template +const T& +max (const T &a) + { return a ; } + + +template +const T& +max (const T &a , const T &b , const Args &...args ) + { return max ( b > a ? b : a, args...); } + + + +#endif // __MATHS_HPP diff --git a/matrix.cpp b/matrix.cpp new file mode 100644 index 00000000..964d1ee2 --- /dev/null +++ b/matrix.cpp @@ -0,0 +1,513 @@ +#include "matrix.hpp" + +#include "debug.hpp" +#include "range.hpp" +#include "maths.hpp" + +#include + +using namespace maths; + + +matrix::matrix (size_t _rows, size_t _columns): + m_rows (_rows), + m_columns (_columns), + m_data (NULL) { + if (m_rows <= 0 || m_columns <= 0) + throw std::runtime_error ("rows and columns must be positive"); + + m_data = new double[size ()]; +} + + +matrix::matrix (size_t _rows, + size_t _columns, + const std::initializer_list &_data): + m_rows (_rows), + m_columns (_columns), + m_data (NULL) +{ + if (m_rows <= 0 || m_columns <= 0) + throw std::runtime_error ("rows and columns must be positive"); + if (size () != _data.size ()) + throw std::runtime_error ("element and initializer size differs"); + check_hard (m_rows * m_columns == _data.size()); + + m_data = new double[size ()]; + std::copy (_data.begin (), _data.end (), m_data); +} + + +matrix::matrix (const std::initializer_list &rhs): + m_rows (rhs.size ()), + m_columns (rhs.begin()->size ()), + m_data (new double[m_rows * m_columns]) +{ + double *row_cursor = m_data; + + for (auto i = rhs.begin (); i != rhs.end (); ++i) { + check (i->size () == m_columns); + + std::copy (i->data (), i->data () + i->size (), row_cursor); + row_cursor += m_columns; + } +} + + +matrix::matrix (const matrix &rhs): + m_rows (rhs.m_rows), + m_columns (rhs.m_columns) { + m_data = new double [m_rows * m_columns]; + std::copy (rhs.m_data, rhs.m_data + m_rows * m_columns, m_data); +} + + +matrix::matrix (matrix &&rhs): + m_rows (rhs.m_rows), + m_columns (rhs.m_columns), + m_data (rhs.m_data) { + rhs.m_data = NULL; +} + + +matrix::~matrix() + { delete [] m_data; } + + +void +matrix::sanity (void) const { + check (m_rows > 0); + check (m_columns > 0); + check (m_data != NULL); +} + + +const double * +matrix::operator [] (unsigned int row) const { + check_hard (row < m_rows); + return m_data + row * m_columns; +} + + +double * +matrix::operator [] (unsigned int row) { + check_hard (row < m_rows); + return m_data + row * m_columns; +} + + +const double * +matrix::data (void) const + { return m_data; } + + +matrix& +matrix::operator =(const matrix& rhs) { + if (size () != rhs.size ()) { + delete [] m_data; + m_data = new double [m_rows * m_columns]; + } + + m_rows = rhs.m_rows; + m_columns = rhs.m_columns; + std::copy (rhs.m_data, rhs.m_data + m_rows * m_columns, m_data); + + return *this; +} + + +matrix +matrix::operator * (double scalar) const { + matrix val (*this); + + for (unsigned int i = 0; i < m_rows; ++i) + for (unsigned int j = 0; j < m_columns; ++j) + val[i][j] *= scalar; + + return val; +} + + +matrix& +matrix::operator *=(double scalar) { + for (unsigned int i = 0; i < m_rows; ++i) + for (unsigned int j = 0; j < m_columns; ++j) + (*this)[i][j] *= scalar; + + return *this; +} + + +matrix& +matrix::operator /= (double scalar) + { return (*this) *= (1.0 / scalar); } + + +matrix +matrix::operator + (double scalar) const { + matrix val (*this); + for (unsigned int i = 0; i < m_rows; ++i) + for (unsigned int j = 0; j < m_columns; ++j) + val[i][j] += scalar; + + return val; +} + + +matrix& +matrix::operator +=(double scalar) { + for (unsigned int i = 0; i < m_rows; ++i) + for (unsigned int j = 0; j < m_columns; ++j) + (*this)[i][j] += scalar; + + return *this; +} + + +matrix +matrix::operator * (const matrix& rhs) const { + if (m_columns != rhs.rows ()) + throw std::invalid_argument ("matrices size mismatch in multiplication"); + + matrix val (matrix::zeroes (m_rows, rhs.columns ())); + + for (unsigned int i = 0; i < m_rows; ++i) + for (unsigned int j = 0; j < rhs.columns (); ++j) + for (unsigned int k = 0; k < m_columns; ++k) + val[i][j] += (*this)[i][k] * rhs[k][j]; + + return val; +} + + +matrix& +matrix::operator *=(const matrix& rhs) + { return *this = *this * rhs; } + + +bool +matrix::operator ==(const matrix& rhs) const { + if (rhs.rows () != rows () || + rhs.columns () != columns ()) + return false; + + return std::equal (m_data, m_data + size (), rhs.data ()); +} + + +//matrix transpose (void) const { ; } + + +size_t +matrix::rows (void) const + { return m_rows; } + + +size_t +matrix::columns (void) const + { return m_columns; } + + +size_t +matrix::size (void) const + { return rows () * columns (); } + + +bool +matrix::is_square (void) const + { return m_rows == m_columns; } + + +bool +matrix::is_magic (void) const { + if (!is_square ()) + return false; + + unsigned int expected = m_rows * (m_rows * m_rows + 1) / 2; + range numbers (1, m_rows * m_rows); + + for (unsigned int i = 0; i < m_rows; ++i) { + unsigned int sum1 = 0, sum2 = 0; + + for (unsigned int j = 0; j < m_columns; ++j) { + if (!numbers.includes ((*this)[i][j]) || + !numbers.includes ((*this)[j][i])) + return false; + + sum1 += (*this)[i][j]; + sum2 += (*this)[j][i]; + } + + if (sum1 != expected || sum2 != expected) + return false; + } + + return true; +} + + +bool +matrix::is_homogeneous (void) const { + if (m_rows != m_columns) + return false; + + // Check the final row is all zeroes + for (unsigned int i = 0; i < m_columns - 1; ++i) { + if (!almost_equal ((*this)[m_rows - 1][i], 0.)) + return false; + } + + // Except for the last element, which has to be one + return almost_equal ((*this)[m_rows - 1][m_columns - 1], 1.); +} + + +double +matrix::determinant (void) const { + if (m_rows != m_columns) + not_implemented (); + + switch (m_rows) { + case 2: return determinant2x2 (); + case 3: return determinant3x3 (); + case 4: return determinant4x4 (); + } + + not_implemented (); +} + + +// With matrix A = [ a, b ] +// [ c, d ] +// +// det (A) = ad - bc + +double +matrix::determinant2x2 (void) const { + check_eq (m_rows, 2); + check_eq (m_columns, 2); + + return (*this)[0][0] * (*this)[1][1] - + (*this)[0][1] * (*this)[1][0]; +} + + + +// [ a, b, c ] +// Given matrix A = [ d, e, f ] +// [ g, h, i ] +// +// det (A) = aei + bfg + cdh - afg - bdi - ceg +// det (A) = a(ei - fg) + b(fg - di) + c(dh - eg) +double +matrix::determinant3x3 (void) const { + check_eq (m_rows, 3); + check_eq (m_columns, 3); + + return (*this)[0][0] * (*this)[1][1] * (*this)[2][2] + // aei + (*this)[0][1] * (*this)[1][2] * (*this)[2][0] + // bfg + (*this)[0][2] * (*this)[1][0] * (*this)[2][1] - // cdh + (*this)[0][0] * (*this)[1][2] * (*this)[2][1] - // afh + (*this)[0][1] * (*this)[1][0] * (*this)[2][2] - // bdi + (*this)[0][2] * (*this)[1][1] * (*this)[2][0]; // ceg +} + + +// From libMathematics, http://www.geometrictools.com/ +double +matrix::determinant4x4 (void) const { + check_eq (m_rows, 4); + check_eq (m_columns, 4); + + double a0 = m_data[ 0] * m_data[ 5] - m_data[ 1] * m_data[ 4], + a1 = m_data[ 0] * m_data[ 6] - m_data[ 2] * m_data[ 4], + a2 = m_data[ 0] * m_data[ 7] - m_data[ 3] * m_data[ 4], + a3 = m_data[ 1] * m_data[ 6] - m_data[ 2] * m_data[ 5], + a4 = m_data[ 1] * m_data[ 7] - m_data[ 3] * m_data[ 5], + a5 = m_data[ 2] * m_data[ 7] - m_data[ 3] * m_data[ 6], + b0 = m_data[ 8] * m_data[13] - m_data[ 9] * m_data[12], + b1 = m_data[ 8] * m_data[14] - m_data[10] * m_data[12], + b2 = m_data[ 8] * m_data[15] - m_data[11] * m_data[12], + b3 = m_data[ 9] * m_data[14] - m_data[10] * m_data[13], + b4 = m_data[ 9] * m_data[15] - m_data[11] * m_data[13], + b5 = m_data[10] * m_data[15] - m_data[11] * m_data[14]; + + return a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; +} + + +matrix +matrix::inverse (void) const { + if (m_rows != m_columns) + not_implemented (); + + switch (m_rows) { + case 2: return inverse2x2 (); + case 3: return inverse3x3 (); + case 4: return inverse4x4 (); + } + + not_implemented (); +} + + +matrix +matrix::inverse2x2 (void) const { + check (m_rows == 2); + check (m_columns == 2); + + double det = determinant2x2 (); + if (almost_equal (det, 0.)) + throw not_invertible (); + return matrix (2, 2, { (*this)[1][1], -(*this)[0][1], + -(*this)[1][0], (*this)[0][0] }) /= det; +} + + +// [ a, b, c ] +// Given matrix A = [ d, e, f ] +// [ g, h, i ] +// +matrix +matrix::inverse3x3 (void) const { + check (m_rows == 3); + check (m_columns == 3); + + double det = determinant3x3(); + if (almost_equal (det, 0.)) + throw not_invertible (); + + matrix val (m_rows, m_columns, { + (*this)[1][1] * (*this)[2][2] - (*this)[1][2] * (*this)[2][1], // ei - fh + (*this)[0][2] * (*this)[2][1] - (*this)[0][1] * (*this)[2][2], // ch - bi + (*this)[0][1] * (*this)[1][2] - (*this)[0][2] * (*this)[1][1], // bf - ce + (*this)[1][2] * (*this)[2][0] - (*this)[1][0] * (*this)[2][2], // fg - di + (*this)[0][0] * (*this)[2][2] - (*this)[0][2] * (*this)[2][0], // ai - cg + (*this)[0][2] * (*this)[1][0] - (*this)[0][0] * (*this)[1][2], // cd - af + (*this)[1][0] * (*this)[2][1] - (*this)[1][1] * (*this)[2][0], // dh - eg + (*this)[0][1] * (*this)[2][0] - (*this)[0][0] * (*this)[2][1], // bg - ah + (*this)[0][0] * (*this)[1][1] - (*this)[0][1] * (*this)[1][0] // ae - bd + }); + + return val /= det; + + //matrix val ({ vector::cross ((*this)[1], (*this)[2], 3), + // vector::cross ((*this)[2], (*this)[0], 3), + // vector::cross ((*this)[0], (*this)[1], 3) }); + //return val /= determinant3x3 (); +} + + +matrix +matrix::inverse4x4 (void) const { + double a0 = m_data[ 0] * m_data[ 5] - m_data[ 1] * m_data[ 4], + a1 = m_data[ 0] * m_data[ 6] - m_data[ 2] * m_data[ 4], + a2 = m_data[ 0] * m_data[ 7] - m_data[ 3] * m_data[ 4], + a3 = m_data[ 1] * m_data[ 6] - m_data[ 2] * m_data[ 5], + a4 = m_data[ 1] * m_data[ 7] - m_data[ 3] * m_data[ 5], + a5 = m_data[ 2] * m_data[ 7] - m_data[ 3] * m_data[ 6], + b0 = m_data[ 8] * m_data[13] - m_data[ 9] * m_data[12], + b1 = m_data[ 8] * m_data[14] - m_data[10] * m_data[12], + b2 = m_data[ 8] * m_data[15] - m_data[11] * m_data[12], + b3 = m_data[ 9] * m_data[14] - m_data[10] * m_data[13], + b4 = m_data[ 9] * m_data[15] - m_data[11] * m_data[13], + b5 = m_data[10] * m_data[15] - m_data[11] * m_data[14]; + + double det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; + if (almost_equal (det, 0.)) + throw not_invertible (); + + return matrix (4, 4, { + + m_data[ 5] * b5 - m_data[ 6] * b4 + m_data[ 7] * b3, + - m_data[ 1] * b5 + m_data[ 2] * b4 - m_data[ 3] * b3, + + m_data[13] * a5 - m_data[14] * a4 + m_data[15] * a3, + - m_data[ 9] * a5 + m_data[10] * a4 - m_data[11] * a3, + - m_data[ 4] * b5 + m_data[ 6] * b2 - m_data[ 7] * b1, + + m_data[ 0] * b5 - m_data[ 2] * b2 + m_data[ 3] * b1, + - m_data[12] * a5 + m_data[14] * a2 - m_data[15] * a1, + + m_data[ 8] * a5 - m_data[10] * a2 + m_data[11] * a1, + + m_data[ 4] * b4 - m_data[ 5] * b2 + m_data[ 7] * b0, + - m_data[ 0] * b4 + m_data[ 1] * b2 - m_data[ 3] * b0, + + m_data[12] * a4 - m_data[13] * a2 + m_data[15] * a0, + - m_data[ 8] * a4 + m_data[ 9] * a2 - m_data[11] * a0, + - m_data[ 4] * b3 + m_data[ 5] * b1 - m_data[ 6] * b0, + + m_data[ 0] * b3 - m_data[ 1] * b1 + m_data[ 2] * b0, + - m_data[12] * a3 + m_data[13] * a1 - m_data[14] * a0, + + m_data[ 8] * a3 - m_data[ 9] * a1 + m_data[10] * a0 + }) /= det; +} + + + +matrix +matrix::zeroes (size_t diag) + { return zeroes (diag, diag); } + + +matrix +matrix::zeroes (size_t rows, size_t columns) { + matrix m (rows, columns); + std::fill (m.m_data, m.m_data + m.size (), 0.0); + return m; +} + + +matrix +matrix::identity (size_t diag) { + matrix val (zeroes (diag)); + for (unsigned int i = 0; i < diag; ++i) + val[i][i] = 1.0; + return val; +} + + +matrix +matrix::magic (size_t n) { + check_hard (n > 2); + + if (n % 2 == 1) + return magic_odd (n); + + if (n % 4 == 0) + return magic_even_single (n); + + return magic_even_double (n); +} + + +// Use the 'siamese' method. Start from the top centre, progress up-left one. +// If filled then drop down one row instead. Wrap around indexing. +matrix +matrix::magic_odd (size_t n) { + check_hard (n > 2); + check_hard (n % 2 == 1); + + matrix val (zeroes (n)); + for (unsigned int i = 1, x = n / 2, y = 0; i <= n * n; ++i) { + val[y][x] = i; + + unsigned int x1 = (x + 1) % n, + y1 = (y + n - 1) % n; + + if (!almost_equal (val[y1][x1], 0)) { + x1 = x; + y1 = (y + 1) % n; + } + + x = x1; + y = y1; + } + + return val; +} + + +matrix +matrix::magic_even_single (size_t) + { not_implemented (); } + + +matrix +matrix::magic_even_double (size_t) + { not_implemented (); } + diff --git a/matrix.hpp b/matrix.hpp new file mode 100644 index 00000000..18f9b071 --- /dev/null +++ b/matrix.hpp @@ -0,0 +1,119 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __UTIL_MATRIX_HPP +#define __UTIL_MATRIX_HPP + +#include "vector.hpp" + +#include +#include +#include +#include +#include + +namespace maths { + class matrix { + protected: + size_t m_rows, + m_columns; + double *restrict m_data; + + public: + matrix (size_t _rows, size_t _columns); + + matrix (size_t _rows, + size_t _columns, + const std::initializer_list &_data); + matrix (const std::initializer_list &_data); + + matrix (const matrix &rhs); + matrix (matrix &&rhs); + + ~matrix(); + + void sanity (void) const; + + const double * operator [] (unsigned int row) const; + double * operator [] (unsigned int row); + + const double * data (void) const; + + matrix& operator =(const matrix &rhs); + matrix operator * (double scalar) const; + matrix& operator *=(double scalar); + matrix operator * (const matrix &rhs) const; + matrix& operator *=(const matrix &rhs); + matrix& operator /=(double scalar); + matrix operator + (double scalar) const; + matrix& operator +=(double scalar); + matrix& operator -=(double scalar); + bool operator ==(const matrix &rhs) const; + + //matrix transpose (void) const { ; } + + size_t rows (void) const; + size_t columns (void) const; + size_t size (void) const; + + /// Checks if this is a sqaure matrix, with a zero final column + /// and row (excepting the final diagonal entry). + bool is_homogeneous (void) const; + bool is_square (void) const; + bool is_magic (void) const; + public: + double determinant (void) const; + matrix inverse (void) const; + + protected: + double determinant2x2 (void) const; + double determinant3x3 (void) const; + double determinant4x4 (void) const; + + matrix inverse2x2 (void) const; + matrix inverse3x3 (void) const; + matrix inverse4x4 (void) const; + + public: + static matrix zeroes (size_t n); + static matrix zeroes (size_t rows, size_t columns); + static matrix identity (size_t n); + + /// Generate a magic square of order 'n' + static matrix magic (size_t n); + + protected: + /// Generate a magic square with 'n' odd + static matrix magic_odd (size_t n); + /// Generate a magic square with 'n' divisible by 2, and not 4 + static matrix magic_even_single (size_t n); + /// Generate a magic square with 'n' divisible by 4, and not 2 + static matrix magic_even_double (size_t n); + }; + + class not_invertible : public std::runtime_error { + public: + not_invertible (): + std::runtime_error ("not_invertible") + { ; } + }; +} + + +#endif diff --git a/nocopy.hpp b/nocopy.hpp new file mode 100644 index 00000000..f8327427 --- /dev/null +++ b/nocopy.hpp @@ -0,0 +1,34 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __NOCOPY_HPP +#define __NOCOPY_HPP + +#include "debug.hpp" + +class nocopy { + public: + nocopy () { ; } + + private: + nocopy (const nocopy &) { ; } + nocopy& operator =(const nocopy &) { unreachable (); } +}; + +#endif diff --git a/noncopyable.hpp b/noncopyable.hpp new file mode 100644 index 00000000..56302501 --- /dev/null +++ b/noncopyable.hpp @@ -0,0 +1,23 @@ +// Derived from boost::noncopyable +// +// (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Contributed by Dave Abrahams + +#ifndef __UTIL_NONCOPYABLE_HPP +#define __UTIL_NONCOPYABLE_HPP + +class noncopyable +{ + protected: + noncopyable() {} + ~noncopyable() {} + + private: // emphasize the following members are private + noncopyable( const noncopyable& ); + const noncopyable& operator=( const noncopyable& ); +}; + +#endif diff --git a/range.cpp b/range.cpp new file mode 100644 index 00000000..f352093f --- /dev/null +++ b/range.cpp @@ -0,0 +1,120 @@ +#include "range.hpp" + +#include "debug.hpp" +#include "maths.hpp" + +#include +#include + + +using namespace std; + + +/* + * Range + */ + + +template +range::range (const json::node &node) { + if (node.is_string () && (node.to_string () == "UNIT" || + node.to_string () == "unit")) { + min = UNIT.min; + max = UNIT.max; + } else if (node.is_string () && (node.to_string () == "UNLIMITED" || + node.to_string () == "unlimited")) { + min = UNLIMITED.min; + max = UNLIMITED.max; + } else { + min = node.to_array ()[0].to_number (); + max = node.to_array ()[0].to_number (); + } + + sanity (); +} + + +template +range::range (T _min, T _max): + min (_min), + max (_max) + { sanity (); } + + +template +bool +range::includes (T val) const + { return val >= min && val <= max; } + + +template +bool +range::includes (const range &r) const + { return r.min >= min && r.max <= max; } + + +template +void +range::sanity (void) const + { check (min <= max); } + + +template +T +range::clamp (T val) const + { return std::max (min, std::min (val, max)); } + + +template +double +range::normalise (T val) const { + return ((double)val - min) / + ((double)max - min); +} + + +template +T +range::rand (void) const { + double pos = ::rand () / (double)(RAND_MAX); + return (max - min) * pos; +} + + +template <> +bool +range::operator ==(const range &rhs) const + { return almost_equal (min, rhs.min) && + almost_equal (max, rhs.max); } + + +template <> +bool +range::operator ==(const range &rhs) const + { return almost_equal (min, rhs.min) && + almost_equal (max, rhs.max); } + + +template +bool +range::operator ==(const range &rhs) const + { return min == rhs.min && max == rhs.max; } + + +template +const range +range::UNLIMITED (numeric_limits ::is_integer ? numeric_limits ::min () : + -numeric_limits ::infinity (), + numeric_limits ::is_integer ? numeric_limits ::max () : + numeric_limits ::infinity ()); + + +template +const range +range::UNIT (0.0, 1.0); + + +template struct range; +template struct range; +template struct range; +template struct range; diff --git a/range.hpp b/range.hpp new file mode 100644 index 00000000..4e180986 --- /dev/null +++ b/range.hpp @@ -0,0 +1,74 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + + +#ifndef __UTIL_RANGE_HPP +#define __UTIL_RANGE_HPP + +#include "json.hpp" + + +/** + * Represents a continuous range of values. Contains convenience functions + * and debugging checks. + */ +template +struct range { + T min; + T max; + + range (const json::node &node); + range (T _min, T _max); + + /// Check whether value falls within this range (inclusive) + bool includes (T val) const; + /// Check whether a range falls completely within (inclusive) this range + bool includes (const range &r) const; + + /// Return the closest number that falls within the range. + T clamp (T val) const; + + /// Normalise a number to [0, 1] within the range. Does not check bounds. + double normalise (T val) const; + + /// Return a pseudo-random uniformly distributed value within the range. + /// There are no statistical randomness guarantees whatsoever. + T rand (void) const; + + bool operator ==(const range& rhs) const; + bool operator !=(const range& rhs) const + { return !(*this == rhs); } + + /// A range which is guaranteed to contain all elements type T + static const range UNLIMITED; + /// A range which only contains elements between 0 and 1 inclusive + static const range UNIT; + + void sanity (void) const; +}; + + +template +std::ostream& +operator <<(std::ostream &os, const range &rhs) { + os << '[' << rhs.min << ", " << rhs.max << ']'; + return os; +} + +#endif diff --git a/region.cpp b/region.cpp new file mode 100644 index 00000000..aa241073 --- /dev/null +++ b/region.cpp @@ -0,0 +1,86 @@ +#include "region.hpp" + +#include "debug.hpp" + + +/* + * Rect + */ +template +_rect::_rect (const T _width, const T _height): + width (_width), + height (_height) + { ; } + + +template +T +_rect::area (void) const + { return width * height; } + + +template +bool +_rect::empty (void) const + { return area() == 0; } + + +template +bool +_rect::operator ==(const _rect& rhs) const + { return width == rhs.width && height == rhs.height; } + + +template +void +_rect::sanity (void) const + { check (width >= 0 && height >= 0); } + + +// Replace the check, as unsigned types do not ever go negative. This would +// trigger a compile warning if left. +template <> +void +_rect::sanity (void) const + { check (true); } + + +template struct _rect; + +/* + * Region + */ + +template +_region::_region (T _x, T _y, T _width, T _height): + x (_x), + y (_y), + width (_width), + height (_height) +{ ; } + + +template +T +_region::area (void) const + { return width * height; } + + +template +bool +_region::empty (void) const + { return area () == 0; } + + +template +bool +_region::operator ==(const _region& rhs) const + { return x == rhs.x && + y == rhs.y && + width == rhs.width && + height == rhs.height; } + + +template +void _region::sanity (void) const + { check (width >= 0 && height >= 0); } diff --git a/region.hpp b/region.hpp new file mode 100644 index 00000000..104bb766 --- /dev/null +++ b/region.hpp @@ -0,0 +1,68 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + + +#ifndef __UTIL_REGION_HPP +#define __UTIL_REGION_HPP + +/** + * A pure two-dimensional size, without positioning + */ +template +struct _rect { + T width, height; + + _rect (const T _width, const T _height); + + T area (void) const; + bool empty (void) const; + + bool operator ==(const _rect& rhs) const; + bool operator !=(const _rect& rhs) const + { return !(*this == rhs); } + + void sanity (void) const; +}; + +typedef _rect rect; + + +/** + * A two-dimensional rectangle, with size and position. + */ +template +struct _region { + T x, y; + T width, height; + + _region (T _x, T _y, T _width, T _height); + + T area (void) const; + bool empty (void) const; + + bool operator ==(const _region& rhs) const; + bool operator !=(const _region& rhs) const + { return !(*this == rhs); } + + void sanity (void) const; +}; + +typedef _region region; + +#endif diff --git a/stream.cpp b/stream.cpp new file mode 100644 index 00000000..25210f23 --- /dev/null +++ b/stream.cpp @@ -0,0 +1,17 @@ +#include "stream.hpp" + +std::ostream& +nullstream::put (char c) + { return *this; } + + +bool +nullstream::good (void) const + { return !bad () && !eof () && !fail (); } + + +bool nullstream::bad (void) const { return false; } +bool nullstream::eof (void) const { return false; } +bool nullstream::fail (void) const { return false; } + + diff --git a/stream.hpp b/stream.hpp new file mode 100644 index 00000000..a3784e55 --- /dev/null +++ b/stream.hpp @@ -0,0 +1,46 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#ifndef __UTIL_STREAM_HPP +#define __UTIL_STREAM_HPP + +#include + + +class nullstream : public std::ostream { + public: + std::ostream & put (char c); + std::ostream & write (const char *s, std::streamsize n); + + std::streampos tellp (void); + std::ostream & seekp (std::streampos pos); + std::ostream & seekp (std::streamoff off, + std::ios_base::seekdir dir); + + std::ostream & flush (void); + + bool good (void) const; + bool bad (void) const; + bool eof (void) const; + bool fail (void) const; + +}; + + +#endif diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000..5bb89202 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,7 @@ +/backtrace +/float +/range +/maths +/matrix +/version +/json-check diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 00000000..36bf06bf --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,35 @@ +AM_CPPFLAGS = \ + $(COMMON_CXXFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ \ + -I$(top_srcdir)/lib/ + +AM_LDFLAGS = $(COMMON_LDFLAGS) + +TEST_BIN = backtrace float range maths matrix version +TESTS = $(TEST_BIN) json.pl +check_PROGRAMS = $(TEST_BIN) json-check +EXTRA_DIST = json.pl + +backtrace_SOURCES = backtrace.cpp +backtrace_CPPFLAGS = $(COMMON_CXXFLAGS) +backtrace_LDADD = $(top_builddir)/libutil.la $(BOOST_SYSTEM_LIB) + +float_SOURCES = float.cpp +float_LDADD = $(top_builddir)/libutil.la $(BOOST_SYSTEM_LIB) + +range_SOURCES = range.cpp +range_LDADD = $(top_builddir)/libutil.la $(BOOST_SYSTEM_LIB) + +maths_SOURCES = maths.cpp +maths_LDADD = $(top_builddir)/libutil.la $(BOOST_SYSTEM_LIB) + +matrix_SOURCES = matrix.cpp +matrix_LDADD = $(top_builddir)/libutil.la $(BOOST_SYSTEM_LIB) + +version_SOURCES = version.cpp +version_LDADD = $(top_builddir)/libutil.la $(BOOST_SYSTEM_LIB) + +json_check_SOURCES = json-check.cpp +json_check_LDADD = $(top_builddir)/libutil.la $(BOOST_FILESYSTEM_LIB) diff --git a/test/backtrace.cpp b/test/backtrace.cpp new file mode 100644 index 00000000..a85a97d2 --- /dev/null +++ b/test/backtrace.cpp @@ -0,0 +1,12 @@ +#include "../backtrace.hpp" +#include + +using namespace std; + + +int +main (int argc, char **argv) { + cout << debug::backtrace() << endl; + + return EXIT_SUCCESS; +} diff --git a/test/float.cpp b/test/float.cpp new file mode 100644 index 00000000..81b8c45d --- /dev/null +++ b/test/float.cpp @@ -0,0 +1,75 @@ +#include "../float.hpp" + +#include "../debug.hpp" +#include + +using namespace std; + +#define elems(x) (sizeof(x) / sizeof(0[x])) + + +void +test_double (void) { + struct sized_test { + ieee_double::uint_t bits; + double floating; + }; + + sized_test tests[] = { + { 0x3ff0000000000000, 1.0 }, + { 0x3ff0000000000001, 1.0 + numeric_limits::epsilon () }, + { 0x3ff0000000000002, 1.0 + numeric_limits::epsilon () * 2}, + { 0x4000000000000000, 2.0 }, + { 0xc000000000000000, -2.0 }, + { 0x0000000000000001, numeric_limits::denorm_min () }, + { 0x0010000000000000, numeric_limits::min () }, // min positive normal + { 0x7fefffffffffffff, numeric_limits::max () }, // max + { 0x0000000000000000, 0.0 }, + { 0x8000000000000000, -0.0 }, + { 0x7ff0000000000000, numeric_limits::infinity() }, + { 0xfff0000000000000, -numeric_limits::infinity() }, + { 0x3fd5555555555555, 1.0 / 3.0 } + }; + + for (unsigned int i = 0; i < elems (tests); ++i) { + ieee_double val; + val.set_bits (tests[i].bits); + check_hard (val == tests[i].floating); + } +} + + +void +test_single (void) { + struct sized_test { + ieee_single::uint_t bits; + float floating; + }; + + sized_test tests[] = { + { 0x3f800000, 1.0f }, + { 0xc0000000, -2.0f }, + { 0x7f7fffff, numeric_limits::max () }, + + { 0x00000000, 0.0f }, + { 0x80000000, -0.0f }, + + { 0x7f800000, numeric_limits::infinity () }, + { 0xff800000, -numeric_limits::infinity () }, + + { 0x3eaaaaab, 1.0f / 3.0f } + }; + + for (unsigned int i = 0; i < elems (tests); ++i) { + ieee_single val; + val.set_bits (tests[i].bits); + check_hard (val == tests[i].floating); + } +} + + +int +main (int, char **) { + test_single (); + test_double (); +} diff --git a/test/json-check.cpp b/test/json-check.cpp new file mode 100644 index 00000000..e383ce29 --- /dev/null +++ b/test/json-check.cpp @@ -0,0 +1,33 @@ +#include "../json.hpp" + +#include +#include +#include + + +enum { + ARG_CMD, + ARG_PATH, + + NUM_ARGS +}; + + +int +main (int argc, char ** argv) { + if (argc != NUM_ARGS) { + std::cerr << "Invalid arguments. " + << argv[ARG_CMD] << " " + << std::endl; + return EXIT_FAILURE; + } + + try { + json::parse (boost::filesystem::path (argv[ARG_PATH])); + } catch (json::error &x) { + std::cerr << x.what () << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/test/json.pl b/test/json.pl new file mode 100755 index 00000000..c9bf8972 --- /dev/null +++ b/test/json.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +$COMMAND = "./json-check"; + +@good = ; +@bad = ; +$success = 1; + + +sub status_to_str { + $status = shift @_; + return $status ? "failed" : "passed"; +} + + +foreach $testfile(@good) { + $status = system("$COMMAND $testfile &>/dev/null"); + $success &&= $status == 0; + + printf "%s\t%s\n", status_to_str($status), $testfile; +} + + +foreach $testfile(@bad) { + $status = system("$COMMAND $testfile &>/dev/null"); + $success &&= $status != 0; + + printf "%s\t%s\n", status_to_str(!$status), $testfile; +} + +exit !$success diff --git a/test/json/bad/0000_object.json b/test/json/bad/0000_object.json new file mode 100644 index 00000000..98232c64 --- /dev/null +++ b/test/json/bad/0000_object.json @@ -0,0 +1 @@ +{ diff --git a/test/json/bad/0001_object.json b/test/json/bad/0001_object.json new file mode 100644 index 00000000..5c34318c --- /dev/null +++ b/test/json/bad/0001_object.json @@ -0,0 +1 @@ +} diff --git a/test/json/bad/2000_trailing_comma.json b/test/json/bad/2000_trailing_comma.json new file mode 100644 index 00000000..23d1eb03 --- /dev/null +++ b/test/json/bad/2000_trailing_comma.json @@ -0,0 +1,3 @@ +{ + "foo" : [1, ] +} diff --git a/test/json/good/0000_empty.json b/test/json/good/0000_empty.json new file mode 100644 index 00000000..2c63c085 --- /dev/null +++ b/test/json/good/0000_empty.json @@ -0,0 +1,2 @@ +{ +} diff --git a/test/json/good/1000_pair_str.json b/test/json/good/1000_pair_str.json new file mode 100644 index 00000000..10583251 --- /dev/null +++ b/test/json/good/1000_pair_str.json @@ -0,0 +1,3 @@ +{ + "foo" : "bar" +} diff --git a/test/json/good/1001_pair_number.json b/test/json/good/1001_pair_number.json new file mode 100644 index 00000000..b86c093e --- /dev/null +++ b/test/json/good/1001_pair_number.json @@ -0,0 +1,3 @@ +{ + "zero" : 0 +} diff --git a/test/json/good/1002_pair_number.json b/test/json/good/1002_pair_number.json new file mode 100644 index 00000000..74b667f8 --- /dev/null +++ b/test/json/good/1002_pair_number.json @@ -0,0 +1,3 @@ +{ + "neg" : -1 +} diff --git a/test/json/good/1003_pair_number.json b/test/json/good/1003_pair_number.json new file mode 100644 index 00000000..97b10960 --- /dev/null +++ b/test/json/good/1003_pair_number.json @@ -0,0 +1,3 @@ +{ + "pos_low_exp" : 1e-5 +} diff --git a/test/json/good/1004_pair_number.json b/test/json/good/1004_pair_number.json new file mode 100644 index 00000000..61cd15cb --- /dev/null +++ b/test/json/good/1004_pair_number.json @@ -0,0 +1,3 @@ +{ + "pos_high_exp" : 1e5 +} diff --git a/test/json/good/1005_pair_number.json b/test/json/good/1005_pair_number.json new file mode 100644 index 00000000..b5166095 --- /dev/null +++ b/test/json/good/1005_pair_number.json @@ -0,0 +1,3 @@ +{ + "neg_low_exp" : -4e-9 +} diff --git a/test/json/good/1006_pair_number.json b/test/json/good/1006_pair_number.json new file mode 100644 index 00000000..2924a16b --- /dev/null +++ b/test/json/good/1006_pair_number.json @@ -0,0 +1,3 @@ +{ + "neg_high_exp" : 12e15 +} diff --git a/test/json/good/1007_pair_number.json b/test/json/good/1007_pair_number.json new file mode 100644 index 00000000..ca4af5f0 --- /dev/null +++ b/test/json/good/1007_pair_number.json @@ -0,0 +1,3 @@ +{ + "frac" : 1.7e-23 +} diff --git a/test/json/good/1008_bool_true.json b/test/json/good/1008_bool_true.json new file mode 100644 index 00000000..4bc63ace --- /dev/null +++ b/test/json/good/1008_bool_true.json @@ -0,0 +1,3 @@ +{ + "foo" : true +} diff --git a/test/json/good/1009_bool_false.json b/test/json/good/1009_bool_false.json new file mode 100644 index 00000000..c1409cca --- /dev/null +++ b/test/json/good/1009_bool_false.json @@ -0,0 +1,3 @@ +{ + "foo" : false +} diff --git a/test/json/good/1010_null.json b/test/json/good/1010_null.json new file mode 100644 index 00000000..fd37e622 --- /dev/null +++ b/test/json/good/1010_null.json @@ -0,0 +1,3 @@ +{ + "foo" : null +} diff --git a/test/json/good/2000_array.json b/test/json/good/2000_array.json new file mode 100644 index 00000000..1134791e --- /dev/null +++ b/test/json/good/2000_array.json @@ -0,0 +1,3 @@ +{ + "numbers" : [0, 1, 2, 3] +} diff --git a/test/json/good/3000_object.json b/test/json/good/3000_object.json new file mode 100644 index 00000000..009fcb0c --- /dev/null +++ b/test/json/good/3000_object.json @@ -0,0 +1,5 @@ +{ + "obj" : { + "foo": "bar" + } +} diff --git a/test/maths.cpp b/test/maths.cpp new file mode 100644 index 00000000..4882b43e --- /dev/null +++ b/test/maths.cpp @@ -0,0 +1,25 @@ +#include "../debug.hpp" +#include "../maths.hpp" + +#include +#include + + +using std::sqrt; + + +int +main (int, char **) { + check_hard (!almost_equal (-2.0, 0.0)); + check_hard (!almost_equal (-2.f, 0.f)); + + check_eq (min (-2, 0, 2), -2); + check_eq (max (-2, 0, 2), 2); + + check_eq (pow2 (2), 4); + check_eq (pow2 (4), 16); + + check_eq (rootsquare (2, 2), sqrt (8)); + + return EXIT_SUCCESS; +} diff --git a/test/matrix.cpp b/test/matrix.cpp new file mode 100644 index 00000000..0f36df4f --- /dev/null +++ b/test/matrix.cpp @@ -0,0 +1,132 @@ +#include "../debug.hpp" +#include "../matrix.hpp" +#include "../maths.hpp" + +#include +#include + +using namespace maths; +using namespace std; + + +std::ostream& +operator <<(std::ostream &os, const matrix &m) { + for (unsigned int i = 0; i < m.rows (); ++i) { + for (unsigned int j = 0; j < m.columns (); ++j) { + os << m[i][j]; + if (j != m.columns () - 1) + os << ", "; + } + + if (i != m.rows () - 1) + os << "\n"; + } + + return os; +} + + +void +test_zeroes (const matrix &m) { + assert (m.rows ()); + assert (m.columns ()); + + for (unsigned int i = 0; i < m.rows (); ++i) + for (unsigned int j = 0; j < m.columns (); ++j) + check_hard (almost_equal (m[i][j], 0.0)); +} + + +void +test_identity (const matrix &m) { + assert (m.rows () == m.columns ()); + + for (unsigned int i = 0; i < m.rows (); ++i) + for (unsigned int j = 0; j < m.columns (); ++j) + if (i == j) + check_hard (almost_equal (m[i][j], 1.0)); + else + check_hard (almost_equal (m[i][j], 0.0)); +} + + +int +main (int, char **) { + for (unsigned int i = 1; i < 10; ++i) { + test_zeroes (matrix::zeroes (i)); + test_identity (matrix::identity (i)); + } + + for (unsigned int i = 3; i < 10; i += 2) + check (matrix::magic (i).is_magic ()); + + // Create a small matrix with unique element values for comparison tests. + // This should be non-square so that row- vs. column-major problems can + // be seen. + matrix a4x2 (4, 2, { 0, 1, + 2, 3, + 4, 5, + 6, 7 }); + check_eq (a4x2, a4x2); + + // Test that copy constructors work correctly. Keep this value around so + // that we can check the following operators don't modify the original + // value. + check_eq (a4x2, matrix(a4x2)); + + // Check multiplication by identity results in the original value. + check_eq (a4x2, a4x2 * matrix::identity (a4x2.columns ())); + + matrix seq2x2(2, 2, { 1, 2, 3, 4 }); + matrix magic3(3, 3, { 2, 7, 6, + 9, 5, 1, + 4, 3, 8 }); + + matrix magic4(4, 4, { 16, 2, 3, 13, + 5, 11, 10, 8, + 9, 7, 6, 12, + 4, 14, 15, 1 }); + + + check_eq (magic3[0][0], 2.0); + check_eq (magic3[0][1], 7.0); + check_eq (magic3[0][2], 6.0); + check_eq (magic3[1][0], 9.0); + check_eq (magic3[1][1], 5.0); + check_eq (magic3[1][2], 1.0); + check_eq (magic3[2][0], 4.0); + check_eq (magic3[2][1], 3.0); + check_eq (magic3[2][2], 8.0); + + check_eq (seq2x2.determinant (), -2.0); + check_eq (magic3.determinant (), -360.0); + + check_hard ( seq2x2.is_square ()); + check_hard ( magic3.is_square ()); + check_hard (! a4x2.is_square ()); + + check_eq (seq2x2.inverse (), matrix (2, 2, { -2.0, 1.0, + 1.5, -0.5 })); + check_eq (magic3.inverse (), matrix (3, 3, { -37.0, 38.0, 23.0, + 68.0, 8.0, -52.0, + - 7.0, -22.0, 53.0 }) /= 360.0); + + matrix invertible4 (4, 4, { 4, 14, 15, 1, + 9, 7, 6, 12, + 5, 11, 10, 8, + 0, 0, 0, 1 }); + check_eq (invertible4.inverse (), matrix (4, 4, { 4, 25, -21, -136, + -60, -35, 111, -408, + 64, 26, -98, 408, + 0, 0, 0, 136 }) /= 136); + + const matrix homo3x3 (3, 3, { 1, 2, 0, + 3, 4, 0, + 0, 0, 1 }); + check_hard (homo3x3.is_homogeneous ()); + check_hard (!matrix::zeroes (3).is_homogeneous ()); + check_hard ( matrix::identity (3).is_homogeneous ()); + check_hard (invertible4.is_homogeneous ()); + + return EXIT_SUCCESS; +} diff --git a/test/range.cpp b/test/range.cpp new file mode 100644 index 00000000..576f2976 --- /dev/null +++ b/test/range.cpp @@ -0,0 +1,31 @@ +#include +#include + +#include "../debug.hpp" +#include "../range.hpp" + +using namespace std; + +int +main (int, char **) { + check_hard ( range::UNIT.includes ( 0.0)); + check_hard ( range::UNIT.includes ( 0.5)); + check_hard ( range::UNIT.includes ( 1.0)); + check_hard (!range::UNIT.includes (-0.00001)); + check_hard (!range::UNIT.includes ( 1.00001)); + + check_hard ( range::UNIT.includes (0)); + check_hard ( range::UNIT.includes (1)); + check_hard (!range::UNIT.includes (2)); + check_hard (!range::UNIT.includes (numeric_limits ::max ())); + + check_hard ( range::UNLIMITED.includes (0.0)); + check_hard ( range::UNLIMITED.includes (+numeric_limits::infinity ())); + check_hard ( range::UNLIMITED.includes (-numeric_limits::infinity ())); + check_hard (!range::UNLIMITED.includes ( numeric_limits::quiet_NaN ())); + + check_hard ( range::UNLIMITED.includes (numeric_limits::min())); + check_hard ( range::UNLIMITED.includes (numeric_limits::max())); + return EXIT_SUCCESS; +} + diff --git a/test/version.cpp b/test/version.cpp new file mode 100644 index 00000000..c8ccc22f --- /dev/null +++ b/test/version.cpp @@ -0,0 +1,50 @@ + +#include +#include + +using namespace std; + + +#include "../version.hpp" +#include "../debug.hpp" + + +struct parsed_version { + string str; + vector parts; +}; + + +int +main (int, char **) { + vector tests ({ + { "1", { 1 } }, + + { "1.2", { 1, 2 } }, + { "1.2.3", { 1, 2, 3 } }, + { "1.2.3.4", { 1, 2, 3, 4 } }, + + { "9.5a", { 9, 5 } }, + { "8.2.5b", { 8, 2, 5 } }, + + /* + { "1.4.1-p8", { 1, 4, 1 } }, + { "4.2.0-r4", { 4, 2, 0 } }, + + { "1.4 RC1", { 1, 4 } } + */ + }); + + for (auto i = tests.begin (); i != tests.end (); ++i) { + version v (i->str); + + if (i->parts.size () > 0) check (v.major () == i->parts[0]); + if (i->parts.size () > 1) check (v.minor () == i->parts[1]); + if (i->parts.size () > 2) check (v.point () == i->parts[2]); + if (i->parts.size () > 3) check (v.build () == i->parts[3]); + + check_hard (i->parts.size () <= 4); + } + + return EXIT_SUCCESS; +} diff --git a/types.cpp b/types.cpp new file mode 100644 index 00000000..82b72f61 --- /dev/null +++ b/types.cpp @@ -0,0 +1,12 @@ +#include "types.hpp" + +using namespace std; + + +#define do_type_to_string(T) \ +template <> std::string type_to_string (void) { return #T; } \ +template <> std::string type_to_string (void) { return "const " #T; } + +do_type_to_string (float) +do_type_to_string (double) + diff --git a/types.hpp b/types.hpp new file mode 100644 index 00000000..f101a529 --- /dev/null +++ b/types.hpp @@ -0,0 +1,56 @@ +#ifndef __TYPES_HPP +#define __TYPES_HPP + +#include +#include + +template +struct bits_type; + + +template <> struct bits_type< 8> { + static const bool has_floating = false; + + typedef uint8_t uint; + typedef int8_t sint; + typedef uint8_t floating; +}; + + +template <> struct bits_type<16> { + static const bool has_floating = false; + + typedef uint16_t uint; + typedef int16_t sint; + typedef uint16_t floating; +}; + + +template <> struct bits_type<32> { + static const bool has_floating = true; + + typedef uint32_t uint; + typedef int32_t sint; + typedef float floating; +}; + + +template <> struct bits_type<64> { + static const bool has_floating = true; + + typedef uint64_t uint; + typedef int64_t sint; + typedef double floating; +}; + + +template +struct sized_type : public bits_type +{ }; + + +template +std::string type_to_string (void); + + +#endif // __TYPES_HPP diff --git a/vector.cpp b/vector.cpp new file mode 100644 index 00000000..b9bb5164 --- /dev/null +++ b/vector.cpp @@ -0,0 +1,80 @@ +#include "vector.hpp" + +#include "debug.hpp" + +#include + + +using namespace maths; + + +/* Constructors */ + +vector::vector (const std::initializer_list &_data): + m_data (_data) +{ ; } + + +vector::vector (unsigned int _size): + m_data (_size) +{ ; } + + +vector::vector (const double *restrict _data, + unsigned int _size): + m_data (_size) +{ std::copy (_data, _data + _size, m_data.begin ()); } + + +vector::vector (const vector &rhs): + m_data (rhs.m_data) +{ ; } + + +vector::vector (const vector &&rhs): + m_data (std::move (rhs.m_data)) +{ ; } + + +vector::~vector (void) +{ ; } + + +/* element accessors */ + +const double* +vector::data (void) const + { return &m_data[0]; } + + +double & +vector::operator[] (unsigned int offset) + { return m_data[offset]; } + + +const double& +vector::operator[] (unsigned int offset) const + { return m_data[offset]; } + + +unsigned int +vector::size (void) const + { return m_data.size (); } + + +/* dot and cross products */ + +double vector::dot (const double *restrict A, + const double *restrict B, + unsigned int size) +{ return std::inner_product(A, A + size, B, 0.0); } + + +vector vector::cross (const double *restrict A, + const double *restrict B, + unsigned int size) { + check_hard (size == 3); + return vector ({ A[1] * B[2] - A[2] * B[1], + A[2] * B[0] - A[0] * B[2], + A[0] * B[1] - A[1] * B[0] }); +} diff --git a/vector.hpp b/vector.hpp new file mode 100644 index 00000000..ea14b126 --- /dev/null +++ b/vector.hpp @@ -0,0 +1,61 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#ifndef __UTIL_VECTOR_HPP +#define __UTIL_VECTOR_HPP + +#include +#include + +namespace maths { + class vector { + protected: + std::vector m_data; + + public: + vector (const std::initializer_list &_data); + explicit + vector (unsigned int _size); + vector (const double *restrict _data, + unsigned int _size); + + vector (const vector &rhs); + vector (const vector &&rhs); + + ~vector (void); + + const double* data (void) const; + double& operator[] (unsigned int); + const double& operator[] (unsigned int) const; + + unsigned int size (void) const; + + + static double dot (const double *restrict A, + const double *restrict B, + unsigned int size); + + static vector cross (const double *restrict A, + const double *restrict B, + unsigned int size); + }; +} + + +#endif diff --git a/version.cpp.rl b/version.cpp.rl new file mode 100644 index 00000000..e413dd35 --- /dev/null +++ b/version.cpp.rl @@ -0,0 +1,134 @@ +#include "version.hpp" + +#include + +#include "debug.hpp" + + +using namespace std; + + +version::version (unsigned int _major, + unsigned int _minor): + m_values (2), + m_release (RELEASE_PRODUCTION) { + m_values[OFFSET_MAJOR] = _major; + m_values[OFFSET_MINOR] = _minor; +} + + +version::version (const string& str): + m_values (NUM_OFFSETS, 0), + m_release (RELEASE_PRODUCTION) { + m_values.clear (); + parse (str); +} + + +static void +check_release (version::release_t r) { + switch (r) { + case version::RELEASE_ALPHA: + case version::RELEASE_BETA: + case version::RELEASE_GAMMA: + case version::RELEASE_PRODUCTION: + return; + } + + panic ("invalid release_t value"); +} + + +void +version::sanity (void) const { + check_release (m_release); + check (!m_values.empty ()); +} + + +%%{ + machine version; + + action clear + { current = 0; } + action increment + { current *= 10; + current += (uintptr_t)(fc - (unsigned char)'0'); } + action finish + { m_values.push_back (current); } + + number = (digit+) + >clear + $increment + %finish; + + dots = (number '.')* number; + + type = ('beta'i | 'b'i) %{ m_release = RELEASE_BETA; } + | ('alpha'i | 'a'i) %{ m_release = RELEASE_ALPHA; } + | ('gamma'i | 'g'i) %{ m_release = RELEASE_GAMMA; }; + + version := (dots type?) + $!{ throw invalid_argument (str); }; + + write data; +}%% + + +void +version::parse (const string& str) { + unsigned int current; + + int cs; + const char *p = str.data (), + *pe = str.data () + str.size (), + *eof = pe; + + %%write init; + %%write exec; +} + + +static string +release_string (const version::release_t r) { + switch (r) { + case (version::RELEASE_ALPHA): return "a"; + case (version::RELEASE_BETA): return "b"; + case (version::RELEASE_GAMMA): return "g"; + case (version::RELEASE_PRODUCTION): return ""; + } + + panic ("invalid release_t"); +} + + +bool +version::operator > (const version &rhs) const { + unsigned int count = min (m_values.size (), rhs.m_values.size ()); + + for (unsigned int i = 0; i < count; ++i) + if (m_values[i] < rhs.m_values[i]) + return false; + + if (m_values.size () < rhs.m_values.size()) + return false; + + if (m_release <= rhs.m_release) + return false; + + return true; +} + + +ostream& +operator <<(ostream& os, const version& rhs) { + auto i = rhs.m_values.begin(); + os << *i; ++i; + + for (; i != rhs.m_values.end(); ++i) + os << '.' << *i; + + os << release_string (rhs.m_release); + return os; +} + diff --git a/version.hpp b/version.hpp new file mode 100644 index 00000000..b9b965c0 --- /dev/null +++ b/version.hpp @@ -0,0 +1,86 @@ +/* + * This file is part of waif. + * + * Waif is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * Waif is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with waif. If not, see . + * + * Copyright 2010 Danny Robson + */ + +#ifndef __VERSION_HPP +#define __VERSION_HPP + +#include +#include +#include + + +class version { + public: + enum release_t { + RELEASE_ALPHA, + RELEASE_BETA, + RELEASE_GAMMA, + RELEASE_PRODUCTION + }; + + version (unsigned int _major, + unsigned int _minor); + version (const std::string& str); + virtual ~version () { ; } + + virtual void sanity (void) const; + + protected: + enum { + OFFSET_MAJOR = 0, + OFFSET_MINOR = 1, + OFFSET_POINT = 2, + OFFSET_BUILD = 3, + + NUM_OFFSETS + }; + + std::vector m_values; + release_t m_release; + + void parse (const std::string&); + + public: + + unsigned int major (void) const + { return m_values[OFFSET_MAJOR]; } + unsigned int minor (void) const + { return m_values[OFFSET_MINOR]; } + unsigned int point (void) const + { return m_values[OFFSET_POINT]; } + unsigned int build (void) const + { return m_values[OFFSET_BUILD]; } + + bool operator < (const version& rhs) const; + bool operator > (const version& rhs) const; + bool operator >= (const version& rhs) const; + bool operator <= (const version& rhs) const; + bool operator == (const version& rhs) const + { return m_values == rhs.m_values && + m_release == rhs.m_release; } + + friend std::ostream& + operator <<(std::ostream& os, const version& rhs); +}; + + +std::ostream& +operator <<(std::ostream& os, const version& rhs); + +#endif // __VERSION_HPP