diff --git a/dlib/CMakeLists.txt b/dlib/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa1901fbb2fc1d185ae17be34dc0124a3b8ce5c8 --- /dev/null +++ b/dlib/CMakeLists.txt @@ -0,0 +1,151 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# + +# setting this makes CMake allow normal looking IF ELSE statements +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +# make macros that can add #define directives to the entire project. Not just +# to the dlib library itself. I.e. to dlib and to any projects that depend +# on dlib. +MACRO ( add_global_define def_name ) + if (NOT CMAKE_CXX_FLAGS MATCHES "-D${def_name}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${def_name}" + CACHE STRING "Flags used by the compiler during all C++ builds." + FORCE) + endif () +ENDMACRO() +MACRO ( remove_global_define def_name ) + if (CMAKE_CXX_FLAGS MATCHES " -D${def_name}") + string (REGEX REPLACE " -D${def_name}" "" temp_var ${CMAKE_CXX_FLAGS}) + set (CMAKE_CXX_FLAGS "${temp_var}" + CACHE STRING "Flags used by the compiler during all C++ builds." + FORCE) + endif () +ENDMACRO() + + +# Make sure ENABLE_ASSERTS is defined for debug builds +if (NOT CMAKE_CXX_FLAGS_DEBUG MATCHES "-DENABLE_ASSERTS") + set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLE_ASSERTS" + CACHE STRING "Flags used by the compiler during C++ debug builds." + FORCE) +endif () + +set (DLIB_ISO_CPP_ONLY_STR +"Enable this if you don't want to compile any non-ISO C++ code (i.e. you don't use any of the API Wrappers)" ) +set (DLIB_NO_GUI_SUPPORT_STR +"Enable this if you don't want to compile any of the dlib GUI code" ) + +OPTION(DLIB_ISO_CPP_ONLY ${DLIB_ISO_CPP_ONLY_STR} OFF) +OPTION(DLIB_NO_GUI_SUPPORT ${DLIB_NO_GUI_SUPPORT_STR} OFF) + + +add_library(dlib all/source.cpp ) + + +IF (NOT DLIB_ISO_CPP_ONLY) + # we want to link to the right stuff depending on our platform. + IF (WIN32) ############################################################################### + if (DLIB_NO_GUI_SUPPORT) + set (dlib_needed_libraries ws2_32) + else() + set (dlib_needed_libraries ws2_32 comctl32 gdi32) + endif() + ELSEIF(APPLE) ############################################################################ + FIND_LIBRARY(pthreadlib pthread) + set (dlib_needed_libraries ${pthreadlib}) + + if (NOT DLIB_NO_GUI_SUPPORT) + FIND_LIBRARY(xlib X11) + # make sure X11 is in the include path + FIND_PATH(xlib_path Xlib.h + PATHS + /Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include + PATH_SUFFIXES X11 + ) + if (xlib AND xlib_path) + GET_FILENAME_COMPONENT(x11_path ${xlib_path} PATH CACHE) + INCLUDE_DIRECTORIES(${x11_path}) + set(dlib_needed_libraries ${dlib_needed_libraries} ${xlib} ) + else() + message(" ***********************************************************************************") + message(" ****** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ******") + message(" ****** Make sure libx11-dev is installed if you want GUI support ******") + message(" ***********************************************************************************") + set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE ) + endif() + endif() + + MARK_AS_ADVANCED(pthreadlib xlib xlib_path x11_path) + ELSE () ################################################################################## + FIND_LIBRARY(pthreadlib pthread) + set (dlib_needed_libraries ${pthreadlib}) + + # link to the nsl library if it exists. this is something you need sometimes + FIND_LIBRARY(nsllib nsl) + if (nsllib) + set (dlib_needed_libraries ${dlib_needed_libraries} ${nsllib}) + endif () + + # link to the socket library if it exists. this is something you need on solaris + FIND_LIBRARY(socketlib socket) + if (socketlib) + set (dlib_needed_libraries ${dlib_needed_libraries} ${socketlib}) + endif () + + if (NOT DLIB_NO_GUI_SUPPORT) + INCLUDE(FindX11) + if (X11_FOUND) + INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR}) + set (dlib_needed_libraries ${dlib_needed_libraries} ${X11_LIBRARIES}) + else() + message(" ***********************************************************************************") + message(" ****** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ******") + message(" ****** Make sure libx11-dev is installed if you want GUI support ******") + message(" ***********************************************************************************") + set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE ) + endif() + endif() + + MARK_AS_ADVANCED(nsllib pthreadlib socketlib) + ENDIF () ################################################################################# + + + INCLUDE(FindPNG) + if (PNG_FOUND) + INCLUDE_DIRECTORIES(${PNG_PNG_INCLUDE_DIR}) + set (dlib_needed_libraries ${dlib_needed_libraries} ${PNG_LIBRARY}) + add_global_define(DLIB_PNG_SUPPORT) + else() + # we could print a message but doing so is sort of irritating when it occurs by default + #message(" *************************************************************************") + #message(" ****** PNG IMAGE FILE SUPPORT NOT ENABLED BECAUSE libpng NOT FOUND ******") + #message(" ****** Make sure libpng is installed if you want PNG support ******") + #message(" *************************************************************************") + endif() + + TARGET_LINK_LIBRARIES(dlib ${dlib_needed_libraries} ) + +ENDIF () + + +#test for some things that really should be true about the compiler +INCLUDE(TestForSTDNamespace) +INCLUDE(TestForANSIStreamHeaders) + + +if (DLIB_ISO_CPP_ONLY) + set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE ) + add_global_define(DLIB_ISO_CPP_ONLY) +else() + remove_global_define(DLIB_ISO_CPP_ONLY) +endif() + + +if (DLIB_NO_GUI_SUPPORT) + add_global_define(DLIB_NO_GUI_SUPPORT) +else() + remove_global_define(DLIB_NO_GUI_SUPPORT) +endif() diff --git a/dlib/LICENSE.txt b/dlib/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..127a5bc39ba030c7cb99cc0aedc4f280ffe27310 --- /dev/null +++ b/dlib/LICENSE.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/dlib/README.txt b/dlib/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2091d475af813fa9516bad4ba42f51df7149bab --- /dev/null +++ b/dlib/README.txt @@ -0,0 +1,38 @@ + + dlib C++ library + +This project is a modern C++ library with a focus on portability +and program correctness. It strives to be easy to use right and +hard to use wrong. Thus, it comes with extensive documentation and +thorough debugging modes. The library provides a platform abstraction +layer for common tasks such as interfacing with network services, +handling threads, or creating graphical user interfaces. Additionally, +the library implements many useful algorithms such as data compression +routines, linked lists, binary search trees, linear algebra and matrix +utilities, machine learning algorithms, XML and text parsing, and many +other general utilities. + +Documentation: + There should be HTML documentation accompanying this library. But + if there isn't you can download it from http://dclib.sourceforge.net + +Installation : + To use this library all you have to do is extract the library + somewhere, make sure the folder *containing* the dlib folder is in + your include path, and finally add dlib/all/source.cpp to your + project. + + An example makefile that uses this library can be found here: + dlib/test/makefile. It is the makefile used to build the regression + test suite for this library. There is also a CMake makefile that + builds the regression test suite at dlib/test/CMakeLists.txt and + another CMake makefile that builds all the example programs in + the examples folder. + + For further information see the accompanying HTML documentation or + visit http://dclib.sourceforge.net + +The license for this library can be found in LICENSE.txt. But the +long and short of the license is that you can use this code however +you like, even in closed source commercial software. + diff --git a/dlib/algs.h b/dlib/algs.h new file mode 100644 index 0000000000000000000000000000000000000000..fec9275645fe9b252fddd46328bae880cc9a2133 --- /dev/null +++ b/dlib/algs.h @@ -0,0 +1,503 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ALGs_ +#define DLIB_ALGs_ + +// this file contains miscellaneous stuff + + +#include // for std::swap +#include // for std::bad_alloc +#include // for the exceptions +#include +#include "platform.h" +#include "assert.h" +#include "error.h" +#include "noncopyable.h" +#include "enable_if.h" +#include "uintn.h" + + + +#ifdef _MSC_VER +// Disable the following warnings for Visual Studio + +// this is to disable the "'this' : used in base member initializer list" +// warning you get from some of the GUI objects since all the objects +// require that their parent class be passed into their constructor. +// In this case though it is totally safe so it is ok to disable this warning. +#pragma warning(disable : 4355) + +// This is a warning you get sometimes when Visual Studio performs a Koenig Lookup. +// This is a bug in visual studio. It is a totally legitimate thing to +// expect from a compiler. +#pragma warning(disable : 4675) + +// This is a warning you get from visual studio 2005 about things in the standard C++ +// library being "deprecated." I checked the C++ standard and it doesn't say jack +// about any of them (I checked the searchable PDF). So this warning is total Bunk. +#pragma warning(disable : 4996) + +// This is a warning you get from visual studio 2003: +// warning C4345: behavior change: an object of POD type constructed with an initializer +// of the form () will be default-initialized. +// I love it when this compiler gives warnings about bugs in previous versions of itself. +#pragma warning(disable : 4345) +#endif + +#ifdef __BORLANDC__ +// Disable the following warnings for the Borland Compilers +// +// These warnings just say that the compiler is refusing to inline functions with +// loops or try blocks in them. +// +#pragma option -w-8027 +#pragma option -w-8026 +#endif + + +// ---------------------------------------------------------------------------------------- +/*!A _dT !*/ + +template +inline const charT _dTcast (const char a, const wchar_t b); +template <> +inline const char _dTcast (const char a, const wchar_t ) { return a; } +template <> +inline const wchar_t _dTcast (const char , const wchar_t b) { return b; } + +template +inline const charT* _dTcast ( const char* a, const wchar_t* b); +template <> +inline const char* _dTcast ( const char* a, const wchar_t* ) { return a; } +template <> +inline const wchar_t* _dTcast ( const char* , const wchar_t* b) { return b; } + + +#define _dT(charT,str) _dTcast(str,L##str) +/*! + requires + - charT == char or wchar_t + - str == a string or character literal + ensures + - returns the literal in the form of a charT type literal. +!*/ + +// ---------------------------------------------------------------------------------------- + + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*!A swap !*/ + // make swap available in the dlib namespace + using std::swap; + +// ---------------------------------------------------------------------------------------- + + /*! + Here is where I define my return codes. It is + important that they all be < 0. + !*/ + + enum general_return_codes + { + TIMEOUT = -1, + WOULDBLOCK = -2, + OTHER_ERROR = -3, + SHUTDOWN = -4, + PORTINUSE = -5 + }; + +// ---------------------------------------------------------------------------------------- + + inline unsigned long square_root ( + unsigned long value + ) + /*! + requires + - value <= 2^32 - 1 + ensures + - returns the square root of value. if the square root is not an + integer then it will be rounded up to the nearest integer. + !*/ + { + unsigned long x; + + // set the initial guess for what the root is depending on + // how big value is + if (value < 3) + return value; + else if (value < 4096) // 12 + x = 45; + else if (value < 65536) // 16 + x = 179; + else if (value < 1048576) // 20 + x = 717; + else if (value < 16777216) // 24 + x = 2867; + else if (value < 268435456) // 28 + x = 11469; + else // 32 + x = 45875; + + + + // find the root + x = (x + value/x)>>1; + x = (x + value/x)>>1; + x = (x + value/x)>>1; + x = (x + value/x)>>1; + + + + if (x*x < value) + return x+1; + else + return x; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void median ( + T& one, + T& two, + T& three + ); + /*! + requires + - T implements operator< + - T is swappable by a global swap() + ensures + - #one is the median + - #one, #two, and #three is some permutation of one, two, and three. + !*/ + + + template < + typename T + > + void median ( + T& one, + T& two, + T& three + ) + { + using std::swap; + using dlib::swap; + + if ( one < two ) + { + // one < two + if ( two < three ) + { + // one < two < three : two + swap(one,two); + + } + else + { + // one < two >= three + if ( one < three) + { + // three + swap(three,one); + } + } + + } + else + { + // one >= two + if ( three < one ) + { + // three <= one >= two + if ( three < two ) + { + // two + swap(two,one); + } + else + { + // three + swap(three,one); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + namespace relational_operators + { + template < + typename A, + typename B + > + bool operator> ( + const A& a, + const B& b + ) { return b < a; } + + // --------------------------------- + + template < + typename A, + typename B + > + bool operator!= ( + const A& a, + const B& b + ) { return !(a == b); } + + // --------------------------------- + + template < + typename A, + typename B + > + bool operator<= ( + const A& a, + const B& b + ) { return !(b < a); } + + // --------------------------------- + + template < + typename A, + typename B + > + bool operator>= ( + const A& a, + const B& b + ) { return !(a < b); } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void exchange ( + T& a, + T& b + ) + /*! + This function does the exact same thing that global swap does and it does it by + just calling swap. But a lot of compilers have problems doing a Koenig Lookup + and the fact that this has a different name (global swap has the same name as + the member functions called swap) makes them compile right. + + So this is a workaround but not too ugly of one. But hopefully I get get + rid of this in a few years. So this function is alredy deprecated. + + This also means you should NOT use this function in your own code unless + you have to support an old buggy compiler that benefits from this hack. + !*/ + { + using std::swap; + using dlib::swap; + swap(a,b); + } + +// ---------------------------------------------------------------------------------------- + + /*!A is_pointer_type + + This is a template where is_pointer_type::value == true when T is a pointer + type ane false otherwise. + !*/ + + template < + typename T + > + class is_pointer_type + { + public: + enum { value = false }; + private: + is_pointer_type(); + }; + + template < + typename T + > + class is_pointer_type + { + public: + enum { value = true }; + private: + is_pointer_type(); + }; + +// ---------------------------------------------------------------------------------------- + + /*!A is_same_type + + This is a template where is_same_type::value == true when T and U are the + same type and false otherwise. + !*/ + + template < + typename T, + typename U + > + class is_same_type + { + public: + enum {value = false}; + private: + is_same_type(); + }; + + template + class is_same_type + { + public: + enum {value = true}; + private: + is_same_type(); + }; + +// ---------------------------------------------------------------------------------------- + + /*!A is_signed_type + + This is a template where is_signed_type::value == true when T is a signed + integral type and false when T is an unsigned integral type. + !*/ + template < + typename T + > + struct is_signed_type + { + static const bool value = static_cast((static_cast(0)-static_cast(1))) < 0; + }; + +// ---------------------------------------------------------------------------------------- + + /*!A is_unsigned_type + + This is a template where is_unsigned_type::value == true when T is an unsigned + integral type and false when T is a signed integral type. + !*/ + template < + typename T + > + struct is_unsigned_type + { + static const bool value = static_cast((static_cast(0)-static_cast(1))) > 0; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class copy_functor + { + public: + void operator() ( + const T& source, + T& destination + ) const + { + destination = source; + } + }; + +// ---------------------------------------------------------------------------------------- + + /*!A static_switch + + To use this template you give it some number of boolean expressions and it + tells you which one of them is true. If more than one of them is true then + it causes a compile time error. + + for example: + static_switch<1 + 1 == 2, 4 - 1 == 4>::value == 1 // because the first expression is true + static_switch<1 + 1 == 3, 4 == 4>::value == 2 // because the second expression is true + static_switch<1 + 1 == 3, 4 == 5>::value == 0 // 0 here because none of them are true + static_switch<1 + 1 == 2, 4 == 4>::value == compiler error // because more than one expression is true + !*/ + + template < bool v1 = 0, bool v2 = 0, bool v3 = 0, bool v4 = 0, bool v5 = 0, + bool v6 = 0, bool v7 = 0, bool v8 = 0, bool v9 = 0, bool v10 = 0, + bool v11 = 0, bool v12 = 0, bool v13 = 0, bool v14 = 0, bool v15 = 0 > + struct static_switch; + + template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 0; }; + template <> struct static_switch<1,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 1; }; + template <> struct static_switch<0,1,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 2; }; + template <> struct static_switch<0,0,1,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 3; }; + template <> struct static_switch<0,0,0,1,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 4; }; + template <> struct static_switch<0,0,0,0,1,0,0,0,0,0,0,0,0,0,0> { const static int value = 5; }; + template <> struct static_switch<0,0,0,0,0,1,0,0,0,0,0,0,0,0,0> { const static int value = 6; }; + template <> struct static_switch<0,0,0,0,0,0,1,0,0,0,0,0,0,0,0> { const static int value = 7; }; + template <> struct static_switch<0,0,0,0,0,0,0,1,0,0,0,0,0,0,0> { const static int value = 8; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,1,0,0,0,0,0,0> { const static int value = 9; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,0,1,0,0,0,0,0> { const static int value = 10; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,1,0,0,0,0> { const static int value = 11; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,1,0,0,0> { const static int value = 12; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,1,0,0> { const static int value = 13; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,1,0> { const static int value = 14; }; + template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,1> { const static int value = 15; }; + +// ---------------------------------------------------------------------------------------- + /*!A is_built_in_scalar_type + + This is a template that allows you to determine if the given type is a built + in scalar type such as an int, char, float, short, etc... + + For example, is_built_in_scalar_type::value == true + For example, is_built_in_scalar_type::value == false + !*/ + + template struct is_built_in_scalar_type { const static bool value = false; }; + + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + template <> struct is_built_in_scalar_type { const static bool value = true; }; + // Don't define one for wchar_t when using a version of visual studio + // older than 8.0 (visual studio 2005) since before then they improperly set + // wchar_t to be a typedef rather than its own type as required by the C++ + // standard. +#if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED + template <> struct is_built_in_scalar_type { const static bool value = true; }; +#endif + +// ---------------------------------------------------------------------------------------- + + /*!A assign_zero_if_built_in_scalar_type + + This function assigns its argument the value of 0 if it is a built in scalar + type according to the is_built_in_scalar_type<> template. If it isn't a + built in scalar type then it does nothing. + !*/ + + template inline typename disable_if,void>::type assign_zero_if_built_in_scalar_type (T&){} + template inline typename enable_if,void>::type assign_zero_if_built_in_scalar_type (T& a){a=0;} + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ALGs_ + diff --git a/dlib/all/source.cpp b/dlib/all/source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4087257c43fe7f8f7096531431430e933d95575b --- /dev/null +++ b/dlib/all/source.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ALL_SOURCe_ +#define DLIB_ALL_SOURCe_ + +// ISO C++ code +#include "../base64/base64_kernel_1.cpp" +#include "../bigint/bigint_kernel_1.cpp" +#include "../bigint/bigint_kernel_2.cpp" +#include "../bit_stream/bit_stream_kernel_1.cpp" +#include "../entropy_decoder/entropy_decoder_kernel_1.cpp" +#include "../entropy_decoder/entropy_decoder_kernel_2.cpp" +#include "../entropy_encoder/entropy_encoder_kernel_1.cpp" +#include "../entropy_encoder/entropy_encoder_kernel_2.cpp" +#include "../md5/md5_kernel_1.cpp" +#include "../pixel.cpp" +#include "../tokenizer/tokenizer_kernel_1.cpp" + +#ifndef DLIB_ISO_CPP_ONLY +// Code that depends on OS specific APIs + +// include this first so that it can disable the older version +// of the winsock API when compiled in windows. +#include "../sockets/sockets_kernel_1.cpp" + +#include "../dir_nav/dir_nav_kernel_1.cpp" +#include "../dir_nav/dir_nav_kernel_2.cpp" +#include "../linker/linker_kernel_1.cpp" +#include "../logger/extra_logger_headers.cpp" +#include "../logger/logger_kernel_1.cpp" +#include "../logger/logger_config_file.cpp" +#include "../misc_api/misc_api_kernel_1.cpp" +#include "../misc_api/misc_api_kernel_2.cpp" +#include "../sockets/sockets_extensions.cpp" +#include "../sockets/sockets_kernel_2.cpp" +#include "../sockstreambuf/sockstreambuf_kernel_1.cpp" +#include "../sockstreambuf/sockstreambuf_kernel_2.cpp" +#include "../threads/multithreaded_object_extension.cpp" +#include "../threads/threaded_object_extension.cpp" +#include "../threads/threads_kernel_1.cpp" +#include "../threads/threads_kernel_2.cpp" +#include "../threads/threads_kernel_shared.cpp" +#include "../timer/timer_kernel_2.cpp" + +#ifdef DLIB_PNG_SUPPORT +#include "../image_loader/png_loader.cpp" +#endif + +#ifndef DLIB_NO_GUI_SUPPORT + +#include "../gui_widgets/fonts.cpp" +#include "../gui_widgets/widgets.cpp" +#include "../gui_widgets/drawable.cpp" +#include "../gui_widgets/canvas_drawing.cpp" +#include "../gui_widgets/style.cpp" +#include "../gui_widgets/base_widgets.cpp" +#include "../gui_core/gui_core_kernel_1.cpp" +#include "../gui_core/gui_core_kernel_2.cpp" + +#endif // DLIB_NO_GUI_SUPPORT + +#endif // DLIB_ISO_CPP_ONLY + +#endif // DLIB_ALL_SOURCe_ + diff --git a/dlib/all_console.cpp b/dlib/all_console.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbcad1bfc8da719c8edcabe7eb3d2e585121daa1 --- /dev/null +++ b/dlib/all_console.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ALL_CONSOLe_ +#define DLIB_ALL_CONSOLe_ + +#error "This file has been replaced. Instead you should add dlib/all/source.cpp to your project" + +#endif // DLIB_ALL_CONSOLe_ + diff --git a/dlib/all_gui.cpp b/dlib/all_gui.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb14e09d140b9f7825ad529ba25933634c7d96f0 --- /dev/null +++ b/dlib/all_gui.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ALL_GUi_ +#define DLIB_ALL_GUi_ + +#error "This file has been replaced. Instead you should add dlib/all/source.cpp to your project" + +#endif // DLIB_ALL_GUi_ + diff --git a/dlib/array.h b/dlib/array.h new file mode 100644 index 0000000000000000000000000000000000000000..99a77d5adb4cb78c6de2a6dd7dd403ce4ed135f4 --- /dev/null +++ b/dlib/array.h @@ -0,0 +1,106 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAy_ +#define DLIB_ARRAy_ + +#include "array/array_kernel_1.h" +#include "array/array_kernel_2.h" +#include "array/array_kernel_c.h" + +#include "array/array_sort_1.h" +#include "array/array_sort_2.h" +#include "array/array_expand_1.h" +#include "array/array_expand_c.h" + +#include "memory_manager.h" + + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array + { + array() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef array_kernel_1 + kernel_1a; + typedef array_kernel_c + kernel_1a_c; + + // kernel_2a + typedef array_kernel_2 + kernel_2a; + typedef array_kernel_c + kernel_2a_c; + + + + //---------- extensions ------------ + + + // sort_1 extend kernel_1a + typedef array_sort_1 + sort_1a; + typedef array_sort_1 + sort_1a_c; + + // sort_1 extend kernel_2a + typedef array_sort_1 + sort_1b; + typedef array_sort_1 + sort_1b_c; + + + + // sort_2 extend kernel_1a + typedef array_sort_2 + sort_2a; + typedef array_sort_2 + sort_2a_c; + + // sort_2 extend kernel_2a + typedef array_sort_2 + sort_2b; + typedef array_sort_2 + sort_2b_c; + + + + + // expand_1 extend sort_1a + typedef array_expand_1 + expand_1a; + typedef array_expand_c > + expand_1a_c; + + // expand_1 extend sort_1b + typedef array_expand_1 + expand_1b; + typedef array_expand_c > + expand_1b_c; + + // expand_1 extend sort_2a + typedef array_expand_1 + expand_1c; + typedef array_expand_c > + expand_1c_c; + + // expand_1 extend sort_2b + typedef array_expand_1 + expand_1d; + typedef array_expand_c > + expand_1d_c; + + }; +} + +#endif // DLIB_ARRAy_ + diff --git a/dlib/array/array_expand_1.h b/dlib/array/array_expand_1.h new file mode 100644 index 0000000000000000000000000000000000000000..5e153038a2d4e21f685227a031dc7f2cddf5f7ff --- /dev/null +++ b/dlib/array/array_expand_1.h @@ -0,0 +1,170 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_EXPANd_1_ +#define DLIB_ARRAY_EXPANd_1_ + +#include "array_expand_abstract.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_expand_1 : public array_base + { + typedef typename array_base::type T; + + public: + + void expand ( + unsigned long new_size + ); + + const T& back ( + ) const; + + T& back ( + ); + + void pop_back ( + ); + + void pop_back ( + T& item + ); + + void push_back ( + T& item + ); + + }; + + template < + typename array_base + > + inline void swap ( + array_expand_1& a, + array_expand_1& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_expand_1:: + expand ( + unsigned long new_size + ) + { + if (this->max_size() < new_size) + { + array_base temp; + temp.set_max_size(new_size); + temp.set_size(new_size); + for (unsigned long i = 0; i < this->size(); ++i) + { + exchange((*this)[i],temp[i]); + } + temp.swap(*this); + } + else + { + this->set_size(new_size); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + typename array_base::type& array_expand_1:: + back ( + ) + { + return (*this)[this->size()-1]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + const typename array_base::type& array_expand_1:: + back ( + ) const + { + return (*this)[this->size()-1]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_expand_1:: + pop_back ( + typename array_base::type& item + ) + { + exchange(item,(*this)[this->size()-1]); + this->set_size(this->size()-1); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_expand_1:: + pop_back ( + ) + { + this->set_size(this->size()-1); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_expand_1:: + push_back ( + typename array_base::type& item + ) + { + if (this->max_size() == this->size()) + { + // double the size of the array + array_base temp; + temp.set_max_size(this->size()*2 + 1); + temp.set_size(this->size()+1); + for (unsigned long i = 0; i < this->size(); ++i) + { + exchange((*this)[i],temp[i]); + } + exchange(item,temp[temp.size()-1]); + temp.swap(*this); + } + else + { + this->set_size(this->size()+1); + exchange(item,(*this)[this->size()-1]); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_EXPANd_1_ + diff --git a/dlib/array/array_expand_abstract.h b/dlib/array/array_expand_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c6256ada4275252412043f2db2874935d82b3aa2 --- /dev/null +++ b/dlib/array/array_expand_abstract.h @@ -0,0 +1,126 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ARRAY_EXPANd_ABSTRACT_ +#ifdef DLIB_ARRAY_EXPANd_ABSTRACT_ + +#include "array_kernel_abstract.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_expand : public array_base + { + + /*! + REQUIREMENTS ON ARRAY_BASE + must be an implementation of array/array_kernel_abstract.h + + POINTERS AND REFERENCES + expand() may invalidate pointers and references to internal data. + + WHAT THIS EXTENSION DOES FOR ARRAY + This extension gives an array the ability to expand its size() beyond + its max_size() without clearing out all its elements. It also adds + a std::vector style push/pop back set of functions. + !*/ + + typedef typename array_base::type T; + public: + + void expand ( + unsigned long new_size + ); + /*! + ensures + - #size() == new_size + - #max_size() == max(new_size,max_size()) + - for all i < size(): + - #(*this)[i] == (*this)[i] + (i.e. all the original elements of *this are still present + and at their same positions.) + - for all valid i >= size(): + - #(*this)[i] has an undefined value + (i.e. any new elements of the array have an undefined value) + throws + - std::bad_alloc or any exception thrown by T's constructor. + If an exception is thrown then it has no effect on *this. + !*/ + + + const T& back ( + ) const; + /*! + requires + - size() != 0 + ensures + - returns a const reference to (*this)[size()-1] + !*/ + + T& back ( + ); + /*! + requires + - size() != 0 + ensures + - returns a non-const reference to (*this)[size()-1] + !*/ + + void pop_back ( + T& item + ); + /*! + requires + - size() != 0 + ensures + - #size() == size() - 1 + - swaps (*this)[size()-1] into item + - All elements with an index less than size()-1 are + unmodified by this operation. + !*/ + + void pop_back ( + ); + /*! + requires + - size() != 0 + ensures + - #size() == size() - 1 + - All elements with an index less than size()-1 are + unmodified by this operation. + !*/ + + void push_back ( + T& item + ); + /*! + ensures + - #size() == size()+1 + - swaps item into (*this)[#size()-1] + - #back() == item + - #item has some undefined value (whatever happens to + get swapped out of the array) + throws + - std::bad_alloc or any exception thrown by T's constructor. + If an exception is thrown then it has no effect on *this. + !*/ + + }; + + template < + typename array_base + > + inline void swap ( + array_expand& a, + array_expand& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_ARRAY_EXPANd_ABSTRACT_ + diff --git a/dlib/array/array_expand_c.h b/dlib/array/array_expand_c.h new file mode 100644 index 0000000000000000000000000000000000000000..14aa6eb6c0ae23d9b80bfd361cc6aca2c412674d --- /dev/null +++ b/dlib/array/array_expand_c.h @@ -0,0 +1,139 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_EXPAND_C_ +#define DLIB_ARRAY_EXPAND_C_ + +#include "array_expand_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_expand_c : public array_base + { + typedef typename array_base::type T; + public: + + + const T& back ( + ) const; + + T& back ( + ); + + void pop_back ( + ); + + void pop_back ( + T& item + ); + }; + + template < + typename array_base + > + inline void swap ( + array_expand_c& a, + array_expand_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + typename array_base::type& array_expand_c:: + back ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->size() > 0 , + "\tT& array_expand::back()" + << "\n\tsize() must be bigger than 0" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return array_base::back(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + const typename array_base::type& array_expand_c:: + back ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->size() > 0 , + "\tconst T& array_expand::back()" + << "\n\tsize() must be bigger than 0" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return array_base::back(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_expand_c:: + pop_back ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->size() > 0 , + "\tvoid array_expand::pop_back()" + << "\n\tsize() must be bigger than 0" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return array_base::pop_back(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_expand_c:: + pop_back ( + typename array_base::type& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->size() > 0 , + "\tvoid array_expand::pop_back()" + << "\n\tsize() must be bigger than 0" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return array_base::pop_back(item); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_EXPAND_C_ + + diff --git a/dlib/array/array_kernel_1.h b/dlib/array/array_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..e69a96e76108eba32df31a2c79d6195c20494748 --- /dev/null +++ b/dlib/array/array_kernel_1.h @@ -0,0 +1,652 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_KERNEl_1_ +#define DLIB_ARRAY_KERNEl_1_ + +#include "array_kernel_abstract.h" +#include "../interfaces/enumerable.h" +#include "../algs.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array_kernel_1 : public enumerable + { + + /*! + INITIAL VALUE + - array_size == 0 + - array_nodes == 0 + - max_array_size == 0 + - number_of_nodes == 0 + - mask == 0 + - mask_size == 0 + - _at_start == true + - pos == 0 + + + CONVENTION + - current_element_valid() == (pos != array_size) + - at_start() == _at_start + - if (pos != array_size) + - element() == (*this)[pos] + + array_size == number of elements in the array. + array_nodes == pointer to array of number_of_nodes pointers. + max_array_size == the maximum allowed number of elements in the array. + mask_size == the number of bits set to 1 in mask + + + if (array_size > 0) + { + Only array_nodes[0] though array_nodes[(array_size-1)/number_of_nodes] + point to valid addresses. All other elements in array_nodes + are set to 0. + } + else + { + for all x: array_nodes[x] == 0 + } + + operator[](pos) == array_nodes[pos>>mask_size][pos&mask] + + if (max_array_size == 0) + { + number_of_nodes == 0 + array_nodes == 0 + array_size == 0 + } + !*/ + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + array_kernel_1 ( + ) : + array_nodes(0) + { + update_max_array_size(0); + } + + virtual ~array_kernel_1 ( + ); + + void clear ( + ); + + inline const T& operator[] ( + unsigned long pos + ) const; + + inline T& operator[] ( + unsigned long pos + ); + + void set_size ( + unsigned long size + ); + + inline unsigned long max_size( + ) const; + + void set_max_size( + unsigned long max + ); + + void swap ( + array_kernel_1& item + ); + + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline T& element ( + ); + + bool move_next ( + ) const; + + + private: + + + void update_max_array_size ( + unsigned long new_max_array_size + ); + /*! + ensures + - everything in the CONVENTION is satisfied + - #max_array_size == new_max_array_size + - #array_size == 0 + - mask_size, mask, and number_of_nodes have been set proper + values for the new max array size + - if (new_max_array_size != 0) then + - #array_nodes == pointer to an array of size #number_of_nodes + - else + - #array_nodes == 0 + - #at_start() == true + !*/ + + // data members + T** array_nodes; + unsigned long max_array_size; + unsigned long array_size; + unsigned long number_of_nodes; + mutable unsigned long pos; + unsigned long mask; + unsigned long mask_size; + mutable bool _at_start; + + + + // restricted functions + array_kernel_1(array_kernel_1&); // copy constructor + array_kernel_1& operator=(array_kernel_1&); // assignment operator + + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + array_kernel_1& a, + array_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void serialize ( + const array_kernel_1& item, + std::ostream& out + ) + { + try + { + serialize(item.max_size(),out); + serialize(item.size(),out); + + for (unsigned long i = 0; i < item.size(); ++i) + serialize(item[i],out); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type array_kernel_1"); + } + } + + template < + typename T, + typename mem_manager + > + void deserialize ( + array_kernel_1& item, + std::istream& in + ) + { + try + { + unsigned long max_size, size; + deserialize(max_size,in); + deserialize(size,in); + item.set_max_size(max_size); + item.set_size(size); + for (unsigned long i = 0; i < size; ++i) + deserialize(item[i],in); + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type array_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + array_kernel_1:: + ~array_kernel_1 ( + ) + { + update_max_array_size(0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_1:: + clear ( + ) + { + update_max_array_size(0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& array_kernel_1:: + operator[] ( + unsigned long pos + ) const + { + return array_nodes[pos>>mask_size][pos&mask]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& array_kernel_1:: + operator[] ( + unsigned long pos + ) + { + return array_nodes[pos>>mask_size][pos&mask]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long array_kernel_1:: + max_size ( + ) const + { + return max_array_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_1:: + set_max_size ( + unsigned long max + ) + { + update_max_array_size(max); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_1:: + set_size ( + unsigned long size + ) + { + if (array_size == 0 && size != 0) + { + const unsigned long new_biggest_node = (size-1)/(mask+1); + try + { + // we need to initialize some array nodes + for (unsigned long i = 0; i <= new_biggest_node; ++i) + array_nodes[i] = new T[mask+1]; + } + catch (...) + { + // undo any changes + for (unsigned long i = 0; i <= new_biggest_node; ++i) + { + if (array_nodes[i] != 0) + delete [] array_nodes[i]; + array_nodes[i] = 0; + } + throw; + } + } + else if (size == 0) + { + // free all nodes + for (unsigned long i = 0; i < number_of_nodes; ++i) + { + if (array_nodes[i] != 0) + delete [] array_nodes[i]; + array_nodes[i] = 0; + } + } + else + { + const unsigned long biggest_node = (array_size-1)/(mask+1); + const unsigned long new_biggest_node = (size-1)/(mask+1); + try + { + if (biggest_node < new_biggest_node) + { + // we need to initialize more array nodes + for (unsigned long i = biggest_node+1; i <= new_biggest_node; ++i) + array_nodes[i] = new T[mask+1]; + } + else if (biggest_node > new_biggest_node) + { + // we need to free some array nodes + for (unsigned long i = new_biggest_node+1; i <= biggest_node; ++i) + { + delete [] array_nodes[i]; + array_nodes[i] = 0; + } + } + } + catch (...) + { + // undo any changes + for (unsigned long i = biggest_node+1; i <= new_biggest_node; ++i) + { + if (array_nodes[i] != 0) + delete [] array_nodes[i]; + array_nodes[i] = 0; + } + throw; + } + } + array_size = size; + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_1:: + swap ( + array_kernel_1& item + ) + { + exchange(_at_start,item._at_start); + exchange(pos,item.pos); + exchange(mask_size,item.mask_size); + exchange(mask,item.mask); + + unsigned long max_array_size_temp = item.max_array_size; + unsigned long array_size_temp = item.array_size; + unsigned long number_of_nodes_temp = item.number_of_nodes; + T** array_nodes_temp = item.array_nodes; + + item.max_array_size = max_array_size; + item.array_size = array_size; + item.number_of_nodes = number_of_nodes; + item.array_nodes = array_nodes; + + max_array_size = max_array_size_temp; + array_size = array_size_temp; + number_of_nodes = number_of_nodes_temp; + array_nodes = array_nodes_temp; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_1:: + update_max_array_size ( + unsigned long new_max_array_size + ) + { + max_array_size = new_max_array_size; + + // first free all memory + if (array_nodes != 0) + { + for (unsigned long i = 0; i < number_of_nodes; ++i) + { + if (array_nodes[i] != 0) + delete [] array_nodes[i]; + else + break; + } + delete [] array_nodes; + } + + if (max_array_size > 0) + { + // select new values for number_of_nodes, mask_size, and mask + if (max_array_size <= 0x1000) + { + number_of_nodes = 0x10; + mask = 0xFF; + mask_size = 8; + } + else if (max_array_size <= 0x10000) + { + number_of_nodes = 0x100; + mask = 0xFF; + mask_size = 8; + } + else if (max_array_size <= 0x100000) + { + number_of_nodes = 1024; + mask = 0x3FF; + mask_size = 10; + } + else if (max_array_size <= 0x1000000) + { + number_of_nodes = 4096; + mask = 0xFFF; + mask_size = 12; + } + else if (max_array_size <= 0x10000000) + { + number_of_nodes = 16384; + mask = 0x3FFF; + mask_size = 14; + } + else if (max_array_size <= 0x40000000) + { + number_of_nodes = 32768; + mask = 0x7FFF; + mask_size = 15; + } + else + { + number_of_nodes = 65536; + mask = 0xFFFF; + mask_size = 16; + } + + try + { + array_nodes = new T*[number_of_nodes]; + for (unsigned long i = 0; i < number_of_nodes; ++i) + array_nodes[i] = 0; + } + catch (...) + { + max_array_size = 0; + array_nodes = 0; + number_of_nodes = 0; + array_size = 0; + reset(); + throw; + } + } + else + { + array_nodes = 0; + number_of_nodes = 0; + } + + array_size = 0; + reset(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool array_kernel_1:: + at_start ( + ) const + { + return _at_start; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_1:: + reset ( + ) const + { + _at_start = true; + pos = array_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool array_kernel_1:: + current_element_valid ( + ) const + { + return (pos != array_size); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& array_kernel_1:: + element ( + ) const + { + return operator[](pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& array_kernel_1:: + element ( + ) + { + return operator[](pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool array_kernel_1:: + move_next ( + ) const + { + if (!_at_start) + { + if (pos+1 < array_size) + { + ++pos; + return true; + } + else + { + pos = array_size; + return false; + } + } + else + { + _at_start = false; + pos = 0; + if (array_size == 0) + return false; + else + return true; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long array_kernel_1:: + size ( + ) const + { + return array_size; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_KERNEl_1_ + diff --git a/dlib/array/array_kernel_2.h b/dlib/array/array_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..05e39577f1c51a25155243b17f3390cf18e5256a --- /dev/null +++ b/dlib/array/array_kernel_2.h @@ -0,0 +1,492 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: GNU LGPL See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_KERNEl_2_ +#define DLIB_ARRAY_KERNEl_2_ + +#include "array_kernel_abstract.h" +#include "../interfaces/enumerable.h" +#include "../algs.h" +#include "../serialize.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array_kernel_2 : public enumerable + { + + /*! + INITIAL VALUE + - array_size == 0 + - max_array_size == 0 + - array_elements == 0 + - pos == 0 + - last_pos == 0 + - _at_start == true + + CONVENTION + - array_size == size() + - max_array_size == max_size() + - if (max_array_size > 0) + - array_elements == pointer to max_array_size elements of type T + - else + - array_elements == 0 + + - if (array_size > 0) + - last_pos == array_elements + array_size - 1 + - else + - last_pos == 0 + + + - at_start() == _at_start + - current_element_valid() == pos != 0 + - if (current_element_valid()) then + - *pos == element() + !*/ + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + array_kernel_2 ( + ) : + array_size(0), + max_array_size(0), + array_elements(0), + pos(0), + last_pos(0), + _at_start(true) + {} + + virtual ~array_kernel_2 ( + ); + + void clear ( + ); + + inline const T& operator[] ( + unsigned long pos + ) const; + + inline T& operator[] ( + unsigned long pos + ); + + void set_size ( + unsigned long size + ); + + inline unsigned long max_size( + ) const; + + void set_max_size( + unsigned long max + ); + + void swap ( + array_kernel_2& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline T& element ( + ); + + bool move_next ( + ) const; + + private: + + typename mem_manager::template rebind::other pool; + + // data members + unsigned long array_size; + unsigned long max_array_size; + T* array_elements; + + mutable T* pos; + T* last_pos; + mutable bool _at_start; + + // restricted functions + array_kernel_2(array_kernel_2&); // copy constructor + array_kernel_2& operator=(array_kernel_2&); // assignment operator + + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + array_kernel_2& a, + array_kernel_2& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void serialize ( + const array_kernel_2& item, + std::ostream& out + ) + { + try + { + serialize(item.max_size(),out); + serialize(item.size(),out); + + for (unsigned long i = 0; i < item.size(); ++i) + serialize(item[i],out); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type array_kernel_2"); + } + } + + template < + typename T, + typename mem_manager + > + void deserialize ( + array_kernel_2& item, + std::istream& in + ) + { + try + { + unsigned long max_size, size; + deserialize(max_size,in); + deserialize(size,in); + item.set_max_size(max_size); + item.set_size(size); + for (unsigned long i = 0; i < size; ++i) + deserialize(item[i],in); + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type array_kernel_2"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + array_kernel_2:: + ~array_kernel_2 ( + ) + { + if (array_elements) + { + pool.deallocate_array(array_elements); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_2:: + clear ( + ) + { + reset(); + last_pos = 0; + array_size = 0; + if (array_elements) + { + pool.deallocate_array(array_elements); + } + array_elements = 0; + max_array_size = 0; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& array_kernel_2:: + operator[] ( + unsigned long pos + ) const + { + return array_elements[pos]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& array_kernel_2:: + operator[] ( + unsigned long pos + ) + { + return array_elements[pos]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_2:: + set_size ( + unsigned long size + ) + { + reset(); + array_size = size; + if (size > 0) + last_pos = array_elements + size - 1; + else + last_pos = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long array_kernel_2:: + size ( + ) const + { + return array_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_2:: + set_max_size( + unsigned long max + ) + { + reset(); + array_size = 0; + last_pos = 0; + if (max != 0) + { + // if new max size is different + if (max != max_array_size) + { + if (array_elements) + { + pool.deallocate_array(array_elements); + } + // try to get more memroy + try { array_elements = pool.allocate_array(max); } + catch (...) { array_elements = 0; max_array_size = 0; throw; } + max_array_size = max; + } + + } + // if the array is being made to be zero + else + { + if (array_elements) + pool.deallocate_array(array_elements); + max_array_size = 0; + array_elements = 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long array_kernel_2:: + max_size ( + ) const + { + return max_array_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_2:: + swap ( + array_kernel_2& item + ) + { + unsigned long array_size_temp = item.array_size; + unsigned long max_array_size_temp = item.max_array_size; + T* array_elements_temp = item.array_elements; + + item.array_size = array_size; + item.max_array_size = max_array_size; + item.array_elements = array_elements; + + array_size = array_size_temp; + max_array_size = max_array_size_temp; + array_elements = array_elements_temp; + + exchange(_at_start,item._at_start); + exchange(pos,item.pos); + exchange(last_pos,item.last_pos); + pool.swap(item.pool); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool array_kernel_2:: + at_start ( + ) const + { + return _at_start; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array_kernel_2:: + reset ( + ) const + { + _at_start = true; + pos = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool array_kernel_2:: + current_element_valid ( + ) const + { + return pos != 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& array_kernel_2:: + element ( + ) const + { + return *pos; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& array_kernel_2:: + element ( + ) + { + return *pos; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool array_kernel_2:: + move_next ( + ) const + { + if (!_at_start) + { + if (pos < last_pos) + { + ++pos; + return true; + } + else + { + pos = 0; + return false; + } + } + else + { + _at_start = false; + if (array_size > 0) + { + pos = array_elements; + return true; + } + else + { + return false; + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_KERNEl_2_ + diff --git a/dlib/array/array_kernel_abstract.h b/dlib/array/array_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..555085efac3369f8815db25551f0d4d041b59c24 --- /dev/null +++ b/dlib/array/array_kernel_abstract.h @@ -0,0 +1,197 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ARRAY_KERNEl_ABSTRACT_ +#ifdef DLIB_ARRAY_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array : public enumerable + { + + /*! + REQUIREMENTS ON T + T must have a default constructor. + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap(), max_size(), set_size(), and operator[] functions do + not invalidate pointers or references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + max_size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements of the array in the + order (*this)[0], (*this)[1], (*this)[2], ... + + WHAT THIS OBJECT REPRESENTS + array contains items of type T + + This object represents an ordered array of items, each item is + associated with an integer value. + The items are numbered from 0 though size() - 1 and + the operator[] functions run in constant time + !*/ + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + array ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + virtual ~array ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear ( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then the array object is unusable + until clear() is called and succeeds + !*/ + + const T& operator[] ( + unsigned long pos + ) const; + /*! + requires + - pos < size() + ensures + - returns a const reference to the element at position pos + !*/ + + T& operator[] ( + unsigned long pos + ); + /*! + requires + - pos < size() + ensures + - returns a non-const reference to the element at position pos + !*/ + + void set_size ( + unsigned long size + ); + /*! + requires + - size <= max_size() + ensures + - #size() == size + - any element with index between 0 and size - 1 which was in the + array before the call to set_size() retains its value and index. + All other elements have undetermined (but valid for their type) + values. (e.g. this object might buffer old T objects and reuse + them without reinitializing them between calls to set_size()) + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + may throw this exception if there is not enough memory and + if it does throw then the call to set_size() has no effect + !*/ + + unsigned long max_size( + ) const; + /*! + ensures + - returns the maximum size of *this + !*/ + + void set_max_size( + unsigned long max + ); + /*! + ensures + - #max_size() == max + - #size() == 0 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + may throw this exception if there is not enough + memory and if it does throw then max_size() == 0 + !*/ + + void swap ( + array& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + array(array&); // copy constructor + array& operator=(array&); // assignment operator + + }; + + template < + typename T + > + inline void swap ( + array& a, + array& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T + > + void serialize ( + const array& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + template < + typename T + > + void deserialize ( + array& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_ARRAY_KERNEl_ABSTRACT_ + diff --git a/dlib/array/array_kernel_c.h b/dlib/array/array_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..88e6cc92a3e20124742061f4e7bbdaf53bcfc0bc --- /dev/null +++ b/dlib/array/array_kernel_c.h @@ -0,0 +1,170 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_KERNEl_C_ +#define DLIB_ARRAY_KERNEl_C_ + +#include "array_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_kernel_c : public array_base + { + typedef typename array_base::type T; + public: + + const T& operator[] ( + unsigned long pos + ) const; + + T& operator[] ( + unsigned long pos + ); + + void set_size ( + unsigned long size + ); + + const T& element ( + ) const; + + T& element( + ); + + }; + + template < + typename array_base + > + inline void swap ( + array_kernel_c& a, + array_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + const typename array_base::type& array_kernel_c:: + operator[] ( + unsigned long pos + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( pos < this->size() , + "\tconst T& array::operator[]" + << "\n\tpos must < size()" + << "\n\tpos: " << pos + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return array_base::operator[](pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + typename array_base::type& array_kernel_c:: + operator[] ( + unsigned long pos + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( pos < this->size() , + "\tT& array::operator[]" + << "\n\tpos must be < size()" + << "\n\tpos: " << pos + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return array_base::operator[](pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_kernel_c:: + set_size ( + unsigned long size + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( size <= this->max_size() ), + "\tvoid array::set_size" + << "\n\tsize must be <= max_size()" + << "\n\tsize: " << size + << "\n\tmax size: " << this->max_size() + << "\n\tthis: " << this + ); + + // call the real function + array_base::set_size(size); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + const typename array_base::type& array_kernel_c:: + element ( + ) const + { + + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid(), + "\tconst T& array::element()" + << "\n\tThe current element must be valid if you are to access it." + << "\n\tthis: " << this + ); + + // call the real function + return array_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + typename array_base::type& array_kernel_c:: + element ( + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid(), + "\tT& array::element()" + << "\n\tThe current element must be valid if you are to access it." + << "\n\tthis: " << this + ); + + // call the real function + return array_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_KERNEl_C_ + diff --git a/dlib/array/array_sort_1.h b/dlib/array/array_sort_1.h new file mode 100644 index 0000000000000000000000000000000000000000..78cc96138731b8fb20be33a04960bde0a6113a84 --- /dev/null +++ b/dlib/array/array_sort_1.h @@ -0,0 +1,77 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_SORt_1_ +#define DLIB_ARRAY_SORt_1_ + +#include "array_sort_abstract.h" +#include "../algs.h" +#include "../sort.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_sort_1 : public array_base + { + typedef typename array_base::type T; + + public: + + /*! + this is a median of three version of the QuickSort algorithm and + it swaps the entire array into a temporary C style array and sorts that and + this uses the dlib::qsort_array function + !*/ + + void sort ( + ); + + }; + + template < + typename array_base + > + inline void swap ( + array_sort_1& a, + array_sort_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_sort_1:: + sort ( + ) + { + if (this->size() > 1) + { + T* temp = new T[this->size()]; + + for (unsigned long i = 0; i < this->size(); ++i) + exchange(temp[i],(*this)[i]); + + // call the quick sort function for arrays that is in algs.h + dlib::qsort_array(temp,0,this->size()-1); + + for (unsigned long i = 0; i < this->size(); ++i) + exchange((*this)[i],temp[i]); + + delete [] temp; + } + this->reset(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_SORt_1_ + diff --git a/dlib/array/array_sort_2.h b/dlib/array/array_sort_2.h new file mode 100644 index 0000000000000000000000000000000000000000..f56b61ea2d3bf1442532435fffdc69b734a1b002 --- /dev/null +++ b/dlib/array/array_sort_2.h @@ -0,0 +1,65 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY_SORt_2_ +#define DLIB_ARRAY_SORt_2_ + +#include "array_sort_abstract.h" +#include "../algs.h" +#include "../sort.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_sort_2 : public array_base + { + + public: + + /*! + this is a median of three version of the QuickSort algorithm and + this uses the dlib::qsort_array function + !*/ + + void sort ( + ); + + }; + + template < + typename array_base + > + inline void swap ( + array_sort_2& a, + array_sort_2& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array_base + > + void array_sort_2:: + sort ( + ) + { + if (this->size() > 1) + { + // call the quick sort function for arrays that is in algs.h + dlib::qsort_array(*this,0,this->size()-1); + } + this->reset(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY_SORt_2_ + diff --git a/dlib/array/array_sort_abstract.h b/dlib/array/array_sort_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..ddacca7cad2aa018dd0076873e3c37963af75dc9 --- /dev/null +++ b/dlib/array/array_sort_abstract.h @@ -0,0 +1,58 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ARRAY_SORt_ABSTRACT_ +#ifdef DLIB_ARRAY_SORt_ABSTRACT_ + +#include "array_kernel_abstract.h" + +namespace dlib +{ + + template < + typename array_base + > + class array_sort : public array_base + { + + /*! + REQUIREMENTS ON ARRAY_BASE + must be an implementation of array/array_kernel_abstract.h + + POINTERS AND REFERENCES + sort() may invalidate pointers and references to internal data. + + WHAT THIS EXTENSION DOES FOR ARRAY + This gives an array the ability to sort its contents by calling sort(). + !*/ + + + public: + + void sort ( + ); + /*! + ensures + - for all elements in #*this the ith element is <= the i+1 element + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + data may be lost if sort() throws + !*/ + + }; + + template < + typename array_base + > + inline void swap ( + array_sort& a, + array_sort& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_ARRAY_SORt_ABSTRACT_ + diff --git a/dlib/array2d.h b/dlib/array2d.h new file mode 100644 index 0000000000000000000000000000000000000000..5366c57a572c8e395d7446cbc9090a897b3bee61 --- /dev/null +++ b/dlib/array2d.h @@ -0,0 +1,43 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY2d_ +#define DLIB_ARRAY2d_ + + +#include "array2d/array2d_kernel_1.h" +#include "array2d/array2d_kernel_c.h" +#include "memory_manager.h" + + + +namespace dlib +{ + + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array2d + { + + array2d() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef array2d_kernel_1 + kernel_1a; + typedef array2d_kernel_c + kernel_1a_c; + + + + }; +} + +#endif // DLIB_ARRAY2d_ + diff --git a/dlib/array2d/array2d_kernel_1.h b/dlib/array2d/array2d_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..c311c8e02ebb81ce4b0db0af98410bc99503ea7b --- /dev/null +++ b/dlib/array2d/array2d_kernel_1.h @@ -0,0 +1,381 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY2D_KERNEl_1_ +#define DLIB_ARRAY2D_KERNEl_1_ + +#include "array2d_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array2d_kernel_1 : public enumerable + { + + /*! + INITIAL VALUE + - nc_ == 0 + - nr_ == 0 + - data == 0 + - rows == 0 + - at_start_ == true + - cur == 0 + - last == 0 + + CONVENTION + - nc_ == nc() + - nr_ == nc() + - if (data != 0) then + - last == a pointer to the last element in the data array + - data == pointer to an array of nc_*nr_ T objects + - rows == pointer to an array of nr_ row objects + - for all x < nr_: + - rows[x].data == data + x*nc_ + - rows[x].nc_ == nc_ + - else + - nc_ == 0 + - nr_ == 0 + - data == 0 + - rows == 0 + - last == 0 + + + - nr_ * nc_ == size() + - if (cur == 0) then + - current_element_valid() == false + - else + - current_element_valid() == true + - *cur == element() + + - at_start_ == at_start() + !*/ + + + class row_helper; + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + // ----------------------------------- + + class row + { + /*! + CONVENTION + - nc_ == nc() + - for all x < nc_: + - (*this)[x] == data[x] + !*/ + + friend class array2d_kernel_1; + friend class row_helper; + + public: + long nc ( + ) const { return nc_; } + + const T& operator[] ( + long column + ) const { return data[column]; } + + T& operator[] ( + long column + ) { return data[column]; } + + private: + + long nc_; + T* data; + + + // restricted functions + row(){} + row(row&); + row& operator=(row&); + }; + + // ----------------------------------- + + array2d_kernel_1 ( + ) : + nc_(0), + nr_(0), + rows(0), + data(0), + cur(0), + last(0), + at_start_(true) + { + } + + virtual ~array2d_kernel_1 ( + ) { clear(); } + + long nc ( + ) const { return nc_; } + + long nr ( + ) const { return nr_; } + + row& operator[] ( + long row + ) { return rows[row]; } + + const row& operator[] ( + long row + ) const { return rows[row]; } + + void swap ( + array2d_kernel_1& item + ) + { + exchange(data,item.data); + exchange(rows,item.rows); + exchange(nr_,item.nr_); + exchange(nc_,item.nc_); + exchange(at_start_,item.at_start_); + exchange(cur,item.cur); + exchange(last,item.last); + pool.swap(item.pool); + rpool.swap(item.rpool); + } + + void clear ( + ) + { + if (data != 0) + { + rpool.deallocate_array(reinterpret_cast(rows)); + pool.deallocate_array(data); + nc_ = 0; + nr_ = 0; + rows = 0; + data = 0; + at_start_ = true; + cur = 0; + last = 0; + } + } + + void set_size ( + long nr__, + long nc__ + ); + + bool at_start ( + ) const { return at_start_; } + + void reset ( + ) const { at_start_ = true; cur = 0; } + + bool current_element_valid ( + ) const { return (cur != 0); } + + const T& element ( + ) const { return *cur; } + + T& element ( + ) { return *cur; } + + bool move_next ( + ) const + { + if (cur != 0) + { + if (cur != last) + { + ++cur; + return true; + } + cur = 0; + return false; + } + else if (at_start_) + { + cur = data; + at_start_ = false; + return (data != 0); + } + else + { + return false; + } + } + + unsigned long size ( + ) const { return static_cast(nc_ * nr_); } + + private: + + // this object exists just so we can have a row type object that + // has a public default constructor so the memory_manager can construct it. + // I would have made rpool a friend of row but some compilers can't handle + // that without crapping out. + class row_helper : public row {}; + + typename mem_manager::template rebind::other pool; + typename mem_manager::template rebind::other rpool; + + long nc_; + long nr_; + row* rows; + T* data; + + mutable T* cur; + T* last; + mutable bool at_start_; + + // restricted functions + array2d_kernel_1(array2d_kernel_1&); // copy constructor + array2d_kernel_1& operator=(array2d_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + inline void swap ( + array2d_kernel_1& a, + array2d_kernel_1& b + ) { a.swap(b); } + + + template < + typename T, + typename mem_manager + > + void serialize ( + const array2d_kernel_1& item, + std::ostream& out + ) + { + try + { + serialize(item.nc(),out); + serialize(item.nr(),out); + + item.reset(); + while (item.move_next()) + serialize(item.element(),out); + item.reset(); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type array2d_kernel_1"); + } + } + + template < + typename T + > + void deserialize ( + array2d_kernel_1& item, + std::istream& in + ) + { + try + { + long nc, nr; + deserialize(nc,in); + deserialize(nr,in); + + item.set_size(nr,nc); + + while (item.move_next()) + deserialize(item.element(),in); + item.reset(); + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type array2d_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void array2d_kernel_1:: + set_size ( + long nr__, + long nc__ + ) + { + // set the enumerator back at the start + at_start_ = true; + cur = 0; + + // don't do anything if we are already the right size. + if (nc_ == nc__ && nr_ == nr__) + { + return; + } + + nc_ = nc__; + nr_ = nr__; + + // free any existing memory + if (data != 0) + { + pool.deallocate_array(data); + rpool.deallocate_array(reinterpret_cast(rows)); + data = 0; + rows = 0; + } + + // now setup this object to have the new size + try + { + if (nr_ > 0) + { + rows = rpool.allocate_array(nr_); + data = pool.allocate_array(nr_*nc_); + last = data + nr_*nc_ - 1; + } + } + catch (...) + { + if (rows) + rpool.deallocate_array(reinterpret_cast(rows)); + if (data) + pool.deallocate_array(data); + + rows = 0; + data = 0; + nc_ = 0; + nr_ = 0; + last = 0; + throw; + } + + // now set up all the rows + for (long i = 0; i < nr_; ++i) + { + rows[i].nc_ = nc_; + rows[i].data = data + i*nc_; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY2D_KERNEl_1_ + diff --git a/dlib/array2d/array2d_kernel_abstract.h b/dlib/array2d/array2d_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..223acb3987aabe288dfee6d340adad1714f7caec --- /dev/null +++ b/dlib/array2d/array2d_kernel_abstract.h @@ -0,0 +1,242 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ARRAY2D_KERNEl_ABSTRACT_ +#ifdef DLIB_ARRAY2D_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class array2d : public enumerable + { + + /*! + REQUIREMENTS ON T + T must have a default constructor. + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + No member functions in this object will invalidate pointers + or references to internal data except for the set_size() + and clear() member functions. + + INITIAL VALUE + nr() == 0 + nc() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements of the array starting + with row 0 and then proceeding to row 1 and so on. Each row will be + fully enumerated before proceeding on to the next row and the elements + in a row will be enumerated beginning with the 0th column, then the 1st + column and so on. + + WHAT THIS OBJECT REPRESENTS + This object represents a 2-Dimensional array of objects of + type T. + !*/ + + + public: + + // ---------------------------------------- + + typedef T type; + typedef mem_manager mem_manager_type; + + // ---------------------------------------- + + class row + { + /*! + POINTERS AND REFERENCES TO INTERNAL DATA + No member functions in this object will invalidate pointers + or references to internal data. + + WHAT THIS OBJECT REPRESENTS + This object represents a row of Ts in an array2d object. + !*/ + public: + long nc ( + ) const; + /*! + ensures + - returns the number of columns in this row + !*/ + + const T& operator[] ( + long column + ) const; + /*! + requires + - 0 <= column < nc() + ensures + - returns a const reference to the T in the given column + !*/ + + T& operator[] ( + long column + ); + /*! + requires + - 0 <= column < nc() + ensures + - returns a non-const reference to the T in the given column + !*/ + + private: + // restricted functions + row(); + row(row&); + row& operator=(row&); + }; + + // ---------------------------------------- + + array2d ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~array2d ( + ); + /*! + ensures + - all resources associated with *this has been released + !*/ + + void clear ( + ); + /*! + ensures + - #*this has an initial value for its type + !*/ + + long nc ( + ) const; + /*! + ensures + - returns the number of elements there are in a row. i.e. returns + the number of columns in *this + !*/ + + long nr ( + ) const; + /*! + ensures + - returns the number of rows in *this + !*/ + + void set_size ( + long rows, + long cols + ); + /*! + requires + - cols > 0 && rows > 0 or + cols == 0 && rows == 0 + ensures + - #nc() == cols + - #nr() == rows + - #at_start() == true + - if (the call to set_size() doesn't change the dimensions of this array) then + - all elements in this array retain their values from before this function was called + - else + - all elements in this array have initial values for their type + throws + - std::bad_alloc + If this exception is thrown then #*this will have an initial + value for its type. + !*/ + + row& operator[] ( + long row_index + ); + /*! + requires + - 0 <= row_index < nr() + ensures + - returns a non-const row of nc() elements that represents the + given row_index'th row in *this. + !*/ + + const row& operator[] ( + long row_index + ) const; + /*! + requires + - 0 <= row_index < nr() + ensures + - returns a const row of nc() elements that represents the + given row_index'th row in *this. + !*/ + + void swap ( + array2d& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + array2d(array2d&); // copy constructor + array2d& operator=(array2d&); // assignment operator + + }; + + template < + typename T + > + inline void swap ( + array2d& a, + array2d& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T + > + void serialize ( + const array2d& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + template < + typename T + > + void deserialize ( + array2d& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_ARRAY2D_KERNEl_ABSTRACT_ + diff --git a/dlib/array2d/array2d_kernel_c.h b/dlib/array2d/array2d_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..0a8ca810b0583576620cdc0f6f14dc8568098f3c --- /dev/null +++ b/dlib/array2d/array2d_kernel_c.h @@ -0,0 +1,382 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ARRAY2D_KERNEl_C_ +#define DLIB_ARRAY2D_KERNEl_C_ + +#include "array2d_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include "../interfaces/enumerable.h" + +namespace dlib +{ + + + template < + typename array2d_base // is an implementation of array2d_kernel_abstract.h + > + class array2d_kernel_c : public enumerable + { + + /*! + CONVENTION + - if (obj.size() > 0) then + - rows == an array of size obj.nr() row objects and + each row object in the array has a valid pointer to its + associated row in obj. + - else + - rows == 0 + + !*/ + + typedef typename array2d_base::type T; + public: + typedef typename array2d_base::type type; + typedef typename array2d_base::mem_manager_type mem_manager_type; + + + // ----------------------------------- + + class row + { + + friend class array2d_kernel_c; + public: + long nc ( + ) const { return data->nc(); } + + const T& operator[] ( + long column + ) const; + + T& operator[] ( + long column + ); + + private: + + typename array2d_base::row* data; + + // restricted functions + row(){} + row(row&); + row& operator=(row&); + }; + + // ----------------------------------- + + array2d_kernel_c ( + ) : + rows(0) + { + } + + virtual ~array2d_kernel_c ( + ) { clear(); } + + long nc ( + ) const { return obj.nc(); } + + long nr ( + ) const { return obj.nr(); } + + row& operator[] ( + long row + ); + + const row& operator[] ( + long row + ) const; + + void swap ( + array2d_kernel_c& item + ) + { + exchange(obj,item.obj); + exchange(rows,item.rows); + } + + void clear ( + ) + { + obj.clear(); + if (rows != 0) + { + delete [] rows; + rows = 0; + } + } + + void set_size ( + long nr__, + long nc__ + ); + + bool at_start ( + ) const { return obj.at_start();; } + + void reset ( + ) const { obj.reset(); } + + bool current_element_valid ( + ) const { return obj.current_element_valid(); } + + const T& element ( + ) const; + + T& element ( + ); + + bool move_next ( + ) const { return obj.move_next(); } + + unsigned long size ( + ) const { return obj.size(); } + + private: + + array2d_base obj; + row* rows; + + }; + + template < + typename array2d_base + > + inline void swap ( + array2d_kernel_c& a, + array2d_kernel_c& b + ) { a.swap(b); } + + + template < + typename array2d_base + > + void serialize ( + const array2d_kernel_c& item, + std::ostream& out + ) + { + try + { + serialize(item.nc(),out); + serialize(item.nr(),out); + + item.reset(); + while (item.move_next()) + serialize(item.element(),out); + item.reset(); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type array2d_kernel_c"); + } + } + + template < + typename array2d_base + > + void deserialize ( + array2d_kernel_c& item, + std::istream& in + ) + { + try + { + long nc, nr; + deserialize(nc,in); + deserialize(nr,in); + + item.set_size(nr,nc); + + while (item.move_next()) + deserialize(item.element(),in); + item.reset(); + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type array2d_kernel_c"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + const typename array2d_base::type& array2d_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(current_element_valid() == true, + "\tT& array2d::element()()" + << "\n\tYou can only call element() when you are at a valid one." + << "\n\tthis: " << this + ); + + return obj.element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + typename array2d_base::type& array2d_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(current_element_valid() == true, + "\tT& array2d::element()()" + << "\n\tYou can only call element() when you are at a valid one." + << "\n\tthis: " << this + ); + + return obj.element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + void array2d_kernel_c:: + set_size ( + long nr_, + long nc_ + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(nc_ > 0 && nr_ > 0 || + nc_ == 0 && nr_ == 0, + "\tvoid array2d::set_size(long nr_, long nc_)" + << "\n\tYou have to give a non zero nc and nr or just make both zero." + << "\n\tthis: " << this + << "\n\tnc_: " << nc_ + << "\n\tnr_: " << nr_ + ); + + obj.set_size(nr_,nc_); + + // set up the rows array + if (rows != 0) + delete [] rows; + + try + { + rows = new row[obj.nr()]; + } + catch (...) + { + rows = 0; + obj.clear(); + throw; + } + + for (long i = 0; i < obj.nr(); ++i) + { + rows[i].data = &obj[i]; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + typename array2d_kernel_c::row& array2d_kernel_c:: + operator[] ( + long row + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(row < nr() && row >= 0, + "\trow& array2d::operator[](long row)" + << "\n\tThe row index given must be less than the number of rows." + << "\n\tthis: " << this + << "\n\trow: " << row + << "\n\tnr(): " << nr() + ); + + return rows[row]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + const typename array2d_kernel_c::row& array2d_kernel_c:: + operator[] ( + long row + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(row < nr() && row >= 0, + "\tconst row& array2d::operator[](long row) const" + << "\n\tThe row index given must be less than the number of rows." + << "\n\tthis: " << this + << "\n\trow: " << row + << "\n\tnr(): " << nr() + ); + + return rows[row]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + const typename array2d_base::type& array2d_kernel_c::row:: + operator[] ( + long column + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(column < nc() && column >= 0, + "\tconst T& array2d::operator[](long column) const" + << "\n\tThe column index given must be less than the number of columns." + << "\n\tthis: " << this + << "\n\tcolumn: " << column + << "\n\tnc(): " << nc() + ); + + return (*data)[column]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename array2d_base + > + typename array2d_base::type& array2d_kernel_c::row:: + operator[] ( + long column + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(column < nc() && column >= 0, + "\tT& array2d::operator[](long column)" + << "\n\tThe column index given must be less than the number of columns." + << "\n\tthis: " << this + << "\n\tcolumn: " << column + << "\n\tnc(): " << nc() + ); + + return (*data)[column]; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ARRAY2D_KERNEl_C_ + diff --git a/dlib/assert.h b/dlib/assert.h new file mode 100644 index 0000000000000000000000000000000000000000..091cbca9f12d240a8ae11248fd4926389b0d1c40 --- /dev/null +++ b/dlib/assert.h @@ -0,0 +1,110 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ASSERt_ +#define DLIB_ASSERt_ + + +#include +#include +#include "error.h" + +// ----------------------------- + +// Use some stuff from boost here +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Darin Adler 2001. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright Bill Kempf 2002. +// (C) Copyright Jens Maurer 2002. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Gennaro Prota 2003. +// (C) Copyright Eric Friedman 2003. +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef BOOST_JOIN +#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) +#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) +#define BOOST_DO_JOIN2( X, Y ) X##Y +#endif + +// ----------------------------- + +namespace dlib +{ + template struct compile_time_assert; + template <> struct compile_time_assert { enum {value=1}; }; + + template struct assert_are_same_type; + template struct assert_are_same_type {enum{value=1};}; + template struct assert_are_not_same_type {enum{value=1}; }; + template struct assert_are_not_same_type {}; +} +#define COMPILE_TIME_ASSERT(expression) \ + typedef char BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value] + +#define ASSERT_ARE_SAME_TYPE(type1, type2) \ + typedef char BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type::value] + +#define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \ + typedef char BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type::value] + +// ----------------------------- + +#if defined DEBUG || defined _DEBUG + // make sure ENABLE_ASSERTS is defined if we are indeed using them. + #ifndef ENABLE_ASSERTS + #define ENABLE_ASSERTS + #endif +#endif + +// ----------------------------- + +#ifdef __GNUC__ +#define DLIB_FUNCTION_NAME __PRETTY_FUNCTION__ +#elif _MSC_VER +#define DLIB_FUNCTION_NAME __FUNCSIG__ +#else +#define DLIB_FUNCTION_NAME "unknown function" +#endif + +#define DLIB_CASSERT(_exp,_message) \ + {if ( !(_exp) ) \ + { \ + std::ostringstream dlib__out; \ + dlib__out << "\n\nError occurred at line " << __LINE__ << ".\n"; \ + dlib__out << "Error occurred in file " << __FILE__ << ".\n"; \ + dlib__out << "Error occurred in function " << DLIB_FUNCTION_NAME << ".\n\n"; \ + dlib__out << "Failing expression was " << #_exp << ".\n"; \ + dlib__out << _message << "\n"; \ + dlib_assert_breakpoint(); \ + throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib__out.str()); \ + }} + + +#ifdef ENABLE_ASSERTS + #define DLIB_ASSERT(_exp,_message) DLIB_CASSERT(_exp,_message) +#else + #define DLIB_ASSERT(_exp,_message) +#endif + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +// breakpoints +extern "C" +{ + inline void dlib_assert_breakpoint( + ) {} + /*! + ensures + - this function does nothing + It exists just so you can put breakpoints on it in a debugging tool. + It is called only when an DLIB_ASSERT or DLIB_CASSERT fails and is about to + throw an exception. + !*/ +} + +// ----------------------------- + +#endif // DLIB_ASSERt_ + diff --git a/dlib/base64.h b/dlib/base64.h new file mode 100644 index 0000000000000000000000000000000000000000..4173465be3f48c1b830c701cdf335ae1346fb3dd --- /dev/null +++ b/dlib/base64.h @@ -0,0 +1,35 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BASe64_ +#define DLIB_BASe64_ + + +#include "base64/base64_kernel_1.h" + + + +namespace dlib +{ + + + class base64 + { + + base64() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef base64_kernel_1 + kernel_1a; + + + + }; +} + +#endif // DLIB_BASe64_ + diff --git a/dlib/base64/base64_kernel_1.cpp b/dlib/base64/base64_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..523c4134e31f1e0991394339668a78572053d0a3 --- /dev/null +++ b/dlib/base64/base64_kernel_1.cpp @@ -0,0 +1,364 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BASE64_KERNEL_1_CPp_ +#define DLIB_BASE64_KERNEL_1_CPp_ + +#include "base64_kernel_1.h" +#include +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + base64_kernel_1:: + base64_kernel_1 ( + ) : + encode_table(0), + decode_table(0), + bad_value(100) + { + try + { + encode_table = new char[64]; + decode_table = new unsigned char[UCHAR_MAX]; + } + catch (...) + { + if (encode_table) delete [] encode_table; + if (decode_table) delete [] decode_table; + throw; + } + + // now set up the tables with the right stuff + encode_table[0] = 'A'; + encode_table[17] = 'R'; + encode_table[34] = 'i'; + encode_table[51] = 'z'; + + encode_table[1] = 'B'; + encode_table[18] = 'S'; + encode_table[35] = 'j'; + encode_table[52] = '0'; + + encode_table[2] = 'C'; + encode_table[19] = 'T'; + encode_table[36] = 'k'; + encode_table[53] = '1'; + + encode_table[3] = 'D'; + encode_table[20] = 'U'; + encode_table[37] = 'l'; + encode_table[54] = '2'; + + encode_table[4] = 'E'; + encode_table[21] = 'V'; + encode_table[38] = 'm'; + encode_table[55] = '3'; + + encode_table[5] = 'F'; + encode_table[22] = 'W'; + encode_table[39] = 'n'; + encode_table[56] = '4'; + + encode_table[6] = 'G'; + encode_table[23] = 'X'; + encode_table[40] = 'o'; + encode_table[57] = '5'; + + encode_table[7] = 'H'; + encode_table[24] = 'Y'; + encode_table[41] = 'p'; + encode_table[58] = '6'; + + encode_table[8] = 'I'; + encode_table[25] = 'Z'; + encode_table[42] = 'q'; + encode_table[59] = '7'; + + encode_table[9] = 'J'; + encode_table[26] = 'a'; + encode_table[43] = 'r'; + encode_table[60] = '8'; + + encode_table[10] = 'K'; + encode_table[27] = 'b'; + encode_table[44] = 's'; + encode_table[61] = '9'; + + encode_table[11] = 'L'; + encode_table[28] = 'c'; + encode_table[45] = 't'; + encode_table[62] = '+'; + + encode_table[12] = 'M'; + encode_table[29] = 'd'; + encode_table[46] = 'u'; + encode_table[63] = '/'; + + encode_table[13] = 'N'; + encode_table[30] = 'e'; + encode_table[47] = 'v'; + + encode_table[14] = 'O'; + encode_table[31] = 'f'; + encode_table[48] = 'w'; + + encode_table[15] = 'P'; + encode_table[32] = 'g'; + encode_table[49] = 'x'; + + encode_table[16] = 'Q'; + encode_table[33] = 'h'; + encode_table[50] = 'y'; + + + + // we can now fill out the decode_table by using the encode_table + for (int i = 0; i < UCHAR_MAX; ++i) + { + decode_table[i] = bad_value; + } + for (unsigned char i = 0; i < 64; ++i) + { + decode_table[encode_table[i]] = i; + } + } + +// ---------------------------------------------------------------------------------------- + + base64_kernel_1:: + ~base64_kernel_1 ( + ) + { + delete [] encode_table; + delete [] decode_table; + } + +// ---------------------------------------------------------------------------------------- + + void base64_kernel_1:: + encode ( + std::istream& in_, + std::ostream& out_ + ) const + { + using namespace std; + streambuf& in = *in_.rdbuf(); + streambuf& out = *out_.rdbuf(); + + unsigned char inbuf[3]; + unsigned char outbuf[4]; + streamsize status = in.sgetn(reinterpret_cast(&inbuf),3); + + unsigned char c1, c2, c3, c4, c5, c6; + + int counter = 19; + const char newline = '\n'; + + // while we haven't hit the end of the input stream + while (status != 0) + { + if (counter == 0) + { + counter = 19; + // write a newline + if (out.sputn(reinterpret_cast(&newline),1)!=1) + { + throw std::ios_base::failure("error occured in the base64 object"); + } + } + --counter; + + if (status == 3) + { + // encode the bytes in inbuf to base64 and write them to the output stream + c1 = inbuf[0]&0xfc; + c2 = inbuf[0]&0x03; + c3 = inbuf[1]&0xf0; + c4 = inbuf[1]&0x0f; + c5 = inbuf[2]&0xc0; + c6 = inbuf[2]&0x3f; + + outbuf[0] = c1>>2; + outbuf[1] = (c2<<4)|(c3>>4); + outbuf[2] = (c4<<2)|(c5>>6); + outbuf[3] = c6; + + + outbuf[0] = encode_table[outbuf[0]]; + outbuf[1] = encode_table[outbuf[1]]; + outbuf[2] = encode_table[outbuf[2]]; + outbuf[3] = encode_table[outbuf[3]]; + + // write the encoded bytes to the output stream + if (out.sputn(reinterpret_cast(&outbuf),4)!=4) + { + throw std::ios_base::failure("error occured in the base64 object"); + } + + // get 3 more input bytes + status = in.sgetn(reinterpret_cast(&inbuf),3); + continue; + } + else if (status == 2) + { + // we are at the end of the input stream and need to add some padding + + // encode the bytes in inbuf to base64 and write them to the output stream + c1 = inbuf[0]&0xfc; + c2 = inbuf[0]&0x03; + c3 = inbuf[1]&0xf0; + c4 = inbuf[1]&0x0f; + c5 = 0; + + outbuf[0] = c1>>2; + outbuf[1] = (c2<<4)|(c3>>4); + outbuf[2] = (c4<<2)|(c5>>6); + outbuf[3] = '='; + + outbuf[0] = encode_table[outbuf[0]]; + outbuf[1] = encode_table[outbuf[1]]; + outbuf[2] = encode_table[outbuf[2]]; + + // write the encoded bytes to the output stream + if (out.sputn(reinterpret_cast(&outbuf),4)!=4) + { + throw std::ios_base::failure("error occured in the base64 object"); + } + + + break; + } + else // in this case status must be 1 + { + // we are at the end of the input stream and need to add some padding + + // encode the bytes in inbuf to base64 and write them to the output stream + c1 = inbuf[0]&0xfc; + c2 = inbuf[0]&0x03; + c3 = 0; + + outbuf[0] = c1>>2; + outbuf[1] = (c2<<4)|(c3>>4); + outbuf[2] = '='; + outbuf[3] = '='; + + outbuf[0] = encode_table[outbuf[0]]; + outbuf[1] = encode_table[outbuf[1]]; + + + // write the encoded bytes to the output stream + if (out.sputn(reinterpret_cast(&outbuf),4)!=4) + { + throw std::ios_base::failure("error occured in the base64 object"); + } + + break; + } + } // while (status != 0) + + + // make sure the stream buffer flushes to its I/O channel + out.pubsync(); + } + +// ---------------------------------------------------------------------------------------- + + void base64_kernel_1:: + decode ( + std::istream& in_, + std::ostream& out_ + ) const + { + using namespace std; + streambuf& in = *in_.rdbuf(); + streambuf& out = *out_.rdbuf(); + + unsigned char inbuf[4]; + unsigned char outbuf[3]; + int inbuf_pos = 0; + streamsize status = in.sgetn(reinterpret_cast(inbuf),1); + + // only count this character if it isn't some kind of filler + if (status == 1 && decode_table[inbuf[0]] != bad_value ) + ++inbuf_pos; + + unsigned char c1, c2, c3, c4, c5, c6; + streamsize outsize; + + // while we haven't hit the end of the input stream + while (status != 0) + { + // if we have 4 valid characters + if (inbuf_pos == 4) + { + inbuf_pos = 0; + + // this might be the end of the encoded data so we need to figure out if + // there was any padding applied. + outsize = 3; + if (inbuf[3] == '=') + { + if (inbuf[2] == '=') + outsize = 1; + else + outsize = 2; + } + + // decode the incoming characters + inbuf[0] = decode_table[inbuf[0]]; + inbuf[1] = decode_table[inbuf[1]]; + inbuf[2] = decode_table[inbuf[2]]; + inbuf[3] = decode_table[inbuf[3]]; + + + // now pack these guys into bytes rather than 6 bit chunks + c1 = inbuf[0]<<2; + c2 = inbuf[1]>>4; + c3 = inbuf[1]<<4; + c4 = inbuf[2]>>2; + c5 = inbuf[2]<<6; + c6 = inbuf[3]; + + outbuf[0] = c1|c2; + outbuf[1] = c3|c4; + outbuf[2] = c5|c6; + + + // write the encoded bytes to the output stream + if (out.sputn(reinterpret_cast(&outbuf),outsize)!=outsize) + { + throw std::ios_base::failure("error occured in the base64 object"); + } + } + + // get more input characters + status = in.sgetn(reinterpret_cast(inbuf + inbuf_pos),1); + // only count this character if it isn't some kind of filler + if ((decode_table[inbuf[inbuf_pos]] != bad_value || inbuf[inbuf_pos] == '=') && + status != 0) + ++inbuf_pos; + } // while (status != 0) + + if (inbuf_pos != 0) + { + ostringstream sout; + sout << inbuf_pos << " extra characters were found at the end of the encoded data." + << " This may indicate that the data stream has been truncated."; + // this happens if we hit EOF in the middle of decoding a 24bit block. + throw decode_error(sout.str()); + } + + // make sure the stream buffer flushes to its I/O channel + out.pubsync(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BASE64_KERNEL_1_CPp_ + diff --git a/dlib/base64/base64_kernel_1.h b/dlib/base64/base64_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..63f7738f40d0a3aa9f25fccafd8343dc8e4679a6 --- /dev/null +++ b/dlib/base64/base64_kernel_1.h @@ -0,0 +1,74 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BASE64_KERNEl_1_ +#define DLIB_BASE64_KERNEl_1_ + +#include "../algs.h" +#include + +namespace dlib +{ + + class base64_kernel_1 + { + /*! + INITIAL VALUE + - bad_value == 100 + - encode_table == a pointer to an array of 64 chars + - where x is a 6 bit value the following is true: + - encode_table[x] == the base64 encoding of x + - decode_table == a pointer to an array of UCHAR_MAX chars + - where x is any char value: + - if (x is a valid character in the base64 coding scheme) then + - decode_table[x] == the 6 bit value that x encodes + - else + - decode_table[x] == bad_value + + CONVENTION + - The state of this object never changes so just refer to its + initial value. + + + !*/ + + public: + + class decode_error : public dlib::error { public: + decode_error( const std::string& e) : error(e) {}}; + + base64_kernel_1 ( + ); + + virtual ~base64_kernel_1 ( + ); + + void encode ( + std::istream& in, + std::ostream& out + ) const; + + void decode ( + std::istream& in, + std::ostream& out + ) const; + + private: + + char* encode_table; + unsigned char* decode_table; + const unsigned char bad_value; + + // restricted functions + base64_kernel_1(base64_kernel_1&); // copy constructor + base64_kernel_1& operator=(base64_kernel_1&); // assignment operator + + }; + +} + +#ifdef NO_MAKEFILE +#include "base64_kernel_1.cpp" +#endif + +#endif // DLIB_BASE64_KERNEl_1_ + diff --git a/dlib/base64/base64_kernel_abstract.h b/dlib/base64/base64_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..e1cb72c1cb0bbb01bd60821155eeba9d90e40110 --- /dev/null +++ b/dlib/base64/base64_kernel_abstract.h @@ -0,0 +1,95 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BASE64_KERNEl_ABSTRACT_ +#ifdef DLIB_BASE64_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include + +namespace dlib +{ + + class base64 + { + /*! + INITIAL VALUE + This object does not have any state associated with it. + + WHAT THIS OBJECT REPRESENTS + This object consists of the two functions encode and decode. + These functions allow you to encode and decode data to and from + the Base64 Content-Transfer-Encoding defined in section 6.8 of + rfc2045. + !*/ + + public: + + class decode_error : public dlib::error {}; + + base64 ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~base64 ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + + void encode ( + std::istream& in, + std::ostream& out + ) const; + /*! + ensures + - reads all data from in (until EOF is reached) and encodes it + and writes it to out + throws + - std::ios_base::failure + if there was a problem writing to out then this exception will + be thrown. + - any other exception + this exception may be thrown if there is any other problem + !*/ + + + void decode ( + std::istream& in, + std::ostream& out + ) const; + /*! + ensures + - reads data from in (until EOF is reached) and decodees it + and writes it to out. + throws + - std::ios_base::failure + if there was a problem writing to out then this exception will + be thrown. + - decode_error + if an error was detected in the encoded data that prevented + it from being correctly decoded then this exception is + thrown. + - any other exception + this exception may be thrown if there is any other problem + !*/ + + + private: + + // restricted functions + base64(base64&); // copy constructor + base64& operator=(base64&); // assignment operator + + }; + +} + +#endif // DLIB_BASE64_KERNEl_ABSTRACT_ + diff --git a/dlib/bayes_utils.h b/dlib/bayes_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..a88ee056ab20cbe7ef9e13b9e50c9c164391fb91 --- /dev/null +++ b/dlib/bayes_utils.h @@ -0,0 +1,11 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BAYES_UTILs_H_ +#define DLIB_BAYES_UTILs_H_ + +#include "bayes_utils/bayes_utils.h" + +#endif // DLIB_BAYES_UTILs_H_ + + + diff --git a/dlib/bayes_utils/bayes_utils.h b/dlib/bayes_utils/bayes_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..8da29652452971e2fb5da8536c8c81db9764c379 --- /dev/null +++ b/dlib/bayes_utils/bayes_utils.h @@ -0,0 +1,1675 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BAYES_UTILs_ +#define DLIB_BAYES_UTILs_ + +#include "bayes_utils_abstract.h" + +#include "../string.h" +#include "../map.h" +#include "../matrix.h" +#include "../rand.h" +#include "../array.h" +#include "../set.h" +#include "../algs.h" +#include "../noncopyable.h" +#include "../smart_pointers.h" +#include "../graph.h" +#include +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class assignment + { + public: + + assignment() + { + } + + assignment( + const assignment& a + ) + { + a.reset(); + while (a.move_next()) + { + unsigned long idx = a.element().key(); + unsigned long value = a.element().value(); + vals.add(idx,value); + } + } + + assignment& operator = ( + const assignment& rhs + ) + { + if (this == &rhs) + return *this; + + assignment(rhs).swap(*this); + return *this; + } + + void clear() + { + vals.clear(); + } + + bool operator < ( + const assignment& item + ) const + { + if (size() < item.size()) + return true; + else if (size() > item.size()) + return false; + + reset(); + item.reset(); + while (move_next()) + { + item.move_next(); + if (element().key() < item.element().key()) + return true; + else if (element().key() > item.element().key()) + return false; + else if (element().value() < item.element().value()) + return true; + else if (element().value() > item.element().value()) + return false; + } + + return false; + } + + bool has_index ( + unsigned long idx + ) const + { + return vals.is_in_domain(idx); + } + + void add ( + unsigned long idx, + unsigned long value = 0 + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( has_index(idx) == false , + "\tvoid assignment::add(idx)" + << "\n\tYou can't add the same index to an assignment object more than once" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + + vals.add(idx, value); + } + + unsigned long& operator[] ( + const long idx + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( has_index(idx) == true , + "\tunsigned long assignment::operator[](idx)" + << "\n\tYou can't access an index value if it isn't already in the object" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + + return vals[idx]; + } + + const unsigned long& operator[] ( + const long idx + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT( has_index(idx) == true , + "\tunsigned long assignment::operator[](idx)" + << "\n\tYou can't access an index value if it isn't already in the object" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + + return vals[idx]; + } + + void swap ( + assignment& item + ) + { + vals.swap(item.vals); + } + + void remove ( + unsigned long idx + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( has_index(idx) == true , + "\tunsigned long assignment::remove(idx)" + << "\n\tYou can't remove an index value if it isn't already in the object" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + + vals.destroy(idx); + } + + unsigned long size() const { return vals.size(); } + + void reset() const { vals.reset(); } + + bool move_next() const { return vals.move_next(); } + + map_pair& element() + { + // make sure requires clause is not broken + DLIB_ASSERT(current_element_valid() == true, + "\tmap_pair& assignment::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + return vals.element(); + } + + const map_pair& element() const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_element_valid() == true, + "\tconst map_pair& assignment::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return vals.element(); + } + + bool at_start() const { return vals.at_start(); } + + bool current_element_valid() const { return vals.current_element_valid(); } + + friend inline void serialize ( + const assignment& item, + std::ostream& out + ) + { + serialize(item.vals, out); + } + + friend inline void deserialize ( + assignment& item, + std::istream& in + ) + { + deserialize(item.vals, in); + } + + private: + mutable dlib::map::kernel_1b_c vals; + }; + + inline std::ostream& operator << ( + std::ostream& out, + const assignment& a + ) + { + a.reset(); + out << "("; + if (a.move_next()) + out << a.element().key() << ":" << a.element().value(); + + while (a.move_next()) + { + out << ", " << a.element().key() << ":" << a.element().value(); + } + + out << ")"; + return out; + } + + + inline void swap ( + assignment& a, + assignment& b + ) + { + a.swap(b); + } + + +// ------------------------------------------------------------------------ + + class joint_probability_table + { + /*! + INITIAL VALUE + - table.size() == 0 + + CONVENTION + - size() == table.size() + - probability(a) == table[a] + !*/ + public: + + joint_probability_table ( + const joint_probability_table& t + ) + { + t.reset(); + while (t.move_next()) + { + assignment a = t.element().key(); + double p = t.element().value(); + set_probability(a,p); + } + } + + joint_probability_table() {} + + joint_probability_table& operator= ( + const joint_probability_table& rhs + ) + { + if (this == &rhs) + return *this; + joint_probability_table(rhs).swap(*this); + return *this; + } + + void set_probability ( + const assignment& a, + double p + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(0.0 <= p && p <= 1.0, + "\tvoid& joint_probability_table::set_probability(a,p)" + << "\n\tyou have given an invalid probability value" + << "\n\ttp: " << p + << "\n\tta: " << a + << "\n\tthis: " << this + ); + + if (table.is_in_domain(a)) + { + table[a] = p; + } + else + { + assignment temp(a); + table.add(temp,p); + } + } + + bool has_entry_for ( + const assignment& a + ) const + { + return table.is_in_domain(a); + } + + void add_probability ( + const assignment& a, + double p + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(0.0 <= p && p <= 1.0, + "\tvoid& joint_probability_table::add_probability(a,p)" + << "\n\tyou have given an invalid probability value" + << "\n\ttp: " << p + << "\n\tta: " << a + << "\n\tthis: " << this + ); + + if (table.is_in_domain(a)) + { + table[a] += p; + } + else + { + assignment temp(a); + table.add(temp,p); + } + } + + const double probability ( + const assignment& a + ) const + { + return table[a]; + } + + void clear() + { + table.clear(); + } + + unsigned long size () const { return table.size(); } + bool move_next() const { return table.move_next(); } + void reset() const { table.reset(); } + map_pair& element() + { + // make sure requires clause is not broken + DLIB_ASSERT(current_element_valid() == true, + "\tmap_pair& joint_probability_table::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return table.element(); + } + + const map_pair& element() const + { + // make sure requires clause is not broken + DLIB_ASSERT(current_element_valid() == true, + "\tconst map_pair& joint_probability_table::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return table.element(); + } + + bool at_start() const { return table.at_start(); } + + bool current_element_valid() const { return table.current_element_valid(); } + + + template + void marginalize ( + const T& vars, + joint_probability_table& out + ) const + { + out.clear(); + double p; + reset(); + while (move_next()) + { + assignment a; + const assignment& asrc = element().key(); + p = element().value(); + + asrc.reset(); + while (asrc.move_next()) + { + if (vars.is_member(asrc.element().key())) + a.add(asrc.element().key(), asrc.element().value()); + } + + out.add_probability(a,p); + } + } + + void marginalize ( + const unsigned long var, + joint_probability_table& out + ) const + { + out.clear(); + double p; + reset(); + while (move_next()) + { + assignment a; + const assignment& asrc = element().key(); + p = element().value(); + + asrc.reset(); + while (asrc.move_next()) + { + if (var == asrc.element().key()) + a.add(asrc.element().key(), asrc.element().value()); + } + + out.add_probability(a,p); + } + } + + void normalize ( + ) + { + double sum = 0; + + reset(); + while (move_next()) + sum += element().value(); + + reset(); + while (move_next()) + element().value() /= sum; + } + + void swap ( + joint_probability_table& item + ) + { + table.swap(item.table); + } + + friend inline void serialize ( + const joint_probability_table& item, + std::ostream& out + ) + { + serialize(item.table, out); + } + + friend inline void deserialize ( + joint_probability_table& item, + std::istream& in + ) + { + deserialize(item.table, in); + } + + private: + + dlib::map::kernel_1b_c table; + }; + + inline void swap ( + joint_probability_table& a, + joint_probability_table& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + class conditional_probability_table : noncopyable + { + /*! + INITIAL VALUE + - table.size() == 0 + + CONVENTION + - if (table.is_in_domain(ps) && value < num_vals && table[ps](value) >= 0) then + - has_entry_for(value,ps) == true + - probability(value,ps) == table[ps](value) + - else + - has_entry_for(value,ps) == false + + - num_values() == num_vals + !*/ + public: + + conditional_probability_table() + { + clear(); + } + + void set_num_values ( + unsigned long num + ) + { + num_vals = num; + table.clear(); + } + + bool has_entry_for ( + unsigned long value, + const assignment& ps + ) const + { + if (table.is_in_domain(ps) && value < num_vals && table[ps](value) >= 0) + return true; + else + return false; + } + + unsigned long num_values ( + ) const { return num_vals; } + + void set_probability ( + unsigned long value, + const assignment& ps, + double p + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( value < num_values() && 0.0 <= p && p <= 1.0 , + "\tvoid conditional_probability_table::set_probability()" + << "\n\tinvalid arguments to set_probability" + << "\n\tvalue: " << value + << "\n\tnum_values(): " << num_values() + << "\n\tp: " << p + << "\n\tps: " << ps + << "\n\tthis: " << this + ); + + if (table.is_in_domain(ps)) + { + table[ps](value) = p; + } + else + { + matrix dist(num_vals); + set_all_elements(dist,-1); + dist(value) = p; + assignment temp(ps); + table.add(temp,dist); + } + } + + double probability( + unsigned long value, + const assignment& ps + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT( value < num_values() && has_entry_for(value,ps) , + "\tvoid conditional_probability_table::probability()" + << "\n\tinvalid arguments to set_probability" + << "\n\tvalue: " << value + << "\n\tnum_values(): " << num_values() + << "\n\tps: " << ps + << "\n\tthis: " << this + ); + + return table[ps](value); + } + + void clear() + { + table.clear(); + num_vals = 0; + } + + void empty_table () + { + table.clear(); + } + + void swap ( + conditional_probability_table& item + ) + { + exchange(num_vals, item.num_vals); + table.swap(item.table); + } + + friend inline void serialize ( + const conditional_probability_table& item, + std::ostream& out + ) + { + serialize(item.table, out); + serialize(item.num_vals, out); + } + + friend inline void deserialize ( + conditional_probability_table& item, + std::istream& in + ) + { + deserialize(item.table, in); + deserialize(item.num_vals, in); + } + + private: + dlib::map >::kernel_1b_c table; + unsigned long num_vals; + }; + + inline void swap ( + conditional_probability_table& a, + conditional_probability_table& b + ) { a.swap(b); } + +// ------------------------------------------------------------------------ + + class bayes_node : noncopyable + { + public: + bayes_node () + { + is_instantiated = false; + value_ = 0; + } + + unsigned long value ( + ) const { return value_;} + + void set_value ( + unsigned long new_value + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( new_value < table().num_values(), + "\tvoid bayes_node::set_value(new_value)" + << "\n\tnew_value must be less than the number of possible values for this node" + << "\n\tnew_value: " << new_value + << "\n\ttable().num_values(): " << table().num_values() + << "\n\tthis: " << this + ); + + value_ = new_value; + } + + conditional_probability_table& table ( + ) { return table_; } + + const conditional_probability_table& table ( + ) const { return table_; } + + bool is_evidence ( + ) const { return is_instantiated; } + + void set_as_nonevidence ( + ) { is_instantiated = false; } + + void set_as_evidence ( + ) { is_instantiated = true; } + + void swap ( + bayes_node& item + ) + { + exchange(value_, item.value_); + exchange(is_instantiated, item.is_instantiated); + table_.swap(item.table_); + } + + friend inline void serialize ( + const bayes_node& item, + std::ostream& out + ) + { + serialize(item.value_, out); + serialize(item.is_instantiated, out); + serialize(item.table_, out); + } + + friend inline void deserialize ( + bayes_node& item, + std::istream& in + ) + { + deserialize(item.value_, in); + deserialize(item.is_instantiated, in); + deserialize(item.table_, in); + } + + private: + + unsigned long value_; + bool is_instantiated; + conditional_probability_table table_; + }; + + inline void swap ( + bayes_node& a, + bayes_node& b + ) { a.swap(b); } + +// ------------------------------------------------------------------------ + + namespace bayes_node_utils + { + + template + void set_node_value ( + T& bn, + unsigned long n, + unsigned long val + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes() && val < node_num_values(bn,n), + "\tvoid bayes_node_utils::set_node_value(bn, n, val)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tval: " << val + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + << "\n\tnode_num_values(bn,n): " << node_num_values(bn,n) + ); + + bn.node(n).data.set_value(val); + } + + // ---------------------------------------------------------------------------------------- + template + unsigned long node_value ( + const T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tunsigned long bayes_node_utils::node_value(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + return bn.node(n).data.value(); + } + // ---------------------------------------------------------------------------------------- + + template + bool node_is_evidence ( + const T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tbool bayes_node_utils::node_is_evidence(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + return bn.node(n).data.is_evidence(); + } + + // ---------------------------------------------------------------------------------------- + + template + void set_node_as_evidence ( + T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tvoid bayes_node_utils::set_node_as_evidence(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + bn.node(n).data.set_as_evidence(); + } + + // ---------------------------------------------------------------------------------------- + template + void set_node_as_nonevidence ( + T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tvoid bayes_node_utils::set_node_as_nonevidence(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + bn.node(n).data.set_as_nonevidence(); + } + + // ---------------------------------------------------------------------------------------- + + template + void set_node_num_values ( + T& bn, + unsigned long n, + unsigned long num + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tvoid bayes_node_utils::set_node_num_values(bn, n, num)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + bn.node(n).data.table().set_num_values(num); + } + + // ---------------------------------------------------------------------------------------- + + template + unsigned long node_num_values ( + const T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tvoid bayes_node_utils::node_num_values(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + return bn.node(n).data.table().num_values(); + } + + // ---------------------------------------------------------------------------------------- + + template + const double node_probability ( + const T& bn, + unsigned long n, + unsigned long value, + const assignment& parents + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes() && value < node_num_values(bn,n), + "\tdouble bayes_node_utils::node_probability(bn, n, value, parents)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tvalue: " << value + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + << "\n\tnode_num_values(bn,n): " << node_num_values(bn,n) + ); + + DLIB_ASSERT( parents.size() == bn.node(n).number_of_parents(), + "\tdouble bayes_node_utils::node_probability(bn, n, value, parents)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tparents.size(): " << parents.size() + << "\n\tb.node(n).number_of_parents(): " << bn.node(n).number_of_parents() + ); + +#ifdef ENABLE_ASSERTS + parents.reset(); + while (parents.move_next()) + { + const unsigned long x = parents.element().key(); + DLIB_ASSERT( bn.has_edge(x, n), + "\tdouble bayes_node_utils::node_probability(bn, n, value, parents)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tx: " << x + ); + DLIB_ASSERT( parents[x] < node_num_values(bn,x), + "\tdouble bayes_node_utils::node_probability(bn, n, value, parents)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tx: " << x + << "\n\tparents[x]: " << parents[x] + << "\n\tnode_num_values(bn,x): " << node_num_values(bn,x) + ); + } +#endif + + return bn.node(n).data.table().probability(value, parents); + } + + // ---------------------------------------------------------------------------------------- + + template + void set_node_probability ( + T& bn, + unsigned long n, + unsigned long value, + const assignment& parents, + double p + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes() && value < node_num_values(bn,n), + "\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tp: " << p + << "\n\tvalue: " << value + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + << "\n\tnode_num_values(bn,n): " << node_num_values(bn,n) + ); + + DLIB_ASSERT( parents.size() == bn.node(n).number_of_parents(), + "\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tp: " << p + << "\n\tparents.size(): " << parents.size() + << "\n\tbn.node(n).number_of_parents(): " << bn.node(n).number_of_parents() + ); + + DLIB_ASSERT( 0.0 <= p && p <= 1.0, + "\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tp: " << p + ); + +#ifdef ENABLE_ASSERTS + parents.reset(); + while (parents.move_next()) + { + const unsigned long x = parents.element().key(); + DLIB_ASSERT( bn.has_edge(x, n), + "\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tx: " << x + ); + DLIB_ASSERT( parents[x] < node_num_values(bn,x), + "\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tx: " << x + << "\n\tparents[x]: " << parents[x] + << "\n\tnode_num_values(bn,x): " << node_num_values(bn,x) + ); + } +#endif + + bn.node(n).data.table().set_probability(value,parents,p); + } + +// ---------------------------------------------------------------------------------------- + + template + const assignment node_first_parent_assignment ( + const T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tconst assignment bayes_node_utils::node_first_parent_assignment(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + ); + + assignment a; + const unsigned long num_parents = bn.node(n).number_of_parents(); + for (unsigned long i = 0; i < num_parents; ++i) + { + a.add(bn.node(n).parent(i).index(), 0); + } + return a; + } + +// ---------------------------------------------------------------------------------------- + + template + bool node_next_parent_assignment ( + const T& bn, + unsigned long n, + assignment& a + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + ); + + DLIB_ASSERT( a.size() == bn.node(n).number_of_parents(), + "\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\ta.size(): " << a.size() + << "\n\tbn.node(n).number_of_parents(): " << bn.node(n).number_of_parents() + ); + +#ifdef ENABLE_ASSERTS + a.reset(); + while (a.move_next()) + { + const unsigned long x = a.element().key(); + DLIB_ASSERT( bn.has_edge(x, n), + "\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tx: " << x + ); + DLIB_ASSERT( a[x] < node_num_values(bn,x), + "\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tx: " << x + << "\n\ta[x]: " << a[x] + << "\n\tnode_num_values(bn,x): " << node_num_values(bn,x) + ); + } +#endif + + // basically this loop just adds 1 to the assignment but performs + // carries if necessary + for (unsigned long p = 0; p < a.size(); ++p) + { + const unsigned long pindex = bn.node(n).parent(p).index(); + a[pindex] += 1; + + // if we need to perform a carry + if (a[pindex] >= node_num_values(bn,pindex)) + { + a[pindex] = 0; + } + else + { + // no carry necessary so we are done + return true; + } + } + + // we got through the entire loop which means a carry propagated all the way out + // so there must not be any more valid assignments left + return false; + } + +// ---------------------------------------------------------------------------------------- + + template + bool node_cpt_filled_out ( + const T& bn, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( n < bn.number_of_nodes(), + "\tbool bayes_node_utils::node_cpt_filled_out(bn, n)" + << "\n\tInvalid arguments to this function" + << "\n\tn: " << n + << "\n\tbn.number_of_nodes(): " << bn.number_of_nodes() + ); + + const unsigned long num_values = node_num_values(bn,n); + + + const conditional_probability_table& table = bn.node(n).data.table(); + + // now loop over all the possible parent assignments for this node + assignment a(node_first_parent_assignment(bn,n)); + do + { + double sum = 0; + // make sure that this assignment has an entry for all the values this node can take one + for (unsigned long value = 0; value < num_values; ++value) + { + if (table.has_entry_for(value,a) == false) + return false; + else + sum += table.probability(value,a); + } + + // check if the sum of probabilities equals 1 as it should + if (std::abs(sum-1.0) > 1e-5) + return false; + } while (node_next_parent_assignment(bn,n,a)); + + return true; + } + + } + +// ---------------------------------------------------------------------------------------- + + class bayesian_network_gibbs_sampler : noncopyable + { + public: + + bayesian_network_gibbs_sampler () + { + rnd.set_seed(cast_to_string(std::time(0))); + } + + + template < + typename T + > + void sample_graph ( + T& bn + ) + { + using namespace bayes_node_utils; + for (unsigned long n = 0; n < bn.number_of_nodes(); ++n) + { + if (node_is_evidence(bn, n)) + continue; + + samples.set_size(node_num_values(bn,n)); + // obtain the probability distribution for this node + for (long i = 0; i < samples.nc(); ++i) + { + set_node_value(bn, n, i); + samples(i) = node_probability(bn, n); + + for (unsigned long j = 0; j < bn.node(n).number_of_children(); ++j) + samples(i) *= node_probability(bn, bn.node(n).child(j).index()); + } + + //normalize samples + samples /= sum(samples); + + + // select a random point in the probability distribution + double prob = rnd.get_random_double(); + + // now find the point in the distribution this probability corresponds to + long j; + for (j = 0; j < samples.nc()-1; ++j) + { + if (prob <= samples(j)) + break; + else + prob -= samples(j); + } + + set_node_value(bn, n, j); + } + } + + + private: + + template < + typename T + > + const double node_probability ( + const T& bn, + unsigned long n + ) + /*! + requires + - n < bn.number_of_nodes() + ensures + - computes the probability of node n having its current value given + the current values of its parents in the network bn + !*/ + { + v.clear(); + for (unsigned long i = 0; i < bn.node(n).number_of_parents(); ++i) + { + v.add(bn.node(n).parent(i).index(), bn.node(n).parent(i).data.value()); + } + return bn.node(n).data.table().probability(bn.node(n).data.value(), v); + } + + assignment v; + + dlib::rand::float_1a rnd; + matrix samples; + }; + +// ---------------------------------------------------------------------------------------- + + namespace bayesian_network_join_tree_helpers + { + class bnjt + { + /*! + this object is the base class used in this pimpl idiom + !*/ + public: + virtual ~bnjt() {} + + virtual const matrix probability( + unsigned long idx + ) const = 0; + }; + + template + class bnjt_impl : public bnjt + { + /*! + This object is the implementation in the pimpl idiom + !*/ + + public: + + bnjt_impl ( + const T& bn, + const U& join_tree + ) + { + create_bayesian_network_join_tree(bn, join_tree, join_tree_values); + + cliques.expand(bn.number_of_nodes()); + + // figure out which cliques contain each node + for (unsigned long i = 0; i < cliques.size(); ++i) + { + // find the smallest clique that contains node with index i + unsigned long smallest_clique = 0; + unsigned long size = std::numeric_limits::max(); + + for (unsigned long n = 0; n < join_tree.number_of_nodes(); ++n) + { + if (join_tree.node(n).data.is_member(i) && join_tree.node(n).data.size() < size) + { + size = join_tree.node(n).data.size(); + smallest_clique = n; + } + } + + cliques[i] = smallest_clique; + } + } + + virtual const matrix probability( + unsigned long idx + ) const + { + join_tree_values.node(cliques[idx]).data.marginalize(idx, table); + table.normalize(); + var.clear(); + var.add(idx); + dist.set_size(table.size()); + + // read the probabilities out of the table and into the row matrix + for (unsigned long i = 0; i < table.size(); ++i) + { + var[idx] = i; + dist(i) = table.probability(var); + } + + return dist; + } + + private: + + graph< joint_probability_table, joint_probability_table >::kernel_1a_c join_tree_values; + array::expand_1a_c cliques; + mutable joint_probability_table table; + mutable assignment var; + mutable matrix dist; + + + // ---------------------------------------------------------------------------------------- + + template + bool set_contains_all_parents_of_node ( + const set_type& set, + const node_type& node + ) + { + for (unsigned long i = 0; i < node.number_of_parents(); ++i) + { + if (set.is_member(node.parent(i).index()) == false) + return false; + } + return true; + } + + // ---------------------------------------------------------------------------------------- + + template < + typename V + > + void pass_join_tree_message ( + const U& join_tree, + V& bn_join_tree , + unsigned long from, + unsigned long to + ) + { + using namespace bayes_node_utils; + const typename U::edge_type& e = edge(join_tree, from, to); + typename V::edge_type& old_s = edge(bn_join_tree, from, to); + + typedef typename V::edge_type joint_prob_table; + + joint_prob_table new_s; + bn_join_tree.node(from).data.marginalize(e, new_s); + + joint_probability_table temp(new_s); + // divide new_s by old_s and store the result in temp. + // if old_s is empty then that is the same as if it was all 1s + // so we don't have to do this if that is the case. + if (old_s.size() > 0) + { + temp.reset(); + old_s.reset(); + while (temp.move_next()) + { + old_s.move_next(); + if (old_s.element().value() != 0) + temp.element().value() /= old_s.element().value(); + } + } + + // now multiply temp by d and store the results in d + joint_probability_table& d = bn_join_tree.node(to).data; + d.reset(); + while (d.move_next()) + { + assignment a; + const assignment& asrc = d.element().key(); + asrc.reset(); + while (asrc.move_next()) + { + if (e.is_member(asrc.element().key())) + a.add(asrc.element().key(), asrc.element().value()); + } + + d.element().value() *= temp.probability(a); + + } + + // store new_s in old_s + new_s.swap(old_s); + + } + + // ---------------------------------------------------------------------------------------- + + template < + typename V + > + void create_bayesian_network_join_tree ( + const T& bn, + const U& join_tree, + V& bn_join_tree + ) + /*! + requires + - bn is a proper bayesian network + - join_tree is the join tree for that bayesian network + ensures + - bn_join_tree == the output of the join tree algorithm for bayesian network inference. + So each node in this graph contains a joint_probability_table for the clique + in the corresponding node in the join_tree graph. + !*/ + { + using namespace bayes_node_utils; + bn_join_tree.clear(); + copy_graph_structure(join_tree, bn_join_tree); + + // we need to keep track of which node is "in" each clique for the purposes of + // initializing the tables in each clique. So this vector will be used to do that + // and a value of join_tree.number_of_nodes() means that the node with + // that index is unassigned. + std::vector node_assigned_to(bn.number_of_nodes(),join_tree.number_of_nodes()); + + // populate evidence with all the evidence node indices and their values + dlib::map::kernel_1b_c evidence; + for (unsigned long i = 0; i < bn.number_of_nodes(); ++i) + { + if (node_is_evidence(bn, i)) + { + unsigned long idx = i; + unsigned long value = node_value(bn, i); + evidence.add(idx,value); + } + } + + + // initialize the bn join tree + for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i) + { + bool contains_evidence = false; + std::vector indices; + assignment value; + + // loop over all the nodes in this clique in the join tree. In this loop + // we are making an assignment with all the values of the nodes it represents set to 0 + join_tree.node(i).data.reset(); + while (join_tree.node(i).data.move_next()) + { + const unsigned long idx = join_tree.node(i).data.element(); + indices.push_back(idx); + value.add(idx); + + if (evidence.is_in_domain(join_tree.node(i).data.element())) + contains_evidence = true; + } + + // now loop over all possible combinations of values that the nodes this + // clique in the join tree can take on. We do this by counting by one through all + // legal values + bool more_assignments = true; + while (more_assignments) + { + bn_join_tree.node(i).data.set_probability(value,1); + + // account for any evidence + if (contains_evidence) + { + // loop over all the nodes in this cluster + for (unsigned long j = 0; j < indices.size(); ++j) + { + // if the current node is an evidence node + if (evidence.is_in_domain(indices[j])) + { + const unsigned long idx = indices[j]; + const unsigned long evidence_value = evidence[idx]; + if (value[idx] != evidence_value) + bn_join_tree.node(i).data.set_probability(value , 0); + } + } + } + + + // now check if any of the nodes in this cluster also have their parents in this cluster + join_tree.node(i).data.reset(); + while (join_tree.node(i).data.move_next()) + { + const unsigned long idx = join_tree.node(i).data.element(); + // if this clique contains all the parents of this node and also hasn't + // been assigned to another clique + if (set_contains_all_parents_of_node(join_tree.node(i).data, bn.node(idx)) && + (i == node_assigned_to[idx] || node_assigned_to[idx] == join_tree.number_of_nodes()) ) + { + // note that this node is now assigned to this clique + node_assigned_to[idx] = i; + // node idx has all its parents in the cluster + assignment parent_values; + for (unsigned long j = 0; j < bn.node(idx).number_of_parents(); ++j) + { + const unsigned long pidx = bn.node(idx).parent(j).index(); + parent_values.add(pidx, value[pidx]); + } + + double temp = bn_join_tree.node(i).data.probability(value); + bn_join_tree.node(i).data.set_probability(value, temp * node_probability(bn, idx, value[idx], parent_values)); + + } + } + + + // now advance the value variable to its next possible state if there is one + more_assignments = false; + value.reset(); + while (value.move_next()) + { + value.element().value() += 1; + // if overflow + if (value.element().value() == node_num_values(bn, value.element().key())) + { + value.element().value() = 0; + } + else + { + more_assignments = true; + break; + } + } + + } // end while (more_assignments) + } + + + + + // the tree is now initialized. Now all we need to do is perform the propagation and + // we are done + dlib::array::compare_1b_c>::expand_1a_c remaining_msg_to_send; + dlib::array::compare_1b_c>::expand_1a_c remaining_msg_to_receive; + remaining_msg_to_receive.expand(join_tree.number_of_nodes()); + remaining_msg_to_send.expand(join_tree.number_of_nodes()); + for (unsigned long i = 0; i < remaining_msg_to_receive.size(); ++i) + { + for (unsigned long j = 0; j < join_tree.node(i).number_of_neighbors(); ++j) + { + const unsigned long idx = join_tree.node(i).neighbor(j).index(); + unsigned long temp; + temp = idx; remaining_msg_to_receive[i].add(temp); + temp = idx; remaining_msg_to_send[i].add(temp); + } + } + + // now remaining_msg_to_receive[i] contains all the nodes that node i hasn't yet received + // a message from. + // we will consider node 0 to be the root node. + + + bool message_sent = true; + std::vector::iterator iter; + while (message_sent) + { + message_sent = false; + for (unsigned long i = 1; i < remaining_msg_to_send.size(); ++i) + { + // if node i hasn't sent any messages but has received all but one then send a message to the one + // node who hasn't sent i a message + if (remaining_msg_to_send[i].size() == join_tree.node(i).number_of_neighbors() && remaining_msg_to_receive[i].size() == 1) + { + unsigned long to; + // get the last remaining thing from this set + remaining_msg_to_receive[i].remove_any(to); + + // send the message + pass_join_tree_message(join_tree, bn_join_tree, i, to); + + // record that we sent this message + remaining_msg_to_send[i].destroy(to); + remaining_msg_to_receive[to].destroy(i); + + // put to back in since we still need to receive it + remaining_msg_to_receive[i].add(to); + message_sent = true; + } + else if (remaining_msg_to_receive[i].size() == 0 && remaining_msg_to_send[i].size() > 0) + { + unsigned long to; + remaining_msg_to_send[i].remove_any(to); + remaining_msg_to_receive[to].destroy(i); + pass_join_tree_message(join_tree, bn_join_tree, i, to); + message_sent = true; + } + } + + if (remaining_msg_to_receive[0].size() == 0) + { + // send a message to all of the root nodes neighbors unless we have already sent out he messages + while (remaining_msg_to_send[0].size() > 0) + { + unsigned long to; + remaining_msg_to_send[0].remove_any(to); + remaining_msg_to_receive[to].destroy(0); + pass_join_tree_message(join_tree, bn_join_tree, 0, to); + message_sent = true; + } + } + + + } + + } + + }; + } + + class bayesian_network_join_tree : noncopyable + { + /*! + use the pimpl idiom to push the template arguments from the class level to the + constructor level + !*/ + + public: + + template < + typename T, + typename U + > + bayesian_network_join_tree ( + const T& bn, + const U& join_tree + ) + { + // make sure requires clause is not broken + DLIB_ASSERT( bn.number_of_nodes() > 0 , + "\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)" + << "\n\tYou have given an invalid bayesian network" + << "\n\tthis: " << this + ); + + DLIB_ASSERT( is_join_tree(bn, join_tree) == true , + "\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)" + << "\n\tYou have given an invalid join tree for the supplied bayesian network" + << "\n\tthis: " << this + ); + DLIB_ASSERT( graph_contains_length_one_cycle(bn) == false, + "\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)" + << "\n\tYou have given an invalid bayesian network" + << "\n\tthis: " << this + ); + DLIB_ASSERT( graph_is_connected(bn) == true, + "\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)" + << "\n\tYou have given an invalid bayesian network" + << "\n\tthis: " << this + ); + +#ifdef ENABLE_ASSERTS + for (unsigned long i = 0; i < bn.number_of_nodes(); ++i) + { + DLIB_ASSERT(bayes_node_utils::node_cpt_filled_out(bn,i) == true, + "\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)" + << "\n\tYou have given an invalid bayesian network. " + << "\n\tYou must finish filling out the conditional_probability_table of node " << i + << "\n\tthis: " << this + ); + } +#endif + + impl.reset(new bayesian_network_join_tree_helpers::bnjt_impl(bn, join_tree)); + num_nodes = bn.number_of_nodes(); + } + + const matrix probability( + unsigned long idx + ) const + { + // make sure requires clause is not broken + DLIB_ASSERT( idx < number_of_nodes() , + "\tconst matrix bayesian_network_join_tree::probability(idx)" + << "\n\tYou have specified an invalid node index" + << "\n\tidx: " << idx + << "\n\tnumber_of_nodes(): " << number_of_nodes() + << "\n\tthis: " << this + ); + + return impl->probability(idx); + } + + unsigned long number_of_nodes ( + ) const { return num_nodes; } + + void swap ( + bayesian_network_join_tree& item + ) + { + exchange(num_nodes, item.num_nodes); + impl.swap(item.impl); + } + + private: + + scoped_ptr impl; + unsigned long num_nodes; + + }; + + inline void swap ( + bayesian_network_join_tree& a, + bayesian_network_join_tree& b + ) { a.swap(b); } + +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_BAYES_UTILs_ + diff --git a/dlib/bayes_utils/bayes_utils_abstract.h b/dlib/bayes_utils/bayes_utils_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..0c89e567de87f7c44996e562e72af96c9af45733 --- /dev/null +++ b/dlib/bayes_utils/bayes_utils_abstract.h @@ -0,0 +1,1041 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BAYES_UTILs_ABSTRACT_ +#ifdef DLIB_BAYES_UTILs_ABSTRACT_ + +#include "../algs.h" +#include "../noncopyable.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/map_pair.h" +#include "../serialize.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class assignment : public enumerable > + { + /*! + INITIAL VALUE + - size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the entries in the assignment in + ascending order according to index values. (i.e. the elements are + enumerated in sorted order according to the value of their keys) + + WHAT THIS OBJECT REPRESENTS + This object models an assignment of random variables to particular values. + It is used with the joint_probability_table and conditional_probability_table + objects to represent assignments of various random variables to actual values. + + So for example, if you had a joint_probability_table that represented the + following table: + P(A = 0, B = 0) = 0.2 + P(A = 0, B = 1) = 0.3 + P(A = 1, B = 0) = 0.1 + P(A = 1, B = 1) = 0.4 + + Also lets define an enum so we have concrete index numbers for A and B + enum { A = 0, B = 1}; + + Then you could query the value of P(A=1, B=0) as follows: + assignment a; + a.set(A, 1); + a.set(B, 0); + // and now it is the case that: + table.probability(a) == 0.1 + a[A] == 1 + a[B] == 0 + + + Also note that when enumerating the elements of an assignment object + the key() refers to the index and the value() refers to the value at that + index. For example: + + // assume a is an assignment object + a.reset(); + while (a.move_next()) + { + // in this loop it is always the case that: + // a[a.element().key()] == a.element().value() + } + !*/ + + public: + + assignment( + ); + /*! + ensures + - this object is properly initialized + !*/ + + assignment( + const assignment& a + ); + /*! + ensures + - #*this is a copy of a + !*/ + + assignment& operator = ( + const assignment& rhs + ); + /*! + ensures + - #*this is a copy of rhs + - returns *this + !*/ + + void clear( + ); + /*! + ensures + - this object has been returned to its initial value + !*/ + + bool operator < ( + const assignment& item + ) const; + /*! + ensures + - The exact functioning of this operator is undefined. The only guarantee + is that it establishes a total ordering on all possible assignment objects. + In other words, this operator makes it so that you can use assignment + objects in the associative containers but otherwise isn't of any + particular use. + !*/ + + bool has_index ( + unsigned long idx + ) const; + /*! + ensures + - if (this assignment object has an entry for index idx) then + - returns true + - else + - returns false + !*/ + + void add ( + unsigned long idx, + unsigned long value = 0 + ); + /*! + requires + - has_index(idx) == false + ensures + - #has_index(idx) == true + - #(*this)[idx] == value + !*/ + + void remove ( + unsigned long idx + ); + /*! + requires + - has_index(idx) == true + ensures + - #has_index(idx) == false + !*/ + + unsigned long& operator[] ( + const long idx + ); + /*! + requires + - has_index(idx) == true + ensures + - returns a reference to the value associated with index idx + !*/ + + const unsigned long& operator[] ( + const long idx + ) const; + /*! + requires + - has_index(idx) == true + ensures + - returns a const reference to the value associated with index idx + !*/ + + void swap ( + assignment& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + inline void swap ( + assignment& a, + assignment& b + ) { a.swap(b); } + /*! + provides a global swap + !*/ + + std::ostream& operator << ( + std::ostream& out, + const assignment& a + ); + /*! + ensures + - writes a to the given output stream in the following format: + (index1:value1, index2:value2, ..., indexN:valueN) + !*/ + + void serialize ( + const assignment& item, + std::ostream& out + ); + /*! + provides deserialization support + !*/ + + void deserialize ( + assignment& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ------------------------------------------------------------------------ + + class joint_probability_table : public enumerable > + { + /*! + INITIAL VALUE + - size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the entries in the probability table + in no particular order but they will all be visited. + + WHAT THIS OBJECT REPRESENTS + This object models a joint probability table. That is, it models + the function p(X). So this object models the probability of a particular + set of variables (referred to as X). + !*/ + + public: + + joint_probability_table( + ); + /*! + ensures + - this object is properly initialized + !*/ + + joint_probability_table ( + const joint_probability_table& t + ); + /*! + ensures + - this object is a copy of t + !*/ + + void clear( + ); + /*! + ensures + - this object has its initial value + !*/ + + joint_probability_table& operator= ( + const joint_probability_table& rhs + ); + /*! + ensures + - this object is a copy of rhs + - returns a reference to *this + !*/ + + bool has_entry_for ( + const assignment& a + ) const; + /*! + ensures + - if (this joint_probability_table has an entry for p(X = a)) then + - returns true + - else + - returns false + !*/ + + void set_probability ( + const assignment& a, + double p + ); + /*! + requires + - 0 <= p <= 1 + ensures + - if (has_entry_for(a) == false) then + - #size() == size() + 1 + - #probability(a) == p + - #has_entry_for(a) == true + !*/ + + void add_probability ( + const assignment& a, + double p + ); + /*! + requires + - 0 <= p <= 1 + ensures + - if (has_entry_for(a) == false) then + - #size() == size() + 1 + - #probability(a) == p + - else + - #probability(a) == probability(a) + p + - #has_entry_for(a) == true + !*/ + + const double probability ( + const assignment& a + ) const; + /*! + ensures + - returns the probability p(X == a) + !*/ + + template < + typename T + > + void marginalize ( + const T& vars, + joint_probability_table& output_table + ) const; + /*! + requires + - T is an implementation of set/set_kernel_abstract.h + ensures + - marginalizes *this by summing over all variables not in vars. The + result is stored in output_table. + !*/ + + void marginalize ( + const unsigned long var, + joint_probability_table& output_table + ) const; + /*! + ensures + - is identical to calling the above marginalize() function with a set + that contains only var. Or in other words, performs a marginalization + with just one variable var. So that output_table will contain a table giving + the marginal probability of var all by itself. + !*/ + + void normalize ( + ); + /*! + ensures + - let sum == the sum of all the probabilities in this table + - after normalize() has finished it will be the case that the sum of all + the entries in this table is 1.0. This is accomplished by dividing all + the entries by the sum described above. + !*/ + + void swap ( + joint_probability_table& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + inline void swap ( + joint_probability_table& a, + joint_probability_table& b + ) { a.swap(b); } + /*! + provides a global swap + !*/ + + void serialize ( + const joint_probability_table& item, + std::ostream& out + ); + /*! + provides deserialization support + !*/ + + void deserialize ( + joint_probability_table& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + class conditional_probability_table : noncopyable + { + /*! + INITIAL VALUE + - num_values() == 0 + - has_value_for(x, y) == false for all values of x and y + + WHAT THIS OBJECT REPRESENTS + This object models a conditional probability table. That is, it models + the function p( X | parents). So this object models the conditional + probability of a particular variable (referred to as X) given another set + of variables (referred to as parents). + !*/ + + public: + + conditional_probability_table( + ); + /*! + ensures + - this object is properly initialized + !*/ + + void clear( + ); + /*! + ensures + - this object has its initial value + !*/ + + void empty_table ( + ); + /*! + ensures + - for all possible v and p: + - #has_entry_for(v,p) == false + (i.e. this function clears out the table when you call it but doesn't + change the value of num_values()) + !*/ + + void set_num_values ( + unsigned long num + ); + /*! + ensures + - #num_values() == num + - for all possible v and p: + - #has_entry_for(v,p) == false + (i.e. this function clears out the table when you call it) + !*/ + + unsigned long num_values ( + ) const; + /*! + ensures + - This object models the probability table p(X | parents). This + function returns the number of values X can take on. + !*/ + + bool has_entry_for ( + unsigned long value, + const assignment& ps + ) const; + /*! + ensures + - if (this conditional_probability_table has an entry for p(X = value, parents = ps)) then + - returns true + - else + - returns false + !*/ + + void set_probability ( + unsigned long value, + const assignment& ps, + double p + ); + /*! + requires + - value < num_values() + - 0 <= p <= 1 + ensures + - #probability(ps, value) == p + - #has_entry_for(value, ps) == true + !*/ + + double probability( + unsigned long value, + const assignment& ps + ) const; + /*! + requires + - value < num_values() + - has_entry_for(value, ps) == true + ensures + - returns the probability p( X = value | parents = ps). + !*/ + + void swap ( + conditional_probability_table& item + ); + /*! + ensures + - swaps *this and item + !*/ + }; + + inline void swap ( + conditional_probability_table& a, + conditional_probability_table& b + ) { a.swap(b); } + /*! + provides a global swap + !*/ + + void serialize ( + const conditional_probability_table& item, + std::ostream& out + ); + /*! + provides deserialization support + !*/ + + void deserialize ( + conditional_probability_table& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ + + class bayes_node : noncopyable + { + /*! + INITIAL VALUE + - is_evidence() == false + - value() == 0 + - table().num_values() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a node in a bayesian network. It is + intended to be used inside the dlib::directed_graph object to + represent bayesian networks. + !*/ + + public: + bayes_node ( + ); + /*! + ensures + - this object is properly initialized + !*/ + + unsigned long value ( + ) const; + /*! + ensures + - returns the current value of this node + !*/ + + void set_value ( + unsigned long new_value + ); + /*! + requires + - new_value < table().num_values() + ensures + - #value() == new_value + !*/ + + conditional_probability_table& table ( + ); + /*! + ensures + - returns a reference to the conditional_probability_table associated with this node + !*/ + + const conditional_probability_table& table ( + ) const; + /*! + ensures + - returns a const reference to the conditional_probability_table associated with this + node. + !*/ + + bool is_evidence ( + ) const; + /*! + ensures + - if (this is an evidence node) then + - returns true + - else + - returns false + !*/ + + void set_as_nonevidence ( + ); + /*! + ensures + - #is_evidence() == false + !*/ + + void set_as_evidence ( + ); + /*! + ensures + - #is_evidence() == true + !*/ + + void swap ( + bayes_node& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + inline void swap ( + bayes_node& a, + bayes_node& b + ) { a.swap(b); } + /*! + provides a global swap + !*/ + + void serialize ( + const bayes_node& item, + std::ostream& out + ); + /*! + provides deserialization support + !*/ + + void deserialize ( + bayes_node& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + /* + The following group of functions are convenience functions for manipulating + bayes_node objects while they are inside a directed_graph. These functions + also have additional requires clauses that, in debug mode, will protect you + from attempts to manipulate a bayesian network in an inappropriate way. + */ + + namespace bayes_node_utils + { + + template < + typename T + > + void set_node_value ( + T& bn, + unsigned long n, + unsigned long val + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + - val < node_num_values(bn, n) + ensures + - #bn.node(n).data.value() = val + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + unsigned long node_value ( + const T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - returns bn.node(n).data.value() + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + bool node_is_evidence ( + const T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - returns bn.node(n).data.is_evidence() + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + void set_node_as_evidence ( + T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - returns bn.node(n).data.set_as_evidence() + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + void set_node_as_nonevidence ( + T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - returns bn.node(n).data.set_as_nonevidence() + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + void set_node_num_values ( + T& bn, + unsigned long n, + unsigned long num + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - #bn.node(n).data.table().num_values() == num + (i.e. sets the number of different values this node can take) + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + unsigned long node_num_values ( + const T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - returns bn.node(n).data.table().num_values() + (i.e. returns the number of different values this node can take) + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + const double node_probability ( + const T& bn, + unsigned long n, + unsigned long value, + const assignment& parents + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + - value < node_num_values(bn,n) + - parents.size() == bn.node(n).number_of_parents() + - if (parents.has_index(x)) then + - bn.has_edge(x, n) + - parents[x] < node_num_values(bn,x) + ensures + - returns bn.node(n).data.table().probability(value, parents) + (i.e. returns the probability of node n having the given value when + its parents have the given assignment) + !*/ + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + const double set_node_probability ( + const T& bn, + unsigned long n, + unsigned long value, + const assignment& parents, + double p + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + - value < node_num_values(bn,n) + - 0 <= p <= 1 + - parents.size() == bn.node(n).number_of_parents() + - if (parents.has_index(x)) then + - bn.has_edge(x, n) + - parents[x] < node_num_values(bn,x) + ensures + - #bn.node(n).data.table().probability(value, parents) == p + (i.e. sets the probability of node n having the given value when + its parents have the given assignment to the probability p) + !*/ + + // ------------------------------------------------------------------------------------ + + template + const assignment node_first_parent_assignment ( + const T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - returns an assignment A such that: + - A.size() == bn.node(n).number_of_parents() + - if (P is a parent of bn.node(n)) then + - A.has_index(P) + - A[P] == 0 + - I.e. this function returns an assignment that contains all + the parents of the given node. Also, all the values of each + parent in the assignment is set to zero. + !*/ + + // ------------------------------------------------------------------------------------ + + template + bool node_next_parent_assignment ( + const T& bn, + unsigned long n, + assignment& A + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + - A.size() == bn.node(n).number_of_parents() + - if (A.has_index(x)) then + - bn.has_edge(x, n) + - A[x] < node_num_values(bn,x) + ensures + - The behavior of this function is defined by the following code: + assignment a(node_first_parent_assignment(bn,n); + do { + // this loop loops over all possible parent assignments + // of the node bn.node(n). Each time through the loop variable a + // will be the next assignment. + } while (node_next_parent_assignment(bn,n,a)) + !*/ + + // ------------------------------------------------------------------------------------ + + template + bool node_cpt_filled_out ( + const T& bn, + unsigned long n + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + - n < bn.number_of_nodes() + ensures + - if (the conditional_probability_table bn.node(n).data.table() is + fully filled out for this node) then + - returns true + - This means that each parent assignment for the given node + along with all possible values of this node shows up in the + table. + - It also means that all the probabilities conditioned on the + same parent assignment sum to 1.0 + - else + - returns false + !*/ + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class bayesian_network_gibbs_sampler : noncopyable + { + /*! + INITIAL VALUE + This object has no state + + WHAT THIS OBJECT REPRESENTS + This object performs Markov Chain Monte Carlo sampling of a bayesian + network using the Gibbs sampling technique. + + Note that this object is limited to only bayesian networks that + don't contain deterministic nodes. That is, incorrect results may + be computed if this object is used when the bayesian network contains + any nodes that have a probability of 1 in their conditional probability + tables for any event. So don't use this object for networks with + deterministic nodes. + !*/ + public: + + bayesian_network_gibbs_sampler ( + ); + /*! + ensures + - this object is properly initialized + !*/ + + template < + typename T + > + void sample_graph ( + T& bn + ) + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + - T::type == bayes_node + ensures + - modifies randomly (via the Gibbs sampling technique) samples all the nodes + in the network and updates their values with the newly sampled values + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class bayesian_network_join_tree : noncopyable + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents an implementation of the join tree algorithm + for inference in bayesian networks. It doesn't have any mutable state. + To you use you just give it a directed_graph that contains a bayesian + network and a graph object that contains that networks corresponding + join tree. Then you may query this object to determine the probabilities + of any variables in the original bayesian network. + !*/ + + public: + + template < + typename bn_type, + typename join_tree_type + > + bayesian_network_join_tree ( + const bn_type& bn, + const join_tree_type& join_tree + ); + /*! + requires + - bn_type is an implementation of directed_graph/directed_graph_kernel_abstract.h + - bn_type::type == bayes_node + - join_tree_type is an implementation of graph/graph_kernel_abstract.h + - join_tree_type::type is an implementation of set/set_compare_abstract.h and + this set type contains unsigned long objects. + - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and + this set type contains unsigned long objects. + - is_join_tree(bn, join_tree) == true + - bn == a valid bayesian network with all its conditional probability tables + filled out + - for all valid n: + - node_cpt_filled_out(bn,n) == true + - graph_contains_length_one_cycle(bn) == false + - graph_is_connected(bn) == true + - bn.number_of_nodes() > 0 + ensures + - this object is properly initialized + !*/ + + unsigned long number_of_nodes ( + ) const; + /*! + ensures + - returns the number of nodes in the bayesian network that this + object was instantiated from. + !*/ + + const matrix probability( + unsigned long idx + ) const; + /*! + requires + - idx < number_of_nodes() + ensures + - returns the probability distribution for the node with index idx that was in the bayesian + network that *this was instantiated from. Let D represent this distribution, then: + - D.nc() == the number of values the node idx ranges over + - D.nr() == 1 + - D(i) == the probability of node idx taking on the value i + !*/ + + void swap ( + bayesian_network_join_tree& item + ); + /*! + ensures + - swaps *this with item + !*/ + + }; + + inline void swap ( + bayesian_network_join_tree& a, + bayesian_network_join_tree& b + ) { a.swap(b); } + /*! + provides a global swap + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BAYES_UTILs_ABSTRACT_ + + diff --git a/dlib/bigint.h b/dlib/bigint.h new file mode 100644 index 0000000000000000000000000000000000000000..eab598682b04f3a759dcc20207df5784f4eb73c6 --- /dev/null +++ b/dlib/bigint.h @@ -0,0 +1,43 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIGINt_ +#define DLIB_BIGINt_ + +#include "bigint/bigint_kernel_1.h" +#include "bigint/bigint_kernel_2.h" +#include "bigint/bigint_kernel_c.h" + + + + +namespace dlib +{ + + + class bigint + { + bigint() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef bigint_kernel_1 + kernel_1a; + typedef bigint_kernel_c + kernel_1a_c; + + // kernel_2a + typedef bigint_kernel_2 + kernel_2a; + typedef bigint_kernel_c + kernel_2a_c; + + + }; +} + +#endif // DLIB_BIGINt_ + diff --git a/dlib/bigint/bigint_kernel_1.cpp b/dlib/bigint/bigint_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9064820523f684498dd9102d94ed1cbb90be0fe3 --- /dev/null +++ b/dlib/bigint/bigint_kernel_1.cpp @@ -0,0 +1,1724 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIGINT_KERNEL_1_CPp_ +#define DLIB_BIGINT_KERNEL_1_CPp_ +#include "bigint_kernel_1.h" + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member/friend function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1:: + bigint_kernel_1 ( + ) : + slack(25), + data(new data_record(slack)) + {} + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1:: + bigint_kernel_1 ( + uint32 value + ) : + slack(25), + data(new data_record(slack)) + { + *(data->number) = static_cast(value&0xFFFF); + *(data->number+1) = static_cast((value>>16)&0xFFFF); + if (*(data->number+1) != 0) + data->digits_used = 2; + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1:: + bigint_kernel_1 ( + const bigint_kernel_1& item + ) : + slack(25), + data(item.data) + { + data->references += 1; + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1:: + ~bigint_kernel_1 ( + ) + { + if (data->references == 1) + { + delete data; + } + else + { + data->references -= 1; + } + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator+ ( + const bigint_kernel_1& rhs + ) const + { + data_record* temp = new data_record ( + std::max(rhs.data->digits_used,data->digits_used) + slack + ); + long_add(data,rhs.data,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator+= ( + const bigint_kernel_1& rhs + ) + { + // if there are other references to our data + if (data->references != 1) + { + data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); + data->references -= 1; + long_add(data,rhs.data,temp); + data = temp; + } + // if data is not big enough for the result + else if (data->size <= std::max(data->digits_used,rhs.data->digits_used)) + { + data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); + long_add(data,rhs.data,temp); + delete data; + data = temp; + } + // there is enough size and no references + else + { + long_add(data,rhs.data,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator- ( + const bigint_kernel_1& rhs + ) const + { + data_record* temp = new data_record ( + data->digits_used + slack + ); + long_sub(data,rhs.data,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator-= ( + const bigint_kernel_1& rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + long_sub(data,rhs.data,temp); + data = temp; + } + else + { + long_sub(data,rhs.data,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator* ( + const bigint_kernel_1& rhs + ) const + { + data_record* temp = new data_record ( + data->digits_used + rhs.data->digits_used + slack + ); + long_mul(data,rhs.data,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator*= ( + const bigint_kernel_1& rhs + ) + { + // create a data_record to store the result of the multiplication in + data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack); + long_mul(data,rhs.data,temp); + + // if there are other references to data + if (data->references != 1) + { + data->references -= 1; + } + else + { + delete data; + } + data = temp; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator/ ( + const bigint_kernel_1& rhs + ) const + { + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + delete remainder; + + + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator/= ( + const bigint_kernel_1& rhs + ) + { + + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + + // check if there are other references to data + if (data->references != 1) + { + data->references -= 1; + } + // if there are no references to data then it must be deleted + else + { + delete data; + } + data = temp; + delete remainder; + + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator% ( + const bigint_kernel_1& rhs + ) const + { + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + delete temp; + return bigint_kernel_1(remainder,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator%= ( + const bigint_kernel_1& rhs + ) + { + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + + // check if there are other references to data + if (data->references != 1) + { + data->references -= 1; + } + // if there are no references to data then it must be deleted + else + { + delete data; + } + data = remainder; + delete temp; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_1:: + operator < ( + const bigint_kernel_1& rhs + ) const + { + return is_less_than(data,rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_1:: + operator == ( + const bigint_kernel_1& rhs + ) const + { + return is_equal_to(data,rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator= ( + const bigint_kernel_1& rhs + ) + { + if (this == &rhs) + return *this; + + // if we have the only reference to our data then delete it + if (data->references == 1) + { + delete data; + data = rhs.data; + data->references += 1; + } + else + { + data->references -= 1; + data = rhs.data; + data->references += 1; + } + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + std::ostream& operator<< ( + std::ostream& out_, + const bigint_kernel_1& rhs + ) + { + std::ostream out(out_.rdbuf()); + + typedef bigint_kernel_1 bigint; + + bigint::data_record* temp = new bigint::data_record(*rhs.data,0); + + + + // get a char array big enough to hold the number in ascii format + char* str; + try { + str = new char[(rhs.data->digits_used)*5+10]; + } catch (...) { delete temp; throw; } + + char* str_start = str; + str += (rhs.data->digits_used)*5+9; + *str = 0; --str; + + + uint16 remainder; + rhs.short_div(temp,10000,temp,remainder); + + // pull the digits out of remainder + char a = remainder % 10 + '0'; + remainder /= 10; + char b = remainder % 10 + '0'; + remainder /= 10; + char c = remainder % 10 + '0'; + remainder /= 10; + char d = remainder % 10 + '0'; + remainder /= 10; + + + *str = a; --str; + *str = b; --str; + *str = c; --str; + *str = d; --str; + + + // keep looping until temp represents zero + while (temp->digits_used != 1 || *(temp->number) != 0) + { + rhs.short_div(temp,10000,temp,remainder); + + // pull the digits out of remainder + char a = remainder % 10 + '0'; + remainder /= 10; + char b = remainder % 10 + '0'; + remainder /= 10; + char c = remainder % 10 + '0'; + remainder /= 10; + char d = remainder % 10 + '0'; + remainder /= 10; + + *str = a; --str; + *str = b; --str; + *str = c; --str; + *str = d; --str; + } + + // throw away and extra leading zeros + ++str; + if (*str == '0') + ++str; + if (*str == '0') + ++str; + if (*str == '0') + ++str; + + + + + out << str; + delete [] str_start; + delete temp; + return out_; + + } + +// ---------------------------------------------------------------------------------------- + + std::istream& operator>> ( + std::istream& in_, + bigint_kernel_1& rhs + ) + { + std::istream in(in_.rdbuf()); + + // ignore any leading whitespaces + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n') + { + in.get(); + } + + // if the first digit is not an integer then this is an error + if ( !(in.peek() >= '0' && in.peek() <= '9')) + { + in_.clear(std::ios::failbit); + return in_; + } + + int num_read; + bigint_kernel_1 temp; + do + { + + // try to get 4 chars from in + num_read = 1; + char a = 0; + char b = 0; + char c = 0; + char d = 0; + + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + a = in.get(); + } + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + b = in.get(); + } + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + c = in.get(); + } + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + d = in.get(); + } + + // merge the for digits into an uint16 + uint16 num = 0; + if (a != 0) + { + num = a - '0'; + } + if (b != 0) + { + num *= 10; + num += b - '0'; + } + if (c != 0) + { + num *= 10; + num += c - '0'; + } + if (d != 0) + { + num *= 10; + num += d - '0'; + } + + + if (num_read != 1) + { + // shift the digits in temp left by the number of new digits we just read + temp *= num_read; + // add in new digits + temp += num; + } + + } while (num_read == 10000); + + + rhs = temp; + return in_; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator+ ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record + (rhs.data->digits_used+rhs.slack); + + rhs.short_add(rhs.data,lhs,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator+ ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + lhs.short_add(lhs.data,rhs,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator+= ( + uint16 rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_add(data,rhs,temp); + data = temp; + } + // or if we need to enlarge data then do so + else if (data->digits_used == data->size) + { + data_record* temp = new data_record(data->digits_used+slack); + short_add(data,rhs,temp); + delete data; + data = temp; + } + // or if there is plenty of space and no references + else + { + short_add(data,rhs,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator- ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record(rhs.slack); + + *(temp->number) = lhs - *(rhs.data->number); + + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator- ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + lhs.short_sub(lhs.data,rhs,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator-= ( + uint16 rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_sub(data,rhs,temp); + data = temp; + } + else + { + short_sub(data,rhs,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator* ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record + (rhs.data->digits_used+rhs.slack); + + rhs.short_mul(rhs.data,lhs,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator* ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + lhs.short_mul(lhs.data,rhs,temp); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator*= ( + uint16 rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_mul(data,rhs,temp); + data = temp; + } + // or if we need to enlarge data + else if (data->digits_used == data->size) + { + data_record* temp = new data_record(data->digits_used+slack); + short_mul(data,rhs,temp); + delete data; + data = temp; + } + else + { + short_mul(data,rhs,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator/ ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record(rhs.slack); + + // if rhs might not be bigger than lhs + if (rhs.data->digits_used == 1) + { + *(temp->number) = lhs/ *(rhs.data->number); + } + + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator/ ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + uint16 remainder; + lhs.short_div(lhs.data,rhs,temp,remainder); + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator/= ( + uint16 rhs + ) + { + uint16 remainder; + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_div(data,rhs,temp,remainder); + data = temp; + } + else + { + short_div(data,rhs,data,remainder); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator% ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + typedef bigint_kernel_1 bigint; + // temp is zero by default + bigint::data_record* temp = new bigint::data_record(rhs.slack); + + if (rhs.data->digits_used == 1) + { + // if rhs is just an uint16 inside then perform the modulus + *(temp->number) = lhs % *(rhs.data->number); + } + else + { + // if rhs is bigger than lhs then the answer is lhs + *(temp->number) = lhs; + } + + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 operator% ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_1 bigint; + bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack); + + uint16 remainder; + + lhs.short_div(lhs.data,rhs,temp,remainder); + temp->digits_used = 1; + *(temp->number) = remainder; + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator%= ( + uint16 rhs + ) + { + uint16 remainder; + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_div(data,rhs,temp,remainder); + data = temp; + } + else + { + short_div(data,rhs,data,remainder); + } + + data->digits_used = 1; + *(data->number) = remainder; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + bool operator < ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) ); + } + +// ---------------------------------------------------------------------------------------- + + bool operator < ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs); + } + +// ---------------------------------------------------------------------------------------- + + bool operator == ( + const bigint_kernel_1& lhs, + uint16 rhs + ) + { + return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs); + } + +// ---------------------------------------------------------------------------------------- + + bool operator == ( + uint16 lhs, + const bigint_kernel_1& rhs + ) + { + return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator= ( + uint16 rhs + ) + { + // check if there are other references to our data + if (data->references != 1) + { + data->references -= 1; + try { + data = new data_record(slack); + } catch (...) { data->references += 1; throw; } + } + else + { + data->digits_used = 1; + } + + *(data->number) = rhs; + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator++ ( + ) + { + // if there are other references to this data then make a copy of it + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + increment(data,temp); + data = temp; + } + // or if we need to enlarge data then do so + else if (data->digits_used == data->size) + { + data_record* temp = new data_record(data->digits_used+slack); + increment(data,temp); + delete data; + data = temp; + } + else + { + increment(data,data); + } + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator++ ( + int + ) + { + data_record* temp; // this is the copy of temp we will return in the end + + data_record* temp2 = new data_record(data->digits_used+slack); + increment(data,temp2); + + temp = data; + data = temp2; + + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_1& bigint_kernel_1:: + operator-- ( + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + decrement(data,temp); + data = temp; + } + else + { + decrement(data,data); + } + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_1 bigint_kernel_1:: + operator-- ( + int + ) + { + data_record* temp; // this is the copy of temp we will return in the end + + data_record* temp2 = new data_record(data->digits_used+slack); + decrement(data,temp2); + + temp = data; + data = temp2; + + return bigint_kernel_1(temp,0); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + short_add ( + const data_record* data, + uint16 value, + data_record* result + ) const + { + // put value into the carry part of temp + uint32 temp = value; + temp <<= 16; + + + const uint16* number = data->number; + const uint16* end = number + data->digits_used; // one past the end of number + uint16* r = result->number; + + while (number != end) + { + // add *number and the current carry + temp = *number + (temp>>16); + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++number; + ++r; + } + + // if there is a final carry + if ((temp>>16) != 0) + { + result->digits_used = data->digits_used + 1; + // store the carry in the most significant digit of the result + *r = static_cast(temp>>16); + } + else + { + result->digits_used = data->digits_used; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + short_sub ( + const data_record* data, + uint16 value, + data_record* result + ) const + { + + + const uint16* number = data->number; + const uint16* end = number + data->digits_used - 1; + uint16* r = result->number; + + uint32 temp = *number - value; + + // put the low word of temp into *data + *r = static_cast(temp & 0xFFFF); + + + while (number != end) + { + ++number; + ++r; + + // subtract the carry from *number + temp = *number - (temp>>31); + + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + } + + // if we lost a digit in the subtraction + if (*r == 0) + { + if (data->digits_used == 1) + result->digits_used = 1; + else + result->digits_used = data->digits_used - 1; + } + else + { + result->digits_used = data->digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + short_mul ( + const data_record* data, + uint16 value, + data_record* result + ) const + { + + uint32 temp = 0; + + + const uint16* number = data->number; + uint16* r = result->number; + const uint16* end = r + data->digits_used; + + + + while ( r != end) + { + + // multiply *data and value and add in the carry + temp = *number*(uint32)value + (temp>>16); + + // put the low word of temp into *data + *r = static_cast(temp & 0xFFFF); + + ++number; + ++r; + } + + // if there is a final carry + if ((temp>>16) != 0) + { + result->digits_used = data->digits_used + 1; + // put the final carry into the most significant digit of the result + *r = static_cast(temp>>16); + } + else + { + result->digits_used = data->digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + short_div ( + const data_record* data, + uint16 value, + data_record* result, + uint16& rem + ) const + { + + uint16 remainder = 0; + uint32 temp; + + + + const uint16* number = data->number + data->digits_used - 1; + const uint16* end = number - data->digits_used; + uint16* r = result->number + data->digits_used - 1; + + + // if we are losing a digit in this division + if (*number < value) + { + if (data->digits_used == 1) + result->digits_used = 1; + else + result->digits_used = data->digits_used - 1; + } + else + { + result->digits_used = data->digits_used; + } + + + // perform the actual division + while (number != end) + { + + temp = *number + (((uint32)remainder)<<16); + + *r = static_cast(temp/value); + remainder = static_cast(temp%value); + + --number; + --r; + } + + rem = remainder; + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + long_add ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const + { + // put value into the carry part of temp + uint32 temp=0; + + uint16* min_num; // the number with the least digits used + uint16* max_num; // the number with the most digits used + uint16* min_end; // one past the end of min_num + uint16* max_end; // one past the end of max_num + uint16* r = result->number; + + uint32 max_digits_used; + if (lhs->digits_used < rhs->digits_used) + { + max_digits_used = rhs->digits_used; + min_num = lhs->number; + max_num = rhs->number; + min_end = min_num + lhs->digits_used; + max_end = max_num + rhs->digits_used; + } + else + { + max_digits_used = lhs->digits_used; + min_num = rhs->number; + max_num = lhs->number; + min_end = min_num + rhs->digits_used; + max_end = max_num + lhs->digits_used; + } + + + + + while (min_num != min_end) + { + // add *min_num, *max_num and the current carry + temp = *min_num + *max_num + (temp>>16); + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++min_num; + ++max_num; + ++r; + } + + + while (max_num != max_end) + { + // add *max_num and the current carry + temp = *max_num + (temp>>16); + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++max_num; + ++r; + } + + // check if there was a final carry + if ((temp>>16) != 0) + { + result->digits_used = max_digits_used + 1; + // put the carry into the most significant digit in the result + *r = static_cast(temp>>16); + } + else + { + result->digits_used = max_digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + long_sub ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const + { + + + const uint16* number1 = lhs->number; + const uint16* number2 = rhs->number; + const uint16* end = number2 + rhs->digits_used; + uint16* r = result->number; + + + + uint32 temp =0; + + + while (number2 != end) + { + + // subtract *number2 from *number1 and then subtract any carry + temp = *number1 - *number2 - (temp>>31); + + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++number1; + ++number2; + ++r; + } + + end = lhs->number + lhs->digits_used; + while (number1 != end) + { + + // subtract the carry from *number1 + temp = *number1 - (temp>>31); + + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++number1; + ++r; + } + + // if we are using one less digit + if (*(r-1) == 0) + { + if (lhs->digits_used != 1) + result->digits_used = lhs->digits_used - 1; + else + result->digits_used = 1; + } + else + { + result->digits_used = lhs->digits_used; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + long_div ( + const data_record* lhs, + const data_record* rhs, + data_record* result, + data_record* remainder + ) const + { + // zero result + result->digits_used = 1; + *(result->number) = 0; + + uint16* a; + uint16* b; + uint16* end; + + // copy lhs into remainder + remainder->digits_used = lhs->digits_used; + a = remainder->number; + end = a + remainder->digits_used; + b = lhs->number; + while (a != end) + { + *a = *b; + ++a; + ++b; + } + + + // if rhs is bigger than lhs then result == 0 and remainder == lhs + // so then we can quit right now + if (is_less_than(lhs,rhs)) + { + return; + } + + + // make a temporary number + data_record temp(lhs->digits_used + slack); + + + // shift rhs left until it is one shift away from being larger than lhs and + // put the number of left shifts necessary into shifts + uint32 shifts; + shifts = (lhs->digits_used - rhs->digits_used) * 8; + + shift_left(rhs,&temp,shifts); + + + // while (lhs > temp) + while (is_less_than(&temp,lhs)) + { + shift_left(&temp,&temp,1); + ++shifts; + } + // make sure lhs isn't smaller than temp + while (is_less_than(lhs,&temp)) + { + shift_right(&temp,&temp); + --shifts; + } + + + + // we want to execute the loop shifts +1 times + ++shifts; + while (shifts != 0) + { + shift_left(result,result,1); + // if (temp <= remainder) + if (!is_less_than(remainder,&temp)) + { + long_sub(remainder,&temp,remainder); + + // increment result + uint16* r = result->number; + uint16* end = r + result->digits_used; + while (true) + { + ++(*r); + // if there was no carry then we are done + if (*r != 0) + break; + + ++r; + + // if we hit the end of r and there is still a carry then + // the next digit of r is 1 and there is one more digit used + if (r == end) + { + *r = 1; + ++(result->digits_used); + break; + } + } + } + shift_right(&temp,&temp); + --shifts; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + long_mul ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const + { + // make result be zero + result->digits_used = 1; + *(result->number) = 0; + + + const data_record* aa; + const data_record* bb; + + if (lhs->digits_used < rhs->digits_used) + { + // make copies of lhs and rhs and give them an appropriate amount of + // extra memory so there won't be any overflows + aa = lhs; + bb = rhs; + } + else + { + // make copies of lhs and rhs and give them an appropriate amount of + // extra memory so there won't be any overflows + aa = rhs; + bb = lhs; + } + // this is where we actually copy lhs and rhs + data_record b(*bb,aa->digits_used+slack); // the larger(approximately) of lhs and rhs + + + uint32 shift_value = 0; + uint16* anum = aa->number; + uint16* end = anum + aa->digits_used; + while (anum != end ) + { + uint16 bit = 0x0001; + + for (int i = 0; i < 16; ++i) + { + // if the specified bit of a is 1 + if ((*anum & bit) != 0) + { + shift_left(&b,&b,shift_value); + shift_value = 0; + long_add(&b,result,result); + } + ++shift_value; + bit <<= 1; + } + + ++anum; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + shift_left ( + const data_record* data, + data_record* result, + uint32 shift_amount + ) const + { + uint32 offset = shift_amount/16; + shift_amount &= 0xf; // same as shift_amount %= 16; + + uint16* r = result->number + data->digits_used + offset; // result + uint16* end = data->number; + uint16* s = end + data->digits_used; // source + const uint32 temp = 16 - shift_amount; + + *r = (*(--s) >> temp); + // set the number of digits used in the result + // if the upper bits from *s were zero then don't count this first word + if (*r == 0) + { + result->digits_used = data->digits_used + offset; + } + else + { + result->digits_used = data->digits_used + offset + 1; + } + --r; + + while (s != end) + { + *r = ((*s << shift_amount) | ( *(s-1) >> temp)); + --r; + --s; + } + *r = *s << shift_amount; + + // now zero the rest of the result + end = result->number; + while (r != end) + *(--r) = 0; + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + shift_right ( + const data_record* data, + data_record* result + ) const + { + + uint16* r = result->number; // result + uint16* s = data->number; // source + uint16* end = s + data->digits_used - 1; + + while (s != end) + { + *r = (*s >> 1) | (*(s+1) << 15); + ++r; + ++s; + } + *r = *s >> 1; + + + // calculate the new number for digits_used + if (*r == 0) + { + if (data->digits_used != 1) + result->digits_used = data->digits_used - 1; + else + result->digits_used = 1; + } + else + { + result->digits_used = data->digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_1:: + is_less_than ( + const data_record* lhs, + const data_record* rhs + ) const + { + uint32 lhs_digits_used = lhs->digits_used; + uint32 rhs_digits_used = rhs->digits_used; + + // if lhs is definitely less than rhs + if (lhs_digits_used < rhs_digits_used ) + return true; + // if lhs is definitely greater than rhs + else if (lhs_digits_used > rhs_digits_used) + return false; + else + { + uint16* end = lhs->number; + uint16* l = end + lhs_digits_used; + uint16* r = rhs->number + rhs_digits_used; + + while (l != end) + { + --l; + --r; + if (*l < *r) + return true; + else if (*l > *r) + return false; + } + + // at this point we know that they are equal + return false; + } + + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_1:: + is_equal_to ( + const data_record* lhs, + const data_record* rhs + ) const + { + // if lhs and rhs are definitely not equal + if (lhs->digits_used != rhs->digits_used ) + { + return false; + } + else + { + uint16* l = lhs->number; + uint16* r = rhs->number; + uint16* end = l + lhs->digits_used; + + while (l != end) + { + if (*l != *r) + return false; + ++l; + ++r; + } + + // at this point we know that they are equal + return true; + } + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + increment ( + const data_record* source, + data_record* dest + ) const + { + uint16* s = source->number; + uint16* d = dest->number; + uint16* end = s + source->digits_used; + while (true) + { + *d = *s + 1; + + // if there was no carry then break out of the loop + if (*d != 0) + { + dest->digits_used = source->digits_used; + + // copy the rest of the digits over to d + ++d; ++s; + while (s != end) + { + *d = *s; + ++d; + ++s; + } + + break; + } + + + ++s; + + // if we have hit the end of s and there was a carry up to this point + // then just make the next digit 1 and add one to the digits used + if (s == end) + { + ++d; + dest->digits_used = source->digits_used + 1; + *d = 1; + break; + } + + ++d; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_1:: + decrement ( + const data_record* source, + data_record* dest + ) const + { + uint16* s = source->number; + uint16* d = dest->number; + uint16* end = s + source->digits_used; + while (true) + { + *d = *s - 1; + + // if there was no carry then break out of the loop + if (*d != 0xFFFF) + { + // if we lost a digit in the subtraction + if (*d == 0 && s+1 == end) + { + if (source->digits_used == 1) + dest->digits_used = 1; + else + dest->digits_used = source->digits_used - 1; + } + else + { + dest->digits_used = source->digits_used; + } + break; + } + else + { + ++d; + ++s; + } + + } + + // copy the rest of the digits over to d + ++d; + ++s; + while (s != end) + { + *d = *s; + ++d; + ++s; + } + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_BIGINT_KERNEL_1_CPp_ + diff --git a/dlib/bigint/bigint_kernel_1.h b/dlib/bigint/bigint_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..3facf8f6ad8ce4e26f442e849334981c7839ef84 --- /dev/null +++ b/dlib/bigint/bigint_kernel_1.h @@ -0,0 +1,541 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIGINT_KERNEl_1_ +#define DLIB_BIGINT_KERNEl_1_ + +#include "bigint_kernel_abstract.h" +#include "../algs.h" +#include "../serialize.h" +#include "../uintn.h" +#include + +namespace dlib +{ + + using namespace dlib::relational_operators; // defined in algs.h + + class bigint_kernel_1 + { + /*! + INITIAL VALUE + slack == 25 + data->number[0] == 0 + data->size == slack + data->references == 1 + data->digits_used == 1 + + + CONVENTION + slack == the number of extra digits placed into the number when it is + created. the slack value should never be less than 1 + + data->number == pointer to an array of data->size uint16s. + data represents a string of base 65535 numbers with data[0] being + the least significant bit and data[data->digits_used-1] being the most + significant + + + NOTE: In the comments I will consider a word to be a 16 bit value + + + data->digits_used == the number of significant digits in the number. + data->digits_used tells us the number of used elements in the + data->number array so everything beyond data->number[data->digits_used-1] + is undefined + + data->references == the number of bigint_kernel_1 objects which refer + to this data_record + + + + !*/ + + + struct data_record + { + + + explicit data_record( + uint32 size_ + ) : + size(size_), + number(new uint16[size_]), + references(1), + digits_used(1) + {*number = 0;} + /*! + ensures + - initializes *this to represent zero + !*/ + + data_record( + const data_record& item, + uint32 additional_size + ) : + size(item.digits_used + additional_size), + number(new uint16[size]), + references(1), + digits_used(item.digits_used) + { + uint16* source = item.number; + uint16* dest = number; + uint16* end = source + digits_used; + while (source != end) + { + *dest = *source; + ++dest; + ++source; + } + } + /*! + ensures + - *this is a copy of item except with + size == item.digits_used + additional_size + !*/ + + ~data_record( + ) + { + delete [] number; + } + + + const uint32 size; + uint16* number; + uint32 references; + uint32 digits_used; + + private: + // no copy constructor + data_record ( data_record&); + }; + + + + // note that the second parameter is just there + // to resolve the ambiguity between this constructor and + // bigint_kernel_1(uint32) + explicit bigint_kernel_1 ( + data_record* data_, int + ): slack(25),data(data_) {} + /*! + ensures + - *this is initialized with data_ as its data member + !*/ + + + public: + + bigint_kernel_1 ( + ); + + bigint_kernel_1 ( + uint32 value + ); + + bigint_kernel_1 ( + const bigint_kernel_1& item + ); + + virtual ~bigint_kernel_1 ( + ); + + const bigint_kernel_1 operator+ ( + const bigint_kernel_1& rhs + ) const; + + bigint_kernel_1& operator+= ( + const bigint_kernel_1& rhs + ); + + const bigint_kernel_1 operator- ( + const bigint_kernel_1& rhs + ) const; + + bigint_kernel_1& operator-= ( + const bigint_kernel_1& rhs + ); + + const bigint_kernel_1 operator* ( + const bigint_kernel_1& rhs + ) const; + + bigint_kernel_1& operator*= ( + const bigint_kernel_1& rhs + ); + + const bigint_kernel_1 operator/ ( + const bigint_kernel_1& rhs + ) const; + + bigint_kernel_1& operator/= ( + const bigint_kernel_1& rhs + ); + + const bigint_kernel_1 operator% ( + const bigint_kernel_1& rhs + ) const; + + bigint_kernel_1& operator%= ( + const bigint_kernel_1& rhs + ); + + bool operator < ( + const bigint_kernel_1& rhs + ) const; + + bool operator == ( + const bigint_kernel_1& rhs + ) const; + + bigint_kernel_1& operator= ( + const bigint_kernel_1& rhs + ); + + friend std::ostream& operator<< ( + std::ostream& out, + const bigint_kernel_1& rhs + ); + + friend std::istream& operator>> ( + std::istream& in, + bigint_kernel_1& rhs + ); + + bigint_kernel_1& operator++ ( + ); + + const bigint_kernel_1 operator++ ( + int + ); + + bigint_kernel_1& operator-- ( + ); + + const bigint_kernel_1 operator-- ( + int + ); + + friend const bigint_kernel_1 operator+ ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + friend const bigint_kernel_1 operator+ ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + bigint_kernel_1& operator+= ( + uint16 rhs + ); + + friend const bigint_kernel_1 operator- ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + friend const bigint_kernel_1 operator- ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + bigint_kernel_1& operator-= ( + uint16 rhs + ); + + friend const bigint_kernel_1 operator* ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + friend const bigint_kernel_1 operator* ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + bigint_kernel_1& operator*= ( + uint16 rhs + ); + + friend const bigint_kernel_1 operator/ ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + friend const bigint_kernel_1 operator/ ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + bigint_kernel_1& operator/= ( + uint16 rhs + ); + + friend const bigint_kernel_1 operator% ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + friend const bigint_kernel_1 operator% ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + bigint_kernel_1& operator%= ( + uint16 rhs + ); + + friend bool operator < ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + friend bool operator < ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + friend bool operator == ( + const bigint_kernel_1& lhs, + uint16 rhs + ); + + friend bool operator == ( + uint16 lhs, + const bigint_kernel_1& rhs + ); + + bigint_kernel_1& operator= ( + uint16 rhs + ); + + + void swap ( + bigint_kernel_1& item + ) { data_record* temp = data; data = item.data; item.data = temp; } + + + private: + + void long_add ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const; + /*! + requires + - result->size >= max(lhs->digits_used,rhs->digits_used) + 1 + ensures + - result == lhs + rhs + !*/ + + void long_sub ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const; + /*! + requires + - lhs >= rhs + - result->size >= lhs->digits_used + ensures + - result == lhs - rhs + !*/ + + void long_div ( + const data_record* lhs, + const data_record* rhs, + data_record* result, + data_record* remainder + ) const; + /*! + requires + - rhs != 0 + - result->size >= lhs->digits_used + - remainder->size >= lhs->digits_used + - each parameter is unique (i.e. lhs != result, lhs != remainder, etc...) + ensures + - result == lhs / rhs + - remainder == lhs % rhs + !*/ + + void long_mul ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const; + /*! + requires + - result->size >= lhs->digits_used + rhs->digits_used + - result != lhs + - result != rhs + ensures + - result == lhs * rhs + !*/ + + void short_add ( + const data_record* data, + uint16 value, + data_record* result + ) const; + /*! + requires + - result->size >= data->size + 1 + ensures + - result == data + value + !*/ + + void short_sub ( + const data_record* data, + uint16 value, + data_record* result + ) const; + /*! + requires + - data >= value + - result->size >= data->digits_used + ensures + - result == data - value + !*/ + + void short_mul ( + const data_record* data, + uint16 value, + data_record* result + ) const; + /*! + requires + - result->size >= data->digits_used + 1 + ensures + - result == data * value + !*/ + + void short_div ( + const data_record* data, + uint16 value, + data_record* result, + uint16& remainder + ) const; + /*! + requires + - value != 0 + - result->size >= data->digits_used + ensures + - result = data*value + - remainder = data%value + !*/ + + void shift_left ( + const data_record* data, + data_record* result, + uint32 shift_amount + ) const; + /*! + requires + - result->size >= data->digits_used + shift_amount/8 + 1 + ensures + - result == data << shift_amount + !*/ + + void shift_right ( + const data_record* data, + data_record* result + ) const; + /*! + requires + - result->size >= data->digits_used + ensures + - result == data >> 1 + !*/ + + bool is_less_than ( + const data_record* lhs, + const data_record* rhs + ) const; + /*! + ensures + - returns true if lhs < rhs + - returns false otherwise + !*/ + + bool is_equal_to ( + const data_record* lhs, + const data_record* rhs + ) const; + /*! + ensures + - returns true if lhs == rhs + - returns false otherwise + !*/ + + void increment ( + const data_record* source, + data_record* dest + ) const; + /*! + requires + - dest->size >= source->digits_used + 1 + ensures + - dest = source + 1 + !*/ + + void decrement ( + const data_record* source, + data_record* dest + ) const; + /*! + requires + source != 0 + ensuers + dest = source - 1 + !*/ + + // member data + const uint32 slack; + data_record* data; + + + + }; + + inline void swap ( + bigint_kernel_1& a, + bigint_kernel_1& b + ) { a.swap(b); } + + inline void serialize ( + const bigint_kernel_1& item, + std::ostream& out + ) + { + std::ios::fmtflags oldflags = out.flags(); + out.flags(); + out << item << ' '; + out.flags(oldflags); + if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c"); + } + + inline void deserialize ( + bigint_kernel_1& item, + std::istream& in + ) + { + std::ios::fmtflags oldflags = in.flags(); + in.flags(); + in >> item; in.flags(oldflags); + if (in.get() != ' ') + { + item = 0; + throw serialization_error("Error deserializing object of type bigint_kernel_c"); + } + } + +} + +#ifdef NO_MAKEFILE +#include "bigint_kernel_1.cpp" +#endif + +#endif // DLIB_BIGINT_KERNEl_1_ + diff --git a/dlib/bigint/bigint_kernel_2.cpp b/dlib/bigint/bigint_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4046144b8c6f74508bca2e7c6454faec2d15e4c1 --- /dev/null +++ b/dlib/bigint/bigint_kernel_2.cpp @@ -0,0 +1,1949 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIGINT_KERNEL_2_CPp_ +#define DLIB_BIGINT_KERNEL_2_CPp_ +#include "bigint_kernel_2.h" + +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member/friend function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2:: + bigint_kernel_2 ( + ) : + slack(25), + data(new data_record(slack)) + {} + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2:: + bigint_kernel_2 ( + uint32 value + ) : + slack(25), + data(new data_record(slack)) + { + *(data->number) = static_cast(value&0xFFFF); + *(data->number+1) = static_cast((value>>16)&0xFFFF); + if (*(data->number+1) != 0) + data->digits_used = 2; + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2:: + bigint_kernel_2 ( + const bigint_kernel_2& item + ) : + slack(25), + data(item.data) + { + data->references += 1; + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2:: + ~bigint_kernel_2 ( + ) + { + if (data->references == 1) + { + delete data; + } + else + { + data->references -= 1; + } + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator+ ( + const bigint_kernel_2& rhs + ) const + { + data_record* temp = new data_record ( + std::max(rhs.data->digits_used,data->digits_used) + slack + ); + long_add(data,rhs.data,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator+= ( + const bigint_kernel_2& rhs + ) + { + // if there are other references to our data + if (data->references != 1) + { + data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); + data->references -= 1; + long_add(data,rhs.data,temp); + data = temp; + } + // if data is not big enough for the result + else if (data->size <= std::max(data->digits_used,rhs.data->digits_used)) + { + data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); + long_add(data,rhs.data,temp); + delete data; + data = temp; + } + // there is enough size and no references + else + { + long_add(data,rhs.data,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator- ( + const bigint_kernel_2& rhs + ) const + { + data_record* temp = new data_record ( + data->digits_used + slack + ); + long_sub(data,rhs.data,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator-= ( + const bigint_kernel_2& rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + long_sub(data,rhs.data,temp); + data = temp; + } + else + { + long_sub(data,rhs.data,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator* ( + const bigint_kernel_2& rhs + ) const + { + data_record* temp = new data_record ( + data->digits_used + rhs.data->digits_used + slack + ); + long_mul(data,rhs.data,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator*= ( + const bigint_kernel_2& rhs + ) + { + // create a data_record to store the result of the multiplication in + data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack); + long_mul(data,rhs.data,temp); + + // if there are other references to data + if (data->references != 1) + { + data->references -= 1; + } + else + { + delete data; + } + data = temp; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator/ ( + const bigint_kernel_2& rhs + ) const + { + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + delete remainder; + + + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator/= ( + const bigint_kernel_2& rhs + ) + { + + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + + // check if there are other references to data + if (data->references != 1) + { + data->references -= 1; + } + // if there are no references to data then it must be deleted + else + { + delete data; + } + data = temp; + delete remainder; + + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator% ( + const bigint_kernel_2& rhs + ) const + { + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + delete temp; + return bigint_kernel_2(remainder,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator%= ( + const bigint_kernel_2& rhs + ) + { + data_record* temp = new data_record(data->digits_used+slack); + data_record* remainder; + try { + remainder = new data_record(data->digits_used+slack); + } catch (...) { delete temp; throw; } + + long_div(data,rhs.data,temp,remainder); + + // check if there are other references to data + if (data->references != 1) + { + data->references -= 1; + } + // if there are no references to data then it must be deleted + else + { + delete data; + } + data = remainder; + delete temp; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_2:: + operator < ( + const bigint_kernel_2& rhs + ) const + { + return is_less_than(data,rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_2:: + operator == ( + const bigint_kernel_2& rhs + ) const + { + return is_equal_to(data,rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator= ( + const bigint_kernel_2& rhs + ) + { + if (this == &rhs) + return *this; + + // if we have the only reference to our data then delete it + if (data->references == 1) + { + delete data; + data = rhs.data; + data->references += 1; + } + else + { + data->references -= 1; + data = rhs.data; + data->references += 1; + } + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + std::ostream& operator<< ( + std::ostream& out_, + const bigint_kernel_2& rhs + ) + { + std::ostream out(out_.rdbuf()); + + typedef bigint_kernel_2 bigint; + + bigint::data_record* temp = new bigint::data_record(*rhs.data,0); + + + + // get a char array big enough to hold the number in ascii format + char* str; + try { + str = new char[(rhs.data->digits_used)*5+10]; + } catch (...) { delete temp; throw; } + + char* str_start = str; + str += (rhs.data->digits_used)*5+9; + *str = 0; --str; + + + uint16 remainder; + rhs.short_div(temp,10000,temp,remainder); + + // pull the digits out of remainder + char a = remainder % 10 + '0'; + remainder /= 10; + char b = remainder % 10 + '0'; + remainder /= 10; + char c = remainder % 10 + '0'; + remainder /= 10; + char d = remainder % 10 + '0'; + remainder /= 10; + + + *str = a; --str; + *str = b; --str; + *str = c; --str; + *str = d; --str; + + + // keep looping until temp represents zero + while (temp->digits_used != 1 || *(temp->number) != 0) + { + rhs.short_div(temp,10000,temp,remainder); + + // pull the digits out of remainder + char a = remainder % 10 + '0'; + remainder /= 10; + char b = remainder % 10 + '0'; + remainder /= 10; + char c = remainder % 10 + '0'; + remainder /= 10; + char d = remainder % 10 + '0'; + remainder /= 10; + + *str = a; --str; + *str = b; --str; + *str = c; --str; + *str = d; --str; + } + + // throw away and extra leading zeros + ++str; + if (*str == '0') + ++str; + if (*str == '0') + ++str; + if (*str == '0') + ++str; + + + + + out << str; + delete [] str_start; + delete temp; + return out_; + + } + +// ---------------------------------------------------------------------------------------- + + std::istream& operator>> ( + std::istream& in_, + bigint_kernel_2& rhs + ) + { + std::istream in(in_.rdbuf()); + + // ignore any leading whitespaces + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n') + { + in.get(); + } + + // if the first digit is not an integer then this is an error + if ( !(in.peek() >= '0' && in.peek() <= '9')) + { + in_.clear(std::ios::failbit); + return in_; + } + + int num_read; + bigint_kernel_2 temp; + do + { + + // try to get 4 chars from in + num_read = 1; + char a = 0; + char b = 0; + char c = 0; + char d = 0; + + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + a = in.get(); + } + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + b = in.get(); + } + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + c = in.get(); + } + if (in.peek() >= '0' && in.peek() <= '9') + { + num_read *= 10; + d = in.get(); + } + + // merge the for digits into an uint16 + uint16 num = 0; + if (a != 0) + { + num = a - '0'; + } + if (b != 0) + { + num *= 10; + num += b - '0'; + } + if (c != 0) + { + num *= 10; + num += c - '0'; + } + if (d != 0) + { + num *= 10; + num += d - '0'; + } + + + if (num_read != 1) + { + // shift the digits in temp left by the number of new digits we just read + temp *= num_read; + // add in new digits + temp += num; + } + + } while (num_read == 10000); + + + rhs = temp; + return in_; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator+ ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record + (rhs.data->digits_used+rhs.slack); + + rhs.short_add(rhs.data,lhs,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator+ ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + lhs.short_add(lhs.data,rhs,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator+= ( + uint16 rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_add(data,rhs,temp); + data = temp; + } + // or if we need to enlarge data then do so + else if (data->digits_used == data->size) + { + data_record* temp = new data_record(data->digits_used+slack); + short_add(data,rhs,temp); + delete data; + data = temp; + } + // or if there is plenty of space and no references + else + { + short_add(data,rhs,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator- ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record(rhs.slack); + + *(temp->number) = lhs - *(rhs.data->number); + + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator- ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + lhs.short_sub(lhs.data,rhs,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator-= ( + uint16 rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_sub(data,rhs,temp); + data = temp; + } + else + { + short_sub(data,rhs,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator* ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record + (rhs.data->digits_used+rhs.slack); + + rhs.short_mul(rhs.data,lhs,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator* ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + lhs.short_mul(lhs.data,rhs,temp); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator*= ( + uint16 rhs + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_mul(data,rhs,temp); + data = temp; + } + // or if we need to enlarge data + else if (data->digits_used == data->size) + { + data_record* temp = new data_record(data->digits_used+slack); + short_mul(data,rhs,temp); + delete data; + data = temp; + } + else + { + short_mul(data,rhs,data); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator/ ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record(rhs.slack); + + // if rhs might not be bigger than lhs + if (rhs.data->digits_used == 1) + { + *(temp->number) = lhs/ *(rhs.data->number); + } + + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator/ ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record + (lhs.data->digits_used+lhs.slack); + + uint16 remainder; + lhs.short_div(lhs.data,rhs,temp,remainder); + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator/= ( + uint16 rhs + ) + { + uint16 remainder; + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_div(data,rhs,temp,remainder); + data = temp; + } + else + { + short_div(data,rhs,data,remainder); + } + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator% ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + typedef bigint_kernel_2 bigint; + // temp is zero by default + bigint::data_record* temp = new bigint::data_record(rhs.slack); + + if (rhs.data->digits_used == 1) + { + // if rhs is just an uint16 inside then perform the modulus + *(temp->number) = lhs % *(rhs.data->number); + } + else + { + // if rhs is bigger than lhs then the answer is lhs + *(temp->number) = lhs; + } + + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 operator% ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + typedef bigint_kernel_2 bigint; + bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack); + + uint16 remainder; + + lhs.short_div(lhs.data,rhs,temp,remainder); + temp->digits_used = 1; + *(temp->number) = remainder; + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator%= ( + uint16 rhs + ) + { + uint16 remainder; + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + short_div(data,rhs,temp,remainder); + data = temp; + } + else + { + short_div(data,rhs,data,remainder); + } + + data->digits_used = 1; + *(data->number) = remainder; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + bool operator < ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) ); + } + +// ---------------------------------------------------------------------------------------- + + bool operator < ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs); + } + +// ---------------------------------------------------------------------------------------- + + bool operator == ( + const bigint_kernel_2& lhs, + uint16 rhs + ) + { + return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs); + } + +// ---------------------------------------------------------------------------------------- + + bool operator == ( + uint16 lhs, + const bigint_kernel_2& rhs + ) + { + return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator= ( + uint16 rhs + ) + { + // check if there are other references to our data + if (data->references != 1) + { + data->references -= 1; + try { + data = new data_record(slack); + } catch (...) { data->references += 1; throw; } + } + else + { + data->digits_used = 1; + } + + *(data->number) = rhs; + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator++ ( + ) + { + // if there are other references to this data then make a copy of it + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + increment(data,temp); + data = temp; + } + // or if we need to enlarge data then do so + else if (data->digits_used == data->size) + { + data_record* temp = new data_record(data->digits_used+slack); + increment(data,temp); + delete data; + data = temp; + } + else + { + increment(data,data); + } + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator++ ( + int + ) + { + data_record* temp; // this is the copy of temp we will return in the end + + data_record* temp2 = new data_record(data->digits_used+slack); + increment(data,temp2); + + temp = data; + data = temp2; + + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- + + bigint_kernel_2& bigint_kernel_2:: + operator-- ( + ) + { + // if there are other references to this data + if (data->references != 1) + { + data_record* temp = new data_record(data->digits_used+slack); + data->references -= 1; + decrement(data,temp); + data = temp; + } + else + { + decrement(data,data); + } + + return *this; + } + +// ---------------------------------------------------------------------------------------- + + const bigint_kernel_2 bigint_kernel_2:: + operator-- ( + int + ) + { + data_record* temp; // this is the copy of temp we will return in the end + + data_record* temp2 = new data_record(data->digits_used+slack); + decrement(data,temp2); + + temp = data; + data = temp2; + + return bigint_kernel_2(temp,0); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + short_add ( + const data_record* data, + uint16 value, + data_record* result + ) const + { + // put value into the carry part of temp + uint32 temp = value; + temp <<= 16; + + + const uint16* number = data->number; + const uint16* end = number + data->digits_used; // one past the end of number + uint16* r = result->number; + + while (number != end) + { + // add *number and the current carry + temp = *number + (temp>>16); + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++number; + ++r; + } + + // if there is a final carry + if ((temp>>16) != 0) + { + result->digits_used = data->digits_used + 1; + // store the carry in the most significant digit of the result + *r = static_cast(temp>>16); + } + else + { + result->digits_used = data->digits_used; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + short_sub ( + const data_record* data, + uint16 value, + data_record* result + ) const + { + + + const uint16* number = data->number; + const uint16* end = number + data->digits_used - 1; + uint16* r = result->number; + + uint32 temp = *number - value; + + // put the low word of temp into *data + *r = static_cast(temp & 0xFFFF); + + + while (number != end) + { + ++number; + ++r; + + // subtract the carry from *number + temp = *number - (temp>>31); + + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + } + + // if we lost a digit in the subtraction + if (*r == 0) + { + if (data->digits_used == 1) + result->digits_used = 1; + else + result->digits_used = data->digits_used - 1; + } + else + { + result->digits_used = data->digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + short_mul ( + const data_record* data, + uint16 value, + data_record* result + ) const + { + + uint32 temp = 0; + + + const uint16* number = data->number; + uint16* r = result->number; + const uint16* end = r + data->digits_used; + + + + while ( r != end) + { + + // multiply *data and value and add in the carry + temp = *number*(uint32)value + (temp>>16); + + // put the low word of temp into *data + *r = static_cast(temp & 0xFFFF); + + ++number; + ++r; + } + + // if there is a final carry + if ((temp>>16) != 0) + { + result->digits_used = data->digits_used + 1; + // put the final carry into the most significant digit of the result + *r = static_cast(temp>>16); + } + else + { + result->digits_used = data->digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + short_div ( + const data_record* data, + uint16 value, + data_record* result, + uint16& rem + ) const + { + + uint16 remainder = 0; + uint32 temp; + + + + const uint16* number = data->number + data->digits_used - 1; + const uint16* end = number - data->digits_used; + uint16* r = result->number + data->digits_used - 1; + + + // if we are losing a digit in this division + if (*number < value) + { + if (data->digits_used == 1) + result->digits_used = 1; + else + result->digits_used = data->digits_used - 1; + } + else + { + result->digits_used = data->digits_used; + } + + + // perform the actual division + while (number != end) + { + + temp = *number + (((uint32)remainder)<<16); + + *r = static_cast(temp/value); + remainder = static_cast(temp%value); + + --number; + --r; + } + + rem = remainder; + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + long_add ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const + { + // put value into the carry part of temp + uint32 temp=0; + + uint16* min_num; // the number with the least digits used + uint16* max_num; // the number with the most digits used + uint16* min_end; // one past the end of min_num + uint16* max_end; // one past the end of max_num + uint16* r = result->number; + + uint32 max_digits_used; + if (lhs->digits_used < rhs->digits_used) + { + max_digits_used = rhs->digits_used; + min_num = lhs->number; + max_num = rhs->number; + min_end = min_num + lhs->digits_used; + max_end = max_num + rhs->digits_used; + } + else + { + max_digits_used = lhs->digits_used; + min_num = rhs->number; + max_num = lhs->number; + min_end = min_num + rhs->digits_used; + max_end = max_num + lhs->digits_used; + } + + + + + while (min_num != min_end) + { + // add *min_num, *max_num and the current carry + temp = *min_num + *max_num + (temp>>16); + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++min_num; + ++max_num; + ++r; + } + + + while (max_num != max_end) + { + // add *max_num and the current carry + temp = *max_num + (temp>>16); + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++max_num; + ++r; + } + + // check if there was a final carry + if ((temp>>16) != 0) + { + result->digits_used = max_digits_used + 1; + // put the carry into the most significant digit in the result + *r = static_cast(temp>>16); + } + else + { + result->digits_used = max_digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + long_sub ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const + { + + + const uint16* number1 = lhs->number; + const uint16* number2 = rhs->number; + const uint16* end = number2 + rhs->digits_used; + uint16* r = result->number; + + + + uint32 temp =0; + + + while (number2 != end) + { + + // subtract *number2 from *number1 and then subtract any carry + temp = *number1 - *number2 - (temp>>31); + + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++number1; + ++number2; + ++r; + } + + end = lhs->number + lhs->digits_used; + while (number1 != end) + { + + // subtract the carry from *number1 + temp = *number1 - (temp>>31); + + // put the low word of temp into *r + *r = static_cast(temp & 0xFFFF); + + ++number1; + ++r; + } + + // if we are using one less digit + if (*(r-1) == 0) + { + if (lhs->digits_used != 1) + result->digits_used = lhs->digits_used - 1; + else + result->digits_used = 1; + } + else + { + result->digits_used = lhs->digits_used; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + long_div ( + const data_record* lhs, + const data_record* rhs, + data_record* result, + data_record* remainder + ) const + { + // zero result + result->digits_used = 1; + *(result->number) = 0; + + uint16* a; + uint16* b; + uint16* end; + + // copy lhs into remainder + remainder->digits_used = lhs->digits_used; + a = remainder->number; + end = a + remainder->digits_used; + b = lhs->number; + while (a != end) + { + *a = *b; + ++a; + ++b; + } + + + // if rhs is bigger than lhs then result == 0 and remainder == lhs + // so then we can quit right now + if (is_less_than(lhs,rhs)) + { + return; + } + + + // make a temporary number + data_record temp(lhs->digits_used + slack); + + + // shift rhs left until it is one shift away from being larger than lhs and + // put the number of left shifts necessary into shifts + uint32 shifts; + shifts = (lhs->digits_used - rhs->digits_used) * 8; + + shift_left(rhs,&temp,shifts); + + + // while (lhs > temp) + while (is_less_than(&temp,lhs)) + { + shift_left(&temp,&temp,1); + ++shifts; + } + // make sure lhs isn't smaller than temp + while (is_less_than(lhs,&temp)) + { + shift_right(&temp,&temp); + --shifts; + } + + + + // we want to execute the loop shifts +1 times + ++shifts; + while (shifts != 0) + { + shift_left(result,result,1); + // if (temp <= remainder) + if (!is_less_than(remainder,&temp)) + { + long_sub(remainder,&temp,remainder); + + // increment result + uint16* r = result->number; + uint16* end = r + result->digits_used; + while (true) + { + ++(*r); + // if there was no carry then we are done + if (*r != 0) + break; + + ++r; + + // if we hit the end of r and there is still a carry then + // the next digit of r is 1 and there is one more digit used + if (r == end) + { + *r = 1; + ++(result->digits_used); + break; + } + } + } + shift_right(&temp,&temp); + --shifts; + } + + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + long_mul ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const + { + // if one of the numbers is small then use this simple but O(n^2) algorithm + if (std::min(lhs->digits_used, rhs->digits_used) < 10) + { + // make result be zero + result->digits_used = 1; + *(result->number) = 0; + + + const data_record* aa; + const data_record* bb; + + if (lhs->digits_used < rhs->digits_used) + { + // make copies of lhs and rhs and give them an appropriate amount of + // extra memory so there won't be any overflows + aa = lhs; + bb = rhs; + } + else + { + // make copies of lhs and rhs and give them an appropriate amount of + // extra memory so there won't be any overflows + aa = rhs; + bb = lhs; + } + + // copy the larger(approximately) of lhs and rhs into b + data_record b(*bb,aa->digits_used+slack); + + + uint32 shift_value = 0; + uint16* anum = aa->number; + uint16* end = anum + aa->digits_used; + while (anum != end ) + { + uint16 bit = 0x0001; + + for (int i = 0; i < 16; ++i) + { + // if the specified bit of a is 1 + if ((*anum & bit) != 0) + { + shift_left(&b,&b,shift_value); + shift_value = 0; + long_add(&b,result,result); + } + ++shift_value; + bit <<= 1; + } + + ++anum; + } + } + else // else if both lhs and rhs are large then use the more complex + // O(n*logn) algorithm + { + uint32 size = 1; + // make size a power of 2 + while (size < (lhs->digits_used + rhs->digits_used)*2) + { + size *= 2; + } + + // allocate some temporary space so we can do the FFT + ct* a = new ct[size]; + ct* b; try {b = new ct[size]; } catch (...) { delete [] a; throw; } + + // load lhs into the a array. We are breaking the input number into + // 8bit chunks for the purpose of using this fft algorithm. The reason + // for this is so that we have smaller numbers coming out of the final + // ifft. This helps avoid overflow. + for (uint32 i = 0; i < lhs->digits_used; ++i) + { + a[i*2] = ct((t)(lhs->number[i]&0xFF),0); + a[i*2+1] = ct((t)(lhs->number[i]>>8),0); + } + for (uint32 i = lhs->digits_used*2; i < size; ++i) + { + a[i] = 0; + } + + // load rhs into the b array + for (uint32 i = 0; i < rhs->digits_used; ++i) + { + b[i*2] = ct((t)(rhs->number[i]&0xFF),0); + b[i*2+1] = ct((t)(rhs->number[i]>>8),0); + } + for (uint32 i = rhs->digits_used*2; i < size; ++i) + { + b[i] = 0; + } + + // perform the forward fft of a and b + fft(a,size); + fft(b,size); + + const double l = 1.0/size; + + // do the pointwise multiply of a and b and also apply the scale + // factor in this loop too. + for (unsigned long i = 0; i < size; ++i) + { + a[i] = l*a[i]*b[i]; + } + + // Now compute the inverse fft of the pointwise multiplication of a and b. + // This is basically the result. We just have to take care of any carries + // that should happen. + ifft(a,size); + + // loop over the result and propigate any carries that need to take place. + // We will also be moving the resulting numbers into result->number at + // the same time. + uint64 carry = 0; + result->digits_used = 0; + int zeros = 0; + const uint32 len = lhs->digits_used + rhs->digits_used; + for (unsigned long i = 0; i < len; ++i) + { + uint64 num1 = static_cast(floor(a[i*2].real()+0.5)); + num1 += carry; + carry = 0; + if (num1 > 255) + { + carry = num1 >> 8; + num1 = (num1&0xFF); + } + + uint64 num2 = static_cast(floor(a[i*2+1].real()+0.5)); + num2 += carry; + carry = 0; + if (num2 > 255) + { + carry = num2 >> 8; + num2 = (num2&0xFF); + } + + // put the new number into its final place + num1 = (num2<<8) | num1; + result->number[i] = static_cast(num1); + + // keep track of the number of leading zeros + if (num1 == 0) + ++zeros; + else + zeros = 0; + ++(result->digits_used); + } + + // adjust digits_used so that it reflects the actual number + // of non-zero digits in our representation. + result->digits_used -= zeros; + + // if the result was zero then adjust the result accordingly + if (result->digits_used == 0) + { + // make result be zero + result->digits_used = 1; + *(result->number) = 0; + } + + // free all the temporary buffers + delete [] a; + delete [] b; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + shift_left ( + const data_record* data, + data_record* result, + uint32 shift_amount + ) const + { + uint32 offset = shift_amount/16; + shift_amount &= 0xf; // same as shift_amount %= 16; + + uint16* r = result->number + data->digits_used + offset; // result + uint16* end = data->number; + uint16* s = end + data->digits_used; // source + const uint32 temp = 16 - shift_amount; + + *r = (*(--s) >> temp); + // set the number of digits used in the result + // if the upper bits from *s were zero then don't count this first word + if (*r == 0) + { + result->digits_used = data->digits_used + offset; + } + else + { + result->digits_used = data->digits_used + offset + 1; + } + --r; + + while (s != end) + { + *r = ((*s << shift_amount) | ( *(s-1) >> temp)); + --r; + --s; + } + *r = *s << shift_amount; + + // now zero the rest of the result + end = result->number; + while (r != end) + *(--r) = 0; + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + shift_right ( + const data_record* data, + data_record* result + ) const + { + + uint16* r = result->number; // result + uint16* s = data->number; // source + uint16* end = s + data->digits_used - 1; + + while (s != end) + { + *r = (*s >> 1) | (*(s+1) << 15); + ++r; + ++s; + } + *r = *s >> 1; + + + // calculate the new number for digits_used + if (*r == 0) + { + if (data->digits_used != 1) + result->digits_used = data->digits_used - 1; + else + result->digits_used = 1; + } + else + { + result->digits_used = data->digits_used; + } + + + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_2:: + is_less_than ( + const data_record* lhs, + const data_record* rhs + ) const + { + uint32 lhs_digits_used = lhs->digits_used; + uint32 rhs_digits_used = rhs->digits_used; + + // if lhs is definitely less than rhs + if (lhs_digits_used < rhs_digits_used ) + return true; + // if lhs is definitely greater than rhs + else if (lhs_digits_used > rhs_digits_used) + return false; + else + { + uint16* end = lhs->number; + uint16* l = end + lhs_digits_used; + uint16* r = rhs->number + rhs_digits_used; + + while (l != end) + { + --l; + --r; + if (*l < *r) + return true; + else if (*l > *r) + return false; + } + + // at this point we know that they are equal + return false; + } + + } + +// ---------------------------------------------------------------------------------------- + + bool bigint_kernel_2:: + is_equal_to ( + const data_record* lhs, + const data_record* rhs + ) const + { + // if lhs and rhs are definitely not equal + if (lhs->digits_used != rhs->digits_used ) + { + return false; + } + else + { + uint16* l = lhs->number; + uint16* r = rhs->number; + uint16* end = l + lhs->digits_used; + + while (l != end) + { + if (*l != *r) + return false; + ++l; + ++r; + } + + // at this point we know that they are equal + return true; + } + + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + increment ( + const data_record* source, + data_record* dest + ) const + { + uint16* s = source->number; + uint16* d = dest->number; + uint16* end = s + source->digits_used; + while (true) + { + *d = *s + 1; + + // if there was no carry then break out of the loop + if (*d != 0) + { + dest->digits_used = source->digits_used; + + // copy the rest of the digits over to d + ++d; ++s; + while (s != end) + { + *d = *s; + ++d; + ++s; + } + + break; + } + + + ++s; + + // if we have hit the end of s and there was a carry up to this point + // then just make the next digit 1 and add one to the digits used + if (s == end) + { + ++d; + dest->digits_used = source->digits_used + 1; + *d = 1; + break; + } + + ++d; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + decrement ( + const data_record* source, + data_record* dest + ) const + { + uint16* s = source->number; + uint16* d = dest->number; + uint16* end = s + source->digits_used; + while (true) + { + *d = *s - 1; + + // if there was no carry then break out of the loop + if (*d != 0xFFFF) + { + // if we lost a digit in the subtraction + if (*d == 0 && s+1 == end) + { + if (source->digits_used == 1) + dest->digits_used = 1; + else + dest->digits_used = source->digits_used - 1; + } + else + { + dest->digits_used = source->digits_used; + } + break; + } + else + { + ++d; + ++s; + } + + } + + // copy the rest of the digits over to d + ++d; + ++s; + while (s != end) + { + *d = *s; + ++d; + ++s; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + fft ( + ct* data, + unsigned long len + ) const + { + const t pi2 = -2.0*3.1415926535897932384626433832795028841971693993751; + + const unsigned long half = len/2; + + std::vector twiddle_factors; + twiddle_factors.resize(half); + + // compute the complex root of unity w + const t temp = pi2/len; + ct w = ct(cos(temp),sin(temp)); + + ct w_pow = 1; + + // compute the twiddle factors + for (std::vector::size_type j = 0; j < twiddle_factors.size(); ++j) + { + twiddle_factors[j] = w_pow; + w_pow *= w; + } + + ct a, b; + + // now compute the decimation in frequency. This first + // outer loop loops log2(len) number of times + unsigned long skip = 1; + for (unsigned long step = half; step != 0; step >>= 1) + { + // do blocks of butterflies in this loop + for (unsigned long j = 0; j < len; j += step*2) + { + // do step butterflies + for (unsigned long k = 0; k < step; ++k) + { + const unsigned long a_idx = j+k; + const unsigned long b_idx = j+k+step; + a = data[a_idx] + data[b_idx]; + b = (data[a_idx] - data[b_idx])*twiddle_factors[k*skip]; + data[a_idx] = a; + data[b_idx] = b; + } + } + skip *= 2; + } + } + +// ---------------------------------------------------------------------------------------- + + void bigint_kernel_2:: + ifft( + ct* data, + unsigned long len + ) const + { + const t pi2 = 2.0*3.1415926535897932384626433832795028841971693993751; + + const unsigned long half = len/2; + + std::vector twiddle_factors; + twiddle_factors.resize(half); + + // compute the complex root of unity w + const t temp = pi2/len; + ct w = ct(cos(temp),sin(temp)); + + ct w_pow = 1; + + // compute the twiddle factors + for (std::vector::size_type j = 0; j < twiddle_factors.size(); ++j) + { + twiddle_factors[j] = w_pow; + w_pow *= w; + } + + ct a, b; + + // now compute the inverse decimation in frequency. This first + // outer loop loops log2(len) number of times + unsigned long skip = half; + for (unsigned long step = 1; step <= half; step <<= 1) + { + // do blocks of butterflies in this loop + for (unsigned long j = 0; j < len; j += step*2) + { + // do step butterflies + for (unsigned long k = 0; k < step; ++k) + { + const unsigned long a_idx = j+k; + const unsigned long b_idx = j+k+step; + data[b_idx] *= twiddle_factors[k*skip]; + a = data[a_idx] + data[b_idx]; + b = data[a_idx] - data[b_idx]; + data[a_idx] = a; + data[b_idx] = b; + } + } + skip /= 2; + } + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_BIGINT_KERNEL_2_CPp_ + diff --git a/dlib/bigint/bigint_kernel_2.h b/dlib/bigint/bigint_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..fa72d7e49c4b099d61d06ce04e9e7131b939e804 --- /dev/null +++ b/dlib/bigint/bigint_kernel_2.h @@ -0,0 +1,567 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIGINT_KERNEl_2_ +#define DLIB_BIGINT_KERNEl_2_ + +#include "bigint_kernel_abstract.h" +#include "../algs.h" +#include "../serialize.h" +#include "../uintn.h" +#include +#include +#include +#include + +namespace dlib +{ + + using namespace dlib::relational_operators; // defined in algs.h + + class bigint_kernel_2 + { + /*! + INITIAL VALUE + slack == 25 + data->number[0] == 0 + data->size == slack + data->references == 1 + data->digits_used == 1 + + + CONVENTION + slack == the number of extra digits placed into the number when it is + created. the slack value should never be less than 1 + + data->number == pointer to an array of data->size uint16s. + data represents a string of base 65535 numbers with data[0] being + the least significant bit and data[data->digits_used-1] being the most + significant + + + NOTE: In the comments I will consider a word to be a 16 bit value + + + data->digits_used == the number of significant digits in the number. + data->digits_used tells us the number of used elements in the + data->number array so everything beyond data->number[data->digits_used-1] + is undefined + + data->references == the number of bigint_kernel_2 objects which refer + to this data_record + !*/ + + + struct data_record + { + + + explicit data_record( + uint32 size_ + ) : + size(size_), + number(new uint16[size_]), + references(1), + digits_used(1) + {*number = 0;} + /*! + ensures + - initializes *this to represent zero + !*/ + + data_record( + const data_record& item, + uint32 additional_size + ) : + size(item.digits_used + additional_size), + number(new uint16[size]), + references(1), + digits_used(item.digits_used) + { + uint16* source = item.number; + uint16* dest = number; + uint16* end = source + digits_used; + while (source != end) + { + *dest = *source; + ++dest; + ++source; + } + } + /*! + ensures + - *this is a copy of item except with + size == item.digits_used + additional_size + !*/ + + ~data_record( + ) + { + delete [] number; + } + + + const uint32 size; + uint16* number; + uint32 references; + uint32 digits_used; + + private: + // no copy constructor + data_record ( data_record&); + }; + + + // note that the second parameter is just there + // to resolve the ambiguity between this constructor and + // bigint_kernel_2(uint32) + explicit bigint_kernel_2 ( + data_record* data_, int + ): slack(25),data(data_) {} + /*! + ensures + - *this is initialized with data_ as its data member + !*/ + + public: + + bigint_kernel_2 ( + ); + + bigint_kernel_2 ( + uint32 value + ); + + bigint_kernel_2 ( + const bigint_kernel_2& item + ); + + virtual ~bigint_kernel_2 ( + ); + + const bigint_kernel_2 operator+ ( + const bigint_kernel_2& rhs + ) const; + + bigint_kernel_2& operator+= ( + const bigint_kernel_2& rhs + ); + + const bigint_kernel_2 operator- ( + const bigint_kernel_2& rhs + ) const; + + bigint_kernel_2& operator-= ( + const bigint_kernel_2& rhs + ); + + const bigint_kernel_2 operator* ( + const bigint_kernel_2& rhs + ) const; + + bigint_kernel_2& operator*= ( + const bigint_kernel_2& rhs + ); + + const bigint_kernel_2 operator/ ( + const bigint_kernel_2& rhs + ) const; + + bigint_kernel_2& operator/= ( + const bigint_kernel_2& rhs + ); + + const bigint_kernel_2 operator% ( + const bigint_kernel_2& rhs + ) const; + + bigint_kernel_2& operator%= ( + const bigint_kernel_2& rhs + ); + + bool operator < ( + const bigint_kernel_2& rhs + ) const; + + bool operator == ( + const bigint_kernel_2& rhs + ) const; + + bigint_kernel_2& operator= ( + const bigint_kernel_2& rhs + ); + + friend std::ostream& operator<< ( + std::ostream& out, + const bigint_kernel_2& rhs + ); + + friend std::istream& operator>> ( + std::istream& in, + bigint_kernel_2& rhs + ); + + bigint_kernel_2& operator++ ( + ); + + const bigint_kernel_2 operator++ ( + int + ); + + bigint_kernel_2& operator-- ( + ); + + const bigint_kernel_2 operator-- ( + int + ); + + friend const bigint_kernel_2 operator+ ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + friend const bigint_kernel_2 operator+ ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + bigint_kernel_2& operator+= ( + uint16 rhs + ); + + friend const bigint_kernel_2 operator- ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + friend const bigint_kernel_2 operator- ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + bigint_kernel_2& operator-= ( + uint16 rhs + ); + + friend const bigint_kernel_2 operator* ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + friend const bigint_kernel_2 operator* ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + bigint_kernel_2& operator*= ( + uint16 rhs + ); + + friend const bigint_kernel_2 operator/ ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + friend const bigint_kernel_2 operator/ ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + bigint_kernel_2& operator/= ( + uint16 rhs + ); + + friend const bigint_kernel_2 operator% ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + friend const bigint_kernel_2 operator% ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + bigint_kernel_2& operator%= ( + uint16 rhs + ); + + friend bool operator < ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + friend bool operator < ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + friend bool operator == ( + const bigint_kernel_2& lhs, + uint16 rhs + ); + + friend bool operator == ( + uint16 lhs, + const bigint_kernel_2& rhs + ); + + bigint_kernel_2& operator= ( + uint16 rhs + ); + + + void swap ( + bigint_kernel_2& item + ) { data_record* temp = data; data = item.data; item.data = temp; } + + + private: + + typedef double t; + typedef std::complex ct; + + void fft( + ct* data, + unsigned long len + ) const; + /*! + requires + - len == x^n for some integer n (i.e. len is a power of 2) + - len > 0 + ensures + - #data == the FT decimation in frequency of data + !*/ + + void ifft( + ct* data, + unsigned long len + ) const; + /*! + requires + - len == x^n for some integer n (i.e. len is a power of 2) + - len > 0 + ensures + - #data == the inverse decimation in frequency of data. + (i.e. the inverse of what fft(data,len,-1) does to data) + !*/ + + void long_add ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const; + /*! + requires + - result->size >= max(lhs->digits_used,rhs->digits_used) + 1 + ensures + - result == lhs + rhs + !*/ + + void long_sub ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const; + /*! + requires + - lhs >= rhs + - result->size >= lhs->digits_used + ensures + - result == lhs - rhs + !*/ + + void long_div ( + const data_record* lhs, + const data_record* rhs, + data_record* result, + data_record* remainder + ) const; + /*! + requires + - rhs != 0 + - result->size >= lhs->digits_used + - remainder->size >= lhs->digits_used + - each parameter is unique (i.e. lhs != result, lhs != remainder, etc...) + ensures + - result == lhs / rhs + - remainder == lhs % rhs + !*/ + + void long_mul ( + const data_record* lhs, + const data_record* rhs, + data_record* result + ) const; + /*! + requires + - result->size >= lhs->digits_used + rhs->digits_used + - result != lhs + - result != rhs + ensures + - result == lhs * rhs + !*/ + + void short_add ( + const data_record* data, + uint16 value, + data_record* result + ) const; + /*! + requires + - result->size >= data->size + 1 + ensures + - result == data + value + !*/ + + void short_sub ( + const data_record* data, + uint16 value, + data_record* result + ) const; + /*! + requires + - data >= value + - result->size >= data->digits_used + ensures + - result == data - value + !*/ + + void short_mul ( + const data_record* data, + uint16 value, + data_record* result + ) const; + /*! + requires + - result->size >= data->digits_used + 1 + ensures + - result == data * value + !*/ + + void short_div ( + const data_record* data, + uint16 value, + data_record* result, + uint16& remainder + ) const; + /*! + requires + - value != 0 + - result->size >= data->digits_used + ensures + - result = data*value + - remainder = data%value + !*/ + + void shift_left ( + const data_record* data, + data_record* result, + uint32 shift_amount + ) const; + /*! + requires + - result->size >= data->digits_used + shift_amount/8 + 1 + ensures + - result == data << shift_amount + !*/ + + void shift_right ( + const data_record* data, + data_record* result + ) const; + /*! + requires + - result->size >= data->digits_used + ensures + - result == data >> 1 + !*/ + + bool is_less_than ( + const data_record* lhs, + const data_record* rhs + ) const; + /*! + ensures + - returns true if lhs < rhs + - returns false otherwise + !*/ + + bool is_equal_to ( + const data_record* lhs, + const data_record* rhs + ) const; + /*! + ensures + - returns true if lhs == rhs + - returns false otherwise + !*/ + + void increment ( + const data_record* source, + data_record* dest + ) const; + /*! + requires + - dest->size >= source->digits_used + 1 + ensures + - dest = source + 1 + !*/ + + void decrement ( + const data_record* source, + data_record* dest + ) const; + /*! + requires + source != 0 + ensuers + dest = source - 1 + !*/ + + // member data + const uint32 slack; + data_record* data; + + + + }; + + inline void swap ( + bigint_kernel_2& a, + bigint_kernel_2& b + ) { a.swap(b); } + + inline void serialize ( + const bigint_kernel_2& item, + std::ostream& out + ) + { + std::ios::fmtflags oldflags = out.flags(); + out.flags(); + out << item << ' '; + out.flags(oldflags); + if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c"); + } + + inline void deserialize ( + bigint_kernel_2& item, + std::istream& in + ) + { + std::ios::fmtflags oldflags = in.flags(); + in.flags(); + in >> item; in.flags(oldflags); + if (in.get() != ' ') + { + item = 0; + throw serialization_error("Error deserializing object of type bigint_kernel_c"); + } + } + +} + +#ifdef NO_MAKEFILE +#include "bigint_kernel_2.cpp" +#endif + +#endif // DLIB_BIGINT_KERNEl_2_ + diff --git a/dlib/bigint/bigint_kernel_abstract.h b/dlib/bigint/bigint_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..e8323d8691f830497736890531f99105d691542b --- /dev/null +++ b/dlib/bigint/bigint_kernel_abstract.h @@ -0,0 +1,667 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BIGINT_KERNEl_ABSTRACT_ +#ifdef DLIB_BIGINT_KERNEl_ABSTRACT_ + +#include +#include "../algs.h" +#include "../serialize.h" +#include "../uintn.h" + +namespace dlib +{ + using namespace dlib::relational_operators; // defined in algs.h + + class bigint + { + /*! + INITIAL VALUE + *this == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents an arbitrary precision unsigned integer + + the following operators are supported: + operator + + operator += + operator - + operator -= + operator * + operator *= + operator / + operator /= + operator % + operator %= + operator == + operator < + operator = + operator << (for writing to ostreams) + operator >> (for reading from istreams) + operator++ // pre increment + operator++(int) // post increment + operator-- // pre decrement + operator--(int) // post decrement + + + the other comparason operators(>, !=, <=, and >=) are + available and come from the templates in dlib::relational_operators + + THREAD SAFETY + bigint may be reference counted so it is very unthread safe. + use with care in a multithreaded program + + !*/ + + public: + + bigint ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + if this is thrown the bigint will be unusable but + will not leak memory + !*/ + + bigint ( + uint32 value + ); + /*! + requires + - value <= (2^32)-1 + ensures + - #*this is properly initialized + - #*this == value + throws + - std::bad_alloc + if this is thrown the bigint will be unusable but + will not leak memory + !*/ + + bigint ( + const bigint& item + ); + /*! + ensures + - #*this is properly initialized + - #*this == value + throws + - std::bad_alloc + if this is thrown the bigint will be unusable but + will not leak memory + !*/ + + virtual ~bigint ( + ); + /*! + ensures + - all resources associated with #*this have been released + !*/ + + const bigint operator+ ( + const bigint& rhs + ) const; + /*! + ensures + - returns the result of adding rhs to *this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator+= ( + const bigint& rhs + ); + /*! + ensures + - #*this == *this + rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + const bigint operator- ( + const bigint& rhs + ) const; + /*! + requires + - *this >= rhs + ensures + - returns the result of subtracting rhs from *this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator-= ( + const bigint& rhs + ); + /*! + requires + - *this >= rhs + ensures + - #*this == *this - rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + const bigint operator* ( + const bigint& rhs + ) const; + /*! + ensures + - returns the result of multiplying *this and rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator*= ( + const bigint& rhs + ); + /*! + ensures + - #*this == *this * rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + const bigint operator/ ( + const bigint& rhs + ) const; + /*! + requires + - rhs != 0 + ensures + - returns the result of dividing *this by rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator/= ( + const bigint& rhs + ); + /*! + requires + - rhs != 0 + ensures + - #*this == *this / rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + const bigint operator% ( + const bigint& rhs + ) const; + /*! + requires + - rhs != 0 + ensures + - returns the result of *this mod rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator%= ( + const bigint& rhs + ); + /*! + requires + - rhs != 0 + ensures + - #*this == *this % rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bool operator < ( + const bigint& rhs + ) const; + /*! + ensures + - returns true if *this is less than rhs + - returns false otherwise + !*/ + + bool operator == ( + const bigint& rhs + ) const; + /*! + ensures + - returns true if *this and rhs represent the same number + - returns false otherwise + !*/ + + bigint& operator= ( + const bigint& rhs + ); + /*! + ensures + - #*this == rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + + friend std::ostream& operator<< ( + std::ostream& out, + const bigint& rhs + ); + /*! + ensures + - the number in *this has been written to #out as a base ten number + throws + - std::bad_alloc + if this function throws then it has no effect (nothing + is written to out) + !*/ + + friend std::istream& operator>> ( + std::istream& in, + bigint& rhs + ); + /*! + ensures + - reads a number from in and puts it into #*this + - if (there is no positive base ten number on the input stream ) then + - #in.fail() == true + throws + - std::bad_alloc + if this function throws the value in rhs is undefined and some + characters may have been read from in. rhs is still usable though, + its value is just unknown. + !*/ + + + bigint& operator++ ( + ); + /*! + ensures + - #*this == *this + 1 + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + const bigint operator++ ( + int + ); + /*! + ensures + - #*this == *this + 1 + - returns *this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator-- ( + ); + /*! + requires + - *this != 0 + ensures + - #*this == *this - 1 + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + const bigint operator-- ( + int + ); + /*! + requires + - *this != 0 + ensures + - #*this == *this - 1 + - returns *this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + void swap ( + bigint& item + ); + /*! + ensures + - swaps *this and item + !*/ + + + // ------------------------------------------------------------------ + // ---- The following functions are identical to the above ----- + // ---- but take uint16 as one of their arguments. They --- + // ---- exist only to allow for a more efficient implementation --- + // ------------------------------------------------------------------ + + + friend const bigint operator+ ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - lhs <= 65535 + ensures + - returns the result of adding rhs to lhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator+ ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - returns the result of adding rhs to lhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator+= ( + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - #*this == *this + rhs + - returns #this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator- ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - lhs >= rhs + - lhs <= 65535 + ensures + - returns the result of subtracting rhs from lhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator- ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - lhs >= rhs + - rhs <= 65535 + ensures + - returns the result of subtracting rhs from lhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator-= ( + uint16 rhs + ); + /*! + requires + - *this >= rhs + - rhs <= 65535 + ensures + - #*this == *this - rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator* ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - lhs <= 65535 + ensures + - returns the result of multiplying lhs and rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator* ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - returns the result of multiplying lhs and rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator*= ( + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - #*this == *this * rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator/ ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - rhs != 0 + - lhs <= 65535 + ensures + - returns the result of dividing lhs by rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator/ ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - rhs != 0 + - rhs <= 65535 + ensures + - returns the result of dividing lhs by rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator/= ( + uint16 rhs + ); + /*! + requires + - rhs != 0 + - rhs <= 65535 + ensures + - #*this == *this / rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator% ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - rhs != 0 + - lhs <= 65535 + ensures + - returns the result of lhs mod rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + friend const bigint operator% ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - rhs != 0 + - rhs <= 65535 + ensures + - returns the result of lhs mod rhs + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + bigint& operator%= ( + uint16 rhs + ); + /*! + requires + - rhs != 0 + - rhs <= 65535 + ensures + - #*this == *this % rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + + friend bool operator < ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - lhs <= 65535 + ensures + - returns true if lhs is less than rhs + - returns false otherwise + !*/ + + friend bool operator < ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - returns true if lhs is less than rhs + - returns false otherwise + !*/ + + friend bool operator == ( + const bigint& lhs, + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - returns true if lhs and rhs represent the same number + - returns false otherwise + !*/ + + friend bool operator == ( + uint16 lhs, + const bigint& rhs + ); + /*! + requires + - lhs <= 65535 + ensures + - returns true if lhs and rhs represent the same number + - returns false otherwise + !*/ + + bigint& operator= ( + uint16 rhs + ); + /*! + requires + - rhs <= 65535 + ensures + - #*this == rhs + - returns #*this + throws + - std::bad_alloc + if this function throws then it has no effect + !*/ + + }; + + inline void swap ( + bigint& a, + bigint& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + void serialize ( + const bigint& item, + std::istream& in + ); + /*! + provides serialization support + !*/ + + void deserialize ( + bigint& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_BIGINT_KERNEl_ABSTRACT_ + diff --git a/dlib/bigint/bigint_kernel_c.h b/dlib/bigint/bigint_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..15cbf8abbf6b3feaa78e866d0b3c56485fc9a672 --- /dev/null +++ b/dlib/bigint/bigint_kernel_c.h @@ -0,0 +1,1130 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIGINT_KERNEl_C_ +#define DLIB_BIGINT_KERNEl_C_ + +#include "bigint_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + class bigint_kernel_c + { + bigint_base data; + + explicit bigint_kernel_c ( + const bigint_base& item + ) : data(item) {} + + public: + + + bigint_kernel_c ( + ); + + bigint_kernel_c ( + uint32 value + ); + + bigint_kernel_c ( + const bigint_kernel_c& item + ); + + ~bigint_kernel_c ( + ); + + const bigint_kernel_c operator+ ( + const bigint_kernel_c& rhs + ) const; + + bigint_kernel_c& operator+= ( + const bigint_kernel_c& rhs + ); + + const bigint_kernel_c operator- ( + const bigint_kernel_c& rhs + ) const; + bigint_kernel_c& operator-= ( + const bigint_kernel_c& rhs + ); + + const bigint_kernel_c operator* ( + const bigint_kernel_c& rhs + ) const; + + bigint_kernel_c& operator*= ( + const bigint_kernel_c& rhs + ); + + const bigint_kernel_c operator/ ( + const bigint_kernel_c& rhs + ) const; + + bigint_kernel_c& operator/= ( + const bigint_kernel_c& rhs + ); + + const bigint_kernel_c operator% ( + const bigint_kernel_c& rhs + ) const; + + bigint_kernel_c& operator%= ( + const bigint_kernel_c& rhs + ); + + bool operator < ( + const bigint_kernel_c& rhs + ) const; + + bool operator == ( + const bigint_kernel_c& rhs + ) const; + + bigint_kernel_c& operator= ( + const bigint_kernel_c& rhs + ); + + template + friend std::ostream& operator<< ( + std::ostream& out, + const bigint_kernel_c& rhs + ); + + template + friend std::istream& operator>> ( + std::istream& in, + bigint_kernel_c& rhs + ); + + bigint_kernel_c& operator++ ( + ); + + const bigint_kernel_c operator++ ( + int + ); + + bigint_kernel_c& operator-- ( + ); + + const bigint_kernel_c operator-- ( + int + ); + + template + friend const bigint_kernel_c operator+ ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + template + friend const bigint_kernel_c operator+ ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + bigint_kernel_c& operator+= ( + uint16 rhs + ); + + template + friend const bigint_kernel_c operator- ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + template + friend const bigint_kernel_c operator- ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + bigint_kernel_c& operator-= ( + uint16 rhs + ); + + template + friend const bigint_kernel_c operator* ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + template + friend const bigint_kernel_c operator* ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + bigint_kernel_c& operator*= ( + uint16 rhs + ); + + template + friend const bigint_kernel_c operator/ ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + template + friend const bigint_kernel_c operator/ ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + bigint_kernel_c& operator/= ( + uint16 rhs + ); + + template + friend const bigint_kernel_c operator% ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + template + friend const bigint_kernel_c operator% ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + bigint_kernel_c& operator%= ( + uint16 rhs + ); + + template + friend bool operator < ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + template + friend bool operator < ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + template + friend bool operator == ( + const bigint_kernel_c& lhs, + uint16 rhs + ); + + template + friend bool operator == ( + uint16 lhs, + const bigint_kernel_c& rhs + ); + + bigint_kernel_c& operator= ( + uint16 rhs + ); + + + void swap ( + bigint_kernel_c& item + ) { data.swap(item.data); } + + }; + + template < + typename bigint_base + > + void swap ( + bigint_kernel_c& a, + bigint_kernel_c& b + ) { a.swap(b); } + + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + inline void serialize ( + const bigint_kernel_c& item, + std::ostream& out + ) + { + std::ios::fmtflags oldflags = out.flags(); + out.flags(); + out << item << ' '; + out.flags(oldflags); + if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c"); + } + + template < + typename bigint_base + > + inline void deserialize ( + bigint_kernel_c& item, + std::istream& in + ) + { + std::ios::fmtflags oldflags = in.flags(); + in.flags(); + in >> item; in.flags(oldflags); + if (in.get() != ' ') + { + item = 0; + throw serialization_error("Error deserializing object of type bigint_kernel_c"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c:: + bigint_kernel_c ( + ) + {} + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c:: + bigint_kernel_c ( + uint32 value + ) : + data(value) + { + // make sure requires clause is not broken + DLIB_CASSERT( value <= 0xFFFFFFFF , + "\tbigint::bigint(uint16)" + << "\n\t value must be <= (2^32)-1" + << "\n\tthis: " << this + << "\n\tvalue: " << value + ); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c:: + bigint_kernel_c ( + const bigint_kernel_c& item + ) : + data(item.data) + {} + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c:: + ~bigint_kernel_c ( + ) + {} + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator+ ( + const bigint_kernel_c& rhs + ) const + { + return bigint_kernel_c(data + rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator+= ( + const bigint_kernel_c& rhs + ) + { + data += rhs.data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator- ( + const bigint_kernel_c& rhs + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( !(*this < rhs), + "\tconst bigint bigint::operator-(const bigint&)" + << "\n\t *this should not be less than rhs" + << "\n\tthis: " << this + << "\n\t*this: " << *this + << "\n\trhs: " << rhs + ); + + // call the real function + return bigint_kernel_c(data-rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator-= ( + const bigint_kernel_c& rhs + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(*this < rhs), + "\tbigint& bigint::operator-=(const bigint&)" + << "\n\t *this should not be less than rhs" + << "\n\tthis: " << this + << "\n\t*this: " << *this + << "\n\trhs: " << rhs + ); + + // call the real function + data -= rhs.data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator* ( + const bigint_kernel_c& rhs + ) const + { + return bigint_kernel_c(data * rhs.data ); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator*= ( + const bigint_kernel_c& rhs + ) + { + data *= rhs.data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator/ ( + const bigint_kernel_c& rhs + ) const + { + //make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0), + "\tconst bigint bigint::operator/(const bigint&)" + << "\n\t can't divide by zero" + << "\n\tthis: " << this + ); + + // call the real function + return bigint_kernel_c(data/rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator/= ( + const bigint_kernel_c& rhs + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0), + "\tbigint& bigint::operator/=(const bigint&)" + << "\n\t can't divide by zero" + << "\n\tthis: " << this + ); + + // call the real function + data /= rhs.data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator% ( + const bigint_kernel_c& rhs + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0), + "\tconst bigint bigint::operator%(const bigint&)" + << "\n\t can't divide by zero" + << "\n\tthis: " << this + ); + + // call the real function + return bigint_kernel_c(data%rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator%= ( + const bigint_kernel_c& rhs + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0), + "\tbigint& bigint::operator%=(const bigint&)" + << "\n\t can't divide by zero" + << "\n\tthis: " << this + ); + + // call the real function + data %= rhs.data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bool bigint_kernel_c:: + operator < ( + const bigint_kernel_c& rhs + ) const + { + return data < rhs.data; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bool bigint_kernel_c:: + operator == ( + const bigint_kernel_c& rhs + ) const + { + return data == rhs.data; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator= ( + const bigint_kernel_c& rhs + ) + { + data = rhs.data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + std::ostream& operator<< ( + std::ostream& out, + const bigint_kernel_c& rhs + ) + { + out << rhs.data; + return out; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + std::istream& operator>> ( + std::istream& in, + bigint_kernel_c& rhs + ) + { + in >> rhs.data; + return in; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator++ ( + ) + { + ++data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator++ ( + int + ) + { + return bigint_kernel_c(data++); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator-- ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(*this == 0), + "\tbigint& bigint::operator--()" + << "\n\t *this to subtract from *this it must not be zero to begin with" + << "\n\tthis: " << this + ); + + // call the real function + --data; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c bigint_kernel_c:: + operator-- ( + int + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(*this == 0), + "\tconst bigint bigint::operator--(int)" + << "\n\t *this to subtract from *this it must not be zero to begin with" + << "\n\tthis: " << this + ); + + // call the real function + return bigint_kernel_c(data--); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator+ ( + uint16 l, + const bigint_kernel_c& rhs + ) + { + uint32 lhs = l; + // make sure requires clause is not broken + DLIB_CASSERT( lhs <= 65535, + "\tconst bigint operator+(uint16, const bigint&)" + << "\n\t lhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return bigint_kernel_c(static_cast(lhs)+rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator+ ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\tconst bigint operator+(const bigint&, uint16)" + << "\n\t rhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return bigint_kernel_c(lhs.data+static_cast(rhs)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator+= ( + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\tbigint& bigint::operator+=(uint16)" + << "\n\t rhs must be <= 65535" + << "\n\tthis: " << this + << "\n\t*this: " << *this + << "\n\trhs: " << rhs + ); + + data += rhs; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator- ( + uint16 l, + const bigint_kernel_c& rhs + ) + { + uint32 lhs = l; + // make sure requires clause is not broken + DLIB_CASSERT( !(static_cast(lhs) < rhs) && lhs <= 65535, + "\tconst bigint operator-(uint16,const bigint&)" + << "\n\t lhs must be greater than or equal to rhs and lhs <= 65535" + << "\n\tlhs: " << lhs + << "\n\trhs: " << rhs + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + ); + + // call the real function + return bigint_kernel_c(static_cast(lhs)-rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator- ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( !(lhs < static_cast(rhs)) && rhs <= 65535, + "\tconst bigint operator-(const bigint&,uint16)" + << "\n\t lhs must be greater than or equal to rhs and rhs <= 65535" + << "\n\tlhs: " << lhs + << "\n\trhs: " << rhs + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + ); + + // call the real function + return bigint_kernel_c(lhs.data-static_cast(rhs)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator-= ( + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( !(*this < static_cast(rhs)) && rhs <= 65535, + "\tbigint& bigint::operator-=(uint16)" + << "\n\t *this must not be less than rhs and rhs <= 65535" + << "\n\tthis: " << this + << "\n\t*this: " << *this + << "\n\trhs: " << rhs + ); + + // call the real function + data -= static_cast(rhs); + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator* ( + uint16 l, + const bigint_kernel_c& rhs + ) + { + uint32 lhs = l; + // make sure requires clause is not broken + DLIB_CASSERT( lhs <= 65535, + "\tconst bigint operator*(uint16, const bigint&)" + << "\n\t lhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return bigint_kernel_c(lhs*rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator* ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\tconst bigint operator*(const bigint&, uint16)" + << "\n\t rhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return bigint_kernel_c(lhs.data*rhs); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator*= ( + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\t bigint bigint::operator*=(uint16)" + << "\n\t rhs must be <= 65535" + << "\n\tthis: " << this + << "\n\t*this: " << *this + << "\n\trhs: " << rhs + ); + + data *= static_cast(rhs); + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator/ ( + uint16 l, + const bigint_kernel_c& rhs + ) + { + uint32 lhs = l; + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0) && lhs <= 65535, + "\tconst bigint operator/(uint16,const bigint&)" + << "\n\t you can't divide by zero and lhs <= 65535" + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + << "\n\tlhs: " << lhs + ); + + // call the real function + return bigint_kernel_c(lhs/rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator/ ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0) && rhs <= 65535, + "\tconst bigint operator/(const bigint&,uint16)" + << "\n\t you can't divide by zero and rhs <= 65535" + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + << "\n\trhs: " << rhs + ); + + // call the real function + return bigint_kernel_c(lhs.data/static_cast(rhs)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator/= ( + uint16 rhs + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0) && static_cast(rhs) <= 65535, + "\tbigint& bigint::operator/=(uint16)" + << "\n\t you can't divide by zero and rhs must be <= 65535" + << "\n\tthis: " << this + << "\n\trhs: " << rhs + ); + + // call the real function + data /= rhs; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator% ( + uint16 lhs, + const bigint_kernel_c& rhs + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0) && static_cast(lhs) <= 65535, + "\tconst bigint operator%(uint16,const bigint&)" + << "\n\t you can't divide by zero and lhs must be <= 65535" + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + << "\n\tlhs: " << lhs + ); + + // call the real function + return bigint_kernel_c(lhs%rhs.data); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + const bigint_kernel_c operator% ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0) && rhs <= 65535, + "\tconst bigint operator%(const bigint&,uint16)" + << "\n\t you can't divide by zero and rhs must be <= 65535" + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + << "\n\trhs: " << rhs + ); + + // call the real function + return bigint_kernel_c(lhs.data%static_cast(rhs)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator%= ( + uint16 r + ) + { + + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( !(rhs == 0) && rhs <= 65535, + "\tbigint& bigint::operator%=(uint16)" + << "\n\t you can't divide by zero and rhs must be <= 65535" + << "\n\tthis: " << this + << "\n\trhs: " << rhs + ); + + // call the real function + data %= rhs; + return *this; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bool operator < ( + uint16 l, + const bigint_kernel_c& rhs + ) + { + uint32 lhs = l; + // make sure requires clause is not broken + DLIB_CASSERT( lhs <= 65535, + "\tbool operator<(uint16, const bigint&)" + << "\n\t lhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return static_cast(lhs) < rhs.data; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bool operator < ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\tbool operator<(const bigint&, uint16)" + << "\n\t rhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return lhs.data < static_cast(rhs); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bool operator == ( + const bigint_kernel_c& lhs, + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\tbool operator==(const bigint&, uint16)" + << "\n\t rhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return lhs.data == static_cast(rhs); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bool operator == ( + uint16 l, + const bigint_kernel_c& rhs + ) + { + uint32 lhs = l; + // make sure requires clause is not broken + DLIB_CASSERT( lhs <= 65535, + "\tbool operator==(uint16, const bigint&)" + << "\n\t lhs must be <= 65535" + << "\n\trhs: " << rhs + << "\n\tlhs: " << lhs + ); + + return static_cast(lhs) == rhs.data; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bigint_base + > + bigint_kernel_c& bigint_kernel_c:: + operator= ( + uint16 r + ) + { + uint32 rhs = r; + // make sure requires clause is not broken + DLIB_CASSERT( rhs <= 65535, + "\tbigint bigint::operator=(uint16)" + << "\n\t rhs must be <= 65535" + << "\n\t*this: " << *this + << "\n\tthis: " << this + << "\n\tlhs: " << rhs + ); + + data = static_cast(rhs); + return *this; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BIGINT_KERNEl_C_ + diff --git a/dlib/binary_search_tree.h b/dlib/binary_search_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..ec9ef81f07397daf692feab65614fa86cdb63e8a --- /dev/null +++ b/dlib/binary_search_tree.h @@ -0,0 +1,50 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREe_ +#define DLIB_BINARY_SEARCH_TREe_ + + +#include "binary_search_tree/binary_search_tree_kernel_1.h" +#include "binary_search_tree/binary_search_tree_kernel_2.h" +#include "binary_search_tree/binary_search_tree_kernel_c.h" + + +#include "memory_manager.h" +#include + + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class binary_search_tree + { + binary_search_tree() {} + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef binary_search_tree_kernel_1 + kernel_1a; + typedef binary_search_tree_kernel_c + kernel_1a_c; + + + // kernel_2a + typedef binary_search_tree_kernel_2 + kernel_2a; + typedef binary_search_tree_kernel_c + kernel_2a_c; + + }; +} + +#endif // DLIB_BINARY_SEARCH_TREe_ + diff --git a/dlib/binary_search_tree/binary_search_tree_kernel_1.h b/dlib/binary_search_tree/binary_search_tree_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..4efc859d539bc6326a6b7432cc2696623f4f8ebd --- /dev/null +++ b/dlib/binary_search_tree/binary_search_tree_kernel_1.h @@ -0,0 +1,2064 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_1_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_1_ + +#include "binary_search_tree_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager, + typename compare = std::less + > + class binary_search_tree_kernel_1 : public enumerable >, + public asc_pair_remover + { + + /*! + INITIAL VALUE + tree_size == 0 + tree_root == 0 + tree_height == 0 + at_start_ == true + current_element == 0 + stack == array of 50 node pointers + stack_pos == 0 + + + CONVENTION + tree_size == size() + tree_height == height() + + stack[stack_pos-1] == pop() + + current_element_valid() == (current_element != 0) + if (current_element_valid()) then + element() == current_element->d and current_element->r + at_start_ == at_start() + if (current_element != 0 && current_element != tree_root) then + stack[stack_pos-1] == the parent of the node pointed to by current_element + + if (tree_size != 0) + tree_root == pointer to the root node of the binary search tree + else + tree_root == 0 + + + for all nodes: + { + left points to the left subtree or 0 if there is no left subtree and + right points to the right subtree or 0 if there is no right subtree and + all elements in a left subtree are <= the root and + all elements in a right subtree are >= the root and + d is the item in the domain of *this contained in the node + r is the item in the range of *this contained in the node + balance: + balance == 0 if both subtrees have the same height + balance == -1 if the left subtree has a height that is greater + than the height of the right subtree by 1 + balance == 1 if the right subtree has a height that is greater + than the height of the left subtree by 1 + for all trees: + the height of the left and right subtrees differ by at most one + } + + !*/ + + class node + { + public: + node* left; + node* right; + domain d; + range r; + signed char balance; + }; + + class mpair : public map_pair + { + public: + const domain* d; + range* r; + + const domain& key( + ) const { return *d; } + + const range& value( + ) const { return *r; } + + range& value( + ) { return *r; } + }; + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + binary_search_tree_kernel_1( + ) : + tree_size(0), + tree_root(0), + current_element(0), + tree_height(0), + at_start_(true), + stack_pos(0), + stack(ppool.allocate_array(50)) + { + } + + virtual ~binary_search_tree_kernel_1( + ); + + inline void clear( + ); + + inline short height ( + ) const; + + inline unsigned long count ( + const domain& item + ) const; + + inline void add ( + domain& d, + range& r + ); + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& item + ); + + inline const range* operator[] ( + const domain& item + ) const; + + inline range* operator[] ( + const domain& item + ); + + inline void swap ( + binary_search_tree_kernel_1& item + ); + + // function from the asc_pair_remover interface + void remove_any ( + domain& d, + range& r + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + bool move_next ( + ) const; + + void remove_last_in_order ( + domain& d, + range& r + ); + + void remove_current_element ( + domain& d, + range& r + ); + + void position_enumerator ( + const domain& d + ) const; + + private: + + + inline void rotate_left ( + node*& t + ); + /*! + requires + - t->balance == 2 + - t->right->balance == 0 or 1 + - t == reference to the pointer in t's parent node that points to t + ensures + - #t is still a binary search tree + - #t->balance is between 1 and -1 + - #t now has a height smaller by 1 if #t->balance == 0 + !*/ + + inline void rotate_right ( + node*& t + ); + /*! + requires + - t->balance == -2 + - t->left->balance == 0 or -1 + - t == reference to the pointer in t's parent node that points to t + ensures + - #t is still a binary search tree + - #t->balance is between 1 and -1 + - #t now has a height smaller by 1 if #t->balance == 0 + + !*/ + + inline void double_rotate_right ( + node*& t + ); + /*! + requires + - t->balance == -2 + - t->left->balance == 1 + - t == reference to the pointer in t's parent node that points to t + ensures + - #t is still a binary search tree + - #t now has a balance of 0 + - #t now has a height smaller by 1 + !*/ + + inline void double_rotate_left ( + node*& t + ); + /*! + requires + - t->balance == 2 + - t->right->balance == -1 + - t == reference to the pointer in t's parent node that points to t + ensures + - #t is still a binary search tree + - #t now has a balance of 0 + - #t now has a height smaller by 1 + !*/ + + bool remove_biggest_element_in_tree ( + node*& t, + domain& d, + range& r + ); + /*! + requires + - t != 0 (i.e. there must be something in the tree to remove) + - t == reference to the pointer in t's parent node that points to t + ensures + - the biggest node in t has been removed + - the biggest node domain element in t has been put into #d + - the biggest node range element in t has been put into #r + - #t is still a binary search tree + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + bool remove_least_element_in_tree ( + node*& t, + domain& d, + range& r + ); + /*! + requires + - t != 0 (i.e. there must be something in the tree to remove) + - t == reference to the pointer in t's parent node that points to t + ensures + - the least node in t has been removed + - the least node domain element in t has been put into #d + - the least node range element in t has been put into #r + - #t is still a binary search tree + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + bool add_to_tree ( + node*& t, + domain& d, + range& r + ); + /*! + requires + - t == reference to the pointer in t's parent node that points to t + ensures + - the mapping (d --> r) has been added to #t + - #d and #r have initial values for their types + - #t is still a binary search tree + - returns false if the height of the tree has not changed + - returns true if the height of the tree has grown by one + !*/ + + bool remove_from_tree ( + node*& t, + const domain& d, + domain& d_copy, + range& r + ); + /*! + requires + - return_reference(t,d) != 0 + - t == reference to the pointer in t's parent node that points to t + ensures + - #d_copy is equivalent to d + - an element in t equivalent to d has been removed and swapped + into #d_copy and its associated range object has been + swapped into #r + - #t is still a binary search tree + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + bool remove_from_tree ( + node*& t, + const domain& item + ); + /*! + requires + - return_reference(t,item) != 0 + - t == reference to the pointer in t's parent node that points to t + ensures + - an element in t equivalent to item has been removed + - #t is still a binary search tree + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + const range* return_reference ( + const node* t, + const domain& d + ) const; + /*! + ensures + - if (there is a domain element equivalent to d in t) then + - returns a pointer to the element in the range equivalent to d + - else + - returns 0 + !*/ + + range* return_reference ( + node* t, + const domain& d + ); + /*! + ensures + - if (there is a domain element equivalent to d in t) then + - returns a pointer to the element in the range equivalent to d + - else + - returns 0 + !*/ + + + inline bool keep_node_balanced ( + node*& t + ); + /*! + requires + - t != 0 + - t == reference to the pointer in t's parent node that points to t + ensures + - if (t->balance is < 1 or > 1) then + - keep_node_balanced() will ensure that #t->balance == 0, -1, or 1 + - #t is still a binary search tree + - returns true if it made the tree one height shorter + - returns false if it didn't change the height + !*/ + + + unsigned long get_count ( + const domain& item, + node* tree_root + ) const; + /*! + requires + - tree_root == the root of a binary search tree or 0 + ensures + - if (tree_root == 0) then + - returns 0 + - else + - returns the number of elements in tree_root that are + equivalent to item + !*/ + + + void delete_tree ( + node* t + ); + /*! + requires + - t != 0 + ensures + - deallocates the node pointed to by t and all of t's left and right children + !*/ + + + void push ( + node* n + ) const { stack[stack_pos] = n; ++stack_pos; } + /*! + ensures + - pushes n onto the stack + !*/ + + + node* pop ( + ) const { --stack_pos; return stack[stack_pos]; } + /*! + ensures + - pops the top of the stack and returns it + !*/ + + + + bool fix_stack ( + node* t, + unsigned char depth = 0 + ); + /*! + requires + - current_element != 0 + - depth == 0 + - t == tree_root + ensures + - makes the stack contain the correct set of parent pointers. + also adjusts stack_pos so it is correct. + - #t is still a binary search tree + !*/ + + bool remove_current_element_from_tree ( + node*& t, + domain& d, + range& r, + unsigned long cur_stack_pos = 1 + ); + /*! + requires + - t == tree_root + - cur_stack_pos == 1 + - current_element != 0 + ensures + - removes the data in the node given by current_element and swaps it into + #d and #r. + - #t is still a binary search tree + - the enumerator is advances on to the next element but its stack is + potentially corrupted. so you must call fix_stack(tree_root) to fix + it. + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + + // data members + + mutable mpair p; + unsigned long tree_size; + node* tree_root; + mutable node* current_element; + typename mem_manager::template rebind::other pool; + typename mem_manager::template rebind::other ppool; + short tree_height; + mutable bool at_start_; + mutable unsigned char stack_pos; + mutable node** stack; + compare comp; + + // restricted functions + binary_search_tree_kernel_1(binary_search_tree_kernel_1&); + binary_search_tree_kernel_1& operator=(binary_search_tree_kernel_1&); + + + }; + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + inline void swap ( + binary_search_tree_kernel_1& a, + binary_search_tree_kernel_1& b + ) { a.swap(b); } + + + + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void deserialize ( + binary_search_tree_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item.add(d,r); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type binary_search_tree_kernel_1"); + } + } + + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + binary_search_tree_kernel_1:: + ~binary_search_tree_kernel_1 ( + ) + { + ppool.deallocate_array(stack); + if (tree_size != 0) + { + delete_tree(tree_root); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + clear ( + ) + { + if (tree_size > 0) + { + delete_tree(tree_root); + tree_root = 0; + tree_size = 0; + tree_height = 0; + } + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long binary_search_tree_kernel_1:: + size ( + ) const + { + return tree_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + short binary_search_tree_kernel_1:: + height ( + ) const + { + return tree_height; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long binary_search_tree_kernel_1:: + count ( + const domain& item + ) const + { + return get_count(item,tree_root); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + add ( + domain& d, + range& r + ) + { + tree_height += add_to_tree(tree_root,d,r); + ++tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + tree_height -= remove_from_tree(tree_root,d,d_copy,r); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + destroy ( + const domain& item + ) + { + tree_height -= remove_from_tree(tree_root,item); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + remove_any ( + domain& d, + range& r + ) + { + tree_height -= remove_least_element_in_tree(tree_root,d,r); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + range* binary_search_tree_kernel_1:: + operator[] ( + const domain& item + ) + { + return return_reference(tree_root,item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const range* binary_search_tree_kernel_1:: + operator[] ( + const domain& item + ) const + { + return return_reference(tree_root,item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + swap ( + binary_search_tree_kernel_1& item + ) + { + pool.swap(item.pool); + ppool.swap(item.ppool); + exchange(p,item.p); + exchange(stack,item.stack); + exchange(stack_pos,item.stack_pos); + exchange(comp,item.comp); + + + node* tree_root_temp = item.tree_root; + unsigned long tree_size_temp = item.tree_size; + short tree_height_temp = item.tree_height; + node* current_element_temp = item.current_element; + bool at_start_temp = item.at_start_; + + item.tree_root = tree_root; + item.tree_size = tree_size; + item.tree_height = tree_height; + item.current_element = current_element; + item.at_start_ = at_start_; + + tree_root = tree_root_temp; + tree_size = tree_size_temp; + tree_height = tree_height_temp; + current_element = current_element_temp; + at_start_ = at_start_temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + remove_last_in_order ( + domain& d, + range& r + ) + { + tree_height -= remove_biggest_element_in_tree(tree_root,d,r); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + remove_current_element ( + domain& d, + range& r + ) + { + tree_height -= remove_current_element_from_tree(tree_root,d,r); + --tree_size; + + // fix the enumerator stack if we need to + if (current_element) + fix_stack(tree_root); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + position_enumerator ( + const domain& d + ) const + { + // clear the enumerator state and make sure the stack is empty + reset(); + at_start_ = false; + node* t = tree_root; + bool went_left = false; + while (t != 0) + { + if ( comp(d , t->d) ) + { + push(t); + // if item is on the left then look in left + t = t->left; + went_left = true; + } + else if (comp(t->d , d)) + { + push(t); + // if item is on the right then look in right + t = t->right; + went_left = false; + } + else + { + current_element = t; + return; + } + } + + // if we didn't find any matches but there might be something after the + // d in this tree. + if (stack_pos > 0) + { + current_element = pop(); + // if we went left from this node then this node is the next + // biggest. + if (went_left) + { + return; + } + else + { + move_next(); + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + reset ( + ) const + { + at_start_ = true; + current_element = 0; + stack_pos = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + current_element_valid ( + ) const + { + return (current_element != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const map_pair& binary_search_tree_kernel_1:: + element ( + ) const + { + p.d = &(current_element->d); + p.r = &(current_element->r); + return p; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + map_pair& binary_search_tree_kernel_1:: + element ( + ) + { + p.d = &(current_element->d); + p.r = &(current_element->r); + return p; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + move_next ( + ) const + { + // if we haven't started iterating yet + if (at_start_) + { + at_start_ = false; + if (tree_size == 0) + { + return false; + } + else + { + // find the first element in the tree + current_element = tree_root; + node* temp = current_element->left; + while (temp != 0) + { + push(current_element); + current_element = temp; + temp = current_element->left; + } + return true; + } + } + else + { + if (current_element == 0) + { + return false; + } + else + { + node* temp; + bool went_up; // true if we went up the tree from a child node to parent + bool from_left = false; // true if we went up and were coming from a left child node + // find the next element in the tree + if (current_element->right != 0) + { + // go right and down + temp = current_element; + push(current_element); + current_element = temp->right; + went_up = false; + } + else + { + // go up to the parent if we can + if (current_element == tree_root) + { + // in this case we have iterated over all the element of the tree + current_element = 0; + return false; + } + went_up = true; + node* parent = pop(); + + + from_left = (parent->left == current_element); + // go up to parent + current_element = parent; + } + + + while (true) + { + if (went_up) + { + if (from_left) + { + // in this case we have found the next node + break; + } + else + { + if (current_element == tree_root) + { + // in this case we have iterated over all the elements + // in the tree + current_element = 0; + return false; + } + // we should go up + node* parent = pop(); + from_left = (parent->left == current_element); + current_element = parent; + } + } + else + { + // we just went down to a child node + if (current_element->left != 0) + { + // go left + went_up = false; + temp = current_element; + push(current_element); + current_element = temp->left; + } + else + { + // if there is no left child then we have found the next node + break; + } + } + } + + return true; + } + } + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + delete_tree ( + node* t + ) + { + if (t->left != 0) + delete_tree(t->left); + if (t->right != 0) + delete_tree(t->right); + pool.deallocate(t); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + rotate_left ( + node*& t + ) + { + + // set the new balance numbers + if (t->right->balance == 1) + { + t->balance = 0; + t->right->balance = 0; + } + else + { + t->balance = 1; + t->right->balance = -1; + } + + // perform the rotation + node* temp = t->right; + t->right = temp->left; + temp->left = t; + t = temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + rotate_right ( + node*& t + ) + { + // set the new balance numbers + if (t->left->balance == -1) + { + t->balance = 0; + t->left->balance = 0; + } + else + { + t->balance = -1; + t->left->balance = 1; + } + + // preform the rotation + node* temp = t->left; + t->left = temp->right; + temp->right = t; + t = temp; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + double_rotate_right ( + node*& t + ) + { + + node* temp = t; + t = t->left->right; + + temp->left->right = t->left; + t->left = temp->left; + + temp->left = t->right; + t->right = temp; + + if (t->balance < 0) + { + t->left->balance = 0; + t->right->balance = 1; + } + else if (t->balance > 0) + { + t->left->balance = -1; + t->right->balance = 0; + } + else + { + t->left->balance = 0; + t->right->balance = 0; + } + t->balance = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_1:: + double_rotate_left ( + node*& t + ) + { + node* temp = t; + t = t->right->left; + + temp->right->left = t->right; + t->right = temp->right; + + temp->right = t->left; + t->left = temp; + + if (t->balance < 0) + { + t->left->balance = 0; + t->right->balance = 1; + } + else if (t->balance > 0) + { + t->left->balance = -1; + t->right->balance = 0; + } + else + { + t->left->balance = 0; + t->right->balance = 0; + } + + t->balance = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + remove_biggest_element_in_tree ( + node*& t, + domain& d, + range& r + ) + { + // make a reference to the current node so we don't have to dereference a + // pointer a bunch of times + node& tree = *t; + + // if the right tree is an empty tree + if ( tree.right == 0) + { + // swap nodes domain and range elements into d and r + exchange(d,tree.d); + exchange(r,tree.r); + + // plug hole left by removing this node + t = tree.left; + + // delete the node that was just removed + pool.deallocate(&tree); + + // return that the height of this part of the tree has decreased + return true; + } + else + { + + // keep going right + + // if remove made the tree one height shorter + if ( remove_biggest_element_in_tree(tree.right,d,r) ) + { + // if this caused the current tree to strink then report that + if ( tree.balance == 1) + { + --tree.balance; + return true; + } + else + { + --tree.balance; + return keep_node_balanced(t); + } + } + + return false; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + remove_least_element_in_tree ( + node*& t, + domain& d, + range& r + ) + { + // make a reference to the current node so we don't have to dereference a + // pointer a bunch of times + node& tree = *t; + + // if the left tree is an empty tree + if ( tree.left == 0) + { + // swap nodes domain and range elements into d and r + exchange(d,tree.d); + exchange(r,tree.r); + + // plug hole left by removing this node + t = tree.right; + + // delete the node that was just removed + pool.deallocate(&tree); + + // return that the height of this part of the tree has decreased + return true; + } + else + { + + // keep going left + + // if remove made the tree one height shorter + if ( remove_least_element_in_tree(tree.left,d,r) ) + { + // if this caused the current tree to strink then report that + if ( tree.balance == -1) + { + ++tree.balance; + return true; + } + else + { + ++tree.balance; + return keep_node_balanced(t); + } + } + + return false; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + add_to_tree ( + node*& t, + domain& d, + range& r + ) + { + + // if found place to add + if (t == 0) + { + // create a node to add new item into + t = pool.allocate(); + + // make a reference to the current node so we don't have to dereference a + // pointer a bunch of times + node& tree = *t; + + + // set left and right pointers to NULL to indicate that there are no + // left or right subtrees + tree.left = 0; + tree.right = 0; + tree.balance = 0; + + // put d and r into t + exchange(tree.d,d); + exchange(tree.r,r); + + // indicate that the height of this tree has increased + return true; + } + else // keep looking for a place to add the new item + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + signed char old_balance = tree.balance; + + // add the new item to whatever subtree it should go into + if (comp( d , tree.d) ) + tree.balance -= add_to_tree(tree.left,d,r); + else + tree.balance += add_to_tree(tree.right,d,r); + + + // if the tree was balanced to start with + if (old_balance == 0) + { + // if its not balanced anymore then it grew in height + if (tree.balance != 0) + return true; + else + return false; + } + else + { + // if the tree is now balanced then it didn't grow + if (tree.balance == 0) + { + return false; + } + else + { + // if the tree needs to be balanced + if (tree.balance != old_balance) + { + return !keep_node_balanced(t); + } + // if there has been no change in the heights + else + { + return false; + } + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + fix_stack ( + node* t, + unsigned char depth + ) + { + // if we found the node we were looking for + if (t == current_element) + { + stack_pos = depth; + return true; + } + else if (t == 0) + { + return false; + } + + if (!( comp(t->d , current_element->d))) + { + // go left + if (fix_stack(t->left,depth+1)) + { + stack[depth] = t; + return true; + } + } + if (!(comp(current_element->d , t->d))) + { + // go right + if (fix_stack(t->right,depth+1)) + { + stack[depth] = t; + return true; + } + } + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + remove_current_element_from_tree ( + node*& t, + domain& d, + range& r, + unsigned long cur_stack_pos + ) + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if we found the node we were looking for + if (t == current_element) + { + + // swap nodes domain and range elements into d_copy and r + exchange(d,tree.d); + exchange(r,tree.r); + + // if there is no left node + if (tree.left == 0) + { + // move the enumerator on to the next element before we mess with the + // tree + move_next(); + + // plug hole left by removing this node and free memory + t = tree.right; // plug hole with right subtree + + // delete old node + pool.deallocate(&tree); + + // indicate that the height has changed + return true; + } + // if there is no right node + else if (tree.right == 0) + { + // move the enumerator on to the next element before we mess with the + // tree + move_next(); + + // plug hole left by removing this node and free memory + t = tree.left; // plug hole with left subtree + + // delete old node + pool.deallocate(&tree); + + // indicate that the height of this tree has changed + return true; + } + // if there are both a left and right sub node + else + { + + // in this case the next current element is going to get swapped back + // into this t node. + current_element = t; + + // get an element that can replace the one being removed and do this + // if it made the right subtree shrink by one + if (remove_least_element_in_tree(tree.right,tree.d,tree.r)) + { + // adjust the tree height + --tree.balance; + + // if the height of the current tree has dropped by one + if (tree.balance == 0) + { + return true; + } + else + { + return keep_node_balanced(t); + } + } + // else this remove did not effect the height of this tree + else + { + return false; + } + + } + + } + else if ( (cur_stack_pos < stack_pos && stack[cur_stack_pos] == tree.left) || + tree.left == current_element ) + { + // go left + if (tree.balance == -1) + { + int balance = tree.balance; + balance += remove_current_element_from_tree(tree.left,d,r,cur_stack_pos+1); + tree.balance = balance; + return !tree.balance; + } + else + { + int balance = tree.balance; + balance += remove_current_element_from_tree(tree.left,d,r,cur_stack_pos+1); + tree.balance = balance; + return keep_node_balanced(t); + } + } + else if ( (cur_stack_pos < stack_pos && stack[cur_stack_pos] == tree.right) || + tree.right == current_element ) + { + // go right + if (tree.balance == 1) + { + int balance = tree.balance; + balance -= remove_current_element_from_tree(tree.right,d,r,cur_stack_pos+1); + tree.balance = balance; + return !tree.balance; + } + else + { + int balance = tree.balance; + balance -= remove_current_element_from_tree(tree.right,d,r,cur_stack_pos+1); + tree.balance = balance; + return keep_node_balanced(t); + } + } + + // this return should never happen but do it anyway to suppress compiler warnings + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + remove_from_tree ( + node*& t, + const domain& d, + domain& d_copy, + range& r + ) + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if item is on the left + if (comp(d , tree.d)) + { + // if the left side of the tree has the greatest height + if (tree.balance == -1) + { + int balance = tree.balance; + balance += remove_from_tree(tree.left,d,d_copy,r); + tree.balance = balance; + return !tree.balance; + } + else + { + int balance = tree.balance; + balance += remove_from_tree(tree.left,d,d_copy,r); + tree.balance = balance; + return keep_node_balanced(t); + } + + } + // if item is on the right + else if (comp(tree.d , d)) + { + + // if the right side of the tree has the greatest height + if (tree.balance == 1) + { + int balance = tree.balance; + balance -= remove_from_tree(tree.right,d,d_copy,r); + tree.balance = balance; + return !tree.balance; + } + else + { + int balance = tree.balance; + balance -= remove_from_tree(tree.right,d,d_copy,r); + tree.balance = balance; + return keep_node_balanced(t); + } + } + // if item is found + else + { + + // swap nodes domain and range elements into d_copy and r + exchange(d_copy,tree.d); + exchange(r,tree.r); + + // if there is no left node + if (tree.left == 0) + { + + // plug hole left by removing this node and free memory + t = tree.right; // plug hole with right subtree + + // delete old node + pool.deallocate(&tree); + + // indicate that the height has changed + return true; + } + // if there is no right node + else if (tree.right == 0) + { + + // plug hole left by removing this node and free memory + t = tree.left; // plug hole with left subtree + + // delete old node + pool.deallocate(&tree); + + // indicate that the height of this tree has changed + return true; + } + // if there are both a left and right sub node + else + { + + // get an element that can replace the one being removed and do this + // if it made the right subtree shrink by one + if (remove_least_element_in_tree(tree.right,tree.d,tree.r)) + { + // adjust the tree height + --tree.balance; + + // if the height of the current tree has dropped by one + if (tree.balance == 0) + { + return true; + } + else + { + return keep_node_balanced(t); + } + } + // else this remove did not effect the height of this tree + else + { + return false; + } + + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + remove_from_tree ( + node*& t, + const domain& d + ) + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if item is on the left + if (comp(d , tree.d)) + { + // if the left side of the tree has the greatest height + if (tree.balance == -1) + { + int balance = tree.balance; + balance += remove_from_tree(tree.left,d); + tree.balance = balance; + return !tree.balance; + } + else + { + int balance = tree.balance; + balance += remove_from_tree(tree.left,d); + tree.balance = balance; + return keep_node_balanced(t); + } + + } + // if item is on the right + else if (comp(tree.d , d)) + { + + // if the right side of the tree has the greatest height + if (tree.balance == 1) + { + int balance = tree.balance; + balance -= remove_from_tree(tree.right,d); + tree.balance = balance; + return !tree.balance; + } + else + { + int balance = tree.balance; + balance -= remove_from_tree(tree.right,d); + tree.balance = balance; + return keep_node_balanced(t); + } + } + // if item is found + else + { + + // if there is no left node + if (tree.left == 0) + { + + // plug hole left by removing this node and free memory + t = tree.right; // plug hole with right subtree + + // delete old node + pool.deallocate(&tree); + + // indicate that the height has changed + return true; + } + // if there is no right node + else if (tree.right == 0) + { + + // plug hole left by removing this node and free memory + t = tree.left; // plug hole with left subtree + + // delete old node + pool.deallocate(&tree); + + // indicate that the height of this tree has changed + return true; + } + // if there are both a left and right sub node + else + { + + // get an element that can replace the one being removed and do this + // if it made the right subtree shrink by one + if (remove_least_element_in_tree(tree.right,tree.d,tree.r)) + { + // adjust the tree height + --tree.balance; + + // if the height of the current tree has dropped by one + if (tree.balance == 0) + { + return true; + } + else + { + return keep_node_balanced(t); + } + } + // else this remove did not effect the height of this tree + else + { + return false; + } + + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + range* binary_search_tree_kernel_1:: + return_reference ( + node* t, + const domain& d + ) + { + while (t != 0) + { + + if ( comp(d , t->d )) + { + // if item is on the left then look in left + t = t->left; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + t = t->right; + } + else + { + // if it's found then return a reference to it + return &(t->r); + } + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const range* binary_search_tree_kernel_1:: + return_reference ( + const node* t, + const domain& d + ) const + { + while (t != 0) + { + + if ( comp(d , t->d) ) + { + // if item is on the left then look in left + t = t->left; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + t = t->right; + } + else + { + // if it's found then return a reference to it + return &(t->r); + } + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_1:: + keep_node_balanced ( + node*& t + ) + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if tree does not need to be balanced then return false + if (tree.balance == 0) + return false; + + + // if tree needs to be rotated left + if (tree.balance == 2) + { + if (tree.right->balance >= 0) + rotate_left(t); + else + double_rotate_left(t); + } + // else if the tree needs to be rotated right + else if (tree.balance == -2) + { + if (tree.left->balance <= 0) + rotate_right(t); + else + double_rotate_right(t); + } + + + if (t->balance == 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long binary_search_tree_kernel_1:: + get_count ( + const domain& d, + node* tree_root + ) const + { + if (tree_root != 0) + { + if (comp(d , tree_root->d)) + { + // go left + return get_count(d,tree_root->left); + } + else if (comp(tree_root->d , d)) + { + // go right + return get_count(d,tree_root->right); + } + else + { + // go left and right to look for more matches + return get_count(d,tree_root->left) + + get_count(d,tree_root->right) + + 1; + } + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_1_ + diff --git a/dlib/binary_search_tree/binary_search_tree_kernel_2.h b/dlib/binary_search_tree/binary_search_tree_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..f54d32bf164303ff95132f26dd36d89714ecb9af --- /dev/null +++ b/dlib/binary_search_tree/binary_search_tree_kernel_2.h @@ -0,0 +1,1897 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_2_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_2_ + +#include "binary_search_tree_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager, + typename compare = std::less + > + class binary_search_tree_kernel_2 : public enumerable >, + public asc_pair_remover + { + + /*! + INITIAL VALUE + NIL == pointer to a node that represents a leaf + tree_size == 0 + tree_root == NIL + at_start == true + current_element == 0 + + + CONVENTION + current_element_valid() == (current_element != 0) + if (current_element_valid()) then + element() == current_element->d and current_element->r + at_start_ == at_start() + + + tree_size == size() + + NIL == pointer to a node that represents a leaf + + if (tree_size != 0) + tree_root == pointer to the root node of the binary search tree + else + tree_root == NIL + + tree_root->color == black + Every leaf is black and all leafs are the NIL node. + The number of black nodes in any path from the root to a leaf is the + same. + + for all nodes: + { + - left points to the left subtree or NIL if there is no left subtree + - right points to the right subtree or NIL if there is no right + subtree + - parent points to the parent node or NIL if the node is the root + - ordering of nodes is determined by comparing each node's d memeber + - all elements in a left subtree are <= the node + - all elements in a right subtree are >= the node + - color == red or black + - if (color == red) + - the node's children are black + } + + !*/ + + class node + { + public: + node* left; + node* right; + node* parent; + domain d; + range r; + char color; + }; + + class mpair : public map_pair + { + public: + const domain* d; + range* r; + + const domain& key( + ) const { return *d; } + + const range& value( + ) const { return *r; } + + range& value( + ) { return *r; } + }; + + + const static char red = 0; + const static char black = 1; + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + binary_search_tree_kernel_2( + ) : + NIL(pool.allocate()), + tree_size(0), + tree_root(NIL), + current_element(0), + at_start_(true) + { + NIL->color = black; + NIL->left = 0; + NIL->right = 0; + NIL->parent = 0; + } + + virtual ~binary_search_tree_kernel_2( + ); + + inline void clear( + ); + + inline short height ( + ) const; + + inline unsigned long count ( + const domain& d + ) const; + + inline void add ( + domain& d, + range& r + ); + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& d + ); + + void remove_any ( + domain& d, + range& r + ); + + inline const range* operator[] ( + const domain& item + ) const; + + inline range* operator[] ( + const domain& item + ); + + inline void swap ( + binary_search_tree_kernel_2& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + bool move_next ( + ) const; + + void remove_last_in_order ( + domain& d, + range& r + ); + + void remove_current_element ( + domain& d, + range& r + ); + + void position_enumerator ( + const domain& d + ) const; + + private: + + inline void rotate_left ( + node* t + ); + /*! + requires + - t != NIL + - t->right != NIL + ensures + - performs a left rotation around t and its right child + !*/ + + inline void rotate_right ( + node* t + ); + /*! + requires + - t != NIL + - t->left != NIL + ensures + - performs a right rotation around t and its left child + !*/ + + inline void double_rotate_right ( + node* t + ); + /*! + requires + - t != NIL + - t->left != NIL + - t->left->right != NIL + - double_rotate_right() is only called in fix_after_add() + ensures + - performs a left rotation around t->left + - then performs a right rotation around t + !*/ + + inline void double_rotate_left ( + node* t + ); + /*! + requires + - t != NIL + - t->right != NIL + - t->right->left != NIL + - double_rotate_left() is only called in fix_after_add() + ensures + - performs a right rotation around t->right + - then performs a left rotation around t + !*/ + + void remove_biggest_element_in_tree ( + node* t, + domain& d, + range& r + ); + /*! + requires + - t != NIL (i.e. there must be something in the tree to remove) + ensures + - the biggest node in t has been removed + - the biggest node element in t has been put into #d and #r + - #t is still a binary search tree + !*/ + + bool remove_least_element_in_tree ( + node* t, + domain& d, + range& r + ); + /*! + requires + - t != NIL (i.e. there must be something in the tree to remove) + ensures + - the least node in t has been removed + - the least node element in t has been put into #d and #r + - #t is still a binary search tree + - if (the node that was removed was the one pointed to by current_element) then + - returns true + - else + - returns false + !*/ + + void add_to_tree ( + node* t, + domain& d, + range& r + ); + /*! + requires + - t != NIL + ensures + - d and r are now in #t + - there is a mapping from d to r in #t + - #d and #r have initial values for their types + - #t is still a binary search tree + !*/ + + void remove_from_tree ( + node* t, + const domain& d, + domain& d_copy, + range& r + ); + /*! + requires + - return_reference(t,d) != 0 + ensures + - #d_copy is equivalent to d + - the first element in t equivalent to d that is encountered when searching down the tree + from t has been removed and swapped into #d_copy. Also, the associated range element + has been removed and swapped into #r. + - if (the node that got removed wasn't current_element) then + - adjusts the current_element pointer if the data in the node that it points to gets moved. + - else + - the value of current_element is now invalid + - #t is still a binary search tree + !*/ + + void remove_from_tree ( + node* t, + const domain& d + ); + /*! + requires + - return_reference(t,d) != 0 + ensures + - an element in t equivalent to d has been removed + - #t is still a binary search tree + !*/ + + const range* return_reference ( + const node* t, + const domain& d + ) const; + /*! + ensures + - if (there is a domain element equivalent to d in t) then + - returns a pointer to the element in the range equivalent to d + - else + - returns 0 + !*/ + + range* return_reference ( + node* t, + const domain& d + ); + /*! + ensures + - if (there is a domain element equivalent to d in t) then + - returns a pointer to the element in the range equivalent to d + - else + - returns 0 + !*/ + + void fix_after_add ( + node* t + ); + /*! + requires + - t == pointer to the node just added + - t->color == red + - t->parent != NIL (t must not be the root) + - fix_after_add() is only called after a new node has been added + to t + ensures + - fixes any deviations from the CONVENTION caused by adding a node + !*/ + + void fix_after_remove ( + node* t + ); + /*! + requires + - t == pointer to the only child of the node that was spliced out + - fix_after_remove() is only called after a node has been removed + from t + - the color of the spliced out node was black + ensures + - fixes any deviations from the CONVENTION causes by removing a node + !*/ + + + short tree_height ( + node* t + ) const; + /*! + ensures + - returns the number of nodes in the longest path from the root of the + tree to a leaf + !*/ + + void delete_tree ( + node* t + ); + /*! + requires + - t == root of binary search tree + - t != NIL + ensures + - deletes all nodes in t except for NIL + !*/ + + unsigned long get_count ( + const domain& item, + node* tree_root + ) const; + /*! + requires + - tree_root == the root of a binary search tree or NIL + ensures + - if (tree_root == NIL) then + - returns 0 + - else + - returns the number of elements in tree_root that are + equivalent to item + !*/ + + + + // data members + typename mem_manager::template rebind::other pool; + node* NIL; + unsigned long tree_size; + node* tree_root; + mutable node* current_element; + mutable bool at_start_; + mutable mpair p; + compare comp; + + + + // restricted functions + binary_search_tree_kernel_2(binary_search_tree_kernel_2&); + binary_search_tree_kernel_2& operator=(binary_search_tree_kernel_2&); + + + }; + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + inline void swap ( + binary_search_tree_kernel_2& a, + binary_search_tree_kernel_2& b + ) { a.swap(b); } + + + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void deserialize ( + binary_search_tree_kernel_2& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item.add(d,r); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type binary_search_tree_kernel_2"); + } + } + + + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + binary_search_tree_kernel_2:: + ~binary_search_tree_kernel_2 ( + ) + { + if (tree_root != NIL) + delete_tree(tree_root); + pool.deallocate(NIL); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + clear ( + ) + { + if (tree_size > 0) + { + delete_tree(tree_root); + tree_root = NIL; + tree_size = 0; + } + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long binary_search_tree_kernel_2:: + size ( + ) const + { + return tree_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + short binary_search_tree_kernel_2:: + height ( + ) const + { + return tree_height(tree_root); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long binary_search_tree_kernel_2:: + count ( + const domain& item + ) const + { + return get_count(item,tree_root); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + add ( + domain& d, + range& r + ) + { + if (tree_size == 0) + { + tree_root = pool.allocate(); + tree_root->color = black; + tree_root->left = NIL; + tree_root->right = NIL; + tree_root->parent = NIL; + exchange(tree_root->d,d); + exchange(tree_root->r,r); + } + else + { + add_to_tree(tree_root,d,r); + } + ++tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + remove_from_tree(tree_root,d,d_copy,r); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + destroy ( + const domain& item + ) + { + remove_from_tree(tree_root,item); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove_any ( + domain& d, + range& r + ) + { + remove_least_element_in_tree(tree_root,d,r); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + range* binary_search_tree_kernel_2:: + operator[] ( + const domain& d + ) + { + return return_reference(tree_root,d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const range* binary_search_tree_kernel_2:: + operator[] ( + const domain& d + ) const + { + return return_reference(tree_root,d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + swap ( + binary_search_tree_kernel_2& item + ) + { + pool.swap(item.pool); + + exchange(p,item.p); + exchange(comp,item.comp); + + node* tree_root_temp = item.tree_root; + unsigned long tree_size_temp = item.tree_size; + node* const NIL_temp = item.NIL; + node* current_element_temp = item.current_element; + bool at_start_temp = item.at_start_; + + item.tree_root = tree_root; + item.tree_size = tree_size; + item.NIL = NIL; + item.current_element = current_element; + item.at_start_ = at_start_; + + tree_root = tree_root_temp; + tree_size = tree_size_temp; + NIL = NIL_temp; + current_element = current_element_temp; + at_start_ = at_start_temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove_last_in_order ( + domain& d, + range& r + ) + { + remove_biggest_element_in_tree(tree_root,d,r); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove_current_element ( + domain& d, + range& r + ) + { + node* t = current_element; + move_next(); + remove_from_tree(t,t->d,d,r); + --tree_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + position_enumerator ( + const domain& d + ) const + { + // clear the enumerator state and make sure the stack is empty + reset(); + at_start_ = false; + node* t = tree_root; + node* parent = NIL; + bool went_left = false; + while (t != NIL) + { + if ( comp(d , t->d )) + { + // if item is on the left then look in left + parent = t; + t = t->left; + went_left = true; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + parent = t; + t = t->right; + went_left = false; + } + else + { + current_element = t; + return; + } + } + + // if we didn't find any matches but there might be something after the + // d in this tree. + if (parent != NIL) + { + current_element = parent; + // if we went left from this node then this node is the next + // biggest. + if (went_left) + { + return; + } + else + { + move_next(); + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_2:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + reset ( + ) const + { + at_start_ = true; + current_element = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_2:: + current_element_valid ( + ) const + { + return (current_element != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const map_pair& binary_search_tree_kernel_2:: + element ( + ) const + { + p.d = &(current_element->d); + p.r = &(current_element->r); + return p; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + map_pair& binary_search_tree_kernel_2:: + element ( + ) + { + p.d = &(current_element->d); + p.r = &(current_element->r); + return p; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_2:: + move_next ( + ) const + { + // if we haven't started iterating yet + if (at_start_) + { + at_start_ = false; + if (tree_size == 0) + { + return false; + } + else + { + // find the first element in the tree + current_element = tree_root; + node* temp = current_element->left; + while (temp != NIL) + { + current_element = temp; + temp = current_element->left; + } + return true; + } + } + else + { + if (current_element == 0) + { + return false; + } + else + { + bool went_up; // true if we went up the tree from a child node to parent + bool from_left = false; // true if we went up and were coming from a left child node + // find the next element in the tree + if (current_element->right != NIL) + { + // go right and down + current_element = current_element->right; + went_up = false; + } + else + { + went_up = true; + node* parent = current_element->parent; + if (parent == NIL) + { + // in this case we have iterated over all the element of the tree + current_element = 0; + return false; + } + + from_left = (parent->left == current_element); + // go up to parent + current_element = parent; + } + + + while (true) + { + if (went_up) + { + if (from_left) + { + // in this case we have found the next node + break; + } + else + { + // we should go up + node* parent = current_element->parent; + from_left = (parent->left == current_element); + current_element = parent; + if (current_element == NIL) + { + // in this case we have iterated over all the elements + // in the tree + current_element = 0; + return false; + } + } + } + else + { + // we just went down to a child node + if (current_element->left != NIL) + { + // go left + went_up = false; + current_element = current_element->left; + } + else + { + // if there is no left child then we have found the next node + break; + } + } + } + + return true; + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + delete_tree ( + node* t + ) + { + if (t->left != NIL) + delete_tree(t->left); + if (t->right != NIL) + delete_tree(t->right); + pool.deallocate(t); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + rotate_left ( + node* t + ) + { + + // perform the rotation + node* temp = t->right; + t->right = temp->left; + if (temp->left != NIL) + temp->left->parent = t; + temp->left = t; + temp->parent = t->parent; + + + if (t == tree_root) + tree_root = temp; + else + { + // if t was on the left + if (t->parent->left == t) + t->parent->left = temp; + else + t->parent->right = temp; + } + + t->parent = temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + rotate_right ( + node* t + ) + { + // perform the rotation + node* temp = t->left; + t->left = temp->right; + if (temp->right != NIL) + temp->right->parent = t; + temp->right = t; + temp->parent = t->parent; + + if (t == tree_root) + tree_root = temp; + else + { + // if t is a left child + if (t->parent->left == t) + t->parent->left = temp; + else + t->parent->right = temp; + } + + t->parent = temp; + } + + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + double_rotate_right ( + node* t + ) + { + + // preform the rotation + node& temp = *(t->left->right); + t->left = temp.right; + temp.right->parent = t; + temp.left->parent = temp.parent; + temp.parent->right = temp.left; + temp.parent->parent = &temp; + temp.right = t; + temp.left = temp.parent; + temp.parent = t->parent; + + + if (tree_root == t) + tree_root = &temp; + else + { + // t is a left child + if (t->parent->left == t) + t->parent->left = &temp; + else + t->parent->right = &temp; + } + t->parent = &temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + double_rotate_left ( + node* t + ) + { + + + // preform the rotation + node& temp = *(t->right->left); + t->right = temp.left; + temp.left->parent = t; + temp.right->parent = temp.parent; + temp.parent->left = temp.right; + temp.parent->parent = &temp; + temp.left = t; + temp.right = temp.parent; + temp.parent = t->parent; + + + if (tree_root == t) + tree_root = &temp; + else + { + // t is a left child + if (t->parent->left == t) + t->parent->left = &temp; + else + t->parent->right = &temp; + } + t->parent = &temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove_biggest_element_in_tree ( + node* t, + domain& d, + range& r + ) + { + + node* next = t->right; + node* child; // the child node of the one we will slice out + + if (next == NIL) + { + // need to determine if t is a right or left child + if (t->parent->right == t) + child = t->parent->right = t->left; + else + child = t->parent->left = t->left; + + // update tree_root if necessary + if (t == tree_root) + tree_root = child; + } + else + { + // find the least node + do + { + t = next; + next = next->right; + } while (next != NIL); + // t is a right child + child = t->parent->right = t->left; + + } + + // swap the item from this node into d and r + exchange(d,t->d); + exchange(r,t->r); + + // plug hole right by removing this node + child->parent = t->parent; + + // keep the red-black properties true + if (t->color == black) + fix_after_remove(child); + + // free the memory for this removed node + pool.deallocate(t); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool binary_search_tree_kernel_2:: + remove_least_element_in_tree ( + node* t, + domain& d, + range& r + ) + { + + node* next = t->left; + node* child; // the child node of the one we will slice out + + if (next == NIL) + { + // need to determine if t is a left or right child + if (t->parent->left == t) + child = t->parent->left = t->right; + else + child = t->parent->right = t->right; + + // update tree_root if necessary + if (t == tree_root) + tree_root = child; + } + else + { + // find the least node + do + { + t = next; + next = next->left; + } while (next != NIL); + // t is a left child + child = t->parent->left = t->right; + + } + + // swap the item from this node into d and r + exchange(d,t->d); + exchange(r,t->r); + + // plug hole left by removing this node + child->parent = t->parent; + + // keep the red-black properties true + if (t->color == black) + fix_after_remove(child); + + bool rvalue = (t == current_element); + // free the memory for this removed node + pool.deallocate(t); + return rvalue; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + add_to_tree ( + node* t, + domain& d, + range& r + ) + { + // parent of the current node + node* parent; + + // find a place to add node + while (true) + { + parent = t; + // if item should be put on the left then go left + if (comp(d , t->d)) + { + t = t->left; + if (t == NIL) + { + t = parent->left = pool.allocate(); + break; + } + } + // if item should be put on the right then go right + else + { + t = t->right; + if (t == NIL) + { + t = parent->right = pool.allocate(); + break; + } + } + } + + // t is now the node where we will add item and + // parent is the parent of t + + t->parent = parent; + t->left = NIL; + t->right = NIL; + t->color = red; + exchange(t->d,d); + exchange(t->r,r); + + + // keep the red-black properties true + fix_after_add(t); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove_from_tree ( + node* t, + const domain& d, + domain& d_copy, + range& r + ) + { + while (true) + { + if ( comp(d , t->d) ) + { + // if item is on the left then look in left + t = t->left; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + t = t->right; + } + else + { + // found the node we want to remove + + // swap out the item into d_copy and r + exchange(d_copy,t->d); + exchange(r,t->r); + + if (t->left == NIL) + { + // if there is no left subtree + + node* parent = t->parent; + + // plug hole with right subtree + + + // if t is on the left + if (parent->left == t) + parent->left = t->right; + else + parent->right = t->right; + t->right->parent = parent; + + // update tree_root if necessary + if (t == tree_root) + tree_root = t->right; + + if (t->color == black) + fix_after_remove(t->right); + + // delete old node + pool.deallocate(t); + } + else if (t->right == NIL) + { + // if there is no right subtree + + node* parent = t->parent; + + // plug hole with left subtree + if (parent->left == t) + parent->left = t->left; + else + parent->right = t->left; + t->left->parent = parent; + + // update tree_root if necessary + if (t == tree_root) + tree_root = t->left; + + if (t->color == black) + fix_after_remove(t->left); + + // delete old node + pool.deallocate(t); + } + else + { + // if there is both a left and right subtree + // get an element to fill this node now that its been swapped into + // item_copy + if (remove_least_element_in_tree(t->right,t->d,t->r)) + { + // the node removed was the one pointed to by current_element so we + // need to update it so that it points to the right spot. + current_element = t; + } + } + + // quit loop + break; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + remove_from_tree ( + node* t, + const domain& d + ) + { + while (true) + { + if ( comp(d , t->d) ) + { + // if item is on the left then look in left + t = t->left; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + t = t->right; + } + else + { + // found the node we want to remove + + + if (t->left == NIL) + { + // if there is no left subtree + + node* parent = t->parent; + + // plug hole with right subtree + + + if (parent->left == t) + parent->left = t->right; + else + parent->right = t->right; + t->right->parent = parent; + + // update tree_root if necessary + if (t == tree_root) + tree_root = t->right; + + if (t->color == black) + fix_after_remove(t->right); + + // delete old node + pool.deallocate(t); + } + else if (t->right == NIL) + { + // if there is no right subtree + + node* parent = t->parent; + + // plug hole with left subtree + if (parent->left == t) + parent->left = t->left; + else + parent->right = t->left; + t->left->parent = parent; + + // update tree_root if necessary + if (t == tree_root) + tree_root = t->left; + + if (t->color == black) + fix_after_remove(t->left); + + // delete old node + pool.deallocate(t); + } + else + { + // if there is both a left and right subtree + // get an element to fill this node now that its been swapped into + // item_copy + remove_least_element_in_tree(t->right,t->d,t->r); + + } + + // quit loop + break; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + range* binary_search_tree_kernel_2:: + return_reference ( + node* t, + const domain& d + ) + { + while (t != NIL) + { + if ( comp(d , t->d )) + { + // if item is on the left then look in left + t = t->left; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + t = t->right; + } + else + { + // if it's found then return a reference to it + return &(t->r); + } + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const range* binary_search_tree_kernel_2:: + return_reference ( + const node* t, + const domain& d + ) const + { + while (t != NIL) + { + if ( comp(d , t->d) ) + { + // if item is on the left then look in left + t = t->left; + } + else if (comp(t->d , d)) + { + // if item is on the right then look in right + t = t->right; + } + else + { + // if it's found then return a reference to it + return &(t->r); + } + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + fix_after_add ( + node* t + ) + { + + while (t->parent->color == red) + { + node& grandparent = *(t->parent->parent); + + // if both t's parent and its sibling are red + if (grandparent.left->color == grandparent.right->color) + { + grandparent.color = red; + grandparent.left->color = black; + grandparent.right->color = black; + t = &grandparent; + } + else + { + // if t is a left child + if (t == t->parent->left) + { + // if t's parent is a left child + if (t->parent == grandparent.left) + { + grandparent.color = red; + grandparent.left->color = black; + rotate_right(&grandparent); + } + // if t's parent is a right child + else + { + t->color = black; + grandparent.color = red; + double_rotate_left(&grandparent); + } + } + // if t is a right child + else + { + // if t's parent is a left child + if (t->parent == grandparent.left) + { + t->color = black; + grandparent.color = red; + double_rotate_right(&grandparent); + } + // if t's parent is a right child + else + { + grandparent.color = red; + grandparent.right->color = black; + rotate_left(&grandparent); + } + } + break; + } + } + tree_root->color = black; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void binary_search_tree_kernel_2:: + fix_after_remove ( + node* t + ) + { + + while (t != tree_root && t->color == black) + { + if (t->parent->left == t) + { + node* sibling = t->parent->right; + if (sibling->color == red) + { + sibling->color = black; + t->parent->color = red; + rotate_left(t->parent); + sibling = t->parent->right; + } + + if (sibling->left->color == black && sibling->right->color == black) + { + sibling->color = red; + t = t->parent; + } + else + { + if (sibling->right->color == black) + { + sibling->left->color = black; + sibling->color = red; + rotate_right(sibling); + sibling = t->parent->right; + } + + sibling->color = t->parent->color; + t->parent->color = black; + sibling->right->color = black; + rotate_left(t->parent); + t = tree_root; + + } + + + } + else + { + + node* sibling = t->parent->left; + if (sibling->color == red) + { + sibling->color = black; + t->parent->color = red; + rotate_right(t->parent); + sibling = t->parent->left; + } + + if (sibling->left->color == black && sibling->right->color == black) + { + sibling->color = red; + t = t->parent; + } + else + { + if (sibling->left->color == black) + { + sibling->right->color = black; + sibling->color = red; + rotate_left(sibling); + sibling = t->parent->left; + } + + sibling->color = t->parent->color; + t->parent->color = black; + sibling->left->color = black; + rotate_right(t->parent); + t = tree_root; + + } + + + } + + } + t->color = black; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + short binary_search_tree_kernel_2:: + tree_height ( + node* t + ) const + { + if (t == NIL) + return 0; + + short height1 = tree_height(t->left); + short height2 = tree_height(t->right); + if (height1 > height2) + return height1 + 1; + else + return height2 + 1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long binary_search_tree_kernel_2:: + get_count ( + const domain& d, + node* tree_root + ) const + { + if (tree_root != NIL) + { + if (comp(d , tree_root->d)) + { + // go left + return get_count(d,tree_root->left); + } + else if (comp(tree_root->d , d)) + { + // go right + return get_count(d,tree_root->right); + } + else + { + // go left and right to look for more matches + return get_count(d,tree_root->left) + + get_count(d,tree_root->right) + + 1; + } + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_2_ + diff --git a/dlib/binary_search_tree/binary_search_tree_kernel_abstract.h b/dlib/binary_search_tree/binary_search_tree_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c6e94b5a4b15cff62d14786df390d9c6d6c30e8c --- /dev/null +++ b/dlib/binary_search_tree/binary_search_tree_kernel_abstract.h @@ -0,0 +1,308 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_ +#ifdef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_ + +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class binary_search_tree : public enumerable >, + public asc_pair_remover + { + + /*! + REQUIREMENTS ON domain + domain must be comparable by compare where compare is a functor compatible with std::less and + domain is swappable by a global swap() and + domain must have a default constructor + + REQUIREMENTS ON range + range is swappable by a global swap() and + range must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + + POINTERS AND REFERENCES TO INTERNAL DATA + swap(), count(), height(), and operator[] functions + do not invalidate pointers or references to internal data. + + position_enumerator() invalidates pointers or references to + data returned by element() and only by element() (i.e. pointers and + references returned by operator[] are still valid). + + All other functions have no such guarantees. + + INITIAL VALUE + size() == 0 + height() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the domain (and each associated + range element) elements in ascending order according to the compare functor. + (i.e. the elements are enumerated in sorted order) + + WHAT THIS OBJECT REPRESENTS + this object represents a data dictionary that is built on top of some + kind of binary search tree. It maps objects of type domain to objects + of type range. + + NOTE: + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + binary_search_tree( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + !*/ + + virtual ~binary_search_tree( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + short height ( + ) const; + /*! + ensures + - returns the number of elements in the longest path from the root + of the tree to a leaf + !*/ + + unsigned long count ( + const domain& d + ) const; + /*! + ensures + - returns the number of elements in the domain of *this that are + equivalent to d + !*/ + + void add ( + domain& d, + range& r + ); + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + ensures + - adds a mapping between d and r to *this + - if (count(d) == 0) then + - #*(*this)[d] == r + - else + - #(*this)[d] != 0 + - #d and #r have initial values for their types + - #count(d) == count(d) + 1 + - #at_start() == true + - #size() == size() + 1 + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if add() throws then it has no effect + !*/ + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + /*! + requires + - (*this)[d] != 0 + - &d != &r (i.e. d and r cannot be the same variable) + - &d != &d_copy (i.e. d and d_copy cannot be the same variable) + - &r != &d_copy (i.e. r and d_copy cannot be the same variable) + ensures + - some element in the domain of *this that is equivalent to d has + been removed and swapped into #d_copy. Additionally, its + associated range element has been removed and swapped into #r. + - #count(d) == count(d) - 1 + - #size() == size() - 1 + - #at_start() == true + !*/ + + void destroy ( + const domain& d + ); + /*! + requires + - (*this)[d] != 0 + ensures + - an element in the domain of *this equivalent to d has been removed. + The element in the range of *this associated with d has also been + removed. + - #count(d) == count(d) - 1 + - #size() == size() - 1 + - #at_start() == true + !*/ + + void remove_last_in_order ( + domain& d, + range& r + ); + /*! + requires + - size() > 0 + ensures + - the last/biggest (according to the compare functor) element in the domain of *this has + been removed and swapped into #d. The element in the range of *this + associated with #d has also been removed and swapped into #r. + - #count(#d) == count(#d) - 1 + - #size() == size() - 1 + - #at_start() == true + !*/ + + void remove_current_element ( + domain& d, + range& r + ); + /*! + requires + - current_element_valid() == true + ensures + - the current element given by element() has been removed and swapped into d and r. + - #d == element().key() + - #r == element().value() + - #count(#d) == count(#d) - 1 + - #size() == size() - 1 + - moves the enumerator to the next element. If element() was the last + element in enumeration order then #current_element_valid() == false + and #at_start() == false. + !*/ + + void position_enumerator ( + const domain& d + ) const; + /*! + ensures + - #at_start() == false + - if (count(d) > 0) then + - #element().key() == d + - else if (there are any items in the domain of *this that are bigger than + d according to the compare functor) then + - #element().key() == the smallest item in the domain of *this that is + bigger than d according to the compare functor. + - else + - #current_element_valid() == false + !*/ + + const range* operator[] ( + const domain& d + ) const; + /*! + ensures + - if (there is an element in the domain equivalent to d) then + - returns a pointer to an element in the range of *this that + is associated with an element in the domain of *this + equivalent to d. + - else + - returns 0 + !*/ + + range* operator[] ( + const domain& d + ); + /*! + ensures + - if (there is an element in the domain equivalent to d) then + - returns a pointer to an element in the range of *this that + is associated with an element in the domain of *this + equivalent to d. + - else + - returns 0 + !*/ + + void swap ( + binary_search_tree& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + binary_search_tree(binary_search_tree&); + binary_search_tree& operator=(binary_search_tree&); + + }; + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + inline void swap ( + binary_search_tree& a, + binary_search_tree& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void deserialize ( + binary_search_tree& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_ + diff --git a/dlib/binary_search_tree/binary_search_tree_kernel_c.h b/dlib/binary_search_tree/binary_search_tree_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..1ff67f0e46b085d8c994b82801b9e30610967e52 --- /dev/null +++ b/dlib/binary_search_tree/binary_search_tree_kernel_c.h @@ -0,0 +1,253 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_C_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_C_ + +#include "../interfaces/map_pair.h" +#include "binary_search_tree_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename bst_base + > + class binary_search_tree_kernel_c : public bst_base + { + typedef typename bst_base::domain_type domain; + typedef typename bst_base::range_type range; + + public: + + binary_search_tree_kernel_c () {} + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& d + ); + + void add ( + domain& d, + range& r + ); + + void remove_any ( + domain& d, + range& r + ); + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + void remove_last_in_order ( + domain& d, + range& r + ); + + void remove_current_element ( + domain& d, + range& r + ); + + + }; + + + template < + typename bst_base + > + inline void swap ( + binary_search_tree_kernel_c& a, + binary_search_tree_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + void binary_search_tree_kernel_c:: + add ( + domain& d, + range& r + ) + { + DLIB_CASSERT( reinterpret_cast(&d) != reinterpret_cast(&r), + "\tvoid binary_search_tree::add" + << "\n\tyou can't call add() and give the same object to both parameters." + << "\n\tthis: " << this + << "\n\t&d: " << &d + << "\n\t&r: " << &r + << "\n\tsize(): " << this->size() + ); + + bst_base::add(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + void binary_search_tree_kernel_c:: + destroy ( + const domain& d + ) + { + DLIB_CASSERT(operator[](d) != 0, + "\tvoid binary_search_tree::destroy" + << "\n\tthe element must be in the tree for it to be removed" + << "\n\tthis: " << this + << "\n\t&d: " << &d + ); + + bst_base::destroy(d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + void binary_search_tree_kernel_c:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + DLIB_CASSERT(operator[](d) != 0 && + (reinterpret_cast(&d) != reinterpret_cast(&d_copy)) && + (reinterpret_cast(&d) != reinterpret_cast(&r)) && + (reinterpret_cast(&r) != reinterpret_cast(&d_copy)), + "\tvoid binary_search_tree::remove" + << "\n\tthe element must be in the tree for it to be removed" + << "\n\tthis: " << this + << "\n\t&d: " << &d + << "\n\t&d_copy: " << &d_copy + << "\n\t&r: " << &r + ); + + bst_base::remove(d,d_copy,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + void binary_search_tree_kernel_c:: + remove_any( + domain& d, + range& r + ) + { + DLIB_CASSERT(this->size() != 0 && + (reinterpret_cast(&d) != reinterpret_cast(&r)), + "\tvoid binary_search_tree::remove_any" + << "\n\ttree must not be empty if something is going to be removed" + << "\n\tthis: " << this + << "\n\t&d: " << &d + << "\n\t&r: " << &r + ); + + bst_base::remove_any(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + const map_pair& binary_search_tree_kernel_c:: + element ( + ) const + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst map_pair& binary_search_tree::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return bst_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + map_pair& binary_search_tree_kernel_c:: + element ( + ) + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tmap_pair& binary_search_tree::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return bst_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + void binary_search_tree_kernel_c:: + remove_last_in_order ( + domain& d, + range& r + ) + { + DLIB_CASSERT(this->size() > 0, + "\tvoid binary_search_tree::remove_last_in_order()" + << "\n\tyou can't remove an element if it doesn't exist" + << "\n\tthis: " << this + ); + + bst_base::remove_last_in_order(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bst_base + > + void binary_search_tree_kernel_c:: + remove_current_element ( + domain& d, + range& r + ) + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tvoid binary_search_tree::remove_current_element()" + << "\n\tyou can't remove the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + bst_base::remove_current_element(d,r); + } + + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_C_ + diff --git a/dlib/bit_stream.h b/dlib/bit_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..fe0cf3b22f1f515b1c2fc930f15172fb93f644f5 --- /dev/null +++ b/dlib/bit_stream.h @@ -0,0 +1,42 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIT_STREAm_ +#define DLIB_BIT_STREAm_ + +#include "bit_stream/bit_stream_kernel_1.h" +#include "bit_stream/bit_stream_kernel_c.h" + +#include "bit_stream/bit_stream_multi_1.h" +#include "bit_stream/bit_stream_multi_c.h" + +namespace dlib +{ + + + class bit_stream + { + bit_stream() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef bit_stream_kernel_1 + kernel_1a; + typedef bit_stream_kernel_c + kernel_1a_c; + + //---------- extensions ------------ + + + // multi_1 extend kernel_1a + typedef bit_stream_multi_1 + multi_1a; + typedef bit_stream_multi_c > + multi_1a_c; + + }; +} + +#endif // DLIB_BIT_STREAm_ + diff --git a/dlib/bit_stream/bit_stream_kernel_1.cpp b/dlib/bit_stream/bit_stream_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..777119c370d757f4fcc9175762aa7b6728df80ca --- /dev/null +++ b/dlib/bit_stream/bit_stream_kernel_1.cpp @@ -0,0 +1,200 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIT_STREAM_KERNEL_1_CPp_ +#define DLIB_BIT_STREAM_KERNEL_1_CPp_ + + +#include "bit_stream_kernel_1.h" +#include "../algs.h" + +#include + +namespace dlib +{ + + inline void swap ( + bit_stream_kernel_1& a, + bit_stream_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void bit_stream_kernel_1:: + clear ( + ) + { + if (write_mode) + { + write_mode = false; + + // flush output buffer + if (buffer_size > 0) + { + buffer <<= 8 - buffer_size; + osp->write(reinterpret_cast(&buffer),1); + } + } + else + read_mode = false; + + } + +// ---------------------------------------------------------------------------------------- + + void bit_stream_kernel_1:: + set_input_stream ( + std::istream& is + ) + { + isp = &is; + read_mode = true; + + buffer_size = 0; + } + +// ---------------------------------------------------------------------------------------- + + void bit_stream_kernel_1:: + set_output_stream ( + std::ostream& os + ) + { + osp = &os; + write_mode = true; + + buffer_size = 0; + } + +// ---------------------------------------------------------------------------------------- + + void bit_stream_kernel_1:: + close ( + ) + { + if (write_mode) + { + write_mode = false; + + // flush output buffer + if (buffer_size > 0) + { + buffer <<= 8 - buffer_size; + osp->write(reinterpret_cast(&buffer),1); + } + } + else + read_mode = false; + } + +// ---------------------------------------------------------------------------------------- + + bool bit_stream_kernel_1:: + is_in_write_mode ( + ) const + { + return write_mode; + } + +// ---------------------------------------------------------------------------------------- + + bool bit_stream_kernel_1:: + is_in_read_mode ( + ) const + { + return read_mode; + } + +// ---------------------------------------------------------------------------------------- + + void bit_stream_kernel_1:: + write ( + int bit + ) + { + // flush buffer if necessary + if (buffer_size == 8) + { + buffer <<= 8 - buffer_size; + if (osp->rdbuf()->sputn(reinterpret_cast(&buffer),1) == 0) + { + throw std::ios_base::failure("error occured in the bit_stream object"); + } + + buffer_size = 0; + } + + ++buffer_size; + buffer <<= 1; + buffer += static_cast(bit); + } + +// ---------------------------------------------------------------------------------------- + + bool bit_stream_kernel_1:: + read ( + int& bit + ) + { + // get new byte if necessary + if (buffer_size == 0) + { + if (isp->rdbuf()->sgetn(reinterpret_cast(&buffer), 1) == 0) + { + // if we didn't read anything then return false + return false; + } + + buffer_size = 8; + } + + // put the most significant bit from buffer into bit + bit = static_cast(buffer >> 7); + + // shift out the bit that was just read + buffer <<= 1; + --buffer_size; + + return true; + } + +// ---------------------------------------------------------------------------------------- + + void bit_stream_kernel_1:: + swap ( + bit_stream_kernel_1& item + ) + { + + std::istream* isp_temp = item.isp; + std::ostream* osp_temp = item.osp; + bool write_mode_temp = item.write_mode; + bool read_mode_temp = item.read_mode; + unsigned char buffer_temp = item.buffer; + unsigned short buffer_size_temp = item.buffer_size; + + item.isp = isp; + item.osp = osp; + item.write_mode = write_mode; + item.read_mode = read_mode; + item.buffer = buffer; + item.buffer_size = buffer_size; + + + isp = isp_temp; + osp = osp_temp; + write_mode = write_mode_temp; + read_mode = read_mode_temp; + buffer = buffer_temp; + buffer_size = buffer_size_temp; + + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_BIT_STREAM_KERNEL_1_CPp_ + diff --git a/dlib/bit_stream/bit_stream_kernel_1.h b/dlib/bit_stream/bit_stream_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..96c80f4017fdd05dca8bddcbc771963e51d0fff6 --- /dev/null +++ b/dlib/bit_stream/bit_stream_kernel_1.h @@ -0,0 +1,120 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIT_STREAM_KERNEl_1_ +#define DLIB_BIT_STREAM_KERNEl_1_ + +#include "bit_stream_kernel_abstract.h" +#include + +namespace dlib +{ + + class bit_stream_kernel_1 + { + + /*! + INITIAL VALUE + write_mode == false + read_mode == false + + CONVENTION + write_mode == is_in_write_mode() + read_mode == is_in_read_mode() + + if (write_mode) + { + osp == pointer to an ostream object + buffer == the low order bits of buffer are the bits to be + written + buffer_size == the number of low order bits in buffer that are + bits that should be written + the lowest order bit is the last bit entered by the user + } + + if (read_mode) + { + isp == pointer to an istream object + buffer == the high order bits of buffer are the bits + waiting to be read by the user + buffer_size == the number of high order bits in buffer that + are bits that are waiting to be read + the highest order bit is the next bit to give to the user + } + !*/ + + + public: + + bit_stream_kernel_1 ( + ) : + write_mode(false), + read_mode(false) + {} + + virtual ~bit_stream_kernel_1 ( + ) + {} + + void clear ( + ); + + void set_input_stream ( + std::istream& is + ); + + void set_output_stream ( + std::ostream& os + ); + + void close ( + ); + + inline bool is_in_write_mode ( + ) const; + + inline bool is_in_read_mode ( + ) const; + + inline void write ( + int bit + ); + + bool read ( + int& bit + ); + + void swap ( + bit_stream_kernel_1& item + ); + + private: + + // member data + std::istream* isp; + std::ostream* osp; + bool write_mode; + bool read_mode; + unsigned char buffer; + unsigned short buffer_size; + + // restricted functions + bit_stream_kernel_1(bit_stream_kernel_1&); // copy constructor + bit_stream_kernel_1& operator=(bit_stream_kernel_1&); // assignment operator + + }; + + inline void swap ( + bit_stream_kernel_1& a, + bit_stream_kernel_1& b + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "bit_stream_kernel_1.cpp" +#endif + +#endif // DLIB_BIT_STREAM_KERNEl_1_ + diff --git a/dlib/bit_stream/bit_stream_kernel_abstract.h b/dlib/bit_stream/bit_stream_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..3b271a019b25b6429701792c09f2fb3c462541b7 --- /dev/null +++ b/dlib/bit_stream/bit_stream_kernel_abstract.h @@ -0,0 +1,185 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BIT_STREAM_KERNEl_ABSTRACT_ +#ifdef DLIB_BIT_STREAM_KERNEl_ABSTRACT_ + +#include + +namespace dlib +{ + + class bit_stream + { + + /*! + INITIAL VALUE + is_in_write_mode() == false + is_in_read_mode() == false + + WHAT THIS OBJECT REPRESENTS + this object is a middle man between a user and the iostream classes. + it allows single bits to be read/written easily to/from + the iostream classes + + BUFFERING: + This object will only read/write single bytes at a time from/to the + iostream objects. Any buffered bits still in the bit_stream object + when it is closed or destructed are lost if it is in read mode. If + it is in write mode then any remaining bits are guaranteed to be + written to the output stream by the time it is closed or destructed. + !*/ + + + public: + + bit_stream ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~bit_stream ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear ( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + + void set_input_stream ( + std::istream& is + ); + /*! + requires + - is_in_write_mode() == false + - is_in_read_mode() == false + - is is ready to give input + ensures + - #is_in_write_mode() == false + - #is_in_read_mode() == true + - #*this will now be reading from is + throws + - std::bad_alloc + !*/ + + void set_output_stream ( + std::ostream& os + ); + /*! + requires + - is_in_write_mode() == false + - is_in_read_mode() == false + - os is ready to take output + ensures + - #is_in_write_mode() == true + - #is_in_read_mode() == false + - #*this will now write to os + throws + - std::bad_alloc + !*/ + + + + void close ( + ); + /*! + requires + - is_in_write_mode() == true || is_in_read_mode() == true + ensures + - #is_in_write_mode() == false + - #is_in_read_mode() == false + !*/ + + bool is_in_write_mode ( + ) const; + /*! + ensures + - returns true if *this is associated with an output stream object + - returns false otherwise + !*/ + + bool is_in_read_mode ( + ) const; + /*! + ensures + - returns true if *this is associated with an input stream object + - returns false otherwise + !*/ + + void write ( + int bit + ); + /*! + requires + - is_in_write_mode() == true + - bit == 0 || bit == 1 + ensures + - bit will be written to the ostream object associated with *this + throws + - std::ios_base::failure + if (there was a problem writing to the output stream) then + this exception will be thrown. #*this will be unusable until + clear() is called and succeeds + - any other exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + bool read ( + int& bit + ); + /*! + requires + - is_in_read_mode() == true + ensures + - the next bit has been read and placed into #bit + - returns true if the read was successful, else false + (ex. false if EOF has been reached) + throws + - any exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void swap ( + bit_stream& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + bit_stream(bit_stream&); // copy constructor + bit_stream& operator=(bit_stream&); // assignment operator + + }; + + inline void swap ( + bit_stream& a, + bit_stream& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_BIT_STREAM_KERNEl_ABSTRACT_ + diff --git a/dlib/bit_stream/bit_stream_kernel_c.h b/dlib/bit_stream/bit_stream_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..17fee194d3a3344d3e1cf3b8d0e2577251f28104 --- /dev/null +++ b/dlib/bit_stream/bit_stream_kernel_c.h @@ -0,0 +1,172 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIT_STREAM_KERNEl_C_ +#define DLIB_BIT_STREAM_KERNEl_C_ + +#include "bit_stream_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename bit_stream_base // implements bit_stream/bit_stream_kernel_abstract.h + > + class bit_stream_kernel_c : public bit_stream_base + { + public: + + + void set_input_stream ( + std::istream& is + ); + + void set_output_stream ( + std::ostream& os + ); + + void close ( + ); + + void write ( + int bit + ); + + bool read ( + int& bit + ); + + }; + + template < + typename bit_stream_base + > + inline void swap ( + bit_stream_kernel_c& a, + bit_stream_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + void bit_stream_kernel_c:: + set_input_stream ( + std::istream& is + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(( this->is_in_write_mode() == false ) && ( this->is_in_read_mode() == false ), + "\tvoid bit_stream::set_intput_stream" + << "\n\tbit_stream must not be in write or read mode" + << "\n\tthis: " << this + ); + + // call the real function + bit_stream_base::set_input_stream(is); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + void bit_stream_kernel_c:: + set_output_stream ( + std::ostream& os + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( this->is_in_write_mode() == false ) && ( this->is_in_read_mode() == false ), + "\tvoid bit_stream::set_output_stream" + << "\n\tbit_stream must not be in write or read mode" + << "\n\tthis: " << this + ); + + // call the real function + bit_stream_base::set_output_stream(os); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + void bit_stream_kernel_c:: + close ( + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( this->is_in_write_mode() == true ) || ( this->is_in_read_mode() == true ), + "\tvoid bit_stream::close" + << "\n\tyou can't close a bit_stream that isn't open" + << "\n\tthis: " << this + ); + + // call the real function + bit_stream_base::close(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + void bit_stream_kernel_c:: + write ( + int bit + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(( this->is_in_write_mode() == true ) && ( bit == 0 || bit == 1 ), + "\tvoid bit_stream::write" + << "\n\tthe bit stream bust be in write mode and bit must be either 1 or 0" + << "\n\tis_in_write_mode() == " << this->is_in_write_mode() + << "\n\tbit == " << bit + << "\n\tthis: " << this + ); + + // call the real function + bit_stream_base::write(bit); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + bool bit_stream_kernel_c:: + read ( + int& bit + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( this->is_in_read_mode() == true ), + "\tbool bit_stream::read" + << "\n\tyou can't read from a bit_stream that isn't in read mode" + << "\n\tthis: " << this + ); + + // call the real function + return bit_stream_base::read(bit); + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BIT_STREAM_KERNEl_C_ + diff --git a/dlib/bit_stream/bit_stream_multi_1.h b/dlib/bit_stream/bit_stream_multi_1.h new file mode 100644 index 0000000000000000000000000000000000000000..42c358904f4e92ec759b9c81ffa0f95669bade9d --- /dev/null +++ b/dlib/bit_stream/bit_stream_multi_1.h @@ -0,0 +1,103 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIT_STREAM_MULTi_1_ +#define DLIB_BIT_STREAM_MULTi_1_ + +#include "bit_stream_multi_abstract.h" + +namespace dlib +{ + template < + typename bit_stream_base + > + class bit_stream_multi_1 : public bit_stream_base + { + + public: + + void multi_write ( + unsigned long data, + int num_to_write + ); + + int multi_read ( + unsigned long& data, + int num_to_read + ); + + }; + + template < + typename bit_stream_base + > + inline void swap ( + bit_stream_multi_1& a, + bit_stream_multi_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + void bit_stream_multi_1:: + multi_write ( + unsigned long data, + int num_to_write + ) + { + // move the first bit into the most significant position + data <<= 32 - num_to_write; + + for (int i = 0; i < num_to_write; ++i) + { + // write the first bit from data + this->write(static_cast(data >> 31)); + + // shift the next bit into position + data <<= 1; + + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + int bit_stream_multi_1:: + multi_read ( + unsigned long& data, + int num_to_read + ) + { + int bit, i; + data = 0; + for (i = 0; i < num_to_read; ++i) + { + + // get a bit + if (this->read(bit) == false) + break; + + // shift data to make room for this new bit + data <<= 1; + + // put bit into the least significant position in data + data += static_cast(bit); + + } + + return i; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BIT_STREAM_MULTi_1_ + diff --git a/dlib/bit_stream/bit_stream_multi_abstract.h b/dlib/bit_stream/bit_stream_multi_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..6e18423d0f063d7175f7936b37634269b0542852 --- /dev/null +++ b/dlib/bit_stream/bit_stream_multi_abstract.h @@ -0,0 +1,77 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BIT_STREAM_MULTi_ABSTRACT_ +#ifdef DLIB_BIT_STREAM_MULTi_ABSTRACT_ + +#include "bit_stream_kernel_abstract.h" + +namespace dlib +{ + template < + typename bit_stream_base + > + class bit_stream_multi : public bit_stream_base + { + + /*! + REQUIREMENTS ON BIT_STREAM_BASE + it is an implementation of bit_stream/bit_stream_kernel_abstract.h + + + WHAT THIS EXTENSION DOES FOR BIT_STREAM + this gives a bit_stream object the ability to read/write multible bits + at a time + !*/ + + + public: + + void multi_write ( + unsigned long data, + int num_to_write + ); + /*! + requires + - is_in_write_mode() == true + - 0 <= num_to_write <= 32 + ensures + - num_to_write low order bits from data will be written to the ostream + - object associated with *this + example: if data is 10010 then the bits will be written in the + order 1,0,0,1,0 + !*/ + + + int multi_read ( + unsigned long& data, + int num_to_read + ); + /*! + requires + - is_in_read_mode() == true + - 0 <= num_to_read <= 32 + ensures + - tries to read num_to_read bits into the low order end of #data + example: if the incoming bits were 10010 then data would end + up with 10010 as its low order bits + - all of the bits in #data not filled in by multi_read() are zero + - returns the number of bits actually read into #data + !*/ + + }; + + template < + typename bit_stream_base + > + inline void swap ( + bit_stream_multi& a, + bit_stream_multi& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_BIT_STREAM_MULTi_ABSTRACT_ + diff --git a/dlib/bit_stream/bit_stream_multi_c.h b/dlib/bit_stream/bit_stream_multi_c.h new file mode 100644 index 0000000000000000000000000000000000000000..cb413df7823fcad78c65e618526ea18c8fd6ed99 --- /dev/null +++ b/dlib/bit_stream/bit_stream_multi_c.h @@ -0,0 +1,101 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BIT_STREAM_MULTi_C_ +#define DLIB_BIT_STREAM_MULTi_C_ + +#include "bit_stream_multi_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + template < + typename bit_stream_base // implements bit_stream/bit_stream_multi_abstract.h + > + class bit_stream_multi_c : public bit_stream_base + { + public: + + void multi_write ( + unsigned long data, + int num_to_write + ); + + int multi_read ( + unsigned long& data, + int num_to_read + ); + + }; + + template < + typename bit_stream_base + > + inline void swap ( + bit_stream_multi_c& a, + bit_stream_multi_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + void bit_stream_multi_c:: + multi_write ( + unsigned long data, + int num_to_write + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (this->is_in_write_mode() == true) && (num_to_write >= 0 && num_to_write <=32), + "\tvoid bit_stream::write" + << "\n\tthe bit stream bust be in write mode and" + << "\n\tnum_to_write must be between 0 and 32 inclusive" + << "\n\tnum_to_write == " << num_to_write + << "\n\tis_in_write_mode() == " << this->is_in_write_mode() + << "\n\tthis: " << this + ); + + // call the real function + bit_stream_base::multi_write(data,num_to_write); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename bit_stream_base + > + int bit_stream_multi_c:: + multi_read ( + unsigned long& data, + int num_to_read + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( this->is_in_read_mode() == true && ( num_to_read >= 0 && num_to_read <=32 ) ), + "\tvoid bit_stream::read" + << "\n\tyou can't read from a bit_stream that isn't in read mode and" + << "\n\tnum_to_read must be between 0 and 32 inclusive" + << "\n\tnum_to_read == " << num_to_read + << "\n\tis_in_read_mode() == " << this->is_in_read_mode() + << "\n\tthis: " << this + ); + + // call the real function + return bit_stream_base::multi_read(data,num_to_read); + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BIT_STREAM_MULTi_C_ + diff --git a/dlib/byte_orderer.h b/dlib/byte_orderer.h new file mode 100644 index 0000000000000000000000000000000000000000..092ff6a9b5bb7f94cfa48af4e289c41c618918cb --- /dev/null +++ b/dlib/byte_orderer.h @@ -0,0 +1,35 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BYTE_ORDEREr_ +#define DLIB_BYTE_ORDEREr_ + + +#include "byte_orderer/byte_orderer_kernel_1.h" + + + +namespace dlib +{ + + + class byte_orderer + { + + byte_orderer() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef byte_orderer_kernel_1 + kernel_1a; + + + + }; +} + +#endif // DLIB_BYTE_ORDEREr_ + diff --git a/dlib/byte_orderer/byte_orderer_kernel_1.h b/dlib/byte_orderer/byte_orderer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..71e2ad62e4a07144e8e78c8e1c3cfe50c6a6e424 --- /dev/null +++ b/dlib/byte_orderer/byte_orderer_kernel_1.h @@ -0,0 +1,183 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BYTE_ORDEREr_KERNEL_1_ +#define DLIB_BYTE_ORDEREr_KERNEL_1_ + +#include "byte_orderer_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + class byte_orderer_kernel_1 + { + /*! + INITIAL VALUE + - if (this machine is little endian) then + - little_endian == true + - else + - little_endian == false + + CONVENTION + - host_is_big_endian() == !little_endian + - host_is_little_endian() == little_endian + + - if (this machine is little endian) then + - little_endian == true + - else + - little_endian == false + + + !*/ + + + public: + + byte_orderer_kernel_1 ( + ) + { + // This will probably never be false but if it is then it means chars are not 8bits + // on this system. Which is a problem for this object. + COMPILE_TIME_ASSERT(sizeof(short) >= 2); + + unsigned long temp = 1; + unsigned char* ptr = reinterpret_cast(&temp); + if (*ptr == 1) + little_endian = true; + else + little_endian = false; + } + + virtual ~byte_orderer_kernel_1 ( + ){} + + bool host_is_big_endian ( + ) const { return !little_endian; } + + bool host_is_little_endian ( + ) const { return little_endian; } + + template < + typename T + > + inline void host_to_network ( + T& item + ) const + { if (little_endian) flip(item); } + + template < + typename T + > + inline void network_to_host ( + T& item + ) const { if (little_endian) flip(item); } + + template < + typename T + > + void host_to_big ( + T& item + ) const { if (little_endian) flip(item); } + + template < + typename T + > + void big_to_host ( + T& item + ) const { if (little_endian) flip(item); } + + template < + typename T + > + void host_to_little ( + T& item + ) const { if (!little_endian) flip(item); } + + template < + typename T + > + void little_to_host ( + T& item + ) const { if (!little_endian) flip(item); } + + + private: + + template < + typename T, + size_t size + > + inline void flip ( + T (&array)[size] + ) const + /*! + ensures + - flips the bytes in every element of this array + !*/ + { + for (size_t i = 0; i < size; ++i) + { + flip(array[i]); + } + } + + template < + typename T + > + inline void flip ( + T& item + ) const + /*! + ensures + - reverses the byte ordering in item + !*/ + { + // this is just here to provide a compile time check that T is a POD. + // this checks *most* of the requrements for being a POD type. + // You should not be calling this function on non POD types! + union + { + int a; + T value; + } temp; + + // If you are getting this as an error then you are probably using + // this object wrong. If you think you aren't then send me (Davis) an + // email and I'll either set you straight or change/remove this check so + // your stuff works :) + COMPILE_TIME_ASSERT(sizeof(T) <= sizeof(long double)); + + // If you are getting a compile error on this line then it means T is + // a pointer type. It doesn't make any sense to byte swap pointers + // since they have no meaning outside the context of their own process. + // So you probably just forgot to dereference that pointer before passing + // it to this function :) + COMPILE_TIME_ASSERT(is_pointer_type::value == false); + + + const size_t size = sizeof(T); + unsigned char* const ptr = reinterpret_cast(&item); + unsigned char* const ptr_temp = reinterpret_cast(&temp.value); + for (size_t i = 0; i < size; ++i) + ptr_temp[size-i-1] = ptr[i]; + + item = temp.value; + } + + bool little_endian; + + // restricted functions + byte_orderer_kernel_1(const byte_orderer_kernel_1&); // copy constructor + byte_orderer_kernel_1& operator=(const byte_orderer_kernel_1&); // assignment operator + + }; + + // make flip not do anything at all for chars + template <> inline void byte_orderer_kernel_1::flip ( char& ) const {} + template <> inline void byte_orderer_kernel_1::flip ( unsigned char& ) const {} + template <> inline void byte_orderer_kernel_1::flip ( signed char& ) const {} +} + +#endif // DLIB_BYTE_ORDEREr_KERNEL_1_ + diff --git a/dlib/byte_orderer/byte_orderer_kernel_abstract.h b/dlib/byte_orderer/byte_orderer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..2096e62875e13e7a9c4a51f09be48e1ee0c3b7d9 --- /dev/null +++ b/dlib/byte_orderer/byte_orderer_kernel_abstract.h @@ -0,0 +1,156 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BYTE_ORDEREr_ABSTRACT_ +#ifdef DLIB_BYTE_ORDEREr_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + class byte_orderer + { + /*! + INITIAL VALUE + This object has no state. + + WHAT THIS OBJECT REPRESENTS + This object simply provides a mechanism to convert data from a + host machine's own byte ordering to big or little endian and to + also do the reverse. + + It also provides a pair of functions to convert to/from network byte + order where network byte order is big endian byte order. This pair of + functions does the exact same thing as the host_to_big() and big_to_host() + functions and is provided simply so that client code can use the most + self documenting name appropriate. + + Also note that this object is capable of correctly flipping the contents + of arrays when the arrays are declared on the stack. e.g. You can + say things like: + int array[10]; + bo.host_to_network(array); + !*/ + + public: + + byte_orderer ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~byte_orderer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + bool host_is_big_endian ( + ) const; + /*! + ensures + - if (the host computer is a big endian machine) then + - returns true + - else + - returns false + !*/ + + bool host_is_little_endian ( + ) const; + /*! + ensures + - if (the host computer is a little endian machine) then + - returns true + - else + - returns false + !*/ + + template < + typename T + > + void host_to_network ( + T& item + ) const; + /*! + ensures + - #item == the value of item converted from host byte order + to network byte order. + !*/ + + template < + typename T + > + void network_to_host ( + T& item + ) const; + /*! + ensures + - #item == the value of item converted from network byte order + to host byte order. + !*/ + + template < + typename T + > + void host_to_big ( + T& item + ) const; + /*! + ensures + - #item == the value of item converted from host byte order + to big endian byte order. + !*/ + + template < + typename T + > + void big_to_host ( + T& item + ) const; + /*! + ensures + - #item == the value of item converted from big endian byte order + to host byte order. + !*/ + + template < + typename T + > + void host_to_little ( + T& item + ) const; + /*! + ensures + - #item == the value of item converted from host byte order + to little endian byte order. + !*/ + + template < + typename T + > + void little_to_host ( + T& item + ) const; + /*! + ensures + - #item == the value of item converted from little endian byte order + to host byte order. + !*/ + + + private: + + // restricted functions + byte_orderer(const byte_orderer&); // copy constructor + byte_orderer& operator=(const byte_orderer&); // assignment operator + + }; +} + +#endif // DLIB_BYTE_ORDEREr_ABSTRACT_ + diff --git a/dlib/cassert b/dlib/cassert new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/cassert @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/cmd_line_parser.h b/dlib/cmd_line_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..ba0d729252c81ce3a61e2ccbfa9ca475b45c6649 --- /dev/null +++ b/dlib/cmd_line_parser.h @@ -0,0 +1,63 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSEr_ +#define DLIB_CMD_LINE_PARSEr_ + +#include "cmd_line_parser/cmd_line_parser_kernel_1.h" +#include "cmd_line_parser/cmd_line_parser_kernel_c.h" +#include "cmd_line_parser/cmd_line_parser_print_1.h" +#include "cmd_line_parser/cmd_line_parser_check_1.h" +#include "cmd_line_parser/cmd_line_parser_check_c.h" +#include + +#include "map.h" +#include "sequence.h" + + + +namespace dlib +{ + + + template < + typename charT + > + class cmd_line_parser + { + cmd_line_parser() {} + + typedef typename sequence >::kernel_2a sequence_2a; + typedef typename sequence*>::kernel_2a psequence_2a; + typedef typename map,void*>::kernel_1a map_1a_string; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef cmd_line_parser_kernel_1 + kernel_1a; + typedef cmd_line_parser_kernel_c + kernel_1a_c; + + + + //----------- extensions --------------- + + // print_1 extend kernel_1a + typedef cmd_line_parser_print_1 + print_1a; + typedef cmd_line_parser_print_1 + print_1a_c; + + // check_1 extend print_1a + typedef cmd_line_parser_check_1 + check_1a; + typedef cmd_line_parser_check_c > + check_1a_c; + + }; +} + +#endif // DLIB_CMD_LINE_PARSEr_ + diff --git a/dlib/cmd_line_parser/cmd_line_parser_check_1.h b/dlib/cmd_line_parser/cmd_line_parser_check_1.h new file mode 100644 index 0000000000000000000000000000000000000000..d045c8d0a8807d1f2e143918ba789b00b52fbc44 --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_check_1.h @@ -0,0 +1,545 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_CHECk_1_ +#define DLIB_CMD_LINE_PARSER_CHECk_1_ + +#include "cmd_line_parser_kernel_abstract.h" +#include +#include +#include "../string.h" +#include + +namespace dlib +{ + + template < + typename clp_base + > + class cmd_line_parser_check_1 : public clp_base + { + + /*! + This extension doesn't add any state. + + !*/ + + + public: + typedef typename clp_base::char_type char_type; + typedef typename clp_base::string_type string_type; + + // ------------------------------------------------------------------------------------ + + class cmd_line_check_error : public dlib::error + { + friend class cmd_line_parser_check_1; + + cmd_line_check_error( + error_type t, + const string_type& opt_, + const string_type& arg_ + ) : + dlib::error(t), + opt(opt_), + arg(arg_) + { set_info_string(); } + + cmd_line_check_error( + error_type t, + const string_type& opt_, + const string_type& opt2_, + int // this is just to make this constructor different from the one above + ) : + dlib::error(t), + opt(opt_), + opt2(opt2_) + { set_info_string(); } + + cmd_line_check_error ( + error_type t, + const string_type& opt_, + const std::vector& vect + ) : + dlib::error(t), + opt(opt_), + required_opts(vect) + { set_info_string(); } + + cmd_line_check_error( + error_type t, + const string_type& opt_ + ) : + dlib::error(t), + opt(opt_) + { set_info_string(); } + + ~cmd_line_check_error() throw() {} + + void set_info_string ( + ) + { + std::ostringstream sout; + switch (type) + { + case EINVALID_OPTION_ARG: + sout << "Command line error: '" << narrow(arg) << "' is not a valid argument to " + << "the '" << narrow(opt) << "' option."; + break; + case EMISSING_REQUIRED_OPTION: + if (required_opts.size() == 1) + { + sout << "Command line error: The '" << narrow(opt) << "' option requires the presence of " + << "the '" << required_opts[0] << "' option."; + } + else + { + sout << "Command line error: The '" << narrow(opt) << "' option requires the presence of " + << "one of the following options: "; + for (unsigned long i = 0; i < required_opts.size(); ++i) + { + if (i == required_opts.size()-2) + sout << "'" << required_opts[i] << "' or "; + else if (i == required_opts.size()-1) + sout << "'" << required_opts[i] << "'."; + else + sout << "'" << required_opts[i] << "', "; + } + } + break; + case EINCOMPATIBLE_OPTIONS: + sout << "Command line error: The '" << narrow(opt) << "' and '" << narrow(opt2) + << "' options can not be given together on the command line."; + break; + case EMULTIPLE_OCCURANCES: + sout << "Command line error: The '" << narrow(opt) << "' option can only " + << "be given on the command line once."; + break; + default: + sout << "Command line error."; + break; + } + const_cast(info) = wrap_string(sout.str(),0,0); + } + + public: + const string_type opt; + const string_type opt2; + const string_type arg; + const std::vector required_opts; + }; + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + void check_option_arg_type ( + const string_type& option_name + ) const; + + template < + typename T + > + void check_option_arg_range ( + const string_type& option_name, + const T& first, + const T& last + ) const; + + template < + typename T, + size_t length + > + void check_option_arg_range ( + const string_type& option_name, + const T (&arg_set)[length] + ) const; + + template < + size_t length + > + void check_option_arg_range ( + const string_type& option_name, + const char_type* (&arg_set)[length] + ) const; + + template < + size_t length + > + void check_incompatible_options ( + const char_type* (&option_set)[length] + ) const; + + template < + size_t length + > + void check_one_time_options ( + const char_type* (&option_set)[length] + ) const; + + void check_incompatible_options ( + const string_type& option_name1, + const string_type& option_name2 + ) const; + + template < + size_t length + > + void check_sub_options ( + const string_type& parent_option, + const char_type* (&sub_option_set)[length] + ) const; + + template < + size_t length + > + void check_sub_options ( + const char_type* (&parent_option_set)[length], + const string_type& sub_option + ) const; + + template < + size_t parent_length, + size_t sub_length + > + void check_sub_options ( + const char_type* (&parent_option_set)[parent_length], + const char_type* (&sub_option_set)[sub_length] + ) const; + }; + + template < + typename clp_base + > + inline void swap ( + cmd_line_parser_check_1& a, + cmd_line_parser_check_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + template + void cmd_line_parser_check_1:: + check_option_arg_type ( + const string_type& option_name + ) const + { + try + { + const typename clp_base::option_type& opt = option(option_name); + const unsigned long number_of_arguments = opt.number_of_arguments(); + const unsigned long count = opt.count(); + for (unsigned long i = 0; i < number_of_arguments; ++i) + { + for (unsigned long j = 0; j < count; ++j) + { + string_cast(opt.argument(i,j)); + } + } + } + catch (string_cast_error& e) + { + throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info); + } + } + +// ---------------------------------------------------------------------------------------- + + template + template + void cmd_line_parser_check_1:: + check_option_arg_range ( + const string_type& option_name, + const T& first, + const T& last + ) const + { + try + { + const typename clp_base::option_type& opt = option(option_name); + const unsigned long number_of_arguments = opt.number_of_arguments(); + const unsigned long count = opt.count(); + for (unsigned long i = 0; i < number_of_arguments; ++i) + { + for (unsigned long j = 0; j < count; ++j) + { + T temp(string_cast(opt.argument(i,j))); + if (temp < first || last < temp) + { + throw cmd_line_check_error( + EINVALID_OPTION_ARG, + option_name, + opt.argument(i,j) + ); + } + } + } + } + catch (string_cast_error& e) + { + throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info); + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < typename T, size_t length > + void cmd_line_parser_check_1:: + check_option_arg_range ( + const string_type& option_name, + const T (&arg_set)[length] + ) const + { + try + { + const typename clp_base::option_type& opt = option(option_name); + const unsigned long number_of_arguments = opt.number_of_arguments(); + const unsigned long count = opt.count(); + for (unsigned long i = 0; i < number_of_arguments; ++i) + { + for (unsigned long j = 0; j < count; ++j) + { + T temp(string_cast(opt.argument(i,j))); + size_t k = 0; + for (; k < length; ++k) + { + if (arg_set[k] == temp) + break; + } + if (k == length) + { + throw cmd_line_check_error( + EINVALID_OPTION_ARG, + option_name, + opt.argument(i,j) + ); + } + } + } + } + catch (string_cast_error& e) + { + throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info); + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_1:: + check_option_arg_range ( + const string_type& option_name, + const char_type* (&arg_set)[length] + ) const + { + const typename clp_base::option_type& opt = option(option_name); + const unsigned long number_of_arguments = opt.number_of_arguments(); + const unsigned long count = opt.count(); + for (unsigned long i = 0; i < number_of_arguments; ++i) + { + for (unsigned long j = 0; j < count; ++j) + { + size_t k = 0; + for (; k < length; ++k) + { + if (arg_set[k] == opt.argument(i,j)) + break; + } + if (k == length) + { + throw cmd_line_check_error( + EINVALID_OPTION_ARG, + option_name, + opt.argument(i,j) + ); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_1:: + check_incompatible_options ( + const char_type* (&option_set)[length] + ) const + { + for (size_t i = 0; i < length; ++i) + { + for (size_t j = i+1; j < length; ++j) + { + if (option(option_set[i]).count() > 0 && + option(option_set[j]).count() > 0 ) + { + throw cmd_line_check_error( + EINCOMPATIBLE_OPTIONS, + option_set[i], + option_set[j], + 0 // this argument has no meaning and is only here to make this + // call different from the other constructor + ); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + void cmd_line_parser_check_1:: + check_incompatible_options ( + const string_type& option_name1, + const string_type& option_name2 + ) const + { + if (option(option_name1).count() > 0 && + option(option_name2).count() > 0 ) + { + throw cmd_line_check_error( + EINCOMPATIBLE_OPTIONS, + option_name1, + option_name2, + 0 // this argument has no meaning and is only here to make this + // call different from the other constructor + ); + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_1:: + check_sub_options ( + const string_type& parent_option, + const char_type* (&sub_option_set)[length] + ) const + { + if (option(parent_option).count() == 0) + { + size_t i = 0; + for (; i < length; ++i) + { + if (option(sub_option_set[i]).count() > 0) + break; + } + if (i != length) + { + std::vector vect; + vect.resize(1); + vect[0] = parent_option; + throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_1:: + check_sub_options ( + const char_type* (&parent_option_set)[length], + const string_type& sub_option + ) const + { + // first check if the sub_option is present + if (option(sub_option).count() > 0) + { + // now check if any of the parents are present + bool parents_present = false; + for (size_t i = 0; i < length; ++i) + { + if (option(parent_option_set[i]).count() > 0) + { + parents_present = true; + break; + } + } + + if (!parents_present) + { + std::vector vect(parent_option_set, parent_option_set+length); + throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t parent_length, size_t sub_length > + void cmd_line_parser_check_1:: + check_sub_options ( + const char_type* (&parent_option_set)[parent_length], + const char_type* (&sub_option_set)[sub_length] + ) const + { + // first check if any of the parent options are present + bool parents_present = false; + for (size_t i = 0; i < parent_length; ++i) + { + if (option(parent_option_set[i]).count() > 0) + { + parents_present = true; + break; + } + } + + if (!parents_present) + { + // none of these sub options should be present + size_t i = 0; + for (; i < sub_length; ++i) + { + if (option(sub_option_set[i]).count() > 0) + break; + } + if (i != sub_length) + { + std::vector vect(parent_option_set, parent_option_set+parent_length); + throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_1:: + check_one_time_options ( + const char_type* (&option_set)[length] + ) const + { + size_t i = 0; + for (; i < length; ++i) + { + if (option(option_set[i]).count() > 1) + break; + } + if (i != length) + { + throw cmd_line_check_error( + EMULTIPLE_OCCURANCES, + option_set[i] + ); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CMD_LINE_PARSER_CHECk_1_ + + diff --git a/dlib/cmd_line_parser/cmd_line_parser_check_abstract.h b/dlib/cmd_line_parser/cmd_line_parser_check_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..084cbc8e9527dea029dd804bd334e8dfe7b57c0b --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_check_abstract.h @@ -0,0 +1,323 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CMD_LINE_PARSER_CHECk_ABSTRACT_ +#ifdef DLIB_CMD_LINE_PARSER_CHECk_ABSTRACT_ + + +#include "cmd_line_parser_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename clp_base + > + class cmd_line_parser_check : public clp_base + { + + /*! + REQUIREMENTS ON CLP_BASE + clp_base is an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h + + POINTERS AND REFERENCES TO INTERNAL DATA + None of the functions added by this extension will invalidate pointers + or references to internal data. + + WHAT THIS EXTENSION DOES FOR CMD_LINE_PARSER + This gives a cmd_line_parser object the ability to easily perform various + kinds of validation on the command line input. + !*/ + + + public: + typedef typename clp_base::char_type char_type; + typedef typename clp_base::string_type string_type; + + // exception class + class cmd_line_check_error : public dlib::error + { + public: + const string_type opt; + const string_type opt2; + const string_type arg; + const std::vector required_opts; + }; + + template < + typename T + > + void check_option_arg_type ( + const string_type& option_name + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(option_name) == true + - T is not a pointer type + ensures + - all the arguments for the given option are convertable + by string_cast() to an object of type T. + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EINVALID_OPTION_ARG + - opt == option_name + - arg == the text of the offending argument + !*/ + + template < + typename T + > + void check_option_arg_range ( + const string_type& option_name, + const T& first, + const T& last + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(option_name) == true + - first <= last + - T is not a pointer type + ensures + - all the arguments for the given option are convertable + by string_cast() to an object of type T and the resuting value is + in the range first to last inclusive. + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EINVALID_OPTION_ARG + - opt == option_name + - arg == the text of the offending argument + !*/ + + template < + typename T, + size_t length + > + void check_option_arg_range ( + const string_type& option_name, + const T (&arg_set)[length] + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(option_name) == true + - T is not a pointer type + ensures + - for each argument to the given option: + - this argument is convertable by string_cast() to an object of + type T and the resulting value is equal to some string in the + arg_set array. + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EINVALID_OPTION_ARG + - opt == option_name + - arg == the text of the offending argument + !*/ + + template < + size_t length + > + void check_option_arg_range ( + const string_type& option_name, + const char_type* (&arg_set)[length] + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(option_name) == true + ensures + - for each argument to the given option: + - there is a string in the arg_set array that is equal to this argument. + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EINVALID_OPTION_ARG + - opt == option_name + - arg == the text of the offending argument + !*/ + + template < + size_t length + > + void check_one_time_options ( + const char_type* (&option_set)[length] + ) const; + /*! + requires + - parsed_line() == true + - for all valid i: + - option_is_defined(option_set[i]) == true + ensures + - all the options in the option_set array occur at most once on the + command line. + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EMULTIPLE_OCCURANCES + - opt == the option that occurred more than once on the command line. + !*/ + + void check_incompatible_options ( + const string_type& option_name1, + const string_type& option_name2 + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(option_name1) == true + - option_is_defined(option_name2) == true + ensures + - option(option_name1).count() == 0 || option(option_name2).count() == 0 + (i.e. at most, only one of the options is currently present) + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EINCOMPATIBLE_OPTIONS + - opt == option_name1 + - opt2 == option_name2 + !*/ + + template < + size_t length + > + void check_incompatible_options ( + const char_type* (&option_set)[length] + ) const; + /*! + requires + - parsed_line() == true + - for all valid i: + - option_is_defined(option_set[i]) == true + ensures + - At most only one of the options in the array option_set has a count() + greater than 0. (i.e. at most, only one of the options is currently present) + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EINCOMPATIBLE_OPTIONS + - opt == One of the incompatible options found. + - opt2 == The next incompatible option found. + !*/ + + template < + size_t length + > + void check_sub_options ( + const char_type* (&parent_option_set)[length], + const string_type& sub_option + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(sub_option) == true + - for all valid i: + - option_is_defined(parent_option_set[i] == true + ensures + - if (option(sub_option).count() > 0) then + - At least one of the options in the array parent_option_set has a count() + greater than 0. (i.e. at least one of the options in parent_option_set + is currently present) + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EMISSING_REQUIRED_OPTION + - opt == the first option from the sub_option that is present. + - required_opts == a vector containing everything from parent_option_set. + !*/ + + template < + size_t length + > + void check_sub_options ( + const string_type& parent_option, + const char_type* (&sub_option_set)[length] + ) const; + /*! + requires + - parsed_line() == true + - option_is_defined(parent_option) == true + - for all valid i: + - option_is_defined(sub_option_set[i]) == true + ensures + - if (option(parent_option).count() == 0) then + - for all valid i: + - option(sub_option_set[i]).count() == 0 + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EMISSING_REQUIRED_OPTION + - opt == the first option from the sub_option_set that is present. + - required_opts == a vector that contains only parent_option. + !*/ + + template < + size_t parent_length, + size_t sub_length + > + void check_sub_options ( + const char_type* (&parent_option_set)[parent_length], + const char_type* (&sub_option_set)[sub_length] + ) const; + /*! + requires + - parsed_line() == true + - for all valid i: + - option_is_defined(parent_option_set[i] == true + - for all valid j: + - option_is_defined(sub_option_set[j]) == true + ensures + - for all valid j: + - if (option(sub_option_set[j]).count() > 0) then + - At least one of the options in the array parent_option_set has a count() + greater than 0. (i.e. at least one of the options in parent_option_set + is currently present) + throws + - std::bad_alloc + - cmd_line_check_error + This exception is thrown if the ensures clause could not be satisfied. + The exception's members will be set as follows: + - type == EMISSING_REQUIRED_OPTION + - opt == the first option from the sub_option_set that is present. + - required_opts == a vector containing everything from parent_option_set. + !*/ + + }; + + template < + template clp_base + > + inline void swap ( + cmd_line_parser_check& a, + cmd_line_parser_check& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_CMD_LINE_PARSER_CHECk_ABSTRACT_ + + diff --git a/dlib/cmd_line_parser/cmd_line_parser_check_c.h b/dlib/cmd_line_parser/cmd_line_parser_check_c.h new file mode 100644 index 0000000000000000000000000000000000000000..d74dccdcc02097ab5d051fdf620b959082da8727 --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_check_c.h @@ -0,0 +1,424 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_CHECk_C_ +#define DLIB_CMD_LINE_PARSER_CHECk_C_ + +#include "cmd_line_parser_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include +#include "../interfaces/cmd_line_parser_option.h" +#include "../string.h" + +namespace dlib +{ + + template < + typename clp_check + > + class cmd_line_parser_check_c : public clp_check + { + public: + + typedef typename clp_check::char_type char_type; + typedef typename clp_check::string_type string_type; + + template < + typename T + > + void check_option_arg_type ( + const string_type& option_name + ) const; + + template < + typename T + > + void check_option_arg_range ( + const string_type& option_name, + const T& first, + const T& last + ) const; + + template < + typename T, + size_t length + > + void check_option_arg_range ( + const string_type& option_name, + const T (&arg_set)[length] + ) const; + + template < + size_t length + > + void check_option_arg_range ( + const string_type& option_name, + const char_type* (&arg_set)[length] + ) const; + + template < + size_t length + > + void check_incompatible_options ( + const char_type* (&option_set)[length] + ) const; + + template < + size_t length + > + void check_one_time_options ( + const char_type* (&option_set)[length] + ) const; + + void check_incompatible_options ( + const string_type& option_name1, + const string_type& option_name2 + ) const; + + template < + size_t length + > + void check_sub_options ( + const string_type& parent_option, + const char_type* (&sub_option_set)[length] + ) const; + + template < + size_t length + > + void check_sub_options ( + const char_type* (&parent_option_set)[length], + const string_type& sub_option + ) const; + + template < + size_t parent_length, + size_t sub_length + > + void check_sub_options ( + const char_type* (&parent_option_set)[parent_length], + const char_type* (&sub_option_set)[sub_length] + ) const; + }; + + + template < + typename clp_check + > + inline void swap ( + cmd_line_parser_check_c& a, + cmd_line_parser_check_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + template + void cmd_line_parser_check_c:: + check_option_arg_type ( + const string_type& option_name + ) const + { + COMPILE_TIME_ASSERT(is_pointer_type::value == false); + + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name), + "\tvoid cmd_line_parser_check::check_option_arg_type()" + << "\n\tYou must have already parsed the command line and option_name must be valid." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_name: " << option_name + ); + + clp_check::template check_option_arg_type(option_name); + } + +// ---------------------------------------------------------------------------------------- + + template + template + void cmd_line_parser_check_c:: + check_option_arg_range ( + const string_type& option_name, + const T& first, + const T& last + ) const + { + COMPILE_TIME_ASSERT(is_pointer_type::value == false); + + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name) && + first <= last, + "\tvoid cmd_line_parser_check::check_option_arg_range()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_name: " << option_name + << "\n\tfirst: " << first + << "\n\tlast: " << last + ); + + clp_check::check_option_arg_range(option_name,first,last); + } + +// ---------------------------------------------------------------------------------------- + + template + template < typename T, size_t length > + void cmd_line_parser_check_c:: + check_option_arg_range ( + const string_type& option_name, + const T (&arg_set)[length] + ) const + { + COMPILE_TIME_ASSERT(is_pointer_type::value == false); + + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name), + "\tvoid cmd_line_parser_check::check_option_arg_range()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_name: " << option_name + ); + + clp_check::check_option_arg_range(option_name,arg_set); + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_c:: + check_option_arg_range ( + const string_type& option_name, + const char_type* (&arg_set)[length] + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name), + "\tvoid cmd_line_parser_check::check_option_arg_range()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_name): " << ((this->option_is_defined(option_name))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_name: " << option_name + ); + + clp_check::check_option_arg_range(option_name,arg_set); + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_c:: + check_incompatible_options ( + const char_type* (&option_set)[length] + ) const + { + // make sure requires clause is not broken + for (size_t i = 0; i < length; ++i) + { + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_set[i]), + "\tvoid cmd_line_parser_check::check_incompatible_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_set[i]): " << ((this->option_is_defined(option_set[i]))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_set[i]: " << option_set[i] + << "\n\ti: " << static_cast(i) + ); + + } + clp_check::check_incompatible_options(option_set); + } + +// ---------------------------------------------------------------------------------------- + + template + void cmd_line_parser_check_c:: + check_incompatible_options ( + const string_type& option_name1, + const string_type& option_name2 + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name1) && + this->option_is_defined(option_name2), + "\tvoid cmd_line_parser_check::check_incompatible_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_name1): " << ((this->option_is_defined(option_name1))?"true":"false") + << "\n\toption_is_defined(option_name2): " << ((this->option_is_defined(option_name2))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_name1: " << option_name1 + << "\n\toption_name2: " << option_name2 + ); + + clp_check::check_incompatible_options(option_name1,option_name2); + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_c:: + check_sub_options ( + const string_type& parent_option, + const char_type* (&sub_option_set)[length] + ) const + { + // make sure requires clause is not broken + for (size_t i = 0; i < length; ++i) + { + DLIB_CASSERT( this->option_is_defined(sub_option_set[i]), + "\tvoid cmd_line_parser_check::check_sub_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(sub_option_set[i]): " + << ((this->option_is_defined(sub_option_set[i]))?"true":"false") + << "\n\tsub_option_set[i]: " << sub_option_set[i] + << "\n\ti: " << static_cast(i) + ); + + } + + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(parent_option), + "\tvoid cmd_line_parser_check::check_sub_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(parent_option): " << ((this->option_is_defined(parent_option))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\tparent_option: " << parent_option + ); + clp_check::check_sub_options(parent_option,sub_option_set); + + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_c:: + check_sub_options ( + const char_type* (&parent_option_set)[length], + const string_type& sub_option + ) const + { + // make sure requires clause is not broken + for (size_t i = 0; i < length; ++i) + { + DLIB_CASSERT( this->option_is_defined(parent_option_set[i]), + "\tvoid cmd_line_parser_check::check_sub_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(parent_option_set[i]): " + << ((this->option_is_defined(parent_option_set[i]))?"true":"false") + << "\n\tparent_option_set[i]: " << parent_option_set[i] + << "\n\ti: " << static_cast(i) + ); + + } + + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(sub_option), + "\tvoid cmd_line_parser_check::check_sub_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(sub_option): " << ((this->option_is_defined(sub_option))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\tsub_option: " << sub_option + ); + clp_check::check_sub_options(parent_option_set,sub_option); + + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t parent_length, size_t sub_length > + void cmd_line_parser_check_c:: + check_sub_options ( + const char_type* (&parent_option_set)[parent_length], + const char_type* (&sub_option_set)[sub_length] + ) const + { + // make sure requires clause is not broken + for (size_t i = 0; i < sub_length; ++i) + { + DLIB_CASSERT( this->option_is_defined(sub_option_set[i]), + "\tvoid cmd_line_parser_check::check_sub_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(sub_option_set[i]): " + << ((this->option_is_defined(sub_option_set[i]))?"true":"false") + << "\n\tsub_option_set[i]: " << sub_option_set[i] + << "\n\ti: " << static_cast(i) + ); + } + + for (size_t i = 0; i < parent_length; ++i) + { + DLIB_CASSERT( this->option_is_defined(parent_option_set[i]), + "\tvoid cmd_line_parser_check::check_parent_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(parent_option_set[i]): " + << ((this->option_is_defined(parent_option_set[i]))?"true":"false") + << "\n\tparent_option_set[i]: " << parent_option_set[i] + << "\n\ti: " << static_cast(i) + ); + } + + + + DLIB_CASSERT( this->parsed_line() == true , + "\tvoid cmd_line_parser_check::check_sub_options()" + << "\n\tYou must have parsed the command line before you call this function." + << "\n\tthis: " << this + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + ); + + clp_check::check_sub_options(parent_option_set,sub_option_set); + + } + +// ---------------------------------------------------------------------------------------- + + template + template < size_t length > + void cmd_line_parser_check_c:: + check_one_time_options ( + const char_type* (&option_set)[length] + ) const + { + // make sure requires clause is not broken + for (size_t i = 0; i < length; ++i) + { + DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_set[i]), + "\tvoid cmd_line_parser_check::check_one_time_options()" + << "\n\tSee the requires clause for this function." + << "\n\tthis: " << this + << "\n\toption_is_defined(option_set[i]): " << ((this->option_is_defined(option_set[i]))?"true":"false") + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\toption_set[i]: " << option_set[i] + << "\n\ti: " << static_cast(i) + ); + + } + clp_check::check_one_time_options(option_set); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CMD_LINE_PARSER_CHECk_C_ + diff --git a/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h b/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..92fd18c9b15859df7332282878f5f794aeb17187 --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_kernel_1.h @@ -0,0 +1,764 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_KERNEl_1_ +#define DLIB_CMD_LINE_PARSER_KERNEl_1_ + +#include "../algs.h" +#include +#include +#include "../interfaces/enumerable.h" +#include "../interfaces/cmd_line_parser_option.h" +#include "../assert.h" +#include "../string.h" + +namespace dlib +{ + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + class cmd_line_parser_kernel_1 : public enumerable > + { + /*! + REQUIREMENTS ON map + is an implementation of map/map_kernel_abstract.h + is instantiated to map items of type std::basic_string to void* + + REQUIREMENTS ON sequence + is an implementation of sequence/sequence_kernel_abstract.h and + is instantiated with std::basic_string + + REQUIREMENTS ON sequence2 + is an implementation of sequence/sequence_kernel_abstract.h and + is instantiated with std::basic_string* + + INITIAL VALUE + options.size() == 0 + argv.size() == 0 + have_parsed_line == false + + CONVENTION + have_parsed_line == parsed_line() + argv[index] == operator[](index) + argv.size() == number_of_arguments() + *((option_t*)options[name]) == option(name) + options.is_in_domain(name) == option_is_defined(name) + !*/ + + + + + public: + + typedef charT char_type; + typedef std::basic_string string_type; + typedef cmd_line_parser_option option_type; + + // exception class + class cmd_line_parse_error : public dlib::error + { + void set_info_string ( + ) + { + std::ostringstream sout; + switch (type) + { + case EINVALID_OPTION: + sout << "Command line error: '" << narrow(item) << "' is not a valid option."; + break; + case ETOO_FEW_ARGS: + if (num > 1) + { + sout << "Command line error: The '" << narrow(item) << "' option requires " << num + << " arguments."; + } + else + { + sout << "Command line error: The '" << narrow(item) << "' option requires " << num + << " argument."; + } + break; + case ETOO_MANY_ARGS: + sout << "Command line error: The '" << narrow(item) << "' option does not take any arguments.\n"; + break; + default: + sout << "Command line error."; + break; + } + const_cast(info) = wrap_string(sout.str(),0,0); + } + + public: + cmd_line_parse_error( + error_type t, + const std::basic_string& _item + ) : + dlib::error(t), + item(_item), + num(0) + { set_info_string();} + + cmd_line_parse_error( + error_type t, + const std::basic_string& _item, + unsigned long _num + ) : + dlib::error(t), + item(_item), + num(_num) + { set_info_string();} + + cmd_line_parse_error( + ) : + dlib::error(), + num(0) + { set_info_string();} + + ~cmd_line_parse_error() throw() {} + + const std::basic_string item; + const unsigned long num; + }; + + + private: + + class option_t : public cmd_line_parser_option + { + /*! + INITIAL VALUE + options.size() == 0 + + CONVENTION + name_ == name() + description_ == description() + number_of_arguments_ == number_of_arguments() + options[index] == operator[](index) + num_present == count() + !*/ + + friend class cmd_line_parser_kernel_1; + + public: + + const std::basic_string& name ( + ) const { return name_; } + + const std::basic_string& description ( + ) const { return description_; } + + unsigned long number_of_arguments( + ) const { return number_of_arguments_; } + + unsigned long count ( + ) const { return num_present; } + + const std::basic_string& argument ( + unsigned long arg, + unsigned long N + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( N < count() && arg < number_of_arguments(), + "\tconst string_type& cmd_line_parser_option::argument(unsigned long,unsigned long)" + << "\n\tsee the requires clause of argument()" + << "\n\tthis: " << this + << "\n\tN: " << N + << "\n\targ: " << arg + << "\n\tcount(): " << count() + << "\n\tnumber_of_arguments(): " << number_of_arguments() + ); + + return options[N][arg]; + } + + protected: + + option_t ( + ) : + num_present(0) + {} + + ~option_t() + { + clear(); + } + + private: + + void clear() + /*! + ensures + - #count() == 0 + - clears everything out of options and frees memory + !*/ + { + for (unsigned long i = 0; i < options.size(); ++i) + { + delete [] options[i]; + } + options.clear(); + num_present = 0; + } + + // data members + std::basic_string name_; + std::basic_string description_; + sequence2 options; + unsigned long number_of_arguments_; + unsigned long num_present; + + + + // restricted functions + option_t(option_t&); // copy constructor + option_t& operator=(option_t&); // assignment operator + }; + + // -------------------------- + + public: + + cmd_line_parser_kernel_1 ( + ); + + virtual ~cmd_line_parser_kernel_1 ( + ); + + void clear( + ); + + void parse ( + int argc, + const charT** argv + ); + + void parse ( + int argc, + charT** argv + ) + { + parse(argc, const_cast(argv)); + } + + bool parsed_line( + ) const; + + bool option_is_defined ( + const string_type& name + ) const; + + void add_option ( + const string_type& name, + const string_type& description, + unsigned long number_of_arguments = 0 + ); + + const cmd_line_parser_option& option ( + const string_type& name + ) const; + + unsigned long number_of_arguments( + ) const; + + const string_type& operator[] ( + unsigned long index + ) const; + + void swap ( + cmd_line_parser_kernel_1& item + ); + + // functions from the enumerable interface + bool at_start ( + ) const { return options.at_start(); } + + void reset ( + ) const { options.reset(); } + + bool current_element_valid ( + ) const { return options.current_element_valid(); } + + const cmd_line_parser_option& element ( + ) const { return *reinterpret_cast*>(options.element().value()); } + + cmd_line_parser_option& element ( + ) { return *reinterpret_cast*>(options.element().value()); } + + bool move_next ( + ) const { return options.move_next(); } + + unsigned long size ( + ) const { return options.size(); } + + private: + + // data members + map options; + sequence argv; + bool have_parsed_line; + + // restricted functions + cmd_line_parser_kernel_1(cmd_line_parser_kernel_1&); // copy constructor + cmd_line_parser_kernel_1& operator=(cmd_line_parser_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + inline void swap ( + cmd_line_parser_kernel_1& a, + cmd_line_parser_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + cmd_line_parser_kernel_1:: + cmd_line_parser_kernel_1 ( + ) : + have_parsed_line(false) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + cmd_line_parser_kernel_1:: + ~cmd_line_parser_kernel_1 ( + ) + { + // delete all option_t objects in options + options.reset(); + while (options.move_next()) + { + delete reinterpret_cast(options.element().value()); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + void cmd_line_parser_kernel_1:: + clear( + ) + { + have_parsed_line = false; + argv.clear(); + + + // delete all option_t objects in options + options.reset(); + while (options.move_next()) + { + delete reinterpret_cast(options.element().value()); + } + options.clear(); + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + void cmd_line_parser_kernel_1:: + parse ( + int argc_, + const charT** argv + ) + { + using namespace std; + + // make sure there aren't any arguments hanging around from the last time + // parse was called + this->argv.clear(); + + // make sure that the options have been cleared of any arguments since + // the last time parse() was called + if (have_parsed_line) + { + options.reset(); + while (options.move_next()) + { + reinterpret_cast(options.element().value())->clear(); + } + options.reset(); + } + + // this tells us if we have seen -- on the command line all by itself + // or not. + bool escape = false; + + const unsigned long argc = static_cast(argc_); + try + { + + for (unsigned long i = 1; i < argc; ++i) + { + if (argv[i][0] == _dT(charT,'-') && !escape) + { + // we are looking at the start of an option + + // -------------------------------------------------------------------- + if (argv[i][1] == _dT(charT,'-')) + { + // we are looking at the start of a "long named" option + string_type temp = &argv[i][2]; + string_type first_argument; + typename string_type::size_type pos = temp.find_first_of(_dT(charT,'=')); + // This variable will be 1 if there is an argument supplied via the = sign + // and 0 otherwise. + unsigned long extra_argument = 0; + if (pos != string_type::npos) + { + // there should be an extra argument + extra_argument = 1; + first_argument = temp.substr(pos+1); + temp = temp.substr(0,pos); + } + + // make sure this name is defined + if (!options.is_in_domain(temp)) + { + // the long name is not a valid option + if (argv[i][2] == _dT(charT,'\0')) + { + // there was nothing after the -- on the command line + escape = true; + continue; + } + else + { + // there was something after the command line but it + // wasn't a valid option + throw cmd_line_parse_error(EINVALID_OPTION,temp); + } + } + + + option_t* o = reinterpret_cast(options[temp]); + + // check the number of arguments after this option and make sure + // it is correct + if (argc + extra_argument <= o->number_of_arguments() + i) + { + // there are too few arguments + throw cmd_line_parse_error(ETOO_FEW_ARGS,temp,o->number_of_arguments()); + } + if (extra_argument && first_argument.size() == 0 ) + { + // if there would be exactly the right number of arguments if + // the first_argument wasn't empty + if (argc == o->number_of_arguments() + i) + throw cmd_line_parse_error(ETOO_FEW_ARGS,temp,o->number_of_arguments()); + else + { + // in this case we just ignore the trailing = and parse everything + // the same. + extra_argument = 0; + } + } + // you can't force an option that doesn't have any arguments to take + // one by using the --option=arg syntax + if (extra_argument == 1 && o->number_of_arguments() == 0) + { + throw cmd_line_parse_error(ETOO_MANY_ARGS,temp); + } + + + + + + + // at this point we know that the option is ok and we should + // populate its options object + if (o->number_of_arguments() > 0) + { + + string_type* stemp = new string_type[o->number_of_arguments()]; + unsigned long j = 0; + + // add the argument after the = sign if one is present + if (extra_argument) + { + stemp[0] = first_argument; + ++j; + } + + for (; j < o->number_of_arguments(); ++j) + { + stemp[j] = argv[i+j+1-extra_argument]; + } + o->options.add(o->options.size(),stemp); + } + o->num_present += 1; + + + // adjust the value of i to account for the arguments to + // this option + i += o->number_of_arguments() - extra_argument; + } + // -------------------------------------------------------------------- + else + { + // we are looking at the start of a list of a single char options + + // make sure there is something in this string other than - + if (argv[i][1] == _dT(charT,'\0')) + { + throw cmd_line_parse_error(); + } + + string_type temp = &argv[i][1]; + const typename string_type::size_type num = temp.size(); + for (unsigned long k = 0; k < num; ++k) + { + string_type name; + name = temp[k]; + + + // make sure this name is defined + if (!options.is_in_domain(name)) + { + // the name is not a valid option + throw cmd_line_parse_error(EINVALID_OPTION,name); + } + + option_t* o = reinterpret_cast(options[name]); + + // if there are chars immediately following this option + int delta = 0; + if (num != k+1) + { + delta = 1; + } + + // check the number of arguments after this option and make sure + // it is correct + if (argc + delta <= o->number_of_arguments() + i) + { + // there are too few arguments + std::ostringstream sout; + throw cmd_line_parse_error(ETOO_FEW_ARGS,name,o->number_of_arguments()); + } + + + o->num_present += 1; + + // at this point we know that the option is ok and we should + // populate its options object + if (o->number_of_arguments() > 0) + { + string_type* stemp = new string_type[o->number_of_arguments()]; + if (delta == 1) + { + temp = &argv[i][2+k]; + k = (unsigned long)num; // this ensures that the argument to this + // option isn't going to be treated as a + // list of options + + stemp[0] = temp; + } + for (unsigned long j = 0; j < o->number_of_arguments()-delta; ++j) + { + stemp[j+delta] = argv[i+j+1]; + } + o->options.add(o->options.size(),stemp); + + // adjust the value of i to account for the arguments to + // this option + i += o->number_of_arguments()-delta; + } + } // for (unsigned long k = 0; k < num; ++k) + } + // -------------------------------------------------------------------- + + } + else + { + // this is just a normal argument + string_type temp = argv[i]; + this->argv.add(this->argv.size(),temp); + } + + } + have_parsed_line = true; + + } + catch (...) + { + have_parsed_line = false; + + // clear all the option objects + options.reset(); + while (options.move_next()) + { + reinterpret_cast(options.element().value())->clear(); + } + options.reset(); + + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + bool cmd_line_parser_kernel_1:: + parsed_line( + ) const + { + return have_parsed_line; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + bool cmd_line_parser_kernel_1:: + option_is_defined ( + const string_type& name + ) const + { + return options.is_in_domain(name); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + void cmd_line_parser_kernel_1:: + add_option ( + const string_type& name, + const string_type& description, + unsigned long number_of_arguments + ) + { + option_t* temp = new option_t; + try + { + temp->name_ = name; + temp->description_ = description; + temp->number_of_arguments_ = number_of_arguments; + void* t = temp; + string_type n(name); + options.add(n,t); + }catch (...) { delete temp; throw;} + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + const cmd_line_parser_option& cmd_line_parser_kernel_1:: + option ( + const string_type& name + ) const + { + return *reinterpret_cast*>(options[name]); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + unsigned long cmd_line_parser_kernel_1:: + number_of_arguments( + ) const + { + return argv.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + const std::basic_string& cmd_line_parser_kernel_1:: + operator[] ( + unsigned long index + ) const + { + return argv[index]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename map, + typename sequence, + typename sequence2 + > + void cmd_line_parser_kernel_1:: + swap ( + cmd_line_parser_kernel_1& item + ) + { + options.swap(item.options); + argv.swap(item.argv); + exchange(have_parsed_line,item.have_parsed_line); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CMD_LINE_PARSER_KERNEl_1_ + diff --git a/dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h b/dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..f018ef597175162c34f5f93603f65c61cbdb5b7e --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h @@ -0,0 +1,314 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_ +#ifdef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include +#include "../interfaces/enumerable.h" +#include "../interfaces/cmd_line_parser_option.h" + +namespace dlib +{ + + template < + typename charT + > + class cmd_line_parser : public enumerable > + { + /*! + REQUIREMENTS ON charT + Must be an integral type suitable for storing characters. (e.g. char + or wchar_t) + + INITIAL VALUE + parsed_line() == false + option_is_defined(x) == false, for all values of x + + ENUMERATION ORDER + The enumerator will enumerate over all the options defined in *this + in alphebetical order according to the name of the option. + + POINTERS AND REFERENCES TO INTERNAL DATA + parsed_line(), option_is_defined(), option(), number_of_arguments(), + operator[](), and swap() functions do not invalidate pointers or + references to internal data. All other functions have no such guarantee. + + + WHAT THIS OBJECT REPRESENTS + This object represents a command line parser. + The command lines must match the following BNF. + + command_line ::= { | } [ -- {} ] + program_name ::= + arg ::= any that does not start with - + option_arg ::= + option_name ::= + long_option_name ::= { | - } + options ::= - {} {} | + -- [=] { } + char ::= any character other than - or = + word ::= any string from argv where argv is the second + parameter to main() + sword ::= any suffix of a string from argv where argv is the + second parameter to main() + bword ::= This is an empty string which denotes the begining of a + . + + + Options with arguments: + An option with N arguments will consider the next N swords to be + its arguments. + + so for example, if we have an option o that expects 2 arguments + then the following are a few legal examples: + + program -o arg1 arg2 general_argument + program -oarg1 arg2 general_argument + + arg1 and arg2 are associated with the option o and general_argument + is not. + + Arguments not associated with an option: + An argument that is not associated with an option is considered a + general command line argument and is indexed by operator[] defined + by the cmd_line_parser object. Additionally, if the string + "--" appears in the command line all by itself then all words + following it are considered to be general command line arguments. + + + Consider the following two examples involving a command line and + a cmd_line_parser object called parser. + + Example 1: + command line: program general_arg1 -o arg1 arg2 general_arg2 + Then the following is true (assuming the o option is defined + and takes 2 arguments). + + parser[0] == "general_arg1" + parser[1] == "general_arg2" + parser.number_of_arguments() == 2 + parser.option("o").argument(0) == "arg1" + parser.option("o").argument(1) == "arg2" + parser.option("o").count() == 1 + + Example 2: + command line: program general_arg1 -- -o arg1 arg2 general_arg2 + Then the following is true (the -- causes everything following + it to be treated as a general argument). + + parser[0] == "general_arg1" + parser[1] == "-o" + parser[2] == "arg1" + parser[3] == "arg2" + parser[4] == "general_arg2" + parser.number_of_arguments() == 5 + parser.option("o").count() == 0 + !*/ + + public: + + typedef charT char_type; + typedef std::basic_string string_type; + typedef cmd_line_parser_option option_type; + + // exception class + class cmd_line_parse_error : public dlib::error + { + /*! + GENERAL + This exception is thrown if there is an error detected in a + command line while it is being parsed. You can consult this + object's type and item members to determine the nature of the + error. (note that the type member is inherited from dlib::error). + + INTERPRETING THIS EXCEPTION + - if (type == EINVALID_OPTION) then + - There was an undefined option on the command line + - item == The invalid option that was on the command line + - if (type == ETOO_FEW_ARGS) then + - An option was given on the command line but it was not + supplied with the required number of arguments. + - item == The name of this option. + - num == The number of arguments expected by this option. + - if (type == ETOO_MANY_ARGS) then + - An option was given on the command line such as --option=arg + but this option doesn't take any arguments. + - item == The name of this option. + !*/ + public: + const std::basic_string item; + const unsigned long num; + }; + + // -------------------------- + + cmd_line_parser ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~cmd_line_parser ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void parse ( + int argc, + const charT** argv + ); + /*! + requires + - argv == an array of strings that was obtained from the second argument + of the function main(). + (i.e. argv[0] should be the token, argv[1] should be + an or token, etc...) + - argc == the number of strings in argv + ensures + - parses the command line given by argc and argv + - #parsed_line() == true + - #at_start() == true + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable until clear() + is called successfully + - cmd_line_parse_error + This exception is thrown if there is an error parsing the command line. + If this exception is thrown then #parsed_line() == false and all + options will have their count() set to 0 but otherwise there will + be no effect (i.e. all registered options will remain registered). + !*/ + + void parse ( + int argc, + charT** argv + ); + /*! + This just calls this->parse(argc,argv) and performs the necessary const_cast + on argv. + !*/ + + bool parsed_line( + ) const; + /*! + ensures + - returns true if parse() has been called successfully + - returns false otherwise + !*/ + + bool option_is_defined ( + const string_type& name + ) const; + /*! + ensures + - returns true if the option has been added to the parser object + by calling add_option(name). + - returns false otherwise + !*/ + + void add_option ( + const string_type& name, + const string_type& description, + unsigned long number_of_arguments = 0 + ); + /*! + requires + - parsed_line() == false + - option_is_defined(name) == false + - name does not contain any ' ', '\t', '\n', or '=' characters + - name[0] != '-' + - name.size() > 0 + ensures + - #option_is_defined(name) == true + - #at_start() == true + - #option(name).count() == 0 + - #option(name).description() == description + - #option(name).number_of_arguments() == number_of_arguments + throws + - std::bad_alloc + if this exception is thrown then the add_option() function has no + effect + !*/ + + const option_type& option ( + const string_type& name + ) const; + /*! + requires + - option_is_defined(name) == true + ensures + - returns the option specified by name + !*/ + + unsigned long number_of_arguments( + ) const; + /*! + requires + - parsed_line() == true + ensures + - returns the number of arguments present in the command line. + This count does not include options or their arguments. Only + arguments unrelated to any option are counted. + !*/ + + const string_type& operator[] ( + unsigned long N + ) const; + /*! + requires + - parsed_line() == true + - N < number_of_arguments() + ensures + - returns the Nth command line argument + !*/ + + void swap ( + cmd_line_parser& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + cmd_line_parser(cmd_line_parser&); // copy constructor + cmd_line_parser& operator=(cmd_line_parser&); // assignment operator + + }; + + + template < + typename charT + > + inline void swap ( + cmd_line_parser& a, + cmd_line_parser& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + +} + +#endif // DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_ + diff --git a/dlib/cmd_line_parser/cmd_line_parser_kernel_c.h b/dlib/cmd_line_parser/cmd_line_parser_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..6270adde6e3b9f52f69a2b7b339d34fd2bcf491c --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_kernel_c.h @@ -0,0 +1,203 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_KERNEl_C_ +#define DLIB_CMD_LINE_PARSER_KERNEl_C_ + +#include "cmd_line_parser_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include +#include "../interfaces/cmd_line_parser_option.h" +#include "../string.h" + +namespace dlib +{ + + template < + typename clp_base + > + class cmd_line_parser_kernel_c : public clp_base + { + public: + + typedef typename clp_base::char_type char_type; + typedef typename clp_base::string_type string_type; + typedef typename clp_base::option_type option_type; + + void add_option ( + const string_type& name, + const string_type& description, + unsigned long number_of_arguments = 0 + ); + + const option_type& option ( + const string_type& name + ) const; + + unsigned long number_of_arguments( + ) const; + + const option_type& element ( + ) const; + + option_type& element ( + ); + + const string_type& operator[] ( + unsigned long N + ) const; + + }; + + + template < + typename clp_base + > + inline void swap ( + cmd_line_parser_kernel_c& a, + cmd_line_parser_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + const typename clp_base::string_type& cmd_line_parser_kernel_c:: + operator[] ( + unsigned long N + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true && N < number_of_arguments(), + "\tvoid cmd_line_parser::operator[](unsigned long N)" + << "\n\tYou must specify a valid option and the parser must have run already." + << "\n\tthis: " << this + << "\n\tN: " << N + << "\n\tparsed_line(): " << ((this->parsed_line())?"true":"false") + << "\n\tnumber_of_arguments(): " << number_of_arguments() + ); + + return clp_base::operator[](N); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + void cmd_line_parser_kernel_c:: + add_option ( + const string_type& name, + const string_type& description, + unsigned long number_of_arguments + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == false && + name.size() > 0 && + this->option_is_defined(name) == false && + name.find_first_of(_dT(char_type," \t\n=")) == string_type::npos && + name[0] != '-', + "\tvoid cmd_line_parser::add_option(const string_type&,const string_type&,unsigned long)" + << "\n\tsee the requires clause of add_option()" + << "\n\tthis: " << this + << "\n\tname.size(): " << static_cast(name.size()) + << "\n\tname: \"" << narrow(name) << "\"" + << "\n\tparsed_line(): " << (this->parsed_line()? "true" : "false") + << "\n\tis_option_defined(\"" << narrow(name) << "\"): " << (this->option_is_defined(name)? "true" : "false") + ); + + clp_base::add_option(name,description,number_of_arguments); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + const typename clp_base::option_type& cmd_line_parser_kernel_c:: + option ( + const string_type& name + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->option_is_defined(name) == true, + "\toption cmd_line_parser::option(const string_type&)" + << "\n\tto get an option it must be defined by a call to add_option()" + << "\n\tthis: " << this + << "\n\tname: \"" << narrow(name) << "\"" + ); + + return clp_base::option(name); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + unsigned long cmd_line_parser_kernel_c:: + number_of_arguments( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->parsed_line() == true , + "\tunsigned long cmd_line_parser::number_of_arguments()" + << "\n\tyou must parse the command line before you can find out how many arguments it has" + << "\n\tthis: " << this + ); + + return clp_base::number_of_arguments(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + const typename clp_base::option_type& cmd_line_parser_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst cmd_line_parser_option& cmd_line_parser::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return clp_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + typename clp_base::option_type& cmd_line_parser_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tcmd_line_parser_option& cmd_line_parser::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return clp_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CMD_LINE_PARSER_KERNEl_C_ + diff --git a/dlib/cmd_line_parser/cmd_line_parser_print_1.h b/dlib/cmd_line_parser/cmd_line_parser_print_1.h new file mode 100644 index 0000000000000000000000000000000000000000..23dea79f97d7e524d183561106ed98faef32c194 --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_print_1.h @@ -0,0 +1,162 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_PRINt_1_ +#define DLIB_CMD_LINE_PARSER_PRINt_1_ + +#include "cmd_line_parser_print_abstract.h" +#include "../algs.h" +#include "../string.h" +#include +#include +#include + +namespace dlib +{ + + template < + typename clp_base + > + class cmd_line_parser_print_1 : public clp_base + { + + public: + + void print_options ( + std::basic_ostream& out + ); + + }; + + template < + typename clp_base + > + inline void swap ( + cmd_line_parser_print_1& a, + cmd_line_parser_print_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename clp_base + > + void cmd_line_parser_print_1:: + print_options ( + std::basic_ostream& out + ) + { + typedef typename clp_base::char_type ct; + typedef std::basic_string string; + typedef typename string::size_type size_type; + + try + { + + out << _dT(ct,"Options:"); + + size_type max_len = 0; + this->reset(); + + // this loop here is just the bottom loop but without the print statements. + // I'm doing this to figure out what len should be. + while (this->move_next()) + { + size_type len = 0; + len += 3; + if (this->element().name().size() > 1) + { + ++len; + } + len += this->element().name().size(); + + if (this->element().number_of_arguments() == 1) + { + len += 6; + } + else + { + for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i) + { + len += 7; + if (i+1 > 9) + ++len; + } + } + + len += 3; + if (len < 33) + max_len = std::max(max_len,len); + } + + + + + + + this->reset(); + + while (this->move_next()) + { + size_type len = 0; + out << _dT(ct,"\n -"); + len += 3; + if (this->element().name().size() > 1) + { + out << _dT(ct,"-"); + ++len; + } + out << this->element().name(); + len += this->element().name().size(); + + if (this->element().number_of_arguments() == 1) + { + out << _dT(ct," "); + len += 6; + } + else + { + for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i) + { + out << _dT(ct," "); + len += 7; + if (i+1 > 9) + ++len; + } + } + + out << " "; + len += 3; + + while (len < max_len) + { + ++len; + out << " "; + } + + const unsigned long ml = static_cast(max_len); + // now print the description but make it wrap around nicely if it + // is to long to fit on one line. + if (len <= max_len) + out << wrap_string(this->element().description(),0,ml); + else + out << "\n" << wrap_string(this->element().description(),ml,ml); + } + this->reset(); + } + catch (...) + { + this->reset(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CMD_LINE_PARSER_PRINt_1_ + diff --git a/dlib/cmd_line_parser/cmd_line_parser_print_abstract.h b/dlib/cmd_line_parser/cmd_line_parser_print_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..121215bdd88c26121e2fd0fa466e4f9b71dffadd --- /dev/null +++ b/dlib/cmd_line_parser/cmd_line_parser_print_abstract.h @@ -0,0 +1,65 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CMD_LINE_PARSER_PRINt_ABSTRACT_ +#ifdef DLIB_CMD_LINE_PARSER_PRINt_ABSTRACT_ + + +#include "cmd_line_parser_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename clp_base + > + class cmd_line_parser_print : public clp_base + { + + /*! + REQUIREMENTS ON CLP_BASE + clp_base is an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h + + + POINTERS AND REFERENCES TO INTERNAL DATA + The print_options() function may invalidate pointers or references to + internal data. + + + WHAT THIS EXTENSION DOES FOR CMD_LINE_PARSER + This gives a cmd_line_parser object the ability to print its options + in a nice format that fits into a console screen. + !*/ + + + public: + + void print_options ( + std::basic_ostream& out + ) const; + /*! + ensures + - prints all the command line options to out. + - #at_start() == true + throws + - any exception. + if an exception is thrown then #at_start() == true but otherwise + it will have no effect on the state of #*this. + !*/ + }; + + template < + typename clp_base + > + inline void swap ( + cmd_line_parser_print& a, + cmd_line_parser_print& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_CMD_LINE_PARSER_PRINt_ABSTRACT_ + diff --git a/dlib/compress_stream.h b/dlib/compress_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..5ae5bb93a08dba9ba7ca67f4e2749ad4c1efca15 --- /dev/null +++ b/dlib/compress_stream.h @@ -0,0 +1,133 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_COMPRESS_STREAm_ +#define DLIB_COMPRESS_STREAm_ + +#include "compress_stream/compress_stream_kernel_1.h" +#include "compress_stream/compress_stream_kernel_2.h" +#include "compress_stream/compress_stream_kernel_3.h" + +#include "conditioning_class.h" +#include "entropy_encoder.h" +#include "entropy_decoder.h" + +#include "entropy_encoder_model.h" +#include "entropy_decoder_model.h" +#include "lz77_buffer.h" +#include "sliding_buffer.h" +#include "lzp_buffer.h" +#include "crc32.h" + + +namespace dlib +{ + + class compress_stream + { + compress_stream() {} + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_1b fce1; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_1b fcd1; + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2b fce2; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2b fcd2; + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_3b fce3; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_3b fcd3; + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4a fce4a; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4a fcd4a; + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4b fce4b; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4b fcd4b; + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5a fce5a; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5a fcd5a; + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5b fce5b; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5b fcd5b; + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5c fce5c; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5c fcd5c; + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_6a fce6; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_6a fcd6; + + + typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2d fce2d; + typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2d fcd2d; + + typedef sliding_buffer::kernel_1a sliding_buffer1; + typedef lz77_buffer::kernel_2a lz77_buffer2a; + + + typedef lzp_buffer::kernel_1a lzp_buf_1; + typedef lzp_buffer::kernel_2a lzp_buf_2; + + + typedef entropy_encoder_model<513,entropy_encoder::kernel_2a>::kernel_1b fce_length; + typedef entropy_decoder_model<513,entropy_decoder::kernel_2a>::kernel_1b fcd_length; + + typedef entropy_encoder_model<65534,entropy_encoder::kernel_2a>::kernel_1b fce_length_2; + typedef entropy_decoder_model<65534,entropy_decoder::kernel_2a>::kernel_1b fcd_length_2; + + + typedef entropy_encoder_model<32257,entropy_encoder::kernel_2a>::kernel_1b fce_index; + typedef entropy_decoder_model<32257,entropy_decoder::kernel_2a>::kernel_1b fcd_index; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef compress_stream_kernel_1 + kernel_1a; + + // kernel_1b + typedef compress_stream_kernel_1 + kernel_1b; + + // kernel_1c + typedef compress_stream_kernel_1 + kernel_1c; + + // kernel_1da + typedef compress_stream_kernel_1 + kernel_1da; + + // kernel_1ea + typedef compress_stream_kernel_1 + kernel_1ea; + + // kernel_1db + typedef compress_stream_kernel_1 + kernel_1db; + + // kernel_1eb + typedef compress_stream_kernel_1 + kernel_1eb; + + // kernel_1ec + typedef compress_stream_kernel_1 + kernel_1ec; + + + + + // kernel_2a + typedef compress_stream_kernel_2 + kernel_2a; + + + + + // kernel_3a + typedef compress_stream_kernel_3 + kernel_3a; + // kernel_3b + typedef compress_stream_kernel_3 + kernel_3b; + + + }; +} + +#endif // DLIB_COMPRESS_STREAm_ + diff --git a/dlib/compress_stream/compress_stream_kernel_1.h b/dlib/compress_stream/compress_stream_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..dbeed3425cf433b380105b86fcaca5ec2eb40faf --- /dev/null +++ b/dlib/compress_stream/compress_stream_kernel_1.h @@ -0,0 +1,245 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_COMPRESS_STREAM_KERNEl_1_ +#define DLIB_COMPRESS_STREAM_KERNEl_1_ + +#include "../algs.h" +#include +#include +#include "compress_stream_kernel_abstract.h" + +namespace dlib +{ + + template < + typename fce, + typename fcd, + typename crc32 + > + class compress_stream_kernel_1 + { + /*! + REQUIREMENTS ON fce + is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h + the alphabet_size of fce must be 257. + fce and fcd share the same kernel number. + + REQUIREMENTS ON fcd + is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h + the alphabet_size of fcd must be 257. + fce and fcd share the same kernel number. + + REQUIREMENTS ON crc32 + is an implementation of crc32/crc32_kernel_abstract.h + + + + INITIAL VALUE + this object has no state + + CONVENTION + this object has no state + !*/ + + const static unsigned long eof_symbol = 256; + + public: + + class decompression_error : public dlib::error + { + public: + decompression_error( + const std::string& i + ) : + dlib::error(i) + {} + }; + + + compress_stream_kernel_1 ( + ) + {} + + ~compress_stream_kernel_1 ( + ) + {} + + void compress ( + std::istream& in, + std::ostream& out + ) const; + + void decompress ( + std::istream& in, + std::ostream& out + ) const; + + private: + + // restricted functions + compress_stream_kernel_1(compress_stream_kernel_1&); // copy constructor + compress_stream_kernel_1& operator=(compress_stream_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename fce, + typename fcd, + typename crc32 + > + void compress_stream_kernel_1:: + compress ( + std::istream& in_, + std::ostream& out_ + ) const + { + std::streambuf::int_type temp; + + std::streambuf& in = *in_.rdbuf(); + + typename fce::entropy_encoder_type coder; + coder.set_stream(out_); + + fce model(coder); + + crc32 crc; + + unsigned long count = 0; + + while (true) + { + // write out a known value every 20000 symbols + if (count == 20000) + { + count = 0; + coder.encode(1500,1501,8000); + } + ++count; + + // get the next character + temp = in.sbumpc(); + + // if we have hit EOF then encode the marker symbol + if (temp != EOF) + { + // encode the symbol + model.encode(static_cast(temp)); + crc.add(static_cast(temp)); + continue; + } + else + { + model.encode(eof_symbol); + + // now write the checksum + unsigned long checksum = crc.get_checksum(); + unsigned char byte1 = static_cast((checksum>>24)&0xFF); + unsigned char byte2 = static_cast((checksum>>16)&0xFF); + unsigned char byte3 = static_cast((checksum>>8)&0xFF); + unsigned char byte4 = static_cast((checksum)&0xFF); + + model.encode(byte1); + model.encode(byte2); + model.encode(byte3); + model.encode(byte4); + + break; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename fce, + typename fcd, + typename crc32 + > + void compress_stream_kernel_1:: + decompress ( + std::istream& in_, + std::ostream& out_ + ) const + { + + std::streambuf& out = *out_.rdbuf(); + + typename fcd::entropy_decoder_type coder; + coder.set_stream(in_); + + fcd model(coder); + + unsigned long symbol; + unsigned long count = 0; + + crc32 crc; + + // decode until we hit the marker symbol + while (true) + { + // make sure this is the value we expect + if (count == 20000) + { + if (coder.get_target(8000) != 1500) + { + throw decompression_error("Error detected in compressed data stream."); + } + count = 0; + coder.decode(1500,1501); + } + ++count; + + // decode the next symbol + model.decode(symbol); + if (symbol != eof_symbol) + { + crc.add(static_cast(symbol)); + // write this symbol to out + if (out.sputc(static_cast(symbol)) != static_cast(symbol)) + { + throw std::ios::failure("error occurred in compress_stream_kernel_1::decompress"); + } + continue; + } + else + { + // we read eof from the encoded data. now we just have to check the checksum and we are done. + unsigned char byte1; + unsigned char byte2; + unsigned char byte3; + unsigned char byte4; + + model.decode(symbol); byte1 = static_cast(symbol); + model.decode(symbol); byte2 = static_cast(symbol); + model.decode(symbol); byte3 = static_cast(symbol); + model.decode(symbol); byte4 = static_cast(symbol); + + unsigned long checksum = byte1; + checksum <<= 8; + checksum |= byte2; + checksum <<= 8; + checksum |= byte3; + checksum <<= 8; + checksum |= byte4; + + if (checksum != crc.get_checksum()) + throw decompression_error("Error detected in compressed data stream."); + + break; + } + } // while (true) + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_COMPRESS_STREAM_KERNEl_1_ + diff --git a/dlib/compress_stream/compress_stream_kernel_2.h b/dlib/compress_stream/compress_stream_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..833b43e67036fa663306896edbcb719bbfcfc745 --- /dev/null +++ b/dlib/compress_stream/compress_stream_kernel_2.h @@ -0,0 +1,419 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_COMPRESS_STREAM_KERNEl_2_ +#define DLIB_COMPRESS_STREAM_KERNEl_2_ + +#include "../algs.h" +#include +#include +#include "compress_stream_kernel_abstract.h" + +namespace dlib +{ + + template < + typename fce, + typename fcd, + typename lz77_buffer, + typename sliding_buffer, + typename fce_length, + typename fcd_length, + typename fce_index, + typename fcd_index, + typename crc32 + > + class compress_stream_kernel_2 + { + /*! + REQUIREMENTS ON fce + is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h + the alphabet_size of fce must be 257. + fce and fcd share the same kernel number. + + REQUIREMENTS ON fcd + is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h + the alphabet_size of fcd must be 257. + fce and fcd share the same kernel number. + + REQUIREMENTS ON lz77_buffer + is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h + + REQUIREMENTS ON sliding_buffer + is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h + is instantiated with T = unsigned char + + REQUIREMENTS ON fce_length + is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h + the alphabet_size of fce must be 513. This will be used to encode the length of lz77 matches. + fce_length and fcd share the same kernel number. + + REQUIREMENTS ON fcd_length + is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h + the alphabet_size of fcd must be 513. This will be used to decode the length of lz77 matches. + fce_length and fcd share the same kernel number. + + REQUIREMENTS ON fce_index + is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h + the alphabet_size of fce must be 32257. This will be used to encode the index of lz77 matches. + fce_index and fcd share the same kernel number. + + REQUIREMENTS ON fcd_index + is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h + the alphabet_size of fcd must be 32257. This will be used to decode the index of lz77 matches. + fce_index and fcd share the same kernel number. + + REQUIREMENTS ON crc32 + is an implementation of crc32/crc32_kernel_abstract.h + + INITIAL VALUE + this object has no state + + CONVENTION + this object has no state + !*/ + + const static unsigned long eof_symbol = 256; + + public: + + class decompression_error : public dlib::error + { + public: + decompression_error( + const std::string& i + ) : + dlib::error(i) + {} + }; + + + compress_stream_kernel_2 ( + ) + {} + + ~compress_stream_kernel_2 ( + ) + {} + + void compress ( + std::istream& in, + std::ostream& out + ) const; + + void decompress ( + std::istream& in, + std::ostream& out + ) const; + + private: + + // restricted functions + compress_stream_kernel_2(compress_stream_kernel_2&); // copy constructor + compress_stream_kernel_2& operator=(compress_stream_kernel_2&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename fce, + typename fcd, + typename lz77_buffer, + typename sliding_buffer, + typename fce_length, + typename fcd_length, + typename fce_index, + typename fcd_index, + typename crc32 + > + void compress_stream_kernel_2:: + compress ( + std::istream& in_, + std::ostream& out_ + ) const + { + std::streambuf::int_type temp; + + std::streambuf& in = *in_.rdbuf(); + + typename fce::entropy_encoder_type coder; + coder.set_stream(out_); + + fce model(coder); + fce_length model_length(coder); + fce_index model_index(coder); + + const unsigned long LOOKAHEAD_LIMIT = 512; + lz77_buffer buffer(15,LOOKAHEAD_LIMIT); + + crc32 crc; + + + unsigned long count = 0; + + unsigned long lz77_count = 1; // number of times we used lz77 to encode + unsigned long ppm_count = 1; // number of times we used ppm to encode + + + while (true) + { + // write out a known value every 20000 symbols + if (count == 20000) + { + count = 0; + coder.encode(150,151,400); + } + ++count; + + // try to fill the lookahead buffer + if (buffer.get_lookahead_buffer_size() < buffer.get_lookahead_buffer_limit()) + { + temp = in.sbumpc(); + while (temp != EOF) + { + crc.add(static_cast(temp)); + buffer.add(static_cast(temp)); + if (buffer.get_lookahead_buffer_size() == buffer.get_lookahead_buffer_limit()) + break; + temp = in.sbumpc(); + } + } + + // compute the sum of ppm_count and lz77_count but make sure + // it is less than 65536 + unsigned long sum = ppm_count + lz77_count; + if (sum >= 65536) + { + ppm_count >>= 1; + lz77_count >>= 1; + ppm_count |= 1; + lz77_count |= 1; + sum = ppm_count+lz77_count; + } + + // if there are still more symbols in the lookahead buffer to encode + if (buffer.get_lookahead_buffer_size() > 0) + { + unsigned long match_index, match_length; + buffer.find_match(match_index,match_length,6); + if (match_length != 0) + { + + // signal the decoder that we are using lz77 + coder.encode(0,lz77_count,sum); + ++lz77_count; + + // encode the index and length pair + model_index.encode(match_index); + model_length.encode(match_length); + + } + else + { + + // signal the decoder that we are using ppm + coder.encode(lz77_count,sum,sum); + ++ppm_count; + + // encode the symbol using the ppm model + model.encode(buffer.lookahead_buffer(0)); + buffer.shift_buffers(1); + } + } + else + { + // signal the decoder that we are using ppm + coder.encode(lz77_count,sum,sum); + + + model.encode(eof_symbol); + // now write the checksum + unsigned long checksum = crc.get_checksum(); + unsigned char byte1 = static_cast((checksum>>24)&0xFF); + unsigned char byte2 = static_cast((checksum>>16)&0xFF); + unsigned char byte3 = static_cast((checksum>>8)&0xFF); + unsigned char byte4 = static_cast((checksum)&0xFF); + + model.encode(byte1); + model.encode(byte2); + model.encode(byte3); + model.encode(byte4); + + break; + } + } // while (true) + } + +// ---------------------------------------------------------------------------------------- + + template < + typename fce, + typename fcd, + typename lz77_buffer, + typename sliding_buffer, + typename fce_length, + typename fcd_length, + typename fce_index, + typename fcd_index, + typename crc32 + > + void compress_stream_kernel_2:: + decompress ( + std::istream& in_, + std::ostream& out_ + ) const + { + + std::streambuf& out = *out_.rdbuf(); + + typename fcd::entropy_decoder_type coder; + coder.set_stream(in_); + + fcd model(coder); + fcd_length model_length(coder); + fcd_index model_index(coder); + + unsigned long symbol; + unsigned long count = 0; + + sliding_buffer buffer; + buffer.set_size(15); + + crc32 crc; + + unsigned long lz77_count = 1; // number of times we used lz77 to encode + unsigned long ppm_count = 1; // number of times we used ppm to encode + bool next_block_lz77; + + + // decode until we hit the marker symbol + while (true) + { + // make sure this is the value we expect + if (count == 20000) + { + if (coder.get_target(400) != 150) + { + throw decompression_error("Error detected in compressed data stream."); + } + count = 0; + coder.decode(150,151); + } + ++count; + + + // compute the sum of ppm_count and lz77_count but make sure + // it is less than 65536 + unsigned long sum = ppm_count + lz77_count; + if (sum >= 65536) + { + ppm_count >>= 1; + lz77_count >>= 1; + ppm_count |= 1; + lz77_count |= 1; + sum = ppm_count+lz77_count; + } + + // check if we are decoding a lz77 or ppm block + if (coder.get_target(sum) < lz77_count) + { + coder.decode(0,lz77_count); + next_block_lz77 = true; + ++lz77_count; + } + else + { + coder.decode(lz77_count,sum); + next_block_lz77 = false; + ++ppm_count; + } + + + if (next_block_lz77) + { + + unsigned long match_length, match_index; + // decode the match index + model_index.decode(match_index); + + // decode the match length + model_length.decode(match_length); + + + match_index += match_length; + buffer.rotate_left(match_length); + for (unsigned long i = 0; i < match_length; ++i) + { + unsigned char ch = buffer[match_index-i]; + buffer[match_length-i-1] = ch; + + crc.add(ch); + // write this ch to out + if (out.sputc(static_cast(ch)) != static_cast(ch)) + { + throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress"); + } + } + + } + else + { + + // decode the next symbol + model.decode(symbol); + if (symbol != eof_symbol) + { + buffer.rotate_left(1); + buffer[0] = static_cast(symbol); + + + crc.add(static_cast(symbol)); + // write this symbol to out + if (out.sputc(static_cast(symbol)) != static_cast(symbol)) + { + throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress"); + } + } + else + { + // this was the eof marker symbol so we are done. now check the checksum + + // now get the checksum and make sure it matches + unsigned char byte1; + unsigned char byte2; + unsigned char byte3; + unsigned char byte4; + + model.decode(symbol); byte1 = static_cast(symbol); + model.decode(symbol); byte2 = static_cast(symbol); + model.decode(symbol); byte3 = static_cast(symbol); + model.decode(symbol); byte4 = static_cast(symbol); + + unsigned long checksum = byte1; + checksum <<= 8; + checksum |= byte2; + checksum <<= 8; + checksum |= byte3; + checksum <<= 8; + checksum |= byte4; + + if (checksum != crc.get_checksum()) + throw decompression_error("Error detected in compressed data stream."); + + break; + } + } + + } // while (true) + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_COMPRESS_STREAM_KERNEl_2_ + diff --git a/dlib/compress_stream/compress_stream_kernel_3.h b/dlib/compress_stream/compress_stream_kernel_3.h new file mode 100644 index 0000000000000000000000000000000000000000..5df6d08c1da394d2414c6edc618fd58c312bb59a --- /dev/null +++ b/dlib/compress_stream/compress_stream_kernel_3.h @@ -0,0 +1,375 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_COMPRESS_STREAM_KERNEl_3_ +#define DLIB_COMPRESS_STREAM_KERNEl_3_ + +#include "../algs.h" +#include "compress_stream_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename lzp_buf, + typename crc32, + unsigned long buffer_size + > + class compress_stream_kernel_3 + { + /*! + REQUIREMENTS ON lzp_buf + is an implementation of lzp_buffer/lzp_buffer_kernel_abstract.h + + REQUIREMENTS ON buffer_size + 10 < buffer_size < 32 + + REQUIREMENTS ON crc32 + is an implementation of crc32/crc32_kernel_abstract.h + + + INITIAL VALUE + this object has no state + + CONVENTION + this object has no state + + + This implementation uses the lzp_buffer and writes out matches + in a byte aligned format. + + !*/ + + + public: + + class decompression_error : public dlib::error + { + public: + decompression_error( + const std::string& i + ) : + dlib::error(i) + {} + }; + + + compress_stream_kernel_3 ( + ) + { + COMPILE_TIME_ASSERT(10 < buffer_size && buffer_size < 32); + } + + ~compress_stream_kernel_3 ( + ) + {} + + void compress ( + std::istream& in, + std::ostream& out + ) const; + + void decompress ( + std::istream& in, + std::ostream& out + ) const; + + + + private: + + inline void write ( + unsigned char symbol + ) const + { + if (out->sputn(reinterpret_cast(&symbol),1)==0) + throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3"); + } + + inline void decode ( + unsigned char& symbol, + unsigned char& flag + ) const + { + if (count == 0) + { + if (((size_t)in->sgetn(reinterpret_cast(buffer),sizeof(buffer)))!=sizeof(buffer)) + throw decompression_error("Error detected in compressed data stream."); + count = 8; + } + --count; + symbol = buffer[8-count]; + flag = buffer[0] >> 7; + buffer[0] <<= 1; + } + + inline void encode ( + unsigned char symbol, + unsigned char flag + ) const + /*! + requires + - 0 <= flag <= 1 + ensures + - writes symbol with the given one bit flag + !*/ + { + // add this symbol and flag to the buffer + ++count; + buffer[0] <<= 1; + buffer[count] = symbol; + buffer[0] |= flag; + + if (count == 8) + { + if (((size_t)out->sputn(reinterpret_cast(buffer),sizeof(buffer)))!=sizeof(buffer)) + throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3"); + count = 0; + buffer[0] = 0; + } + } + + void clear ( + ) const + /*! + ensures + - resets the buffers + !*/ + { + count = 0; + } + + void flush ( + ) const + /*! + ensures + - flushes any data in the buffers to out + !*/ + { + if (count != 0) + { + buffer[0] <<= (8-count); + if (((size_t)out->sputn(reinterpret_cast(buffer),sizeof(buffer)))!=sizeof(buffer)) + throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3"); + } + } + + mutable unsigned int count; + // count tells us how many bytes are buffered in buffer and how many flag + // bit are currently in buffer[0] + mutable unsigned char buffer[9]; + // buffer[0] holds the flag bits to be writen. + // the rest of the buffer holds the bytes to be writen. + + mutable std::streambuf* in; + mutable std::streambuf* out; + + // restricted functions + compress_stream_kernel_3(compress_stream_kernel_3&); // copy constructor + compress_stream_kernel_3& operator=(compress_stream_kernel_3&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename lzp_buf, + typename crc32, + unsigned long buffer_size + > + void compress_stream_kernel_3:: + compress ( + std::istream& in_, + std::ostream& out_ + ) const + { + in = in_.rdbuf(); + out = out_.rdbuf(); + clear(); + + crc32 crc; + + lzp_buf buffer(buffer_size); + + std::streambuf::int_type temp = in->sbumpc(); + unsigned long index; + unsigned char symbol; + unsigned char length; + + while (temp != EOF) + { + symbol = static_cast(temp); + if (buffer.predict_match(index)) + { + if (buffer[index] == symbol) + { + // this is a match so we must find out how long it is + length = 1; + + buffer.add(symbol); + crc.add(symbol); + + temp = in->sbumpc(); + while (length < 255) + { + if (temp == EOF) + { + break; + } + else if (static_cast(length) >= index) + { + break; + } + else if (static_cast(temp) == buffer[index]) + { + ++length; + buffer.add(static_cast(temp)); + crc.add(static_cast(temp)); + temp = in->sbumpc(); + } + else + { + break; + } + } + + encode(length,1); + } + else + { + // this is also not a match + encode(symbol,0); + buffer.add(symbol); + crc.add(symbol); + + // get the next symbol + temp = in->sbumpc(); + } + } + else + { + // there wasn't a match so just write this symbol + encode(symbol,0); + buffer.add(symbol); + crc.add(symbol); + + // get the next symbol + temp = in->sbumpc(); + } + } + + // use a match of zero length to indicate EOF + encode(0,1); + + // now write the checksum + unsigned long checksum = crc.get_checksum(); + unsigned char byte1 = static_cast((checksum>>24)&0xFF); + unsigned char byte2 = static_cast((checksum>>16)&0xFF); + unsigned char byte3 = static_cast((checksum>>8)&0xFF); + unsigned char byte4 = static_cast((checksum)&0xFF); + + encode(byte1,0); + encode(byte2,0); + encode(byte3,0); + encode(byte4,0); + + flush(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename lzp_buf, + typename crc32, + unsigned long buffer_size + > + void compress_stream_kernel_3:: + decompress ( + std::istream& in_, + std::ostream& out_ + ) const + { + in = in_.rdbuf(); + out = out_.rdbuf(); + clear(); + + crc32 crc; + + lzp_buf buffer(buffer_size); + + + unsigned long index = 0; + unsigned char symbol; + unsigned char length; + unsigned char flag; + + decode(symbol,flag); + while (flag == 0 || symbol != 0) + { + buffer.predict_match(index); + + if (flag == 1) + { + length = symbol; + do + { + --length; + symbol = buffer[index]; + write(symbol); + buffer.add(symbol); + crc.add(symbol); + } while (length != 0); + } + else + { + // this is just a literal + write(symbol); + buffer.add(symbol); + crc.add(symbol); + } + decode(symbol,flag); + } + + + // now get the checksum and make sure it matches + unsigned char byte1; + unsigned char byte2; + unsigned char byte3; + unsigned char byte4; + + decode(byte1,flag); + if (flag != 0) + throw decompression_error("Error detected in compressed data stream."); + decode(byte2,flag); + if (flag != 0) + throw decompression_error("Error detected in compressed data stream."); + decode(byte3,flag); + if (flag != 0) + throw decompression_error("Error detected in compressed data stream."); + decode(byte4,flag); + if (flag != 0) + throw decompression_error("Error detected in compressed data stream."); + + unsigned long checksum = byte1; + checksum <<= 8; + checksum |= byte2; + checksum <<= 8; + checksum |= byte3; + checksum <<= 8; + checksum |= byte4; + + if (checksum != crc.get_checksum()) + throw decompression_error("Error detected in compressed data stream."); + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_COMPRESS_STREAM_KERNEl_3_ + diff --git a/dlib/compress_stream/compress_stream_kernel_abstract.h b/dlib/compress_stream/compress_stream_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..f14b501bb3fe186771bdefa982cbaa1c029b8a3f --- /dev/null +++ b/dlib/compress_stream/compress_stream_kernel_abstract.h @@ -0,0 +1,94 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_ +#ifdef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include + +namespace dlib +{ + + class compression_stream + { + /*! + INITIAL VALUE + This object does not have any state associated with it. + + WHAT THIS OBJECT REPRESENTS + This object consists of the two functions compress and decompress. + These functions allow you to compress and decompress data. + !*/ + + public: + + class decompression_error : public dlib::error {}; + + compression_stream ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~compression_stream ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + + void compress ( + std::istream& in, + std::ostream& out + ) const; + /*! + ensures + - reads all data from in (until EOF is reached) and compresses it + and writes it to out + throws + - std::ios_base::failure + if there was a problem writing to out then this exception will + be thrown. + - any other exception + this exception may be thrown if there is any other problem + !*/ + + + void decompress ( + std::istream& in, + std::ostream& out + ) const; + /*! + ensures + - reads data from in, decompresses it and writes it to out. note that + it stops reading data from in when it encounters the end of the + compressed data, not when it encounters EOF. + throws + - std::ios_base::failure + if there was a problem writing to out then this exception will + be thrown. + - decompression_error + if an error was detected in the compressed data that prevented + it from being correctly decompressed then this exception is + thrown. + - any other exception + this exception may be thrown if there is any other problem + !*/ + + + private: + + // restricted functions + compression_stream(compression_stream&); // copy constructor + compression_stream& operator=(compression_stream&); // assignment operator + + }; + +} + +#endif // DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_ + diff --git a/dlib/conditioning_class.h b/dlib/conditioning_class.h new file mode 100644 index 0000000000000000000000000000000000000000..91f82c528565e6b284d7909016b91c0a13d06b8d --- /dev/null +++ b/dlib/conditioning_class.h @@ -0,0 +1,80 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONDITIONING_CLASs_ +#define DLIB_CONDITIONING_CLASs_ + +#include "conditioning_class/conditioning_class_kernel_1.h" +#include "conditioning_class/conditioning_class_kernel_2.h" +#include "conditioning_class/conditioning_class_kernel_3.h" +#include "conditioning_class/conditioning_class_kernel_4.h" +#include "conditioning_class/conditioning_class_kernel_c.h" + + +#include "memory_manager.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size + > + class conditioning_class + { + conditioning_class() {} + + typedef memory_manager::kernel_2b mm; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef conditioning_class_kernel_1 + kernel_1a; + typedef conditioning_class_kernel_c + kernel_1a_c; + + // kernel_2a + typedef conditioning_class_kernel_2 + kernel_2a; + typedef conditioning_class_kernel_c + kernel_2a_c; + + // kernel_3a + typedef conditioning_class_kernel_3 + kernel_3a; + typedef conditioning_class_kernel_c + kernel_3a_c; + + + // -------- kernel_4 --------- + + // kernel_4a + typedef conditioning_class_kernel_4 + kernel_4a; + typedef conditioning_class_kernel_c + kernel_4a_c; + + // kernel_4b + typedef conditioning_class_kernel_4 + kernel_4b; + typedef conditioning_class_kernel_c + kernel_4b_c; + + // kernel_4c + typedef conditioning_class_kernel_4 + kernel_4c; + typedef conditioning_class_kernel_c + kernel_4c_c; + + // kernel_4d + typedef conditioning_class_kernel_4 + kernel_4d; + typedef conditioning_class_kernel_c + kernel_4d_c; + + }; +} + +#endif // DLIB_CONDITIONING_CLASS_ + diff --git a/dlib/conditioning_class/conditioning_class_kernel_1.h b/dlib/conditioning_class/conditioning_class_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..d7dfa74f3a0555de73f4e6f0b4a44c74f7bec673 --- /dev/null +++ b/dlib/conditioning_class/conditioning_class_kernel_1.h @@ -0,0 +1,333 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONDITIONING_CLASS_KERNEl_1_ +#define DLIB_CONDITIONING_CLASS_KERNEl_1_ + +#include "conditioning_class_kernel_abstract.h" +#include "../assert.h" +#include "../algs.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size + > + class conditioning_class_kernel_1 + { + /*! + INITIAL VALUE + total == 1 + counts == pointer to an array of alphabet_size unsigned shorts + for all i except i == alphabet_size-1: counts[i] == 0 + counts[alphabet_size-1] == 1 + + CONVENTION + counts == pointer to an array of alphabet_size unsigned shorts + get_total() == total + get_count(symbol) == counts[symbol] + + LOW_COUNT(symbol) == sum of counts[0] though counts[symbol-1] + or 0 if symbol == 0 + + get_memory_usage() == global_state.memory_usage + !*/ + + public: + + class global_state_type + { + public: + global_state_type () : memory_usage(0) {} + private: + unsigned long memory_usage; + + friend class conditioning_class_kernel_1; + }; + + conditioning_class_kernel_1 ( + global_state_type& global_state_ + ); + + ~conditioning_class_kernel_1 ( + ); + + void clear( + ); + + bool increment_count ( + unsigned long symbol, + unsigned short amount = 1 + ); + + unsigned long get_count ( + unsigned long symbol + ) const; + + unsigned long get_total ( + ) const; + + unsigned long get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const; + + void get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const; + + unsigned long get_memory_usage ( + ) const; + + global_state_type& get_global_state ( + ); + + static unsigned long get_alphabet_size ( + ); + + + private: + + // restricted functions + conditioning_class_kernel_1(conditioning_class_kernel_1&); // copy constructor + conditioning_class_kernel_1& operator=(conditioning_class_kernel_1&); // assignment operator + + // data members + unsigned short total; + unsigned short* counts; + global_state_type& global_state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + conditioning_class_kernel_1:: + conditioning_class_kernel_1 ( + global_state_type& global_state_ + ) : + total(1), + counts(new unsigned short[alphabet_size]), + global_state(global_state_) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 ); + + unsigned short* start = counts; + unsigned short* end = counts+alphabet_size-1; + while (start != end) + { + *start = 0; + ++start; + } + *start = 1; + + // update memory usage + global_state.memory_usage += sizeof(unsigned short)*alphabet_size + + sizeof(conditioning_class_kernel_1); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + conditioning_class_kernel_1:: + ~conditioning_class_kernel_1 ( + ) + { + delete [] counts; + // update memory usage + global_state.memory_usage -= sizeof(unsigned short)*alphabet_size + + sizeof(conditioning_class_kernel_1); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + void conditioning_class_kernel_1:: + clear( + ) + { + total = 1; + unsigned short* start = counts; + unsigned short* end = counts+alphabet_size-1; + while (start != end) + { + *start = 0; + ++start; + } + *start = 1; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_1:: + get_memory_usage( + ) const + { + return global_state.memory_usage; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + typename conditioning_class_kernel_1::global_state_type& conditioning_class_kernel_1:: + get_global_state( + ) + { + return global_state; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + bool conditioning_class_kernel_1:: + increment_count ( + unsigned long symbol, + unsigned short amount + ) + { + // if we are going over a total of 65535 then scale down all counts by 2 + if (static_cast(total)+static_cast(amount) >= 65536) + { + total = 0; + unsigned short* start = counts; + unsigned short* end = counts+alphabet_size; + while (start != end) + { + *start >>= 1; + total += *start; + ++start; + } + // make sure it is at least one + if (counts[alphabet_size-1]==0) + { + ++total; + counts[alphabet_size-1] = 1; + } + } + counts[symbol] += amount; + total += amount; + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_1:: + get_count ( + unsigned long symbol + ) const + { + return counts[symbol]; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_1:: + get_alphabet_size ( + ) + { + return alphabet_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_1:: + get_total ( + ) const + { + return total; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_1:: + get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const + { + if (counts[symbol] == 0) + return 0; + + total_count = total; + + const unsigned short* start = counts; + const unsigned short* end = counts+symbol; + unsigned short high_count_temp = *start; + while (start != end) + { + ++start; + high_count_temp += *start; + } + low_count = high_count_temp - *start; + high_count = high_count_temp; + return *start; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + void conditioning_class_kernel_1:: + get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const + { + unsigned long high_count_temp = *counts; + const unsigned short* start = counts; + while (target >= high_count_temp) + { + ++start; + high_count_temp += *start; + } + + low_count = high_count_temp - *start; + high_count = high_count_temp; + symbol = static_cast(start-counts); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_ + diff --git a/dlib/conditioning_class/conditioning_class_kernel_2.h b/dlib/conditioning_class/conditioning_class_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..9d46d4bdc619cdcf11b4b23f227dd29fb4a59d4c --- /dev/null +++ b/dlib/conditioning_class/conditioning_class_kernel_2.h @@ -0,0 +1,500 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONDITIONING_CLASS_KERNEl_2_ +#define DLIB_CONDITIONING_CLASS_KERNEl_2_ + +#include "conditioning_class_kernel_abstract.h" +#include "../assert.h" +#include "../algs.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size + > + class conditioning_class_kernel_2 + { + /*! + INITIAL VALUE + total == 1 + symbols == pointer to array of alphabet_size data structs + for all i except i == alphabet_size-1: symbols[i].count == 0 + symbols[i].left_count == 0 + + symbols[alphabet_size-1].count == 1 + symbols[alpahbet_size-1].left_count == 0 + + CONVENTION + symbols == pointer to array of alphabet_size data structs + get_total() == total + get_count(symbol) == symbols[symbol].count + + symbols is organized as a tree with symbols[0] as the root. + + the left subchild of symbols[i] is symbols[i*2+1] and + the right subchild is symbols[i*2+2]. + the partent of symbols[i] == symbols[(i-1)/2] + + symbols[i].left_count == the sum of the counts of all the + symbols to the left of symbols[i] + + get_memory_usage() == global_state.memory_usage + !*/ + + public: + + class global_state_type + { + public: + global_state_type () : memory_usage(0) {} + private: + unsigned long memory_usage; + + friend class conditioning_class_kernel_2; + }; + + conditioning_class_kernel_2 ( + global_state_type& global_state_ + ); + + ~conditioning_class_kernel_2 ( + ); + + void clear( + ); + + bool increment_count ( + unsigned long symbol, + unsigned short amount = 1 + ); + + unsigned long get_count ( + unsigned long symbol + ) const; + + inline unsigned long get_total ( + ) const; + + unsigned long get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const; + + void get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const; + + unsigned long get_memory_usage ( + ) const; + + global_state_type& get_global_state ( + ); + + static unsigned long get_alphabet_size ( + ); + + private: + + // restricted functions + conditioning_class_kernel_2(conditioning_class_kernel_2&); // copy constructor + conditioning_class_kernel_2& operator=(conditioning_class_kernel_2&); // assignment operator + + // data members + unsigned short total; + struct data + { + unsigned short count; + unsigned short left_count; + }; + + data* symbols; + global_state_type& global_state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + conditioning_class_kernel_2:: + conditioning_class_kernel_2 ( + global_state_type& global_state_ + ) : + total(1), + symbols(new data[alphabet_size]), + global_state(global_state_) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 ); + + data* start = symbols; + data* end = symbols + alphabet_size-1; + + while (start != end) + { + start->count = 0; + start->left_count = 0; + ++start; + } + + start->count = 1; + start->left_count = 0; + + + // update the left_counts for the symbol alphabet_size-1 + unsigned short temp; + unsigned long symbol = alphabet_size-1; + while (symbol != 0) + { + // temp will be 1 if symbol is odd, 0 if it is even + temp = static_cast(symbol&0x1); + + // set symbol to its parent + symbol = (symbol-1)>>1; + + // note that all left subchidren are odd and also that + // if symbol was a left subchild then we want to increment + // its parents left_count + if (temp) + ++symbols[symbol].left_count; + } + + global_state.memory_usage += sizeof(data)*alphabet_size + + sizeof(conditioning_class_kernel_2); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + conditioning_class_kernel_2:: + ~conditioning_class_kernel_2 ( + ) + { + delete [] symbols; + global_state.memory_usage -= sizeof(data)*alphabet_size + + sizeof(conditioning_class_kernel_2); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + void conditioning_class_kernel_2:: + clear( + ) + { + data* start = symbols; + data* end = symbols + alphabet_size-1; + + total = 1; + + while (start != end) + { + start->count = 0; + start->left_count = 0; + ++start; + } + + start->count = 1; + start->left_count = 0; + + // update the left_counts + unsigned short temp; + unsigned long symbol = alphabet_size-1; + while (symbol != 0) + { + // temp will be 1 if symbol is odd, 0 if it is even + temp = static_cast(symbol&0x1); + + // set symbol to its parent + symbol = (symbol-1)>>1; + + // note that all left subchidren are odd and also that + // if symbol was a left subchild then we want to increment + // its parents left_count + symbols[symbol].left_count += temp; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_2:: + get_memory_usage( + ) const + { + return global_state.memory_usage; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + typename conditioning_class_kernel_2::global_state_type& conditioning_class_kernel_2:: + get_global_state( + ) + { + return global_state; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + bool conditioning_class_kernel_2:: + increment_count ( + unsigned long symbol, + unsigned short amount + ) + { + // if we need to renormalize then do so + if (static_cast(total)+static_cast(amount) >= 65536) + { + unsigned long s; + unsigned short temp; + for (unsigned short i = 0; i < alphabet_size-1; ++i) + { + s = i; + + // divide the count for this symbol by 2 + symbols[i].count >>= 1; + + symbols[i].left_count = 0; + + // bubble this change up though the tree + while (s != 0) + { + // temp will be 1 if symbol is odd, 0 if it is even + temp = static_cast(s&0x1); + + // set s to its parent + s = (s-1)>>1; + + // note that all left subchidren are odd and also that + // if s was a left subchild then we want to increment + // its parents left_count + if (temp) + symbols[s].left_count += symbols[i].count; + } + } + + // update symbols alphabet_size-1 + { + s = alphabet_size-1; + + // divide alphabet_size-1 symbol by 2 if it's > 1 + if (symbols[alphabet_size-1].count > 1) + symbols[alphabet_size-1].count >>= 1; + + // bubble this change up though the tree + while (s != 0) + { + // temp will be 1 if symbol is odd, 0 if it is even + temp = static_cast(s&0x1); + + // set s to its parent + s = (s-1)>>1; + + // note that all left subchidren are odd and also that + // if s was a left subchild then we want to increment + // its parents left_count + if (temp) + symbols[s].left_count += symbols[alphabet_size-1].count; + } + } + + + + + + + // calculate the new total + total = 0; + unsigned long m = 0; + while (m < alphabet_size) + { + total += symbols[m].count + symbols[m].left_count; + m = (m<<1) + 2; + } + + } + + + + + // increment the count for the specified symbol + symbols[symbol].count += amount;; + total += amount; + + + unsigned short temp; + while (symbol != 0) + { + // temp will be 1 if symbol is odd, 0 if it is even + temp = static_cast(symbol&0x1); + + // set symbol to its parent + symbol = (symbol-1)>>1; + + // note that all left subchidren are odd and also that + // if symbol was a left subchild then we want to increment + // its parents left_count + if (temp) + symbols[symbol].left_count += amount; + } + + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_2:: + get_count ( + unsigned long symbol + ) const + { + return symbols[symbol].count; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_2:: + get_alphabet_size ( + ) + { + return alphabet_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_2:: + get_total ( + ) const + { + return total; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_2:: + get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const + { + if (symbols[symbol].count == 0) + return 0; + + unsigned long current = symbol; + total_count = total; + unsigned long high_count_temp = 0; + bool came_from_right = true; + while (true) + { + if (came_from_right) + { + high_count_temp += symbols[current].count + symbols[current].left_count; + } + + // note that if current is even then it is a right child + came_from_right = !(current&0x1); + + if (current == 0) + break; + + // set current to its parent + current = (current-1)>>1 ; + } + + + low_count = high_count_temp - symbols[symbol].count; + high_count = high_count_temp; + + return symbols[symbol].count; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + void conditioning_class_kernel_2:: + get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const + { + unsigned long current = 0; + unsigned long low_count_temp = 0; + + while (true) + { + if (static_cast(target) < symbols[current].left_count) + { + // we should go left + current = (current<<1) + 1; + } + else + { + target -= symbols[current].left_count; + low_count_temp += symbols[current].left_count; + if (static_cast(target) < symbols[current].count) + { + // we have found our target + symbol = current; + high_count = low_count_temp + symbols[current].count; + low_count = low_count_temp; + break; + } + else + { + // go right + target -= symbols[current].count; + low_count_temp += symbols[current].count; + current = (current<<1) + 2; + } + } + + } + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_ + diff --git a/dlib/conditioning_class/conditioning_class_kernel_3.h b/dlib/conditioning_class/conditioning_class_kernel_3.h new file mode 100644 index 0000000000000000000000000000000000000000..41b5f78060799ed5fe5d6a21611fd5ac3853410f --- /dev/null +++ b/dlib/conditioning_class/conditioning_class_kernel_3.h @@ -0,0 +1,438 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONDITIONING_CLASS_KERNEl_3_ +#define DLIB_CONDITIONING_CLASS_KERNEl_3_ + +#include "conditioning_class_kernel_abstract.h" +#include "../assert.h" +#include "../algs.h" + + +namespace dlib +{ + + template < + unsigned long alphabet_size + > + class conditioning_class_kernel_3 + { + /*! + INITIAL VALUE + total == 1 + counts == pointer to an array of alphabet_size data structs + for all i except i == 0: counts[i].count == 0 + counts[0].count == 1 + counts[0].symbol == alphabet_size-1 + for all i except i == alphabet_size-1: counts[i].present == false + counts[alphabet_size-1].present == true + + CONVENTION + counts == pointer to an array of alphabet_size data structs + get_total() == total + get_count(symbol) == counts[x].count where + counts[x].symbol == symbol + + + LOW_COUNT(symbol) == sum of counts[0].count though counts[x-1].count + where counts[x].symbol == symbol + if (counts[0].symbol == symbol) LOW_COUNT(symbol)==0 + + + if (counts[i].count == 0) then + counts[i].symbol == undefined value + + if (symbol has a nonzero count) then + counts[symbol].present == true + + get_memory_usage() == global_state.memory_usage + !*/ + + public: + + class global_state_type + { + public: + global_state_type () : memory_usage(0) {} + private: + unsigned long memory_usage; + + friend class conditioning_class_kernel_3; + }; + + conditioning_class_kernel_3 ( + global_state_type& global_state_ + ); + + ~conditioning_class_kernel_3 ( + ); + + void clear( + ); + + bool increment_count ( + unsigned long symbol, + unsigned short amount = 1 + ); + + unsigned long get_count ( + unsigned long symbol + ) const; + + unsigned long get_total ( + ) const; + + unsigned long get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const; + + void get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const; + + unsigned long get_memory_usage ( + ) const; + + global_state_type& get_global_state ( + ); + + static unsigned long get_alphabet_size ( + ); + + private: + + // restricted functions + conditioning_class_kernel_3(conditioning_class_kernel_3&); // copy constructor + conditioning_class_kernel_3& operator=(conditioning_class_kernel_3&); // assignment operator + + struct data + { + unsigned short count; + unsigned short symbol; + bool present; + }; + + // data members + unsigned short total; + data* counts; + global_state_type& global_state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + conditioning_class_kernel_3:: + conditioning_class_kernel_3 ( + global_state_type& global_state_ + ) : + total(1), + counts(new data[alphabet_size]), + global_state(global_state_) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 ); + + data* start = counts; + data* end = counts+alphabet_size; + start->count = 1; + start->symbol = alphabet_size-1; + start->present = false; + ++start; + while (start != end) + { + start->count = 0; + start->present = false; + ++start; + } + counts[alphabet_size-1].present = true; + + // update memory usage + global_state.memory_usage += sizeof(data)*alphabet_size + + sizeof(conditioning_class_kernel_3); + + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + conditioning_class_kernel_3:: + ~conditioning_class_kernel_3 ( + ) + { + delete [] counts; + // update memory usage + global_state.memory_usage -= sizeof(data)*alphabet_size + + sizeof(conditioning_class_kernel_3); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + void conditioning_class_kernel_3:: + clear( + ) + { + total = 1; + data* start = counts; + data* end = counts+alphabet_size; + start->count = 1; + start->symbol = alphabet_size-1; + start->present = false; + ++start; + while (start != end) + { + start->count = 0; + start->present = false; + ++start; + } + counts[alphabet_size-1].present = true; + + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + typename conditioning_class_kernel_3::global_state_type& conditioning_class_kernel_3:: + get_global_state( + ) + { + return global_state; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_3:: + get_memory_usage( + ) const + { + return global_state.memory_usage; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + bool conditioning_class_kernel_3:: + increment_count ( + unsigned long symbol, + unsigned short amount + ) + { + // if we are going over a total of 65535 then scale down all counts by 2 + if (static_cast(total)+static_cast(amount) >= 65536) + { + total = 0; + data* start = counts; + data* end = counts+alphabet_size; + + while (start != end) + { + if (start->count == 1) + { + if (start->symbol == alphabet_size-1) + { + // this symbol must never be zero so we will leave its count at 1 + ++total; + } + else + { + start->count = 0; + counts[start->symbol].present = false; + } + } + else + { + start->count >>= 1; + total += start->count; + } + + ++start; + } + } + + + data* start = counts; + data* swap_spot = counts; + + if (counts[symbol].present) + { + while (true) + { + if (start->symbol == symbol && start->count!=0) + { + unsigned short temp = start->count + amount; + + start->symbol = swap_spot->symbol; + start->count = swap_spot->count; + + swap_spot->symbol = static_cast(symbol); + swap_spot->count = temp; + break; + } + + if ( (start->count) < (swap_spot->count)) + { + swap_spot = start; + } + + + ++start; + } + } + else + { + counts[symbol].present = true; + while (true) + { + if (start->count == 0) + { + start->symbol = swap_spot->symbol; + start->count = swap_spot->count; + + swap_spot->symbol = static_cast(symbol); + swap_spot->count = amount; + break; + } + + if ((start->count) < (swap_spot->count)) + { + swap_spot = start; + } + + ++start; + } + } + + total += amount; + + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_3:: + get_count ( + unsigned long symbol + ) const + { + if (counts[symbol].present == false) + return 0; + + data* start = counts; + while (start->symbol != symbol) + { + ++start; + } + return start->count; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_3:: + get_alphabet_size ( + ) + { + return alphabet_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_3:: + get_total ( + ) const + { + return total; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + unsigned long conditioning_class_kernel_3:: + get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const + { + if (counts[symbol].present == false) + return 0; + + total_count = total; + unsigned long low_count_temp = 0; + data* start = counts; + while (start->symbol != symbol) + { + low_count_temp += start->count; + ++start; + } + + low_count = low_count_temp; + high_count = low_count_temp + start->count; + return start->count; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size + > + void conditioning_class_kernel_3:: + get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const + { + unsigned long high_count_temp = counts->count; + const data* start = counts; + while (target >= high_count_temp) + { + ++start; + high_count_temp += start->count; + } + + low_count = high_count_temp - start->count; + high_count = high_count_temp; + symbol = static_cast(start->symbol); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONDITIONING_CLASS_KERNEl_3_ + diff --git a/dlib/conditioning_class/conditioning_class_kernel_4.h b/dlib/conditioning_class/conditioning_class_kernel_4.h new file mode 100644 index 0000000000000000000000000000000000000000..9ee6ca50cbbe5a065ca2a4e4b2bb6fc94cdbf57f --- /dev/null +++ b/dlib/conditioning_class/conditioning_class_kernel_4.h @@ -0,0 +1,533 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONDITIONING_CLASS_KERNEl_4_ +#define DLIB_CONDITIONING_CLASS_KERNEl_4_ + +#include "conditioning_class_kernel_abstract.h" +#include "../assert.h" +#include "../algs.h" + +namespace dlib +{ + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + class conditioning_class_kernel_4 + { + /*! + REQUIREMENTS ON pool_size + pool_size > 0 + this will be the number of nodes contained in our memory pool + + REQUIREMENTS ON mem_manager + mem_manager is an implementation of memory_manager/memory_manager_kernel_abstract.h + + INITIAL VALUE + total == 1 + escapes == 1 + next == 0 + + CONVENTION + get_total() == total + get_count(alphabet_size-1) == escapes + + if (next != 0) then + next == pointer to the start of a linked list and the linked list + is terminated by a node with a next pointer of 0. + + get_count(symbol) == node::count for the node where node::symbol==symbol + or 0 if no such node currently exists. + + if (there is a node for the symbol) then + LOW_COUNT(symbol) == the sum of all node's counts in the linked list + up to but not including the node for the symbol. + + get_memory_usage() == global_state.memory_usage + !*/ + + + struct node + { + unsigned short symbol; + unsigned short count; + node* next; + }; + + public: + + class global_state_type + { + public: + global_state_type ( + ) : + memory_usage(pool_size*sizeof(node)+sizeof(global_state_type)) + {} + private: + unsigned long memory_usage; + + typename mem_manager::template rebind::other pool; + + friend class conditioning_class_kernel_4; + }; + + conditioning_class_kernel_4 ( + global_state_type& global_state_ + ); + + ~conditioning_class_kernel_4 ( + ); + + void clear( + ); + + bool increment_count ( + unsigned long symbol, + unsigned short amount = 1 + ); + + unsigned long get_count ( + unsigned long symbol + ) const; + + inline unsigned long get_total ( + ) const; + + unsigned long get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const; + + void get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const; + + unsigned long get_memory_usage ( + ) const; + + global_state_type& get_global_state ( + ); + + static unsigned long get_alphabet_size ( + ); + + + private: + + void half_counts ( + ); + /*! + ensures + - divides all counts by 2 but ensures that escapes is always at least 1 + !*/ + + // restricted functions + conditioning_class_kernel_4(conditioning_class_kernel_4&); // copy constructor + conditioning_class_kernel_4& operator=(conditioning_class_kernel_4&); // assignment operator + + // data members + unsigned short total; + unsigned short escapes; + node* next; + global_state_type& global_state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + conditioning_class_kernel_4:: + conditioning_class_kernel_4 ( + global_state_type& global_state_ + ) : + total(1), + escapes(1), + next(0), + global_state(global_state_) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 ); + + // update memory usage + global_state.memory_usage += sizeof(conditioning_class_kernel_4); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + conditioning_class_kernel_4:: + ~conditioning_class_kernel_4 ( + ) + { + clear(); + // update memory usage + global_state.memory_usage -= sizeof(conditioning_class_kernel_4); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + void conditioning_class_kernel_4:: + clear( + ) + { + total = 1; + escapes = 1; + while (next) + { + node* temp = next; + next = next->next; + global_state.pool.deallocate(temp); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + unsigned long conditioning_class_kernel_4:: + get_memory_usage( + ) const + { + return global_state.memory_usage; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + typename conditioning_class_kernel_4::global_state_type& conditioning_class_kernel_4:: + get_global_state( + ) + { + return global_state; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + bool conditioning_class_kernel_4:: + increment_count ( + unsigned long symbol, + unsigned short amount + ) + { + if (symbol == alphabet_size-1) + { + // make sure we won't cause any overflow + if (total >= 65536 - amount ) + half_counts(); + + escapes += amount; + total += amount; + return true; + } + + + // find the symbol and increment it or add a new node to the list + if (next) + { + node* temp = next; + node* previous = 0; + while (true) + { + if (temp->symbol == static_cast(symbol)) + { + // make sure we won't cause any overflow + if (total >= 65536 - amount ) + half_counts(); + + // we have found the symbol + total += amount; + temp->count += amount; + + // if this node now has a count greater than its parent node + if (previous && temp->count > previous->count) + { + // swap the nodes so that the nodes will be in semi-sorted order + swap(temp->count,previous->count); + swap(temp->symbol,previous->symbol); + } + return true; + } + else if (temp->next == 0) + { + // we did not find the symbol so try to add it to the list + if (global_state.pool.get_number_of_allocations() < pool_size) + { + // make sure we won't cause any overflow + if (total >= 65536 - amount ) + half_counts(); + + node* t = global_state.pool.allocate(); + t->next = 0; + t->symbol = static_cast(symbol); + t->count = amount; + temp->next = t; + total += amount; + return true; + } + else + { + // no memory left + return false; + } + } + else if (temp->count == 0) + { + // remove nodes that have a zero count + if (previous) + { + previous->next = temp->next; + node* t = temp; + temp = temp->next; + global_state.pool.deallocate(t); + } + else + { + next = temp->next; + node* t = temp; + temp = temp->next; + global_state.pool.deallocate(t); + } + } + else + { + previous = temp; + temp = temp->next; + } + } // while (true) + } + // if there aren't any nodes in the list yet then do this instead + else + { + if (global_state.pool.get_number_of_allocations() < pool_size) + { + // make sure we won't cause any overflow + if (total >= 65536 - amount ) + half_counts(); + + next = global_state.pool.allocate(); + next->next = 0; + next->symbol = static_cast(symbol); + next->count = amount; + total += amount; + return true; + } + else + { + // no memory left + return false; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + unsigned long conditioning_class_kernel_4:: + get_count ( + unsigned long symbol + ) const + { + if (symbol == alphabet_size-1) + { + return escapes; + } + else + { + node* temp = next; + while (temp) + { + if (temp->symbol == symbol) + return temp->count; + temp = temp->next; + } + return 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + unsigned long conditioning_class_kernel_4:: + get_alphabet_size ( + ) + { + return alphabet_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + unsigned long conditioning_class_kernel_4:: + get_total ( + ) const + { + return total; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + unsigned long conditioning_class_kernel_4:: + get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const + { + if (symbol != alphabet_size-1) + { + node* temp = next; + unsigned long low = 0; + while (temp) + { + if (temp->symbol == static_cast(symbol)) + { + high_count = temp->count + low; + low_count = low; + total_count = total; + return temp->count; + } + low += temp->count; + temp = temp->next; + } + return 0; + } + else + { + total_count = total; + high_count = total; + low_count = total-escapes; + return escapes; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + void conditioning_class_kernel_4:: + get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const + { + node* temp = next; + unsigned long high = 0; + while (true) + { + if (temp != 0) + { + high += temp->count; + if (target < high) + { + symbol = temp->symbol; + high_count = high; + low_count = high - temp->count; + return; + } + temp = temp->next; + } + else + { + // this must be the escape symbol + symbol = alphabet_size-1; + low_count = total-escapes; + high_count = total; + return; + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + + template < + unsigned long alphabet_size, + unsigned long pool_size, + typename mem_manager + > + void conditioning_class_kernel_4:: + half_counts ( + ) + { + total = 0; + if (escapes > 1) + escapes >>= 1; + + //divide all counts by 2 + node* temp = next; + while (temp) + { + temp->count >>= 1; + total += temp->count; + temp = temp->next; + } + total += escapes; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONDITIONING_CLASS_KERNEl_4_ + diff --git a/dlib/conditioning_class/conditioning_class_kernel_abstract.h b/dlib/conditioning_class/conditioning_class_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..bb3ca9a3040b156d40963b72ce0cf87166cd865a --- /dev/null +++ b/dlib/conditioning_class/conditioning_class_kernel_abstract.h @@ -0,0 +1,228 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_ +#ifdef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size + > + class conditioning_class + { + /*! + REQUIREMENTS ON alphabet_size + 1 < alphabet_size < 65536 + + INITIAL VALUE + get_total() == 1 + get_count(X) == 0 : for all valid values of X except alphabet_size-1 + get_count(alphabet_size-1) == 1 + + WHAT THIS OBJECT REPRESENTS + This object represents a conditioning class used for arithmetic style + compression. It maintains the cumulative counts which are needed + by the entropy_coder and entropy_decoder objects. + + At any moment a conditioning_class object represents a set of + alphabet_size symbols. Each symbol is associated with an integer + called its count. + + All symbols start out with a count of zero except for alphabet_size-1. + This last symbol will always have a count of at least one. It is + intended to be used as an escape into a lower context when coding + and so it must never have a zero probability or the decoder won't + be able to identify the escape symbol. + + NOTATION: + Let MAP(i) be a function which maps integers to symbols. MAP(i) is + one to one and onto. Its domain is 1 to alphabet_size inclusive. + + Let RMAP(s) be the inverse of MAP(i). + ( i.e. RMAP(MAP(i)) == i and MAP(RMAP(s)) == s ) + + Let COUNT(i) give the count for the symbol MAP(i). + ( i.e. COUNT(i) == get_count(MAP(i)) ) + + + Let LOW_COUNT(s) == the sum of COUNT(x) for x == 1 to x == RMAP(s)-1 + (note that the sum of COUNT(x) for x == 1 to x == 0 is 0) + Let HIGH_COUNT(s) == LOW_COUNT(s) + get_count(s) + + + + Basically what this is saying is just that you shoudln't assume you know + what order the symbols are placed in when calculating the cumulative + sums. The specific mapping provided by the MAP() function is unspecified. + + THREAD SAFETY + This object can be used safely in a multithreaded program as long as the + global state is not shared between conditioning classes which run on + different threads. + + GLOBAL_STATE_TYPE + The global_state_type obejct allows instances of the conditioning_class + object to share any kind of global state the implementer desires. + However, the global_state_type object exists primarily to facilitate the + sharing of a memory pool between many instances of a conditioning_class + object. But note that it is not required that there be any kind of + memory pool at all, it is just a possibility. + !*/ + + public: + + class global_state_type + { + global_state_type ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + // my contents are implementation specific. + }; + + conditioning_class ( + global_state_type& global_state + ); + /*! + ensures + - #*this is properly initialized + - &#get_global_state() == &global_state + throws + - std::bad_alloc + !*/ + + ~conditioning_class ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + !*/ + + bool increment_count ( + unsigned long symbol, + unsigned short amount = 1 + ); + /*! + requires + - 0 <= symbol < alphabet_size + - 0 < amount < 32768 + ensures + - if (sufficient memory is available to complete this operation) then + - returns true + - if (get_total()+amount < 65536) then + - #get_count(symbol) == get_count(symbol) + amount + - else + - #get_count(symbol) == get_count(symbol)/2 + amount + - if (get_count(alphabet_size-1) == 1) then + - #get_count(alphabet_size-1) == 1 + - else + - #get_count(alphabet_size-1) == get_count(alphabet_size-1)/2 + - for all X where (X != symbol)&&(X != alpahbet_size-1): + #get_count(X) == get_count(X)/2 + - else + - returns false + !*/ + + unsigned long get_count ( + unsigned long symbol + ) const; + /*! + requires + - 0 <= symbol < alphabet_size + ensures + - returns the count for the specified symbol + !*/ + + unsigned long get_total ( + ) const; + /*! + ensures + - returns the sum of get_count(X) for all valid values of X + (i.e. returns the sum of the counts for all the symbols) + !*/ + + unsigned long get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const; + /*! + requires + - 0 <= symbol < alphabet_size + ensures + - returns get_count(symbol) + - if (get_count(symbol) != 0) then + - #total_count == get_total() + - #low_count == LOW_COUNT(symbol) + - #high_count == HIGH_COUNT(symbol) + - #low_count < #high_count <= #total_count + !*/ + + void get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const; + /*! + requires + - 0 <= target < get_total() + ensures + - LOW_COUNT(#symbol) <= target < HIGH_COUNT(#symbol) + - #low_count == LOW_COUNT(#symbol) + - #high_count == HIGH_COUNT(#symbol) + - #low_count < #high_count <= get_total() + !*/ + + global_state_type& get_global_state ( + ); + /*! + ensures + - returns a reference to the global state used by *this + !*/ + + unsigned long get_memory_usage ( + ) const; + /*! + ensures + - returns the number of bytes of memory allocated by all conditioning_class + objects that share the global state given by get_global_state() + !*/ + + static unsigned long get_alphabet_size ( + ); + /*! + ensures + - returns alphabet_size + !*/ + + private: + + // restricted functions + conditioning_class(conditioning_class&); // copy constructor + conditioning_class& operator=(conditioning_class&); // assignment operator + + }; + +} + +#endif // DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_ + diff --git a/dlib/conditioning_class/conditioning_class_kernel_c.h b/dlib/conditioning_class/conditioning_class_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..00bcb843be790e8ce12d21b0a5f4d99f64cc0974 --- /dev/null +++ b/dlib/conditioning_class/conditioning_class_kernel_c.h @@ -0,0 +1,162 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONDITIONING_CLASS_KERNEl_C_ +#define DLIB_CONDITIONING_CLASS_KERNEl_C_ + +#include "conditioning_class_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename cc_base + > + class conditioning_class_kernel_c : public cc_base + { + const unsigned long alphabet_size; + + public: + + conditioning_class_kernel_c ( + typename cc_base::global_state_type& global_state + ) : cc_base(global_state),alphabet_size(cc_base::get_alphabet_size()) {} + + bool increment_count ( + unsigned long symbol, + unsigned short amount = 1 + ); + + unsigned long get_count ( + unsigned long symbol + ) const; + + unsigned long get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const; + + void get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const; + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename cc_base + > + bool conditioning_class_kernel_c:: + increment_count ( + unsigned long symbol, + unsigned short amount + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(symbol < alphabet_size && + 0 < amount && amount < 32768, + "\tvoid conditioning_class::increment_count()" + << "\n\tthe symbol must be in the range 0 to alphabet_size-1. and" + << "\n\tamount must be in the range 1 to 32767" + << "\n\talphabet_size: " << alphabet_size + << "\n\tsymbol: " << symbol + << "\n\tamount: " << amount + << "\n\tthis: " << this + ); + + // call the real function + return cc_base::increment_count(symbol,amount); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename cc_base + > + unsigned long conditioning_class_kernel_c:: + get_count ( + unsigned long symbol + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(symbol < alphabet_size, + "\tvoid conditioning_class::get_count()" + << "\n\tthe symbol must be in the range 0 to alphabet_size-1" + << "\n\talphabet_size: " << alphabet_size + << "\n\tsymbol: " << symbol + << "\n\tthis: " << this + ); + + // call the real function + return cc_base::get_count(symbol); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename cc_base + > + unsigned long conditioning_class_kernel_c:: + get_range ( + unsigned long symbol, + unsigned long& low_count, + unsigned long& high_count, + unsigned long& total_count + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(symbol < alphabet_size, + "\tvoid conditioning_class::get_range()" + << "\n\tthe symbol must be in the range 0 to alphabet_size-1" + << "\n\talphabet_size: " << alphabet_size + << "\n\tsymbol: " << symbol + << "\n\tthis: " << this + ); + + // call the real function + return cc_base::get_range(symbol,low_count,high_count,total_count); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename cc_base + > + void conditioning_class_kernel_c:: + get_symbol ( + unsigned long target, + unsigned long& symbol, + unsigned long& low_count, + unsigned long& high_count + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( target < this->get_total(), + "\tvoid conditioning_class::get_symbol()" + << "\n\tthe target must be in the range 0 to get_total()-1" + << "\n\tget_total(): " << this->get_total() + << "\n\ttarget: " << target + << "\n\tthis: " << this + ); + + // call the real function + cc_base::get_symbol(target,symbol,low_count,high_count); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONDITIONING_CLASS_KERNEl_C_ + diff --git a/dlib/config_reader.h b/dlib/config_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..de4b9794078cc0ad92ff3bda78fbd853466fc202 --- /dev/null +++ b/dlib/config_reader.h @@ -0,0 +1,64 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONFIG_READEr_ +#define DLIB_CONFIG_READEr_ + +#include "config_reader/config_reader_kernel_1.h" +#include "map.h" +#include "tokenizer.h" + +#include "algs.h" + +#ifndef DLIB_ISO_CPP_ONLY +#include "config_reader/config_reader_thread_safe_1.h" +#endif + +namespace dlib +{ + + + class config_reader + { + config_reader() {} + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef config_reader_kernel_1< + map::kernel_1b, + map::kernel_1b, + tokenizer::kernel_1a + > kernel_1a; + // kernel_1a_c + typedef config_reader_kernel_1< + map::kernel_1b, + map::kernel_1b, + tokenizer::kernel_1a, + true + > kernel_1a_c; + + +#ifndef DLIB_ISO_CPP_ONLY + // thread_safe_1a + typedef config_reader_thread_safe_1< + kernel_1a, + map::kernel_1b, + false + > thread_safe_1a; + + // thread_safe_1a_c + typedef config_reader_thread_safe_1< + kernel_1a_c, + map::kernel_1b, + true + > thread_safe_1a_c; +#endif // DLIB_ISO_CPP_ONLY + + }; + +} + +#endif // DLIB_CONFIG_READEr_ + diff --git a/dlib/config_reader/config_reader_kernel_1.h b/dlib/config_reader/config_reader_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..57aba59816172e51554a89d41f05962a78927ef2 --- /dev/null +++ b/dlib/config_reader/config_reader_kernel_1.h @@ -0,0 +1,715 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONFIG_READER_KERNEl_1_ +#define DLIB_CONFIG_READER_KERNEl_1_ + +#include "config_reader_kernel_abstract.h" +#include +#include +#include +#include "../algs.h" +#include "../interfaces/enumerable.h" + +namespace dlib +{ + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking = false + > + class config_reader_kernel_1 : public enumerable > + { + + /*! + REQUIREMENTS ON map_string_string + is an implementation of map/map_kernel_abstract.h that maps std::string to std::string + + REQUIREMENTS ON map_string_void + is an implementation of map/map_kernel_abstract.h that maps std::string to void* + + REQUIREMENTS ON tokenizer + is an implementation of tokenizer/tokenizer_kernel_abstract.h + + REQUIREMENTS ON checking + - if (checking == true) then + - The preconditions for this object will be checked. + - else + - The preconditions for this object will NOT be checked. + + CONVENTION + key_table.is_in_domain(x) == is_key_defined(x) + block_table.is_in_domain(x) == is_block_defined(x) + + key_table[x] == operator[](x) + block_table[x] == (void*)&block(x) + !*/ + + public: + + config_reader_kernel_1(); + + class config_reader_error : public dlib::error + { + friend class config_reader_kernel_1; + config_reader_error( + unsigned long ln, + bool r = false + ) : + dlib::error(ECONFIG_READER), + line_number(ln), + redefinition(r) + { + std::ostringstream sout; + sout << "Error in config_reader while parsing at line number " << line_number << "."; + if (redefinition) + sout << "\nThe identifier on this line has already been defined in this scope."; + const_cast(info) = sout.str(); + } + public: + const unsigned long line_number; + const bool redefinition; + }; + + + config_reader_kernel_1( + std::istream& in + ); + + virtual ~config_reader_kernel_1( + ); + + void clear ( + ); + + void load_from ( + std::istream& in + ); + + bool is_key_defined ( + const std::string& key + ) const; + + bool is_block_defined ( + const std::string& name + ) const; + + typedef config_reader_kernel_1 this_type; + const this_type& block ( + const std::string& name + ) const; + + const std::string& operator[] ( + const std::string& key + ) const; + + template < + typename queue_of_strings + > + void get_keys ( + queue_of_strings& keys + ) const; + + inline bool at_start ( + ) const ; + + inline void reset ( + ) const ; + + inline bool current_element_valid ( + ) const ; + + inline const this_type& element ( + ) const ; + + inline this_type& element ( + ) ; + + inline bool move_next ( + ) const ; + + inline unsigned long size ( + ) const ; + + inline const std::string& current_block_name ( + ) const; + + private: + + static void parse_config_file ( + config_reader_kernel_1& cr, + tokenizer& tok, + unsigned long& line_number, + const bool top_of_recursion = true + ); + /*! + requires + - line_number == 1 + - cr == *this + - top_of_recursion == true + ensures + - parses the data coming from tok and puts it into cr. + throws + - config_reader_error + !*/ + + map_string_string key_table; + map_string_void block_table; + + // restricted functions + config_reader_kernel_1(config_reader_kernel_1&); + config_reader_kernel_1& operator=(config_reader_kernel_1&); + + }; + +// ---------------------------------------------------------------------------------------- + + /* + This is a bunch of crap so we can enable and disable the DLIB_CASSERT statements + without getting warnings about conditions always being true or false. + */ + namespace config_reader_kernel_1_helpers + { + template + struct helper; + + template + struct helper + { + static void check_operator_bracket_precondition (const cr_type&, const std::string& ) {} + static void check_block_precondition (const cr_type&, const std::string& ) {} + static void check_current_block_name_precondition (const cr_type& cr) {} + static void check_element_precondition (const cr_type& cr) {} + }; + + template + struct helper + { + static void check_operator_bracket_precondition (const cr_type& cr, const std::string& key) + { + DLIB_CASSERT ( cr.is_key_defined(key) == true , + "\tconst std::string& config_reader::operator[](key)" + << "\n\tTo access a key's value in the config_reader the key must actually exist." + << "\n\tkey == " << key + << "\n\t&cr: " << &cr + ); + } + + static void check_block_precondition (const cr_type& cr, const std::string& name) + { + DLIB_CASSERT ( cr.is_block_defined(name) == true , + "\tconst this_type& config_reader::block(name)" + << "\n\tTo access a sub block in the config_reader the block must actually exist." + << "\n\tname == " << name + << "\n\t&cr: " << &cr + ); + } + + static void check_current_block_name_precondition (const cr_type& cr) + { + DLIB_CASSERT ( cr.current_element_valid() == true , + "\tconst std::string& config_reader::current_block_name()" + << "\n\tYou can't call current_block_name() if the current element isn't valid." + << "\n\t&cr: " << &cr + ); + } + + static void check_element_precondition (const cr_type& cr) + { + DLIB_CASSERT ( cr.current_element_valid() == true , + "\tthis_type& config_reader::element()" + << "\n\tYou can't call element() if the current element isn't valid." + << "\n\t&cr: " << &cr + ); + } + }; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + config_reader_kernel_1:: + config_reader_kernel_1( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + void config_reader_kernel_1:: + clear( + ) + { + // free all our blocks + block_table.reset(); + while (block_table.move_next()) + { + delete reinterpret_cast(block_table.element().value()); + } + block_table.clear(); + key_table.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + void config_reader_kernel_1:: + load_from( + std::istream& in + ) + { + clear(); + + tokenizer tok; + tok.set_stream(in); + tok.set_identifier_token( + tok.lowercase_letters() + tok.uppercase_letters(), + tok.lowercase_letters() + tok.uppercase_letters() + tok.numbers() + "_-." + ); + + unsigned long line_number = 1; + try + { + parse_config_file(*this,tok,line_number); + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + config_reader_kernel_1:: + config_reader_kernel_1( + std::istream& in + ) + { + load_from(in); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + void config_reader_kernel_1:: + parse_config_file( + config_reader_kernel_1& cr, + tokenizer& tok, + unsigned long& line_number, + const bool top_of_recursion + ) + { + int type; + std::string token; + bool in_comment = false; + bool seen_identifier = false; + std::string identifier; + while (true) + { + tok.get_token(type,token); + // ignore white space + if (type == tokenizer::WHITE_SPACE) + continue; + + // basically ignore end of lines + if (type == tokenizer::END_OF_LINE) + { + ++line_number; + in_comment = false; + continue; + } + + // we are in a comment still so ignore this + if (in_comment) + continue; + + // if this is the start of a comment + if (type == tokenizer::CHAR && token[0] == '#') + { + in_comment = true; + continue; + } + + // if this is the case then we have just finished parsing a block so we should + // quit this function + if ( (type == tokenizer::CHAR && token[0] == '}' && !top_of_recursion) || + (type == tokenizer::END_OF_FILE && top_of_recursion) ) + { + break; + } + + if (seen_identifier) + { + seen_identifier = false; + // the next character should be either a '=' or a '{' + if (type != tokenizer::CHAR || (token[0] != '=' && token[0] != '{')) + throw config_reader_error(line_number); + + if (token[0] == '=') + { + // we should parse the value out now + // first discard any white space + if (tok.peek_type() == tokenizer::WHITE_SPACE) + tok.get_token(type,token); + + std::string value; + type = tok.peek_type(); + token = tok.peek_token(); + while (true) + { + if (type == tokenizer::END_OF_FILE || type == tokenizer::END_OF_LINE) + break; + + if (type == tokenizer::CHAR && token[0] == '\\') + { + tok.get_token(type,token); + if (tok.peek_type() == tokenizer::CHAR && + tok.peek_token()[0] == '#') + { + tok.get_token(type,token); + value += '#'; + } + else if (tok.peek_type() == tokenizer::CHAR && + tok.peek_token()[0] == '}') + { + tok.get_token(type,token); + value += '}'; + } + else + { + value += '\\'; + } + } + else if (type == tokenizer::CHAR && + (token[0] == '#' || token[0] == '}')) + { + break; + } + else + { + value += token; + tok.get_token(type,token); + } + type = tok.peek_type(); + token = tok.peek_token(); + } // while(true) + + // strip of any tailing white space from value + std::string::size_type pos = value.find_last_not_of(" \t\r\n"); + if (pos == std::string::npos) + value.clear(); + else + value.erase(pos+1); + + // make sure this key isn't already in the key_table + if (cr.key_table.is_in_domain(identifier)) + throw config_reader_error(line_number,true); + + // add this key/value pair to the key_table + cr.key_table.add(identifier,value); + + } + else // when token[0] == '{' + { + // make sure this identifier isn't already in the block_table + if (cr.block_table.is_in_domain(identifier)) + throw config_reader_error(line_number,true); + + config_reader_kernel_1* new_cr = new config_reader_kernel_1; + void* vtemp = new_cr; + try { cr.block_table.add(identifier,vtemp); } + catch (...) { delete new_cr; throw; } + + // now parse this block + parse_config_file(*new_cr,tok,line_number,false); + } + } + else + { + // the next thing should be an identifier but if it isn't this is an error + if (type != tokenizer::IDENTIFIER) + throw config_reader_error(line_number); + + seen_identifier = true; + identifier = token; + } + } // while (true) + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + config_reader_kernel_1:: + ~config_reader_kernel_1( + ) + { + clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + bool config_reader_kernel_1:: + is_key_defined ( + const std::string& key + ) const + { + return key_table.is_in_domain(key); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + bool config_reader_kernel_1:: + is_block_defined ( + const std::string& name + ) const + { + return block_table.is_in_domain(name); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename mss, + typename msv, + typename tokenizer, + bool checking + > + const config_reader_kernel_1& config_reader_kernel_1:: + block ( + const std::string& name + ) const + { + config_reader_kernel_1_helpers::helper:: + check_block_precondition(*this,name); + return *reinterpret_cast(block_table[name]); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + const std::string& config_reader_kernel_1:: + operator[] ( + const std::string& key + ) const + { + config_reader_kernel_1_helpers::helper:: + check_operator_bracket_precondition(*this,key); + return key_table[key]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + template < + typename queue_of_strings + > + void config_reader_kernel_1:: + get_keys ( + queue_of_strings& keys + ) const + { + keys.clear(); + key_table.reset(); + std::string temp; + while (key_table.move_next()) + { + temp = key_table.element().key(); + keys.enqueue(temp); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + bool config_reader_kernel_1:: + at_start ( + ) const + { + return block_table.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + void config_reader_kernel_1:: + reset ( + ) const + { + block_table.reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + bool config_reader_kernel_1:: + current_element_valid ( + ) const + { + return block_table.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename mss, + typename msv, + typename tokenizer, + bool checking + > + const config_reader_kernel_1& config_reader_kernel_1:: + element ( + ) const + { + config_reader_kernel_1_helpers::helper:: + check_element_precondition(*this); + return *reinterpret_cast(block_table.element().value()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename mss, + typename msv, + typename tokenizer, + bool checking + > + config_reader_kernel_1& config_reader_kernel_1:: + element ( + ) + { + config_reader_kernel_1_helpers::helper:: + check_element_precondition(*this); + return *reinterpret_cast(block_table.element().value()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + bool config_reader_kernel_1:: + move_next ( + ) const + { + return block_table.move_next(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + unsigned long config_reader_kernel_1:: + size ( + ) const + { + return block_table.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_string_string, + typename map_string_void, + typename tokenizer, + bool checking + > + const std::string& config_reader_kernel_1:: + current_block_name ( + ) const + { + config_reader_kernel_1_helpers::helper:: + check_current_block_name_precondition(*this); + return block_table.element().key(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONFIG_READER_KERNEl_1_ + diff --git a/dlib/config_reader/config_reader_kernel_abstract.h b/dlib/config_reader/config_reader_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..ef645a5d1e7be07e3a54e0a697b1c0d1c05e1b93 --- /dev/null +++ b/dlib/config_reader/config_reader_kernel_abstract.h @@ -0,0 +1,265 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CONFIG_READER_KERNEl_ABSTRACT_ +#ifdef DLIB_CONFIG_READER_KERNEl_ABSTRACT_ + +#include +#include +#include "../interfaces/enumerable.h" + +namespace dlib +{ + + class config_reader : public enumerable + { + + /*! + INITIAL VALUE + - there aren't any keys defined for this object + - there aren't any blocks defined for this object + + ENUMERATION ORDER + The enumerator will iterate over the sub blocks in the config_reader. + They will be enumerated in sorted order according to the ordering + established on the block names by operator<. + + POINTERS AND REFERENCES TO INTERNAL DATA + The destructor, clear(), and load_from() invalidate pointers + and references to internal data. All other functions are guaranteed + to NOT invalidate pointers or references to internal data. + + WHAT THIS OBJECT REPRESENTS + This object represents something which is intended to be used to read + text configuration files that are defined by the following EBNF (with + config_file as the starting symbol): + + config_file = block; + block = { key_value_pair | sub_block }; + key_value_pair = key_name, "=", value; + sub_block = block_name, "{", block, "}"; + + key_name = identifier; + block_name = identifier; + value = matches any string of text that ends with a newline character, # or }. + note that the trailing newline, # or } is not part of the value though. + identifier = Any string that matches the following regular expression: + [a-zA-Z][a-zA-Z0-9_-\.]* + i.e. Any string that starts with a letter and then is continued + with any number of letters, numbers, _ . or - characters. + + Whitespace and comments are ignored. A comment is text that starts with # (but not \# + since the \ escapes the # so that you can have a # symbol in a value if you want) and + ends in a new line. You can also escape a } (e.g. "\}") if you want to have one in a + value. + + Note that in a value the leading and trailing white spaces are stripped off but any + white space inside the value is preserved. + + Also note that all key_names and block_names within a block syntax group must be unique + but don't have to be globally unique. I.e. different blocks can reuse names. + + EXAMPLE CONFIG FILES: + + Example 1: + #comment. This line is ignored because it starts with # + + #here we have key1 which will have the value of "my value" + key1 = my value + + another_key= another value # this is another key called "another_key" with + # a value of "another value" + + # this key's value is the empty string. I.e. "" + key2= + + Example 2: + #this example illustrates the use of blocks + some_key = blah blah + + # now here is a block + our_block + { + # here we can define some keys and values that are local to this block. + a_key = something + foo = bar + some_key = more stuff # note that it is ok to name our key this even though + # there is a key called some_key above. This is because + # we are doing so inside a different block + } + + another_block { foo = bar2 } # this block has only one key and is all on a single line + !*/ + + public: + + // exception class + class config_reader_error : public dlib::error + { + /*! + GENERAL + This exception is thrown if there is an error while parsing the + config file. The type member of this exception will be set + to ECONFIG_READER. + + INTERPRETING THIS EXCEPTION + - line_number == the line number the parser was at when the + error occurred. + - if (redefinition) then + - The key or block name on line line_number has already + been defined in this scope which is an error. + - else + - Some other general syntax error was detected + !*/ + public: + const unsigned long line_number; + const bool redefinition; + }; + + // -------------------------- + + config_reader( + ); + /*! + ensures + - #*this is properly initialized + - This object will not have any keys or blocks defined in it. + throws + - std::bad_alloc + - config_reader_error + !*/ + + config_reader( + std::istream& in + ); + /*! + ensures + - #*this is properly initialized + - reads the config file to parse from the given input stream, + parses it and loads this object up with all the sub blocks and + key/value pairs it finds. + - This object will represent the top most block of the config file. + throws + - std::bad_alloc + - config_reader_error + !*/ + + virtual ~config_reader( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + If this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void load_from ( + std::istream& in + ); + /*! + ensures + - reads the config file to parse from the given input stream, + parses it and loads this object up with all the sub blocks and + key/value pairs it finds. + - *this will represent the top most block of the config file contained + in the input stream in. + throws + - std::bad_alloc + If this exception is thrown then *this is unusable + until clear() is called and succeeds + - config_reader_error + If this exception is thrown then this object will + revert to its initial value. + !*/ + + bool is_key_defined ( + const std::string& key_name + ) const; + /*! + ensures + - if (there is a key with the given name defined within this config_reader's block) then + - returns true + - else + - returns false + !*/ + + bool is_block_defined ( + const std::string& block_name + ) const; + /*! + ensures + - if (there is a sub block with the given name defined within this config_reader's block) then + - returns true + - else + - returns false + !*/ + + typedef config_reader this_type; + const this_type& block ( + const std::string& block_name + ) const; + /*! + requires + - is_block_defined(block_name) == true + ensures + - returns a const reference to the config_reader that represents the given named sub block + !*/ + + const std::string& operator[] ( + const std::string& key_name + ) const; + /*! + requires + - is_key_defined(key_name) == true + ensures + - returns a const reference to the value string associated with the given key in + this config_reader's block. + !*/ + + template < + typename queue_of_strings + // Is an implementation of queue/queue_kernel_abstract.h with T set to std::string + > + void get_keys ( + queue_of_strings& keys + ) const; + /*! + ensures + - #keys == a queue containing all the keys defined in this config_reader's block. + (i.e. for all strings str in keys it is the case that is_key_defined(str) == true) + throws + - std::bad_alloc + If this exception is thrown then this call has no effect on *this and #keys is + unusable until keys.clear() is called and succeeds. + !*/ + + const std::string& current_block_name ( + ) const; + /*! + requires + - current_element_valid() == true + ensures + - returns a string block_name such that: &block(block_name) == &element() + (i.e. returns the name of the block that the enumerator is currently at) + !*/ + + private: + + // restricted functions + config_reader(config_reader&); // copy constructor + config_reader& operator=(config_reader&); // assignment operator + + }; + +} + +#endif // DLIB_CONFIG_READER_KERNEl_ABSTRACT_ + diff --git a/dlib/config_reader/config_reader_thread_safe_1.h b/dlib/config_reader/config_reader_thread_safe_1.h new file mode 100644 index 0000000000000000000000000000000000000000..e996e01a0b42ade2bfe1a8eb63b5e94c25f90232 --- /dev/null +++ b/dlib/config_reader/config_reader_thread_safe_1.h @@ -0,0 +1,590 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CONFIG_READER_THREAD_SAFe_ +#define DLIB_CONFIG_READER_THREAD_SAFe_ + +#include "config_reader_kernel_abstract.h" +#include +#include +#include +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../threads.h" +#include "config_reader_thread_safe_abstract.h" + +namespace dlib +{ + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + class config_reader_thread_safe_1 : public enumerable > + { + + /*! + CONVENTION + - get_mutex() == m + - *cr == the config reader being extended + - block_table[x] == (void*)&block(x) + - cr->size == block_table.size() + - block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key) + - if (own_pointers) then + - this object owns the m and cr pointers and should delete them when destructed + !*/ + + public: + + config_reader_thread_safe_1 ( + const config_reader_base* base, + rmutex* m_ + ); + + config_reader_thread_safe_1(); + + typedef typename config_reader_base::config_reader_error config_reader_error; + + config_reader_thread_safe_1( + std::istream& in + ); + + virtual ~config_reader_thread_safe_1( + ); + + void clear ( + ); + + void load_from ( + std::istream& in + ); + + bool is_key_defined ( + const std::string& key + ) const; + + bool is_block_defined ( + const std::string& name + ) const; + + typedef config_reader_thread_safe_1 this_type; + const this_type& block ( + const std::string& name + ) const; + + const std::string& operator[] ( + const std::string& key + ) const; + + template < + typename queue_of_strings + > + void get_keys ( + queue_of_strings& keys + ) const; + + inline bool at_start ( + ) const ; + + inline void reset ( + ) const ; + + inline bool current_element_valid ( + ) const ; + + inline const this_type& element ( + ) const ; + + inline this_type& element ( + ) ; + + inline bool move_next ( + ) const ; + + inline unsigned long size ( + ) const ; + + inline const std::string& current_block_name ( + ) const; + + inline const rmutex& get_mutex ( + ) const; + + private: + + void fill_block_table ( + ); + /*! + ensures + - block_table.size() == cr->size() + - block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key) + !*/ + + rmutex* m; + config_reader_base* cr; + map_string_void block_table; + const bool own_pointers; + + // restricted functions + config_reader_thread_safe_1(config_reader_thread_safe_1&); + config_reader_thread_safe_1& operator=(config_reader_thread_safe_1&); + + }; + +// ---------------------------------------------------------------------------------------- + + /* + This is a bunch of crap so we can enable and disable the DLIB_CASSERT statements + without getting warnings about conditions always being true or false. + */ + namespace config_reader_thread_safe_1_helpers + { + template + struct helper; + + template + struct helper + { + static void check_block_precondition (const cr_type&, const std::string& ) {} + static void check_current_block_name_precondition (const cr_type& cr) {} + static void check_element_precondition (const cr_type& cr) {} + }; + + template + struct helper + { + static void check_block_precondition (const cr_type& cr, const std::string& name) + { + DLIB_CASSERT ( cr.is_block_defined(name) == true , + "\tconst this_type& config_reader_thread_safe::block(name)" + << "\n\tTo access a sub block in the config_reader the block must actually exist." + << "\n\tname == " << name + << "\n\t&cr: " << &cr + ); + } + + static void check_current_block_name_precondition (const cr_type& cr) + { + DLIB_CASSERT ( cr.current_element_valid() == true , + "\tconst std::string& config_reader_thread_safe::current_block_name()" + << "\n\tYou can't call current_block_name() if the current element isn't valid." + << "\n\t&cr: " << &cr + ); + } + + static void check_element_precondition (const cr_type& cr) + { + DLIB_CASSERT ( cr.current_element_valid() == true , + "\tthis_type& config_reader_thread_safe::element()" + << "\n\tYou can't call element() if the current element isn't valid." + << "\n\t&cr: " << &cr + ); + } + }; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + config_reader_thread_safe_1:: + config_reader_thread_safe_1( + const config_reader_base* base, + rmutex* m_ + ) : + m(m_), + cr(const_cast(base)), + own_pointers(false) + { + fill_block_table(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + config_reader_thread_safe_1:: + config_reader_thread_safe_1( + ) : + m(0), + cr(0), + own_pointers(true) + { + try + { + m = new rmutex; + cr = new config_reader_base; + } + catch (...) + { + if (m) delete m; + if (cr) delete cr; + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + void config_reader_thread_safe_1:: + clear( + ) + { + auto_mutex M(*m); + cr->clear(); + fill_block_table(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + void config_reader_thread_safe_1:: + load_from( + std::istream& in + ) + { + auto_mutex M(*m); + cr->load_from(in); + fill_block_table(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + config_reader_thread_safe_1:: + config_reader_thread_safe_1( + std::istream& in + ) : + m(0), + cr(0), + own_pointers(true) + { + try + { + m = new rmutex; + cr = new config_reader_base(in); + fill_block_table(); + } + catch (...) + { + if (m) delete m; + if (cr) delete cr; + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + config_reader_thread_safe_1:: + ~config_reader_thread_safe_1( + ) + { + if (own_pointers) + { + delete m; + delete cr; + } + + // clear out the block table + block_table.reset(); + while (block_table.move_next()) + { + delete reinterpret_cast(block_table.element().value()); + } + block_table.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + bool config_reader_thread_safe_1:: + is_key_defined ( + const std::string& key + ) const + { + auto_mutex M(*m); + return cr->is_key_defined(key); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + bool config_reader_thread_safe_1:: + is_block_defined ( + const std::string& name + ) const + { + auto_mutex M(*m); + return cr->is_block_defined(name); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + const config_reader_thread_safe_1& config_reader_thread_safe_1:: + block ( + const std::string& name + ) const + { + auto_mutex M(*m); + config_reader_thread_safe_1_helpers::helper:: + check_block_precondition(*this,name); + return *reinterpret_cast(block_table[name]); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + const std::string& config_reader_thread_safe_1:: + operator[] ( + const std::string& key + ) const + { + auto_mutex M(*m); + return (*cr)[key]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + template < + typename queue_of_strings + > + void config_reader_thread_safe_1:: + get_keys ( + queue_of_strings& keys + ) const + { + auto_mutex M(*m); + cr->get_keys(keys); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + bool config_reader_thread_safe_1:: + at_start ( + ) const + { + auto_mutex M(*m); + return block_table.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + void config_reader_thread_safe_1:: + reset ( + ) const + { + auto_mutex M(*m); + block_table.reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + bool config_reader_thread_safe_1:: + current_element_valid ( + ) const + { + auto_mutex M(*m); + return block_table.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + const config_reader_thread_safe_1& config_reader_thread_safe_1:: + element ( + ) const + { + auto_mutex M(*m); + config_reader_thread_safe_1_helpers::helper:: + check_element_precondition(*this); + return *reinterpret_cast(block_table.element().value()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + config_reader_thread_safe_1& config_reader_thread_safe_1:: + element ( + ) + { + auto_mutex M(*m); + config_reader_thread_safe_1_helpers::helper:: + check_element_precondition(*this); + return *reinterpret_cast(block_table.element().value()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + bool config_reader_thread_safe_1:: + move_next ( + ) const + { + auto_mutex M(*m); + return block_table.move_next(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + unsigned long config_reader_thread_safe_1:: + size ( + ) const + { + auto_mutex M(*m); + return block_table.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + const std::string& config_reader_thread_safe_1:: + current_block_name ( + ) const + { + auto_mutex M(*m); + config_reader_thread_safe_1_helpers::helper:: + check_current_block_name_precondition(*this); + return block_table.element().key(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + const rmutex& config_reader_thread_safe_1:: + get_mutex ( + ) const + { + return *m; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// private member functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename config_reader_base, + typename map_string_void, + bool checking + > + void config_reader_thread_safe_1:: + fill_block_table ( + ) + { + using namespace std; + // first empty out the block table + block_table.reset(); + while (block_table.move_next()) + { + delete reinterpret_cast(block_table.element().value()); + } + block_table.clear(); + + // now fill the block table up to match what is in cr + cr->reset(); + while (cr->move_next()) + { + config_reader_thread_safe_1* block = new config_reader_thread_safe_1(&cr->element(),m); + void* temp = block; + std::string key(cr->current_block_name()); + block_table.add(key,temp); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CONFIG_READER_THREAD_SAFe_ + + diff --git a/dlib/config_reader/config_reader_thread_safe_abstract.h b/dlib/config_reader/config_reader_thread_safe_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..dd49b63798d894bba78b54f3785c6560400dc0e9 --- /dev/null +++ b/dlib/config_reader/config_reader_thread_safe_abstract.h @@ -0,0 +1,51 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_ +#ifdef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_ + +#include +#include +#include "config_reader_kernel_abstract.h" +#include "../threads/threads_kernel_abstract.h" + +namespace dlib +{ + + template < + typename config_reader_base + > + class config_reader_thread_safe + { + + /*! + REQUIREMENTS ON config_reader_base + is an implementation of config_reader/config_reader_kernel_abstract.h + + WHAT THIS EXTENSION DOES FOR config_reader + This object extends a normal config_reader by simply wrapping all + its member functions inside mutex locks to make it safe to use + in a threaded program. + + So this object provides an interface identical to the one defined + in the config_reader/config_reader_kernel_abstract.h file except that + the rmutex returned by get_mutex() is always locked when this + object's member functions are called. + !*/ + + public: + + const rmutex& get_mutex ( + ) const; + /*! + ensures + - returns the rmutex used to make this object thread safe. i.e. returns + the rmutex that is locked when this object's functions are called. + !*/ + + }; + +} + +#endif // DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_ + + diff --git a/dlib/cpp_pretty_printer.h b/dlib/cpp_pretty_printer.h new file mode 100644 index 0000000000000000000000000000000000000000..e4b8ba815355a1b3d07f58568e12954ece7ebe15 --- /dev/null +++ b/dlib/cpp_pretty_printer.h @@ -0,0 +1,39 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CPP_PRETTY_PRINTEr_ +#define DLIB_CPP_PRETTY_PRINTEr_ + + +#include "cpp_pretty_printer/cpp_pretty_printer_kernel_1.h" +#include "cpp_pretty_printer/cpp_pretty_printer_kernel_2.h" +#include "cpp_tokenizer.h" +#include "stack.h" + +namespace dlib +{ + + class cpp_pretty_printer + { + cpp_pretty_printer() {} + + + typedef stack::kernel_1a stack; + typedef cpp_tokenizer::kernel_1a tok; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef cpp_pretty_printer_kernel_1 + kernel_1a; + + // kernel_2a + typedef cpp_pretty_printer_kernel_2 + kernel_2a; + + }; +} + +#endif // DLIB_CPP_PRETTY_PRINTEr_ + diff --git a/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h b/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..e83c47809f20ba76e75141dfa3d2d4a8e9f8d0a6 --- /dev/null +++ b/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h @@ -0,0 +1,583 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_1_ +#define DLIB_CPP_PRETTY_PRINTER_KERNEl_1_ + +#include +#include +#include +#include "cpp_pretty_printer_kernel_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + template < + typename stack, + typename tok + > + class cpp_pretty_printer_kernel_1 + { + /*! + REQUIREMENTS ON stack + must be an implementation of stack/stack_kernel_abstract.h and + stack::type == unsigned long + + REQUIREMENTS ON tok + must be an implementation of tokenizer/tokenizer_kernel_abstract.h + + INFO + This implementation applies a color scheme, turns include directives + such as #include "file.h" into links to file.h.html, and it also puts + HTML anchor points on function and class declarations. + !*/ + + public: + + cpp_pretty_printer_kernel_1 ( + ); + + virtual ~cpp_pretty_printer_kernel_1 ( + ); + + void print ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const; + + void print_and_number ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const; + + private: + + const std::string htmlify ( + const std::string& str + ) const; + /*! + ensures + - str == str but with any '<' replaced with '<', any '>' replaced + with '>', and any '&' replaced with '&' + !*/ + + // data members + mutable tok t; + + void number ( + std::istream& in, + std::ostream& out + ) const; + /*! + ensures + - prints in to out and adds line numbers + !*/ + + // restricted functions + cpp_pretty_printer_kernel_1(const cpp_pretty_printer_kernel_1&); // copy constructor + cpp_pretty_printer_kernel_1& operator=(const cpp_pretty_printer_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + cpp_pretty_printer_kernel_1:: + cpp_pretty_printer_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + cpp_pretty_printer_kernel_1:: + ~cpp_pretty_printer_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + void cpp_pretty_printer_kernel_1:: + print ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const + { + using namespace std; + + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print"); + + t.set_stream(in); + + out << "" << title << "
\n";
+        if (!out)
+            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
+
+        unsigned long scope = 0; // counts the number of new scopes we have entered 
+                        // since we were at a scope where functions can be declared
+
+        bool recently_seen_class_keyword = false;
+            // true if we have seen the keywords class, struct, or enum and
+            // we have not seen any identifiers or { characters
+
+        bool recently_seen_include = false;
+            // true if we have seen the #include keyword and have not seen double
+            // quoted text or >
+
+        bool recently_seen_new_scope = false;  
+            // true if we have seen the keywords class, namespace, or struct and
+            // we have not seen the characters {, ), or ; since then
+
+        bool recently_seen_paren = false;
+            // true if we have seen a ) and we have only seen white_space or comments since
+
+        bool in_initialization_list = false;
+            // true if we have seen a ) followed by any white space or comments and then
+            // followed by a : (in scope==0 with recently_seen_preprocessor==false) and we 
+            // have not yet seen the character { or ;
+
+        bool recently_seen_preprocessor = false;
+            // true if we have seen the #pragma or #if or #define or #elif keywords and have 
+            // not seen an end of line.
+
+        bool recently_seen_extern = false;
+            // true if we have seen the extern keyword and haven't seen a ; or { yet.
+
+        unsigned long paren_count = 0; 
+            // this is the number of ( we have seen minus the number of ) we have
+            // seen.
+            
+
+        int type;
+        stack scopes; // a stack to hold old scopes
+        string token, temp;
+        t.get_token(type,token);
+        while (type != tok::END_OF_FILE)
+        {
+            switch (type)
+            {
+            case tok::IDENTIFIER: // ------------------------------------------
+                if ( recently_seen_class_keyword)
+                {
+                    // this might be a class name so check if there is a 
+                    // ; or identifier or * or & coming up.
+                    type = t.peek_type();
+                    temp.clear();
+                    if (type == tok::WHITE_SPACE)
+                    {
+                        t.get_token(type,temp);
+                        if (temp.find_first_of("\n\r") != string::npos)
+                            recently_seen_preprocessor = false;
+                    }
+                    if (t.peek_token() != ";" && t.peek_type() != tok::IDENTIFIER &&
+                        t.peek_token() != "*" && t.peek_token() != "&")
+                    {
+                        // this is the name of a class or struct in a class or
+                        // struct declaration.
+                        out << "" << token << "" << temp;
+                    }
+                    else
+                    {
+                        out << token << temp;
+                    }
+                }
+                else if ( !in_initialization_list &&
+                     !recently_seen_preprocessor )
+                {
+                    // this might be a function name so check if there is a 
+                    // ( coming up.
+                    type = t.peek_type();
+                    temp.clear();
+                    if (type == tok::WHITE_SPACE)
+                    {
+                        t.get_token(type,temp);
+                        type = t.peek_type();
+                    }
+                    if (type == tok::OTHER && t.peek_token() == "(")
+                    {
+                        if (scope == 0 && paren_count == 0)
+                        {
+                            // this is a function definition or prototype
+                            out << "" << token << "" << temp;
+                        }
+                        else
+                        {
+                            // this is a function call (probably) 
+                            out << "" << token << "" << temp;
+                        }
+                    }
+                    else
+                    {
+                        out << token << temp;
+                    }
+                }
+                else
+                {
+                    out << token;
+                }
+                
+
+
+                recently_seen_class_keyword = false;
+                recently_seen_paren = false;
+                break;
+
+            case tok::KEYWORD: // ---------------------------------------------
+                if (scope == 0 && token == "operator")
+                {
+                    // Doing this is sort of weird since operator is really a keyword
+                    // but I just like how this looks.
+                    out << "" << token << "";
+                }
+                // this isn't a keyword if it is something like #include 
+                else if ( token == "true" || token == "false")
+                {
+                    // color 'true' and 'false' the same way we color numbers
+                    out << "" << token << "";
+                }
+                else if (!recently_seen_include) 
+                {
+                    // This is a normal keyword
+                    if (token == "char" || token == "unsigned" || token == "signed" ||
+                        token == "short" || token == "int" || token == "long" || 
+                        token == "float" || token == "double" || token == "bool" ||
+                        token == "void" || token == "size_t" || token == "wchar_t")
+                    {
+                        out << "" << token << "";
+                    }
+                    else
+                    {
+                        out << "" << token << "";
+                    }
+                }
+                else
+                {
+                    out << token;
+                }
+
+                if (token == "#include") 
+                {
+                    recently_seen_include = true;
+                }
+                else if (token == "class")
+                {
+                    recently_seen_new_scope = true;
+                    recently_seen_class_keyword = true;
+                }
+                else if (token == "namespace")
+                {
+                    recently_seen_new_scope = true;
+                }
+                else if (token == "enum")
+                {
+                    recently_seen_class_keyword = true;
+                }
+                else if (token == "struct")
+                {
+                    recently_seen_new_scope = true;
+                    recently_seen_class_keyword = true;
+                }
+                else if (token == "#pragma" || token == "#if" || token == "#define" || token == "#elif")
+                {
+                    recently_seen_preprocessor = true;
+                }
+                else if (token == "extern")
+                {
+                    recently_seen_extern = true;
+                }
+                recently_seen_paren = false;
+                break;
+
+            case tok::COMMENT: // ---------------------------------------------
+                {
+                    // if this is a special anchor comment
+                    if (token.size() > 4 &&
+                        token[0] == '/' &&
+                        token[1] == '*' &&
+                        token[2] == '!' &&
+                        token[3] == 'A' &&
+                        token[4] == ' '
+                    )
+                    {
+                        temp = token;
+                        istringstream sin(token);
+                        sin >> temp;
+                        sin >> temp;
+                        sin.get();
+                        // if there was still more stuff in the token then we are ok.
+                        if (sin)
+                            out << "";
+                    }
+                    out << "" << htmlify(token) << "";
+                }
+                break;
+
+            case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
+                {
+                    out << "" << htmlify(token) << "";
+                    recently_seen_paren = false;
+                }
+                break;
+
+            case tok::NUMBER: // -----------------------------------------
+                {
+                    out << "" << token << "";
+                    recently_seen_include = false;
+                }
+                break;
+
+            case tok::WHITE_SPACE: // -----------------------------------------
+                {
+                    out << token;
+                    if (token.find_first_of("\n\r") != string::npos)
+                        recently_seen_preprocessor = false;
+                }
+                break;
+
+            case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
+                {
+                    if (recently_seen_include)
+                    {
+                        // this is the name of an included file
+                        recently_seen_include = false;
+                        out << "" << htmlify(token) << "";                
+                    }
+                    else
+                    {
+                        // this is just a normal quoted string
+                        out << "" << htmlify(token) << "";
+                    }
+                    recently_seen_paren = false;
+                }
+                break;
+
+            case tok::OTHER: // -----------------------------------------------               
+                switch (token[0])
+                {
+                case '{':
+                    out << "{";  
+                    // if we are entering a new scope
+                    if (recently_seen_new_scope || recently_seen_extern)
+                    {
+                        recently_seen_new_scope = false;
+                        scopes.push(scope);
+                        scope = 0;
+                    }
+                    else
+                    {
+                        ++scope;
+                    }
+                    in_initialization_list = false;
+                    recently_seen_paren = false;
+                    recently_seen_class_keyword = false;
+                    recently_seen_extern = false;
+                    break;
+                case '}':
+                    out << "}";
+                    if (scope > 0)
+                    {
+                        --scope;
+                    }
+                    else if (scopes.size())
+                    {
+                        scopes.pop(scope);
+                    }
+                    recently_seen_paren = false;
+                    break;
+
+                case ':':
+                    out << ':';
+                    if (recently_seen_paren && scope == 0 && 
+                        recently_seen_preprocessor == false)
+                    {
+                        in_initialization_list = true;
+                    }
+                    recently_seen_paren = false;
+                    break;
+
+                case ';': 
+                    out << ';';
+                    recently_seen_new_scope = false;
+                    recently_seen_paren = false;
+                    recently_seen_extern = false;
+                    break;
+
+                case ')':
+                    out << ")";
+                    recently_seen_paren = true;
+                    recently_seen_new_scope = false;
+                    --paren_count;
+                    break;
+
+                case '(':
+                    out << "(";
+                    recently_seen_paren = false;
+                    ++paren_count;
+                    break;
+
+                case '>':
+                    recently_seen_include = false;
+                    out << ">";
+                    recently_seen_paren = false;
+                    break;
+
+                case '<':
+                    out << "<";
+                    recently_seen_paren = false;
+                    break;
+
+                case '&':
+                    out << "&";
+                    recently_seen_paren = false;
+                    break;
+
+                case '=':
+                case '+':
+                case '-':
+                case '/':
+                case '*':
+                case '!':
+                case '|':
+                case '%':
+                    out << "" << token << "";
+                    recently_seen_paren = false;
+                    break;
+
+                default:
+                    out << token;
+                    recently_seen_paren = false;
+                    break;
+
+                } // switch (token[0])
+                break;
+
+            } // switch (type)
+
+            t.get_token(type,token);
+        } // while (type != tok::END_OF_FILE)
+
+
+        out << "\n
"; + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print"); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + void cpp_pretty_printer_kernel_1:: + print_and_number ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const + { + using namespace std; + ostringstream sout; + print(in,sout,title); + istringstream sin(sout.str()); + number(sin,out); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + void cpp_pretty_printer_kernel_1:: + number ( + std::istream& in, + std::ostream& out + ) const + { + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number"); + + std::string space = "   "; + std::ios::int_type ch; + unsigned long count = 1; + while ((ch=in.get()) != EOF) + { + if (ch != '\n') + { + out << (char)ch; + } + else + { + out << "\n" << count << " " + space; + ++count; + if (count == 10) + space = "  "; + if (count == 100) + space = " "; + if (count == 1000) + space = ""; + } + } + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number"); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + const std::string cpp_pretty_printer_kernel_1:: + htmlify ( + const std::string& str + ) const + { + std::string::size_type i; + std::string temp; + for (i = 0; i < str.size(); ++i) + { + if (str[i] == '<') + temp += "<"; + else if (str[i] == '>') + temp += ">"; + else if (str[i] == '&') + temp += "&"; + else + temp += str[i]; + } + return temp; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_1_ + diff --git a/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_2.h b/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..a2f490c31832011b99c188771bf4a3f2c78fab12 --- /dev/null +++ b/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_2.h @@ -0,0 +1,520 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_2_ +#define DLIB_CPP_PRETTY_PRINTER_KERNEl_2_ + +#include +#include +#include +#include "cpp_pretty_printer_kernel_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + template < + typename stack, + typename tok + > + class cpp_pretty_printer_kernel_2 + { + /*! + REQUIREMENTS ON stack + must be an implementation of stack/stack_kernel_abstract.h and + stack::type == unsigned long + + REQUIREMENTS ON tok + must be an implementation of tokenizer/tokenizer_kernel_abstract.h + + INFO + This implementation applies a black and white color scheme suitable + for printing on a black and white printer. It also places the document + title prominently at the top of the pretty printed source file. + !*/ + + public: + + cpp_pretty_printer_kernel_2 ( + ); + + virtual ~cpp_pretty_printer_kernel_2 ( + ); + + void print ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const; + + void print_and_number ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const; + + private: + + // data members + mutable tok t; + + const std::string htmlify ( + const std::string& str + ) const; + /*! + ensures + - str == str but with any '<' replaced with '<', any '>' replaced + with '>', and any '&' replaced with '&' + !*/ + + void number ( + std::istream& in, + std::ostream& out + ) const; + /*! + ensures + - prints in to out and adds line numbers + !*/ + + // restricted functions + cpp_pretty_printer_kernel_2(const cpp_pretty_printer_kernel_2&); // copy constructor + cpp_pretty_printer_kernel_2& operator=(const cpp_pretty_printer_kernel_2&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + cpp_pretty_printer_kernel_2:: + cpp_pretty_printer_kernel_2 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + cpp_pretty_printer_kernel_2:: + ~cpp_pretty_printer_kernel_2 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + void cpp_pretty_printer_kernel_2:: + print ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const + { + using namespace std; + + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print"); + + t.set_stream(in); + + out << "" + << "" << title << "" + << "

" << title << "

\n"
+            << "\n";
+        if (!out)
+            throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print");
+
+        unsigned long scope = 0; // counts the number of new scopes we have entered 
+                        // since we were at a scope where functions can be declared
+
+        bool recently_seen_class_keyword = false;
+            // true if we have seen the keywords class or struct and
+            // we have not seen any identifiers or { characters
+
+        bool recently_seen_include = false;
+            // true if we have seen the #include keyword and have not seen double
+            // quoted text or >
+
+        bool recently_seen_new_scope = false;  
+            // true if we have seen the keywords class, namespace, or struct and
+            // we have not seen the characters {, ), or ; since then
+
+        bool recently_seen_paren = false;
+            // true if we have seen a ) and we have only seen white_space or comments since
+
+        bool in_initialization_list = false;
+            // true if we have seen a ) followed by any white space or comments and then
+            // followed by a : (in scope==0 with recently_seen_preprocessor==false) and we 
+            // have not yet seen the character { or ;
+
+        bool recently_seen_preprocessor = false;
+            // true if we have seen the #pragma or #if or #define or #elif keyword and 
+            // have not seen an identifier.
+
+
+        bool recently_seen_extern = false;
+            // true if we have seen the extern keyword and haven't yet seen a 
+            // { or ; character.
+
+        unsigned long paren_count = 0; 
+            // this is the number of ( we have seen minus the number of ) we have
+            // seen.
+            
+
+        int type;
+        stack scopes; // a stack to hold old scopes
+        string token, temp;
+        t.get_token(type,token);
+        while (type != tok::END_OF_FILE)
+        {
+            switch (type)
+            {
+            case tok::IDENTIFIER: // ------------------------------------------
+                if ( recently_seen_class_keyword)
+                {
+                    // this might be a class name so check if there is a 
+                    // ; or identifier or * or & coming up.
+                    type = t.peek_type();
+                    temp.clear();
+                    if (type == tok::WHITE_SPACE)
+                    {
+                        t.get_token(type,temp);
+                        if (temp.find_first_of("\n\r") != string::npos)
+                            recently_seen_preprocessor = false;
+                    }
+                    if (t.peek_token() != ";" && t.peek_type() != tok::IDENTIFIER &&
+                        t.peek_token() != "*" && t.peek_token() != "&")
+                    {
+                        // this is the name of a class or struct in a class or
+                        // struct declaration.
+                        out << "" << token << "" << temp;
+                    }
+                    else
+                    {
+                        out << token << temp;
+                    }
+                }
+                else if ( !in_initialization_list &&
+                     !recently_seen_preprocessor &&
+                     scope == 0 &&
+                     paren_count == 0)
+                {
+                    // this might be a function name so check if there is a 
+                    // ( coming up.
+                    type = t.peek_type();
+                    temp.clear();
+                    if (type == tok::WHITE_SPACE)
+                    {
+                        t.get_token(type,temp);
+                        type = t.peek_type();
+                    }
+                    if (type == tok::OTHER && t.peek_token() == "(")
+                    {
+                        // this is a function definition or prototype
+                        out << "" << token << "" << temp;
+                    }
+                    else
+                    {
+                        out << token << temp;
+                    }
+                }
+                else
+                {
+                    out << token;
+                }
+                
+
+
+                recently_seen_class_keyword = false;
+                recently_seen_paren = false;
+                break;
+
+            case tok::KEYWORD: // ---------------------------------------------
+                if (scope == 0 && token == "operator")
+                {
+                    // Doing this is sort of weird since operator is really a keyword
+                    // but I just like how this looks.
+                    out << "" << token << "";
+                }
+                // this isn't a keyword if it is something like #include 
+                else if (!recently_seen_include) 
+                {
+                    // This is a normal keyword
+                    out << "" << token << "";
+                }
+                else
+                {
+                    out << token;
+                }
+
+                if (token == "#include") 
+                {
+                    recently_seen_include = true;
+                }
+                else if (token == "class")
+                {
+                    recently_seen_new_scope = true;
+                    recently_seen_class_keyword = true;
+                }
+                else if (token == "namespace")
+                {
+                    recently_seen_new_scope = true;
+                }
+                else if (token == "struct")
+                {
+                    recently_seen_new_scope = true;
+                    recently_seen_class_keyword = true;
+                }
+                else if (token == "#pragma" || token == "#define" || token == "#elif" || token == "#if")
+                {
+                    recently_seen_preprocessor = true;
+                }
+                else if (token == "extern")
+                {
+                    recently_seen_extern = true;
+                }
+                recently_seen_paren = false;
+                break;
+
+            case tok::COMMENT: // ---------------------------------------------
+                {
+                    out << "" << htmlify(token) << "";
+                }
+                break;
+
+            case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
+                {
+                    out << htmlify(token);
+                    recently_seen_paren = false;
+                }
+                break;
+
+            case tok::WHITE_SPACE: // -----------------------------------------
+                {
+                    out << token;
+                    if (token.find_first_of("\n\r") != string::npos)
+                        recently_seen_preprocessor = false;
+                }
+                break;
+
+            case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
+                {                    
+                    out << htmlify(token);
+                    recently_seen_paren = false;
+                    recently_seen_include = false;
+                }
+                break;
+
+            case tok::NUMBER:
+            case tok::OTHER: // -----------------------------------------------               
+                switch (token[0])
+                {
+                case '{':
+                    out << "{";  
+                    // if we are entering a new scope
+                    if (recently_seen_new_scope || recently_seen_extern)
+                    {
+                        recently_seen_new_scope = false;
+                        scopes.push(scope);
+                        scope = 0;
+                    }
+                    else
+                    {
+                        ++scope;
+                    }
+                    in_initialization_list = false;
+                    recently_seen_paren = false;
+                    recently_seen_class_keyword = false;
+                    recently_seen_extern = false;
+                    break;
+                case '}':
+                    out << "}";
+                    if (scope > 0)
+                    {
+                        --scope;
+                    }
+                    else if (scopes.size())
+                    {
+                        scopes.pop(scope);
+                    }
+                    recently_seen_paren = false;
+                    break;
+
+                case ':':
+                    out << ':';
+                    if (recently_seen_paren && scope == 0 &&
+                        recently_seen_preprocessor == false)
+                    {
+                        in_initialization_list = true;
+                    }
+                    recently_seen_paren = false;
+                    break;
+
+                case ';': 
+                    out << ';';
+                    recently_seen_new_scope = false;
+                    recently_seen_paren = false;
+                    recently_seen_extern = false;
+                    break;
+
+                case ')':
+                    out << ')';
+                    recently_seen_paren = true;
+                    recently_seen_new_scope = false;
+                    --paren_count;
+                    break;
+
+                case '(':
+                    out << '(';
+                    recently_seen_paren = false;
+                    ++paren_count;
+                    break;
+
+                case '>':
+                    recently_seen_include = false;
+                    out << ">";
+                    recently_seen_paren = true;
+                    break;
+
+                case '<':
+                    out << "<";
+                    recently_seen_paren = true;
+                    break;
+
+                case '&':
+                    out << "&";
+                    recently_seen_paren = true;
+                    break;
+
+                default:
+                    out << token;
+                    recently_seen_paren = false;
+                    if (token == ">")
+                        recently_seen_include = false;
+                    break;
+
+                } // switch (token[0])
+                break;
+
+            } // switch (type)
+
+            t.get_token(type,token);
+        } // while (type != tok::END_OF_FILE)
+
+
+        out << "
"; + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::print"); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + void cpp_pretty_printer_kernel_2:: + print_and_number ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const + { + using namespace std; + ostringstream sout; + print(in,sout,title); + istringstream sin(sout.str()); + number(sin,out); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + void cpp_pretty_printer_kernel_2:: + number ( + std::istream& in, + std::ostream& out + ) const + { + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::number"); + + std::string space = "   "; + std::ios::int_type ch; + unsigned long count = 1; + while ((ch=in.get()) != EOF) + { + if (ch != '\n') + { + out << (char)ch; + } + else + { + out << "\n" << count << " " + space; + ++count; + if (count == 10) + space = "  "; + if (count == 100) + space = " "; + if (count == 1000) + space = ""; + } + } + if (!out) + throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_2::number"); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack, + typename tok + > + const std::string cpp_pretty_printer_kernel_2:: + htmlify ( + const std::string& str + ) const + { + std::string::size_type i; + std::string temp; + for (i = 0; i < str.size(); ++i) + { + if (str[i] == '<') + temp += "<"; + else if (str[i] == '>') + temp += ">"; + else if (str[i] == '&') + temp += "&"; + else + temp += str[i]; + } + return temp; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_2_ + diff --git a/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_abstract.h b/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..ee93a0bf4b81c7276b4b0245fffd8c83c2b72d9d --- /dev/null +++ b/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_abstract.h @@ -0,0 +1,88 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_ +#ifdef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_ + +#include +#include + +namespace dlib +{ + + class cpp_pretty_printer + { + /*! + INITIAL VALUE + This object does not have any state associated with it. + + WHAT THIS OBJECT REPRESENTS + This object represents an HTML pretty printer for C++ source code. + + !*/ + + public: + + cpp_pretty_printer ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~cpp_pretty_printer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void print ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const; + /*! + ensures + - treats data from in as C++ source code and pretty prints it in + HTML and writes it to out. + - The title of the HTML document writen to out will be title + throws + - std::ios_base::failure + If there was a problem writing to out then this exception will + be thrown. + - any other exception + This exception may be thrown if there is any other problem. + !*/ + + void print_and_number ( + std::istream& in, + std::ostream& out, + const std::string& title + ) const; + /*! + ensures + - treats data from in as C++ source code and pretty prints it in + HTML with line numbers and writes it to out. + - The title of the HTML document writen to out will be title + throws + - std::ios_base::failure + If there was a problem writing to out then this exception will + be thrown. + - any other exception + This exception may be thrown if there is any other problem. + !*/ + + private: + + // restricted functions + cpp_pretty_printer(const cpp_pretty_printer&); // copy constructor + cpp_pretty_printer& operator=(const cpp_pretty_printer&); // assignment operator + + }; + +} + +#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_ + diff --git a/dlib/cpp_tokenizer.h b/dlib/cpp_tokenizer.h new file mode 100644 index 0000000000000000000000000000000000000000..fb9f2362f6bebb4bcca02044fdec3d4d48f542dc --- /dev/null +++ b/dlib/cpp_tokenizer.h @@ -0,0 +1,40 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CPP_TOKENIZEr_ +#define DLIB_CPP_TOKENIZEr_ + +#include +#include "cpp_tokenizer/cpp_tokenizer_kernel_1.h" +#include "cpp_tokenizer/cpp_tokenizer_kernel_c.h" +#include "tokenizer.h" +#include "queue.h" +#include "set.h" + +namespace dlib +{ + + class cpp_tokenizer + { + cpp_tokenizer() {} + + + typedef set::kernel_1a set; + typedef queue::kernel_2a queue; + typedef tokenizer::kernel_1a tok; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef cpp_tokenizer_kernel_1 + kernel_1a; + typedef cpp_tokenizer_kernel_c + kernel_1a_c; + + + }; +} + +#endif // DLIB_CPP_TOKENIZEr_ + diff --git a/dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h b/dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..de7bf2f67c41a3fdeabe89096a0047cac27bdfce --- /dev/null +++ b/dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h @@ -0,0 +1,674 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CPP_TOKENIZER_KERNEl_1_ +#define DLIB_CPP_TOKENIZER_KERNEl_1_ + +#include +#include +#include "cpp_tokenizer_kernel_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + namespace cpp_tok_kernel_1_helper + { + struct token_text_pair + { + std::string token; + int type; + }; + + } + + template < + typename tok, + typename queue, + typename set + > + class cpp_tokenizer_kernel_1 + { + /*! + REQUIREMENTS ON tok + tok must be an implementation of tokenizer/tokenizer_kernel_abstract.h + + REQUIREMENTS ON queue + queue must be an implementation of queue/queue_kernel_abstract.h + and must have T==cpp_tok_kernel_1_helper::token_text_pair + + REQUIREMENTS ON set + set must be an implemention of set/set_kernel_abstract.h or + hash_set/hash_set_kernel_abstract.h and must have T==std::string. + + INITIAL VALUE + - keywords == a set of all the C++ keywords + - tokenizer.stream_is_set() == false + - buffer.size() == 0 + - tokenizer.get_identifier_head() == "$_" + tokenizer.lowercase_letters() + + tokenizer.uppercase_letters() + - tokenizer.get_identifier_body() == "$_" + tokenizer.lowercase_letters() + + tokenizer.uppercase_letters() + tokenizer.numbers() + - have_peeked == false + + + CONVENTION + - tokenizer.stream_is_set() == stream_is_set() + - tokenizer.get_stream() == get_stream() + - keywords == a set of all the C++ keywords + + - tokenizer.get_identifier_head() == "$_" + tokenizer.lowercase_letters() + + tokenizer.uppercase_letters() + - tokenizer.get_identifier_body() == "$_" + tokenizer.lowercase_letters() + + tokenizer.uppercase_letters() + tokenizer.numbers() + + - buffer == a queue of tokens. This is where we put tokens + we gathered early due to looking ahead. + + + - if (have_peeked) then + - next_token == the next token to be returned from get_token() + - next_type == the type of token in peek_token + !*/ + + typedef cpp_tok_kernel_1_helper::token_text_pair token_text_pair; + + public: + + enum + { + END_OF_FILE, + KEYWORD, + COMMENT, + SINGLE_QUOTED_TEXT, + DOUBLE_QUOTED_TEXT, + IDENTIFIER, + OTHER, + NUMBER, + WHITE_SPACE + }; + + cpp_tokenizer_kernel_1 ( + ); + + virtual ~cpp_tokenizer_kernel_1 ( + ); + + void clear( + ); + + void set_stream ( + std::istream& in + ); + + bool stream_is_set ( + ) const; + + std::istream& get_stream ( + ) const; + + void get_token ( + int& type, + std::string& token + ); + + int peek_type ( + ) const; + + const std::string& peek_token ( + ) const; + + void swap ( + cpp_tokenizer_kernel_1& item + ); + + private: + + void buffer_token( + int type, + const std::string& token + ) + /*! + ensures + - stores the token and its type into buffer + !*/ + { + token_text_pair temp; + temp.token = token; + temp.type = type; + buffer.enqueue(temp); + } + + void buffer_token( + int type, + char token + ) + /*! + ensures + - stores the token and its type into buffer + !*/ + { + token_text_pair temp; + temp.token = token; + temp.type = type; + buffer.enqueue(temp); + } + + // restricted functions + cpp_tokenizer_kernel_1(const cpp_tokenizer_kernel_1&); // copy constructor + cpp_tokenizer_kernel_1& operator=(const cpp_tokenizer_kernel_1&); // assignment operator + + // data members + set keywords; + queue buffer; + tok tokenizer; + + mutable std::string next_token; + mutable int next_type; + mutable bool have_peeked; + + + }; + + template < + typename tok, + typename queue, + typename set + > + inline void swap ( + cpp_tokenizer_kernel_1& a, + cpp_tokenizer_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + cpp_tokenizer_kernel_1:: + cpp_tokenizer_kernel_1( + ) : + have_peeked(false) + { + // add C++ keywords to keywords + std::string temp; + temp = "#include"; keywords.add(temp); + temp = "__asm"; keywords.add(temp); + temp = "_asm"; keywords.add(temp); + temp = "if"; keywords.add(temp); + temp = "int"; keywords.add(temp); + temp = "else"; keywords.add(temp); + temp = "template"; keywords.add(temp); + temp = "void"; keywords.add(temp); + temp = "false"; keywords.add(temp); + temp = "class"; keywords.add(temp); + temp = "public"; keywords.add(temp); + temp = "while"; keywords.add(temp); + temp = "bool"; keywords.add(temp); + temp = "new"; keywords.add(temp); + temp = "delete"; keywords.add(temp); + temp = "true"; keywords.add(temp); + temp = "typedef"; keywords.add(temp); + temp = "const"; keywords.add(temp); + temp = "virtual"; keywords.add(temp); + temp = "inline"; keywords.add(temp); + temp = "for"; keywords.add(temp); + temp = "break"; keywords.add(temp); + temp = "struct"; keywords.add(temp); + temp = "float"; keywords.add(temp); + temp = "case"; keywords.add(temp); + temp = "enum"; keywords.add(temp); + temp = "this"; keywords.add(temp); + temp = "typeid"; keywords.add(temp); + temp = "double"; keywords.add(temp); + temp = "char"; keywords.add(temp); + temp = "typename"; keywords.add(temp); + temp = "signed"; keywords.add(temp); + temp = "friend"; keywords.add(temp); + temp = "wint_t"; keywords.add(temp); + temp = "default"; keywords.add(temp); + temp = "asm"; keywords.add(temp); + temp = "reinterpret_cast"; keywords.add(temp); + temp = "#define"; keywords.add(temp); + temp = "do"; keywords.add(temp); + temp = "continue"; keywords.add(temp); + temp = "auto"; keywords.add(temp); + temp = "unsigned"; keywords.add(temp); + temp = "size_t"; keywords.add(temp); + temp = "#undef"; keywords.add(temp); + temp = "#pragma"; keywords.add(temp); + temp = "namespace"; keywords.add(temp); + temp = "private"; keywords.add(temp); + temp = "#endif"; keywords.add(temp); + temp = "catch"; keywords.add(temp); + temp = "#else"; keywords.add(temp); + temp = "register"; keywords.add(temp); + temp = "volatile"; keywords.add(temp); + temp = "const_cast"; keywords.add(temp); + temp = "#end"; keywords.add(temp); + temp = "mutable"; keywords.add(temp); + temp = "static_cast"; keywords.add(temp); + temp = "wchar_t"; keywords.add(temp); + temp = "#if"; keywords.add(temp); + temp = "protected"; keywords.add(temp); + temp = "throw"; keywords.add(temp); + temp = "using"; keywords.add(temp); + temp = "dynamic_cast"; keywords.add(temp); + temp = "#ifdef"; keywords.add(temp); + temp = "return"; keywords.add(temp); + temp = "short"; keywords.add(temp); + temp = "#error"; keywords.add(temp); + temp = "#line"; keywords.add(temp); + temp = "explicit"; keywords.add(temp); + temp = "union"; keywords.add(temp); + temp = "#ifndef"; keywords.add(temp); + temp = "try"; keywords.add(temp); + temp = "sizeof"; keywords.add(temp); + temp = "goto"; keywords.add(temp); + temp = "long"; keywords.add(temp); + temp = "#elif"; keywords.add(temp); + temp = "static"; keywords.add(temp); + temp = "operator"; keywords.add(temp); + temp = "switch"; keywords.add(temp); + temp = "extern"; keywords.add(temp); + + + // set the tokenizer's IDENTIFIER token for C++ identifiers + tokenizer.set_identifier_token( + "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(), + "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() + + tokenizer.numbers() + ); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + cpp_tokenizer_kernel_1:: + ~cpp_tokenizer_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + void cpp_tokenizer_kernel_1:: + clear( + ) + { + tokenizer.clear(); + buffer.clear(); + have_peeked = false; + + // set the tokenizer's IDENTIFIER token for C++ identifiers + tokenizer.set_identifier_token( + "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(), + "$_" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() + + tokenizer.numbers() + ); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + void cpp_tokenizer_kernel_1:: + set_stream ( + std::istream& in + ) + { + tokenizer.set_stream(in); + buffer.clear(); + have_peeked = false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + bool cpp_tokenizer_kernel_1:: + stream_is_set ( + ) const + { + return tokenizer.stream_is_set(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + std::istream& cpp_tokenizer_kernel_1:: + get_stream ( + ) const + { + return tokenizer.get_stream(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + void cpp_tokenizer_kernel_1:: + get_token ( + int& type, + std::string& token + ) + { + using namespace std; + + if (!have_peeked) + { + + if (buffer.size() > 0) + { + // just return what is in the buffer + token_text_pair temp; + buffer.dequeue(temp); + type = temp.type; + token = temp.token; + return; + } + + tokenizer.get_token(type,token); + + switch (type) + { + case tok::END_OF_FILE: + { + type = END_OF_FILE; + } break; + + case tok::END_OF_LINE: + case tok::WHITE_SPACE: + { + type = tokenizer.peek_type(); + if (type == tok::END_OF_LINE || type == tok::WHITE_SPACE) + { + std::string temp; + do + { + tokenizer.get_token(type,temp); + token += temp; + type = tokenizer.peek_type(); + }while (type == tok::END_OF_LINE || type == tok::WHITE_SPACE); + } + type = WHITE_SPACE; + + } break; + + case tok::NUMBER: + { + // this could be a hex number such as 0xa33. we should check for this. + if (tokenizer.peek_type() == tok::IDENTIFIER && token == "0" && + (tokenizer.peek_token()[0] == 'x' || tokenizer.peek_token()[0] == 'X')) + { + // this is a hex number so accumulate all the numbers and identifiers that follow + // because they have to be part of the number + std::string temp; + tokenizer.get_token(type,temp); + token = "0" + temp; + + // get the rest of the hex number + while (tokenizer.peek_type() == tok::IDENTIFIER || + tokenizer.peek_type() == tok::NUMBER + ) + { + tokenizer.get_token(type,temp); + token += temp; + } + + } + // or this could be a floating point value + else if (tokenizer.peek_type() == tok::CHAR && tokenizer.peek_token()[0] == '.') + { + std::string temp; + tokenizer.get_token(type,temp); + token += '.'; + // now get the rest of the floating point value + while (tokenizer.peek_type() == tok::IDENTIFIER || + tokenizer.peek_type() == tok::NUMBER + ) + { + tokenizer.get_token(type,temp); + token += temp; + } + } + type = NUMBER; + + } break; + + case tok::IDENTIFIER: + { + if (keywords.is_member(token)) + { + type = KEYWORD; + } + else + { + type = IDENTIFIER; + } + } break; + + case tok::CHAR: + type = OTHER; + switch (token[0]) + { + case '#': + { + // this might be a preprocessor keyword so we should check the + // next token + if (tokenizer.peek_type() == tok::IDENTIFIER && + keywords.is_member('#'+tokenizer.peek_token())) + { + tokenizer.get_token(type,token); + token = '#' + token; + type = KEYWORD; + } + else + { + token = '#'; + type = OTHER; + } + } + break; + + case '"': + { + string temp; + tokenizer.get_token(type,token); + while (type != tok::END_OF_FILE) + { + // if this is the end of the quoted string + if (type == tok::CHAR && token[0] == '"' && + (temp.size() == 0 || temp[temp.size()-1] != '\\' || + (temp.size() > 1 && temp[temp.size()-2] == '\\') )) + { + buffer_token(DOUBLE_QUOTED_TEXT,temp); + buffer_token(OTHER,'"'); + break; + } + else + { + temp += token; + } + tokenizer.get_token(type,token); + } + + + type = OTHER; + token = '"'; + } break; + + case '\'': + { + string temp; + tokenizer.get_token(type,token); + if (type == tok::CHAR && token[0] == '\\') + { + temp += '\\'; + tokenizer.get_token(type,token); + } + temp += token; + buffer_token(SINGLE_QUOTED_TEXT,temp); + + // The next character should be a ' so take it out and put it in + // the buffer. + tokenizer.get_token(type,token); + buffer_token(OTHER,token); + + type = OTHER; + token = '\''; + } break; + + case '/': + { + // look ahead to see if this is the start of a comment + if (tokenizer.peek_type() == tok::CHAR) + { + if (tokenizer.peek_token()[0] == '/') + { + tokenizer.get_token(type,token); + // this is the start of a line comment + token = "//"; + string temp; + tokenizer.get_token(type,temp); + while (type != tok::END_OF_FILE) + { + // if this is the end of the comment + if (type == tok::END_OF_LINE && + token[token.size()-1] != '\\' ) + { + token += '\n'; + break; + } + else + { + token += temp; + } + tokenizer.get_token(type,temp); + } + type = COMMENT; + + } + else if (tokenizer.peek_token()[0] == '*') + { + tokenizer.get_token(type,token); + // this is the start of a block comment + token = "/*"; + string temp; + tokenizer.get_token(type,temp); + while (type != tok::END_OF_FILE) + { + // if this is the end of the comment + if (type == tok::CHAR && temp[0] == '/' && + token[token.size()-1] == '*') + { + token += '/'; + break; + } + else + { + token += temp; + } + tokenizer.get_token(type,temp); + } + type = COMMENT; + } + } + } break; + + default: + break; + } // switch (token[0]) + } // switch (type) + } + else + { + // if we get this far it means we have peeked so we should + // return the peek data. + type = next_type; + token = next_token; + have_peeked = false; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + int cpp_tokenizer_kernel_1:: + peek_type ( + ) const + { + const_cast*>(this)->get_token(next_type,next_token); + have_peeked = true; + return next_type; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + const std::string& cpp_tokenizer_kernel_1:: + peek_token ( + ) const + { + const_cast*>(this)->get_token(next_type,next_token); + have_peeked = true; + return next_token; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tok, + typename queue, + typename set + > + void cpp_tokenizer_kernel_1:: + swap ( + cpp_tokenizer_kernel_1& item + ) + { + tokenizer.swap(item.tokenizer); + buffer.swap(item.buffer); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CPP_TOKENIZER_KERNEl_1_ + diff --git a/dlib/cpp_tokenizer/cpp_tokenizer_kernel_abstract.h b/dlib/cpp_tokenizer/cpp_tokenizer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..77213c1ac87af5cfed9166a214cfeef0cbf3f546 --- /dev/null +++ b/dlib/cpp_tokenizer/cpp_tokenizer_kernel_abstract.h @@ -0,0 +1,224 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_ +#ifdef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_ + +#include +#include + +namespace dlib +{ + + class cpp_tokenizer + { + /*! + INITIAL VALUE + stream_is_set() == false + + WHAT THIS OBJECT REPRESENTS + This object represents a simple tokenizer for C++ source code. + + BUFFERING + This object is allowed to buffer data from the input stream. + Thus if you clear it or switch streams (via calling set_stream()) + any buffered data will be lost. + + TOKENS + When picking out tokens the cpp_tokenizer will always extract the + longest token it can. For example, if faced with the string + "AAA" it will consider the three As to be a single IDENTIFIER + token not three smaller IDENTIFIER tokens. + + Also note that no characters in the input stream are discarded. + They will all be returned in the text of some token. + Additionally, each character will never be returned more than once. + This means that if you concatenated all returned tokens it would exactly + reproduce the contents of the input stream. + + The tokens are defined as follows: + + END_OF_FILE + This token represents the end of file. It doesn't have any + actual characters associated with it. + + KEYWORD + This token matches a C++ keyword. (This includes the preprocessor + directives). + + COMMENT + This token matches a C++ comment. + + SINGLE_QUOTED_TEXT + This token matches the text of any single quoted literal. + For example, 'a' would be a match and the text of this token + would be the single character a. + + DOUBLE_QUOTED_TEXT + This token matches the text of any double quoted string. + For example, "C++" would be a match and the text of this token + would be the three character string C++. + + WHITE_SPACE + This is a multi character token. It is defined as a sequence of + one or more spaces, carrage returns, newlines, and tabs. I.e. It + is composed of characters from the following string " \r\n\t". + + IDENTIFIER + This token matches any C++ identifier that isn't matched by any + of the above tokens. (A C++ identifier being a string matching + the regular expression [_$a-zA-Z][_$a-zA-Z0-9]*). + + NUMBER + This token matches any C++ numerical constant. + + OTHER + This matches anything that isn't part of one of the above tokens. + It is always a single character. + !*/ + + public: + + enum + { + END_OF_FILE, + KEYWORD, + COMMENT, + SINGLE_QUOTED_TEXT, + DOUBLE_QUOTED_TEXT, + IDENTIFIER, + OTHER, + NUMBER, + WHITE_SPACE + }; + + cpp_tokenizer ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~cpp_tokenizer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + If this exception is thrown then #*this is unusable + until clear() is called and succeeds. + !*/ + + void set_stream ( + std::istream& in + ); + /*! + ensures + - #*this will read data from in and tokenize it + - #stream_is_set() == true + - #get_stream() == in + !*/ + + bool stream_is_set ( + ) const; + /*! + ensures + - returns true if a stream has been associated with *this by calling + set_stream() + !*/ + + std::istream& get_stream ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns a reference to the istream object that *this is reading + from. + !*/ + + void get_token ( + int& type, + std::string& token + ); + /*! + requires + - stream_is_set() == true + ensures + - #token == the next token from the input stream get_stream() + - #type == the type of the token in #token + throws + - bad_alloc + If this exception is thrown then the call to this function will + have no effect on *this but the values of #type and #token will be + undefined. Additionally, some characters may have been read + from the stream get_stream() and lost. + !*/ + + int peek_type ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns the type of the token that will be returned from + the next call to get_token() + throws + - bad_alloc + If this exception is thrown then the call to this function will + have no effect on *this. However, some characters may have been + read from the stream get_stream() and lost. + !*/ + + const std::string& peek_token ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns the text of the token that will be returned from + the next call to get_token() + throws + - bad_alloc + If this exception is thrown then the call to this function will + have no effect on *this. However, some characters may have been + read from the stream get_stream() and lost. + !*/ + + void swap ( + cpp_tokenizer& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + cpp_tokenizer(const cpp_tokenizer&); // copy constructor + cpp_tokenizer& operator=(const cpp_tokenizer&); // assignment operator + + }; + + inline void swap ( + cpp_tokenizer& a, + cpp_tokenizer& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_ + diff --git a/dlib/cpp_tokenizer/cpp_tokenizer_kernel_c.h b/dlib/cpp_tokenizer/cpp_tokenizer_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..d8f3ba721b996f56e934aefd7cab18082a61e164 --- /dev/null +++ b/dlib/cpp_tokenizer/cpp_tokenizer_kernel_c.h @@ -0,0 +1,137 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CPP_TOKENIZER_KERNEl_C_ +#define DLIB_CPP_TOKENIZER_KERNEl_C_ + +#include "cpp_tokenizer_kernel_abstract.h" +#include "../assert.h" +#include +#include + +namespace dlib +{ + + template < + typename tokenizer + > + class cpp_tokenizer_kernel_c : public tokenizer + { + + public: + std::istream& get_stream ( + ) const; + + void get_token ( + int& type, + std::string& token + ); + + int peek_type ( + ) const; + + const std::string& peek_token ( + ) const; + + }; + + template < + typename tokenizer + > + inline void swap ( + cpp_tokenizer_kernel_c& a, + cpp_tokenizer_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + std::istream& cpp_tokenizer_kernel_c:: + get_stream ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tstd::istream& cpp_tokenizer::get_stream()" + << "\n\tyou must set a stream for this object before you can get it" + << "\n\tthis: " << this + ); + + // call the real function + return tokenizer::get_stream(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + const std::string& cpp_tokenizer_kernel_c:: + peek_token ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tconst std::string& cpp_tokenizer::peek_token()" + << "\n\tyou must set a stream for this object before you can peek at what it contains" + << "\n\tthis: " << this + ); + + // call the real function + return tokenizer::peek_token(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + int cpp_tokenizer_kernel_c:: + peek_type ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tint cpp_tokenizer::peek_type()" + << "\n\tyou must set a stream for this object before you can peek at what it contains" + << "\n\tthis: " << this + ); + + // call the real function + return tokenizer::peek_type(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + void cpp_tokenizer_kernel_c:: + get_token ( + int& type, + std::string& token + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tvoid cpp_tokenizer::get_token()" + << "\n\tyou must set a stream for this object before you can get tokens from it." + << "\n\tthis: " << this + ); + + // call the real function + tokenizer::get_token(type,token); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TOKENIZER_KERNEl_C_ + + diff --git a/dlib/crc32.h b/dlib/crc32.h new file mode 100644 index 0000000000000000000000000000000000000000..f9d9b493edbcffada5d2101832841fdc4916a0ad --- /dev/null +++ b/dlib/crc32.h @@ -0,0 +1,35 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CRc32_ +#define DLIB_CRc32_ + + +#include "crc32/crc32_kernel_1.h" + + + +namespace dlib +{ + + + class crc32 + { + + crc32() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef crc32_kernel_1 + kernel_1a; + + + + }; +} + +#endif // DLIB_CRc32_ + diff --git a/dlib/crc32/crc32_kernel_1.h b/dlib/crc32/crc32_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..88a553bb6994737e41392951dc217b35c3e6c700 --- /dev/null +++ b/dlib/crc32/crc32_kernel_1.h @@ -0,0 +1,158 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CRC32_KERNEl_1_ +#define DLIB_CRC32_KERNEl_1_ + +#include "../algs.h" +#include +#include "crc32_kernel_abstract.h" + +namespace dlib +{ + + class crc32_kernel_1 + { + /*! + INITIAL VALUE + checksum == 0xFFFFFFFF + table == crc table + + CONVENTION + get_checksum() == checksum ^ 0xFFFFFFFF + table == crc table + !*/ + + public: + + inline crc32_kernel_1 ( + ); + + inline virtual ~crc32_kernel_1 ( + ); + + inline void clear( + ); + + inline void add ( + unsigned char item + ); + + inline void add ( + const std::string& item + ); + + inline unsigned long get_checksum ( + ) const; + + inline void swap ( + crc32_kernel_1& item + ); + + private: + + unsigned long checksum; + unsigned long table[256]; + + // restricted functions + crc32_kernel_1(const crc32_kernel_1&); // copy constructor + crc32_kernel_1& operator=(const crc32_kernel_1&); // assignment operator + + }; + + inline void swap ( + crc32_kernel_1& a, + crc32_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + crc32_kernel_1:: + crc32_kernel_1 ( + ) + { + checksum = 0xFFFFFFFF; + unsigned long temp; + + // fill out the crc table + for (unsigned long i = 0; i < 256; ++i) + { + temp = i; + for (unsigned long j = 0; j < 8; ++j) + { + if (temp&1) + temp = (temp>>1)^0xedb88320; + else + temp >>= 1; + } + table[i] = temp; + } + + } + +// ---------------------------------------------------------------------------------------- + + crc32_kernel_1:: + ~crc32_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + void crc32_kernel_1:: + clear( + ) + { + checksum = 0xFFFFFFFF; + } + +// ---------------------------------------------------------------------------------------- + + void crc32_kernel_1:: + add ( + unsigned char item + ) + { + checksum = (checksum>>8) ^ table[(checksum^item) & 0xFF]; + } + +// ---------------------------------------------------------------------------------------- + + void crc32_kernel_1:: + add ( + const std::string& item + ) + { + for (std::string::size_type i = 0; i < item.size(); ++i) + checksum = (checksum>>8) ^ table[(checksum^item[i]) & 0xFF]; + } + +// ---------------------------------------------------------------------------------------- + + unsigned long crc32_kernel_1:: + get_checksum ( + ) const + { + return checksum ^ 0xFFFFFFFF; + } + +// ---------------------------------------------------------------------------------------- + + void crc32_kernel_1:: + swap ( + crc32_kernel_1& item + ) + { + exchange(checksum,item.checksum); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CRC32_KERNEl_1_ + diff --git a/dlib/crc32/crc32_kernel_abstract.h b/dlib/crc32/crc32_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c7ade07b7c9c8d5beb6f5d178fd35e28fd8e3ac7 --- /dev/null +++ b/dlib/crc32/crc32_kernel_abstract.h @@ -0,0 +1,105 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CRC32_KERNEl_ABSTRACT_ +#ifdef DLIB_CRC32_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include + +namespace dlib +{ + + class crc32 + { + /*! + INITIAL VALUE + The current checksum covers zero bytes. + get_checksum() == 0x00000000 + + WHAT THIS OBJECT REPRESENTS + This object represents the CRC32 algorithm for calculating + checksums. + !*/ + + public: + + crc32 ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~crc32 ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void add ( + unsigned char item + ); + /*! + ensures + - #get_checksum() == The checksum of all items added to *this previously + concatenated with item. + !*/ + + void add ( + const std::string& item + ); + /*! + ensures + - #get_checksum() == The checksum of all items added to *this previously + concatenated with item. + !*/ + + unsigned long get_checksum ( + ) const; + /*! + ensures + - returns the current checksum + !*/ + + void swap ( + crc32& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + crc32(const crc32&); // copy constructor + crc32& operator=(const crc32&); // assignment operator + + }; + + void swap ( + crc32& a, + crc32& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_CRC32_KERNEl_ABSTRACT_ + diff --git a/dlib/cstring b/dlib/cstring new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/cstring @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/dir_nav.h b/dlib/dir_nav.h new file mode 100644 index 0000000000000000000000000000000000000000..e2418a21aedacf8846262a94c7a3a6b2721874eb --- /dev/null +++ b/dlib/dir_nav.h @@ -0,0 +1,20 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAv_ +#define DLIB_DIR_NAv_ + + +#include "platform.h" + + +#ifdef WIN32 +#include "dir_nav/windows.h" +#endif + +#ifndef WIN32 +#include "dir_nav/posix.h" +#endif + + +#endif // DLIB_DIR_NAv_ + diff --git a/dlib/dir_nav/dir_nav_kernel_1.cpp b/dlib/dir_nav/dir_nav_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1477bc2dd64890cf0db6910d67c3bb81e17fcfe --- /dev/null +++ b/dlib/dir_nav/dir_nav_kernel_1.cpp @@ -0,0 +1,256 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEL_1_CPp_ +#define DLIB_DIR_NAV_KERNEL_1_CPp_ +#include "../platform.h" + +#ifdef WIN32 + +#include "dir_nav_kernel_1.h" +#include "../string.h" + + +#ifdef __BORLANDC__ +// Apparently the borland compiler doesn't define this. +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + file:: + file ( + const std::string& name + ) + { + using namespace std; + state = new data; + state->count = 1; + + + char buf[3000]; + char* str; + if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0) + { + // the file was not found + throw file_not_found("Unable to find file " + name); + } + state->full_name = buf; + + + string::size_type pos = state->full_name.find_last_of(directory::get_separator()); + if (pos == string::npos) + { + // no valid full path has no separtor characters. + throw file_not_found("Unable to find file " + name); + } + state->name = state->full_name.substr(pos+1); + + + // now find the size of this file + WIN32_FIND_DATAA data; + HANDLE ffind = FindFirstFileA(state->full_name.c_str(), &data); + if (ffind == INVALID_HANDLE_VALUE || + (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0) + { + throw file_not_found("Unable to find file " + name); + } + else + { + uint64 temp = data.nFileSizeHigh; + temp <<= 32; + temp |= data.nFileSizeLow; + state->file_size = temp; + FindClose(ffind); + } + + } + +// ---------------------------------------------------------------------------------------- + + bool file:: + operator == ( + const file& rhs + ) const + { + using namespace std; + + if (state->full_name.size() != rhs.state->full_name.size()) + return false; + + // compare the strings but ignore the case because file names + // are not case sensitive on windows + return tolower(state->full_name) == tolower(rhs.state->full_name); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + directory:: + directory ( + const std::string& name + ) + { + using namespace std; + + state = new data; + state->count = 1; + + char buf[3000]; + char* str; + if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + state->full_name = buf; + + + const char sep = get_separator(); + if (is_root_path(state->full_name) == false) + { + // ensure that thre is not a trialing separator + if (state->full_name[state->full_name.size()-1] == sep) + state->full_name.erase(state->full_name.size()-1); + + // pick out the directory name + string::size_type pos = state->full_name.find_last_of(sep); + state->name = state->full_name.substr(pos+1); + } + else + { + // ensure that there is a trailing separator + if (state->full_name[state->full_name.size()-1] != sep) + state->full_name += sep; + } + + + // now check that this is actually a valid directory + DWORD attribs = GetFileAttributesA(state->full_name.c_str()); + if (attribs == INVALID_FILE_ATTRIBUTES || + (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + + } + +// ---------------------------------------------------------------------------------------- + + char directory:: + get_separator ( + ) + { + return '\\'; + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + operator == ( + const directory& rhs + ) const + { + using namespace std; + + if (state->full_name.size() != rhs.state->full_name.size()) + return false; + + // compare the strings but ignore the case because file names + // are not case sensitive on windows + return tolower(state->full_name) == tolower(rhs.state->full_name); + } + +// ---------------------------------------------------------------------------------------- + + const directory directory:: + get_parent ( + ) const + { + using namespace std; + // if *this is the root then just return *this + if (is_root()) + { + return *this; + } + else + { + directory temp; + + const char sep = get_separator(); + + string::size_type pos = state->full_name.find_last_of(sep); + temp.state->full_name = state->full_name.substr(0,pos); + + if ( is_root_path(temp.state->full_name)) + { + temp.state->full_name += sep; + } + else + { + pos = temp.state->full_name.find_last_of(sep); + if (pos != string::npos) + { + temp.state->name = temp.state->full_name.substr(pos+1); + } + else + { + temp.state->full_name += sep; + } + } + return temp; + } + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + is_root_path ( + const std::string& path + ) const + { + using namespace std; + const char sep = get_separator(); + bool root_path = false; + if (path.size() > 2 && path[0] == sep && path[1] == sep) + { + // in this case this is a windows share path + string::size_type pos = path.find_first_of(sep,2); + if (pos != string::npos) + { + pos = path.find_first_of(sep,pos+1); + + if (pos == string::npos && path[path.size()-1] != sep) + root_path = true; + else if (pos == path.size()-1) + root_path = true; + } + + } + else if ( (path.size() == 2 || path.size() == 3) && path[1] == ':') + { + // if this is a valid windows path then it must be a root path + root_path = true; + } + + return root_path; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // WIN32 + +#endif // DLIB_DIR_NAV_KERNEL_1_CPp_ + diff --git a/dlib/dir_nav/dir_nav_kernel_1.h b/dlib/dir_nav/dir_nav_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..a9fae23b4593b98f4de58f9d3aa8c0fbc8ac40ea --- /dev/null +++ b/dlib/dir_nav/dir_nav_kernel_1.h @@ -0,0 +1,523 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_1_ +#define DLIB_DIR_NAV_KERNEl_1_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#include "../platform.h" + + +#include "dir_nav_kernel_abstract.h" +#include +#include "../uintn.h" +#include "../algs.h" + +#include "../windows_magic.h" +#include + +namespace dlib +{ + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + INITIAL VALUES + state->name == name() + state->full_name == full_name() + state->file_size == size() + + CONVENTION + state->name == name() + state->full_name == full_name() + state->file_size == size() + state->count == the number of file objects that point to state + + !*/ + + friend class directory; + + struct data + { + uint64 file_size; + std::string name; + std::string full_name; + unsigned long count; + }; + + inline file ( + const std::string& name, + const std::string& full_name, + const uint64 file_size + ) + { + state = new data; + state->count = 1; + state->file_size = file_size; + state->name = name; + state->full_name = full_name; + } + + + + + public: + class file_not_found : public error { + public: file_not_found(const std::string& s): error(s){} + }; + + inline file ( + ) + { + state = new data; + state->count = 1; + state->file_size = 0; + } + + file ( + const std::string& name + ); + + inline file ( + const file& item + ) + { + state = item.state; + state->count += 1; + } + + inline ~file ( + ) + { + if (state->count == 1) + delete state; + else + state->count -= 1; + } + + inline const std::string& name ( + ) const { return state->name; } + + inline const std::string& full_name ( + ) const { return state->full_name; } + + inline uint64 size ( + ) const { return state->file_size; } + + inline file& operator= ( + const file& rhs + ) + { + if (&rhs == this) + return *this; + + if (state->count == 1) + delete state; + else + state->count -= 1; + + state = rhs.state; + state->count += 1; + return *this; + } + + bool operator == ( + const file& rhs + ) const; + + inline bool operator < ( + const file& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + file& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data* state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + INITIAL VALUES + state->name == name() + state->full_name == full_name() + + CONVENTION + state->name == name() + state->full_name == full_name() + state->count == the number of directory objects that point to state + is_root() == state->name.size() == 0 + + !*/ + struct data + { + std::string name; + std::string full_name; + unsigned long count; + }; + + public: + + /* + The reason we don't just make this constructor actually + private is because doing it this way avoids a bug that + sometimes occurs in visual studio 7.1. The bug has + something to do with templated friend functions + such as the get_filesystem_roots() function below if + it was declared as a friend template of this class. + */ + struct private_constructor{}; + inline directory ( + const std::string& name, + const std::string& full_name, + private_constructor + ) + { + state = new data; + state->count = 1; + state->name = name; + state->full_name = full_name; + } + + + class dir_not_found : public error { + public: dir_not_found(const std::string& s):error(s){} + }; + class listing_error : public error { + public: listing_error(const std::string& s):error(s){} + }; + + inline directory ( + ) + { + state = new data; + state->count = 1; + } + + directory ( + const std::string& name + ); + + inline directory ( + const directory& item + ) + { + state = item.state; + state->count += 1; + } + + inline ~directory ( + ) + { + if (state->count == 1) + delete state; + else + state->count -= 1; + } + + static char get_separator ( + ); + + template < + typename queue_of_files + // Is an implementation of queue/queue_kernel_abstract.h with T set to file. + > + void get_files ( + queue_of_files& files + ) const; + + template < + typename queue_of_dirs + // Is an implementation of queue/queue_kernel_abstract.h with T set to directory. + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + + const directory get_parent ( + ) const; + + inline bool is_root ( + ) const { return state->name.size() == 0; } + + inline const std::string& name ( + ) const { return state->name; } + + inline const std::string& full_name ( + ) const { return state->full_name; } + + directory& operator= ( + const directory& rhs + ) + { + if (&rhs == this) + return *this; + + if (state->count == 1) + delete state; + else + state->count -= 1; + + state = rhs.state; + state->count += 1; + return *this; + } + + bool operator == ( + const directory& rhs + ) const; + + inline bool operator < ( + const directory& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + directory& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data* state; + + bool is_root_path ( + const std::string& path + ) const; + /*! + ensures + - returns true if path is a root path. + Note that this function considers root paths that don't + have a trailing separator to also be valid. + !*/ + + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + > + void get_filesystem_roots ( + queue_of_dir& roots + ) + { + roots.clear(); + const DWORD mask = GetLogicalDrives(); + DWORD bit = 1; + char buf[] = "A:\\"; + + do + { + if (mask & bit) + { + directory dir("",buf,directory::private_constructor()); + roots.enqueue(dir); + } + bit <<= 1; + ++buf[0]; + } while (buf[0] != 'Z'); + } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // templated member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + void directory:: + get_files ( + queue_of_files& files + ) const + { + using namespace std; + + files.clear(); + if (state->full_name.size() == 0) + throw listing_error("This directory object currently doesn't represent any directory."); + + HANDLE ffind = INVALID_HANDLE_VALUE; + try + { + WIN32_FIND_DATAA data; + string path = state->full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != get_separator()) + path += get_separator(); + + ffind = FindFirstFileA((path+"*").c_str(), &data); + if (ffind == INVALID_HANDLE_VALUE) + { + throw listing_error("Unable to list the contents of " + state->full_name); + } + + + bool no_more_files = false; + do + { + if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == 0) + { + uint64 file_size = data.nFileSizeHigh; + file_size <<= 32; + file_size |= data.nFileSizeLow; + // this is a file so add it to the queue + file temp(data.cFileName,path+data.cFileName,file_size); + files.enqueue(temp); + } + + if (FindNextFileA(ffind,&data) == 0) + { + // an error occurred + if ( GetLastError() == ERROR_NO_MORE_FILES) + { + // there are no more files + no_more_files = true; + } + else + { + // there was an error + throw listing_error("Unable to list the contents of " + state->full_name); + } + } + } while (no_more_files == false); + + FindClose(ffind); + ffind = INVALID_HANDLE_VALUE; + } + catch (...) + { + if (ffind != INVALID_HANDLE_VALUE) + FindClose(ffind); + files.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + void directory:: + get_dirs ( + queue_of_dirs& dirs + ) const + { + using namespace std; + + dirs.clear(); + if (state->full_name.size() == 0) + throw listing_error("This directory object currently doesn't represent any directory."); + + HANDLE dfind = INVALID_HANDLE_VALUE; + try + { + WIN32_FIND_DATAA data; + string path = state->full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != get_separator()) + path += get_separator(); + + dfind = FindFirstFileA((path+"*").c_str(), &data); + if (dfind == INVALID_HANDLE_VALUE) + { + throw listing_error("Unable to list the contents of " + state->full_name); + } + + + bool no_more_files = false; + do + { + string tname(data.cFileName); + if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 && + tname != "." && + tname != "..") + { + // this is a directory so add it to the queue + directory temp(tname,path+tname,private_constructor()); + dirs.enqueue(temp); + } + + if (FindNextFileA(dfind,&data) == 0) + { + // an error occurred + if ( GetLastError() == ERROR_NO_MORE_FILES) + { + // there are no more files + no_more_files = true; + } + else + { + // there was an error + throw listing_error("Unable to list the contents of " + state->full_name); + } + } + } while (no_more_files == false); + + FindClose(dfind); + dfind = INVALID_HANDLE_VALUE; + } + catch (...) + { + if (dfind != INVALID_HANDLE_VALUE) + FindClose(dfind); + dirs.clear(); + throw; + } + + } + +// ---------------------------------------------------------------------------------------- + +} + + +#ifdef NO_MAKEFILE +#include "dir_nav_kernel_1.cpp" +#endif + +#endif // DLIB_DIR_NAV_KERNEl_1_ + diff --git a/dlib/dir_nav/dir_nav_kernel_2.cpp b/dlib/dir_nav/dir_nav_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3101750e340ec57696c1b6a36e1654fd0a2e421 --- /dev/null +++ b/dlib/dir_nav/dir_nav_kernel_2.cpp @@ -0,0 +1,252 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEL_2_CPp_ +#define DLIB_DIR_NAV_KERNEL_2_CPp_ + +#include "../platform.h" + +#ifdef POSIX + + +#include "dir_nav_kernel_2.h" + + + + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + file:: + file ( + const std::string& name + ) + { + using namespace std; + state = new data; + state->count = 1; + + + + char buf[PATH_MAX]; + if (realpath(name.c_str(),buf) == 0) + { + // the file was not found + throw file_not_found("Unable to find file " + name); + } + state->full_name = buf; + + + string::size_type pos = state->full_name.find_last_of(directory::get_separator()); + if (pos == string::npos) + { + // no valid full path has no separtor characters. + throw file_not_found("Unable to find file " + name); + } + state->name = state->full_name.substr(pos+1); + + + // now find the size of this file + struct stat64 buffer; + if (::stat64(state->full_name.c_str(), &buffer) || + S_ISDIR(buffer.st_mode)) + { + // there was an error during the call to stat64 or + // name is actually a directory + throw file_not_found("Unable to find file " + name); + } + else + { + state->file_size = static_cast(buffer.st_size); + } + + } + +// ---------------------------------------------------------------------------------------- + + bool file:: + operator == ( + const file& rhs + ) const + { + using namespace std; + if (state->full_name.size() == 0 && rhs.state->full_name.size() == 0) + return true; + + // These files might have different names but actually represent the same + // file due to the presence of symbolic links. + char buf[PATH_MAX]; + string left, right; + if (realpath(state->full_name.c_str(),buf) == 0) + return false; + left = buf; + + if (realpath(rhs.state->full_name.c_str(),buf) == 0) + return false; + right = buf; + + return (left == right); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object implementation +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + directory:: + directory ( + const std::string& name + ) + { + using namespace std; + + state = new data; + state->count = 1; + + char buf[PATH_MAX]; + if (realpath(name.c_str(),buf) == 0) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + state->full_name = buf; + + + const char sep = get_separator(); + if (is_root_path(state->full_name) == false) + { + // ensure that thre is not a trialing separator + if (state->full_name[state->full_name.size()-1] == sep) + state->full_name.erase(state->full_name.size()-1); + + // pick out the directory name + string::size_type pos = state->full_name.find_last_of(sep); + state->name = state->full_name.substr(pos+1); + } + else + { + // ensure that there is a trailing separator + if (state->full_name[state->full_name.size()-1] != sep) + state->full_name += sep; + } + + + struct stat64 buffer; + // now check that this is actually a valid directory + if (::stat64(state->full_name.c_str(),&buffer)) + { + // the directory was not found + throw dir_not_found("Unable to find directory " + name); + } + else if (S_ISDIR(buffer.st_mode) == 0) + { + // It is not a directory + throw dir_not_found("Unable to find directory " + name); + } + } + +// ---------------------------------------------------------------------------------------- + + char directory:: + get_separator ( + ) + { + return '/'; + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + operator == ( + const directory& rhs + ) const + { + using namespace std; + if (state->full_name.size() == 0 && rhs.state->full_name.size() == 0) + return true; + + // These directories might have different names but actually represent the same + // directory due to the presence of symbolic links. + char buf[PATH_MAX]; + string left, right; + if (realpath(state->full_name.c_str(),buf) == 0) + return false; + left = buf; + + if (realpath(rhs.state->full_name.c_str(),buf) == 0) + return false; + right = buf; + + return (left == right); + } + +// ---------------------------------------------------------------------------------------- + + const directory directory:: + get_parent ( + ) const + { + using namespace std; + // if *this is the root then just return *this + if (is_root()) + { + return *this; + } + else + { + directory temp; + + const char sep = get_separator(); + + string::size_type pos = state->full_name.find_last_of(sep); + temp.state->full_name = state->full_name.substr(0,pos); + + if ( is_root_path(temp.state->full_name)) + { + temp.state->full_name += sep; + } + else + { + pos = temp.state->full_name.find_last_of(sep); + if (pos != string::npos) + { + temp.state->name = temp.state->full_name.substr(pos+1); + } + else + { + temp.state->full_name += sep; + } + } + return temp; + } + } + +// ---------------------------------------------------------------------------------------- + + bool directory:: + is_root_path ( + const std::string& path + ) const + { + const char sep = get_separator(); + if (path.size() == 1 && path[0] == sep) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // POSIX + +#endif // DLIB_DIR_NAV_KERNEL_2_CPp_ + diff --git a/dlib/dir_nav/dir_nav_kernel_2.h b/dlib/dir_nav/dir_nav_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..7b511d4f7d6c276c204517567f495b6285a02ffd --- /dev/null +++ b/dlib/dir_nav/dir_nav_kernel_2.h @@ -0,0 +1,564 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_2_ +#define DLIB_DIR_NAV_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + + +#include "dir_nav_kernel_abstract.h" + +#include +#include "../uintn.h" +#include "../algs.h" + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(__USE_LARGEFILE64 ) && !defined(_LARGEFILE64_SOURCE) +#define stat64 stat +#endif + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + INITIAL VALUES + state->name == name() + state->full_name == full_name() + state->file_size == size() + + CONVENTION + state->name == name() + state->full_name == full_name() + state->file_size == size() + state->count == the number of file objects that point to state + + !*/ + + friend class directory; + + struct data + { + uint64 file_size; + std::string name; + std::string full_name; + unsigned long count; + }; + + inline file ( + const std::string& name, + const std::string& full_name, + const uint64 file_size + ) + { + state = new data; + state->count = 1; + state->file_size = file_size; + state->name = name; + state->full_name = full_name; + } + + public: + class file_not_found : public error { + public: file_not_found(const std::string& s): error(s){} + }; + + inline file ( + ) + { + state = new data; + state->count = 1; + state->file_size = 0; + } + + file ( + const std::string& name + ); + + inline file ( + const file& item + ) + { + state = item.state; + state->count += 1; + } + + inline ~file ( + ) + { + if (state->count == 1) + delete state; + else + state->count -= 1; + } + + inline const std::string& name ( + ) const { return state->name; } + + inline const std::string& full_name ( + ) const { return state->full_name; } + + inline uint64 size ( + ) const { return state->file_size; } + + inline file& operator= ( + const file& rhs + ) + { + if (&rhs == this) + return *this; + + if (state->count == 1) + delete state; + else + state->count -= 1; + + state = rhs.state; + state->count += 1; + return *this; + } + + bool operator == ( + const file& rhs + ) const; + + inline bool operator < ( + const file& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + file& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data* state; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + INITIAL VALUES + state->name == name() + state->full_name == full_name() + + CONVENTION + state->name == name() + state->full_name == full_name() + state->count == the number of directory objects that point to state + is_root() == state->name.size() == 0 + + !*/ + struct data + { + std::string name; + std::string full_name; + unsigned long count; + }; + + inline directory ( + const std::string& name, + const std::string& full_name + ) + { + state = new data; + state->count = 1; + state->name = name; + state->full_name = full_name; + } + + public: + + class dir_not_found : public error { + public: dir_not_found(const std::string& s):error(s){} + }; + class listing_error : public error { + public: listing_error(const std::string& s):error(s){} + }; + + inline directory ( + ) + { + state = new data; + state->count = 1; + } + + directory ( + const std::string& name + ); + + inline directory ( + const directory& item + ) + { + state = item.state; + state->count += 1; + } + + inline ~directory ( + ) + { + if (state->count == 1) + delete state; + else + state->count -= 1; + } + + static char get_separator ( + ); + + template < + typename queue_of_files + // Is an implementation of queue/queue_kernel_abstract.h with T set to file. + > + void get_files ( + queue_of_files& files + ) const; + + template < + typename queue_of_dirs + // Is an implementation of queue/queue_kernel_abstract.h with T set to directory. + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + + const directory get_parent ( + ) const; + + inline bool is_root ( + ) const { return state->name.size() == 0; } + + inline const std::string& name ( + ) const { return state->name; } + + inline const std::string& full_name ( + ) const { return state->full_name; } + + directory& operator= ( + const directory& rhs + ) + { + if (&rhs == this) + return *this; + + if (state->count == 1) + delete state; + else + state->count -= 1; + + state = rhs.state; + state->count += 1; + return *this; + } + + bool operator == ( + const directory& rhs + ) const; + + inline bool operator < ( + const directory& item + ) const { return full_name() < item.full_name(); } + + inline void swap ( + directory& item + ) + { + exchange(state,item.state); + } + + private: + + // member data + data* state; + + bool is_root_path ( + const std::string& path + ) const; + /*! + ensures + - returns true if path is a root path. + Note that this function considers root paths that don't + have a trailing separator to also be valid. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // templated member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_files + > + void directory:: + get_files ( + queue_of_files& files + ) const + { + using namespace std; + + files.clear(); + if (state->full_name.size() == 0) + throw listing_error("This directory object currently doesn't represent any directory."); + + DIR* ffind = 0; + struct dirent* data; + struct stat64 buffer; + + try + { + string path = state->full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != get_separator()) + path += get_separator(); + + // get a handle to something we can search with + ffind = opendir(state->full_name.c_str()); + if (ffind == 0) + { + throw listing_error("Unable to list the contents of " + state->full_name); + } + + while(true) + { + errno = 0; + if ( (data = readdir(ffind)) == 0) + { + // there was an error or no more files + if ( errno == 0) + { + // there are no more files + break; + } + else + { + // there was an error + throw listing_error("Unable to list the contents of " + state->full_name); + } + } + + uint64 file_size; + // get a stat64 structure so we can see if this is a file + if (::stat64((path+data->d_name).c_str(), &buffer) != 0) + { + // this might be a broken symbolic link. We can check by calling + // readlink and seeing if it finds anything. + char buf[PATH_MAX]; + ssize_t temp = readlink((path+data->d_name).c_str(),buf,sizeof(buf)); + if (temp == -1) + throw listing_error("Unable to list the contents of " + state->full_name); + else + file_size = static_cast(temp); + } + else + { + file_size = static_cast(buffer.st_size); + } + + if (S_ISDIR(buffer.st_mode) == 0) + { + // this is actually a file + file temp( + data->d_name, + path+data->d_name, + file_size + ); + files.enqueue(temp); + } + } // while (true) + + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + + } + catch (...) + { + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + files.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dirs + > + void directory:: + get_dirs ( + queue_of_dirs& dirs + ) const + { + using namespace std; + + dirs.clear(); + if (state->full_name.size() == 0) + throw listing_error("This directory object currently doesn't represent any directory."); + + DIR* ffind = 0; + struct dirent* data; + struct stat64 buffer; + + try + { + string path = state->full_name; + // ensure that the path ends with a separator + if (path[path.size()-1] != get_separator()) + path += get_separator(); + + // get a handle to something we can search with + ffind = opendir(state->full_name.c_str()); + if (ffind == 0) + { + throw listing_error("Unable to list the contents of " + state->full_name); + } + + while(true) + { + errno = 0; + if ( (data = readdir(ffind)) == 0) + { + // there was an error or no more files + if ( errno == 0) + { + // there are no more files + break; + } + else + { + // there was an error + throw listing_error("Unable to list the contents of " + state->full_name); + } + } + + // get a stat64 structure so we can see if this is a file + if (::stat64((path+data->d_name).c_str(), &buffer) != 0) + { + // just assume this isn't a directory. It is probably a broken + // symbolic link. + continue; + } + + string dtemp(data->d_name); + if (S_ISDIR(buffer.st_mode) && + dtemp != "." && + dtemp != ".." ) + { + // this is a directory so add it to dirs + directory temp(dtemp,path+dtemp); + dirs.enqueue(temp); + } + } // while (true) + + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + + } + catch (...) + { + if (ffind != 0) + { + while (closedir(ffind)) + { + if (errno != EINTR) + break; + } + ffind = 0; + } + dirs.clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + > + void get_filesystem_roots ( + queue_of_dir& roots + ) + { + roots.clear(); + directory dir("/"); + roots.enqueue(dir); + } + +// ---------------------------------------------------------------------------------------- + +} + + +#ifdef NO_MAKEFILE +#include "dir_nav_kernel_2.cpp" +#endif + +#endif // DLIB_DIR_NAV_KERNEl_2_ + diff --git a/dlib/dir_nav/dir_nav_kernel_abstract.h b/dlib/dir_nav/dir_nav_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c55211ec20f6a746dee7dc7b38645bd146ed123e --- /dev/null +++ b/dlib/dir_nav/dir_nav_kernel_abstract.h @@ -0,0 +1,418 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DIR_NAV_KERNEl_ABSTRACT_ +#ifdef DLIB_DIR_NAV_KERNEl_ABSTRACT_ + +#include +#include "../uintn.h" +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + GENERAL WARNING + Don't call any of these functions or make any of these objects + before main() has been entered. That means no instances + of file or directory at the global scope. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_of_dir + // Is an implementation of queue/queue_kernel_abstract.h with T set to directory. + > + void get_filesystem_roots ( + queue_of_dir& roots + ); + /*! + ensures + - #roots == a queue containing directories that represent all the roots + of the filesystem on this machine. (e.g. in windows you have c:\, d:\ + etc...) + throws + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // file object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class file + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a file. + + Note that the size of a file is determined at the time the file + object is constructed. Thus if a file changes sizes after its + file object has been created its file object's size() method + will not reflect the new file size. + + THREAD SAFETY + This object is reference counted so use with caution in a threaded + environment. + !*/ + + public: + + class file_not_found : public error {}; + + file ( + ); + /*! + ensures + - #*this has been properly initialized + - #name() == "" + - #full_name() == "" + - #size() == 0 + - #*this does not represent any file + throws + - std::bad_alloc + !*/ + + file ( + const std::string& name + ); + /*! + ensures + - #*this has been properly initialized + - #*this represents the file given by name + Note that name can be a fully qualified path or just a path + relative to the current working directory. Also, any symbolic + links in name will be resolved. + throws + - std::bad_alloc + - file_not_found + This exception is thrown if the file can not be found or + accessed. + !*/ + + file ( + const file& item + ); + /*! + ensures + - #*this == item + throws + - std::bad_alloc + !*/ + + ~file ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + const std::string& name ( + ) const; + /*! + ensures + - returns the name of the file. This is full_name() minus + the path to the file. + !*/ + + const std::string& full_name ( + ) const; + /*! + ensures + - returns the fully qualified name for the file represented by *this + !*/ + + uint64 size ( + ) const; + /*! + ensures + - returns the size of this file in bytes. + !*/ + + file& operator= ( + const file& rhs + ); + /*! + ensures + - #*this == rhs + !*/ + + bool operator == ( + const file& rhs + ) const; + /*! + ensures + - if (*this and rhs represent the same file) then + - returns true + - else + - returns false + !*/ + + bool operator < ( + const file& item + ) const; + /*! + ensures + - if (full_name() < item.full_name()) then + - returns true + - else + - returns false + !*/ + + void swap ( + file& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // directory object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class directory + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a directory in a file system. It gives + the ability to traverse a directory tree. + + Note that the directories . and .. are not returned by get_dirs() + + THREAD SAFETY + This object is reference counted so use with caution in a threaded + environment. + !*/ + + public: + + class dir_not_found : public error {}; + class listing_error : public error {}; + + directory ( + ); + /*! + ensures + - #*this has been properly initialized + - #full_name() == "" + - #name() == "" + - #is_root() == true + - #*this does not represent any directory + throws + - std::bad_alloc + !*/ + + directory ( + const std::string& name + ); + /*! + ensures + - #*this has been properly initialized + - #*this represents the directory given by name. + Note that name can be a fully qualified path or just a path + relative to the current working directory. Also, any symbolic + links in name will be resolved. + throws + - std::bad_alloc + - dir_not_found + This exception is thrown if the directory can not be found or + accessed. + !*/ + + directory ( + const directory& item + ); + /*! + ensures + - #*this == item + throws + - std::bad_alloc + !*/ + + ~directory ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + static char get_separator ( + ); + /*! + ensures + - returns the character used to separate directories and file names in a + path. (i.e. \ on windows and / in unix) + !*/ + + template < + typename queue_of_files + // Is an implementation of queue/queue_kernel_abstract.h with T set to file. + > + void get_files ( + queue_of_files& files + ) const; + /*! + ensures + - #files == A queue containing all the files present in this directory. + (Note that symbolic links will not have been resolved in the names + of the returned files.) + - #files.size() == the number of files in this directory + throws + - bad_alloc + If this exception is thrown then the call to get_files() has + no effect on *this and #files is unusable until files.clear() + is called and succeeds. + - listing_error + This exception is thrown if listing access has been denied to this + directory or if some error occurred that prevented us from successfully + getting the contents of this directory. + If this exception is thrown then the call to get_files() has + no effect on *this and #files.size()==0. + !*/ + + template < + typename queue_of_dirs + // Is an implementation of queue/queue_kernel_abstract.h with T set to directory. + > + void get_dirs ( + queue_of_dirs& dirs + ) const; + /*! + ensures + - #dirs == a queue containing all the directories present in this directory. + (note that symbolic links will not have been resolved in the names + of the returned directories.) + - #dirs.size() == the number of subdirectories in this directory + throws + - bad_alloc + If this exception is thrown then the call to get_files() has + no effect on *this and #files is unusable until files.clear() + is called and succeeds. + - listing_error + This exception is thrown if listing access has been denied to this + directory or if some error occurred that prevented us from successfully + getting the contents of this directory. + If this exception is thrown then the call to get_dirs() has + no effect on *this and #dirs.size()==0. + !*/ + + bool is_root ( + ) const; + /*! + ensures + - if (*this represents the root of this directory tree) then + - returns true + - else + - returns false + !*/ + + const directory get_parent ( + ) const; + /*! + ensures + - if (is_root()) then + - returns a copy of *this + - else + - returns the parent directory of *this + throws + - bad_alloc + If this exception is thrown then the call to get_parent() will + have no effect. + !*/ + + const std::string& name ( + ) const; + /*! + ensures + - if (is_root()) then + - returns "" + - else + - returns the name of the directory. This is full_name() minus + the path to the directory. + !*/ + + const std::string& full_name ( + ) const; + /*! + ensures + - returns the fully qualified directory name for *this + - if (is_root()) then + - the last character of #full_name() is get_separator() + - else + - the last character of #full_name() is NOT get_separator() + !*/ + + directory& operator= ( + const directory& rhs + ); + /*! + ensures + - #*this == rhs + !*/ + + bool operator == ( + const directory& rhs + ) const; + /*! + ensures + - if (*this and rhs represent the same directory) then + - returns true + - else + - returns false + !*/ + + bool operator < ( + const directory& item + ) const; + /*! + ensures + - if (full_name() < item.full_name()) then + - returns true + - else + - returns false + !*/ + + void swap ( + directory& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + file& a, + file& b + ) { a.swap(b); } + /*! + provides a global swap function for file objects + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void swap ( + directory& a, + directory& b + ) { a.swap(b); } + /*! + provides a global swap function for directory objects + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DIR_NAV_KERNEl_ABSTRACT_ + diff --git a/dlib/dir_nav/posix.h b/dlib/dir_nav/posix.h new file mode 100644 index 0000000000000000000000000000000000000000..76492f308155c9cc084da92b7509ac89e1a97861 --- /dev/null +++ b/dlib/dir_nav/posix.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_1_ +#include "dir_nav_kernel_2.h" +#endif + diff --git a/dlib/dir_nav/windows.h b/dlib/dir_nav/windows.h new file mode 100644 index 0000000000000000000000000000000000000000..25e5cdd59dcf9ff37fb16bce2899c491cb7dc12d --- /dev/null +++ b/dlib/dir_nav/windows.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIR_NAV_KERNEl_2_ +#include "dir_nav_kernel_1.h" +#endif + diff --git a/dlib/directed_graph.h b/dlib/directed_graph.h new file mode 100644 index 0000000000000000000000000000000000000000..f5f44085d2cc72aa9fdd035919a01d09d29458d1 --- /dev/null +++ b/dlib/directed_graph.h @@ -0,0 +1,37 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIRECTED_GRAPh_ +#define DLIB_DIRECTED_GRAPh_ + +#include "directed_graph/directed_graph_kernel_1.h" + +#include "memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename E = char, + typename mem_manager = memory_manager::kernel_1a + > + class directed_graph + { + directed_graph() {} + public: + + + //----------- kernels --------------- + + // kernel_1a + typedef directed_graph_kernel_1 + kernel_1a; + typedef directed_graph_kernel_1 + kernel_1a_c; + + }; +} + +#endif // DLIB_DIRECTED_GRAPh_ + + diff --git a/dlib/directed_graph/directed_graph_kernel_1.h b/dlib/directed_graph/directed_graph_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..f813a7ff70fc8375aabdd8b46eb444f802c3ed9c --- /dev/null +++ b/dlib/directed_graph/directed_graph_kernel_1.h @@ -0,0 +1,704 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DIRECTED_GRAPH_KERNEl_1_ +#define DLIB_DIRECTED_GRAPH_KERNEl_1_ + +#include "../serialize.h" +#include "../noncopyable.h" +#include "../std_allocator.h" +#include "../smart_pointers.h" +#include "../algs.h" +#include +#include "../memory_manager.h" +#include "directed_graph_kernel_abstract.h" +#include "../is_kind.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + struct directed_graph_checker_helper + { + /*! + This object is used to check preconditions based on the value of is_checked + !*/ + + static void check_parent_edge ( + unsigned long edge_index, + const node_type& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(edge_index < self.number_of_parents(), + "\tnode_type& directed_graph::node_type::parent_edge(edge_index)" + << "\n\tYou have specified an invalid index" + << "\n\tedge_index: " << edge_index + << "\n\tnumber_of_parents(): " << self.number_of_parents() + << "\n\tthis: " << &self + ); + } + + static void check_child_edge ( + unsigned long edge_index, + const node_type& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(edge_index < self.number_of_children(), + "\tnode_type& directed_graph::node_type::child_edge(edge_index)" + << "\n\tYou have specified an invalid index" + << "\n\tedge_index: " << edge_index + << "\n\tnumber_of_children(): " << self.number_of_children() + << "\n\tthis: " << &self + ); + } + + static void check_parent ( + unsigned long edge_index, + const node_type& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(edge_index < self.number_of_parents(), + "\tnode_type& directed_graph::node_type::parent(edge_index)" + << "\n\tYou have specified an invalid index" + << "\n\tedge_index: " << edge_index + << "\n\tnumber_of_parents(): " << self.number_of_parents() + << "\n\tthis: " << &self + ); + } + + static void check_child ( + unsigned long edge_index, + const node_type& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(edge_index < self.number_of_children(), + "\tnode_type& directed_graph::node_type::child(edge_index)" + << "\n\tYou have specified an invalid index" + << "\n\tedge_index: " << edge_index + << "\n\tnumber_of_children(): " << self.number_of_children() + << "\n\tthis: " << &self + ); + } + + static void check_node ( + unsigned long index, + const directed_graph& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(index < self.number_of_nodes(), + "\tnode_type& directed_graph::node(index)" + << "\n\tYou have specified an invalid index" + << "\n\tindex: " << index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + } + + static void check_has_edge ( + unsigned long parent_node_index, + unsigned long child_node_index, + const directed_graph& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(parent_node_index < self.number_of_nodes() && + child_node_index < self.number_of_nodes(), + "\tvoid directed_graph::has_edge(parent_node_index, child_node_index)" + << "\n\tYou have specified an invalid index" + << "\n\tparent_node_index: " << parent_node_index + << "\n\tchild_node_index: " << child_node_index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + } + + static void check_add_edge ( + unsigned long parent_node_index, + unsigned long child_node_index, + const directed_graph& self + ) + { + DLIB_CASSERT(parent_node_index < self.number_of_nodes() && + child_node_index < self.number_of_nodes(), + "\tvoid directed_graph::add_edge(parent_node_index, child_node_index)" + << "\n\tYou have specified an invalid index" + << "\n\tparent_node_index: " << parent_node_index + << "\n\tchild_node_index: " << child_node_index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == false, + "\tvoid directed_graph::add_edge(parent_node_index, child_node_index)" + << "\n\tYou can't add an edge if it already exists in the graph" + << "\n\tparent_node_index: " << parent_node_index + << "\n\tchild_node_index: " << child_node_index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + } + + static void check_remove_edge ( + unsigned long parent_node_index, + unsigned long child_node_index, + const directed_graph& self + ) + { + DLIB_CASSERT(parent_node_index < self.number_of_nodes() && + child_node_index < self.number_of_nodes(), + "\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)" + << "\n\tYou have specified an invalid index" + << "\n\tparent_node_index: " << parent_node_index + << "\n\tchild_node_index: " << child_node_index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == true, + "\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)" + << "\n\tYou can't remove an edge if it isn't in the graph" + << "\n\tparent_node_index: " << parent_node_index + << "\n\tchild_node_index: " << child_node_index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + } + + static void check_remove_node ( + unsigned long index, + const directed_graph& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(index < self.number_of_nodes(), + "\tvoid directed_graph::remove_node(index)" + << "\n\tYou have specified an invalid index" + << "\n\tindex: " << index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + } + }; + + template + struct directed_graph_checker_helper + { + static inline void check_parent ( unsigned long edge_index, const node_type& self) { } + static inline void check_child ( unsigned long edge_index, const node_type& self) { } + static inline void check_parent_edge ( unsigned long edge_index, const node_type& self) { } + static inline void check_child_edge ( unsigned long edge_index, const node_type& self) { } + static inline void check_node ( unsigned long index, const directed_graph& self) { } + static inline void check_has_edge ( unsigned long , unsigned long , const directed_graph& ) { } + static inline void check_add_edge ( unsigned long , unsigned long , const directed_graph& ) { } + static inline void check_remove_edge ( unsigned long , unsigned long , const directed_graph& ) { } + static inline void check_remove_node ( unsigned long index, const directed_graph& self) { } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E = char, + typename mem_manager = memory_manager::kernel_1a, + bool is_checked = true + > + class directed_graph_kernel_1 : noncopyable + { + + /*! + INITIAL VALUE + - nodes.size() == 0 + + CONVENTION + - nodes.size() == number_of_nodes() + - for all valid i: + - *nodes[i] == node(i) + - nodes[i]->parents.size() == nodes[i]->number_of_parents(i) + - nodes[i]->children.size() == nodes[i]->number_of_children(i) + - nodes[i]->edge_parents.size() == nodes[i]->number_of_parents(i) + - nodes[i]->edge_children.size() == nodes[i]->number_of_children(i) + - nodes[i]->idx == i == nodes[i]->index() + - for all valid p: + - nodes[i]->parents[p] == pointer to the p'th parent node of i + - *nodes[i]->parents[p] == nodes[i]->parent(p) + - *nodes[i]->edge_parents[p] == nodes[i]->parent_edge(p) + - for all valid c: + - nodes[i]->children[c] == pointer to the c'th child node of i + - *nodes[i]->children[c] == nodes[i]->child(c) + - *nodes[i]->edge_children[c] == nodes[i]->child_edge(c) + !*/ + + public: + struct node_type; + + private: + typedef directed_graph_checker_helper checker; + + + public: + + typedef T type; + typedef E edge_type; + typedef mem_manager mem_manager_type; + + template + struct rebind { + typedef directed_graph_kernel_1 other; + }; + + directed_graph_kernel_1( + ) {} + + virtual ~directed_graph_kernel_1( + ) {} + + void clear( + ) { nodes.clear(); } + + void set_number_of_nodes ( + unsigned long new_size + ); + + unsigned long number_of_nodes ( + ) const { return nodes.size(); } + + node_type& node ( + unsigned long index + ) { checker::check_node(index,*this); return *nodes[index]; } + + const node_type& node ( + unsigned long index + ) const { checker::check_node(index,*this); return *nodes[index]; } + + bool has_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ) const; + + void add_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ); + + void remove_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ); + + unsigned long add_node ( + ); + + void remove_node ( + unsigned long index + ); + + void swap ( + directed_graph_kernel_1& item + ) { nodes.swap(item.nodes); } + + private: + + + public: + + struct node_type + { + T data; + typedef directed_graph_kernel_1 graph_type; + + unsigned long index( + ) const { return idx; } + + unsigned long number_of_parents ( + ) const { return parents.size(); } + + unsigned long number_of_children ( + ) const { return children.size(); } + + const node_type& parent ( + unsigned long edge_index + ) const { checker::check_parent(edge_index,*this); return *parents[edge_index]; } + + node_type& parent ( + unsigned long edge_index + ) { checker::check_parent(edge_index,*this); return *parents[edge_index]; } + + const node_type& child ( + unsigned long edge_index + ) const { checker::check_child(edge_index,*this); return *children[edge_index]; } + + node_type& child ( + unsigned long edge_index + ) { checker::check_child(edge_index,*this); return *children[edge_index]; } + + const E& parent_edge ( + unsigned long edge_index + ) const { checker::check_parent_edge(edge_index,*this); return *edge_parents[edge_index]; } + + E& parent_edge ( + unsigned long edge_index + ) { checker::check_parent_edge(edge_index,*this); return *edge_parents[edge_index]; } + + const E& child_edge ( + unsigned long edge_index + ) const { checker::check_child_edge(edge_index,*this); return *edge_children[edge_index]; } + + E& child_edge ( + unsigned long edge_index + ) { checker::check_child_edge(edge_index,*this); return *edge_children[edge_index]; } + + private: + friend class directed_graph_kernel_1; + typedef std_allocator alloc_type; + typedef std_allocator,mem_manager> alloc_edge_type; + std::vector parents; + std::vector children; + std::vector,alloc_edge_type> edge_parents; + std::vector,alloc_edge_type> edge_children; + unsigned long idx; + }; + + private: + + typedef std_allocator,mem_manager> alloc_type; + typedef std::vector, alloc_type> vector_type; + vector_type nodes; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + struct is_directed_graph > + { + static const bool value = true; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + inline void swap ( + directed_graph_kernel_1& a, + directed_graph_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void serialize ( + const directed_graph_kernel_1& item, + std::ostream& out + ) + { + try + { + serialize(item.number_of_nodes(), out); + + // serialize each node + for (unsigned long i = 0; i < item.number_of_nodes(); ++i) + { + serialize(item.node(i).data, out); + + // serialize all the child edges + serialize(item.node(i).number_of_children(), out); + for (unsigned long c = 0; c < item.node(i).number_of_children(); ++c) + { + serialize(item.node(i).child(c).index(), out); + serialize(item.node(i).child_edge(c), out); + } + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type directed_graph_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void deserialize ( + directed_graph_kernel_1& item, + std::istream& in + ) + { + try + { + unsigned long size; + deserialize(size, in); + + item.clear(); + item.set_number_of_nodes(size); + + // deserialize each node + for (unsigned long i = 0; i < item.number_of_nodes(); ++i) + { + deserialize(item.node(i).data, in); + + unsigned long num_children; + deserialize(num_children, in); + + // Add all the edges going to this nodes children nodes + for (unsigned long c = 0; c < num_children; ++c) + { + unsigned long child_index; + deserialize(child_index, in); + + item.add_edge(i, child_index); + + // find the edge we just added + for (unsigned long j = 0; j < item.node(i).number_of_children(); ++j) + { + if (item.node(i).child(j).index() == child_index) + { + deserialize(item.node(i).child_edge(j), in); + break; + } + } + } + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type directed_graph_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void directed_graph_kernel_1:: + set_number_of_nodes ( + unsigned long new_size + ) + { + try + { + nodes.resize(new_size); + for (unsigned long i = 0; i < nodes.size(); ++i) + { + nodes[i].reset(new node_type); + nodes[i]->idx = i; + } + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + bool directed_graph_kernel_1:: + has_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ) const + { + checker::check_has_edge(parent_node_index, child_node_index, *this); + + node_type& n = *nodes[parent_node_index]; + + // search all the child nodes to see if there is a link to the right node + for (unsigned long i = 0; i < n.children.size(); ++i) + { + if (n.children[i]->idx == child_node_index) + return true; + } + + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void directed_graph_kernel_1:: + add_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ) + { + checker::check_add_edge(parent_node_index, child_node_index, *this); + try + { + node_type& p = *nodes[parent_node_index]; + node_type& c = *nodes[child_node_index]; + + p.children.push_back(&c); + c.parents.push_back(&p); + + p.edge_children.push_back(shared_ptr(new E)); + c.edge_parents.push_back(p.edge_children.back()); + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void directed_graph_kernel_1:: + remove_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ) + { + checker::check_remove_edge(parent_node_index, child_node_index, *this); + + node_type& p = *nodes[parent_node_index]; + node_type& c = *nodes[child_node_index]; + + // remove the record of the link from the parent node + unsigned long pos = find( p.children.begin(), + p.children.end(), + &c) - p.children.begin(); + p.children.erase(p.children.begin()+pos); + p.edge_children.erase(p.edge_children.begin()+pos); + + // remove the record of the link from the child node + pos = find( c.parents.begin(), + c.parents.end(), + &p) - c.parents.begin(); + c.parents.erase(c.parents.begin() + pos); + c.edge_parents.erase(c.edge_parents.begin() + pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + unsigned long directed_graph_kernel_1:: + add_node ( + ) + { + try + { + shared_ptr n(new node_type); + n->idx = nodes.size(); + nodes.push_back(n); + return n->idx; + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void directed_graph_kernel_1:: + remove_node ( + unsigned long index + ) + { + checker::check_remove_node(index,*this); + + node_type& n = *nodes[index]; + + // remove all edges pointing to this node from its parents + for (unsigned long i = 0; i < n.parents.size(); ++i) + { + // remove the edge from this specific parent + unsigned long pos = find(n.parents[i]->children.begin(), + n.parents[i]->children.end(), + &n) - n.parents[i]->children.begin(); + + n.parents[i]->children.erase(n.parents[i]->children.begin() + pos); + n.parents[i]->edge_children.erase(n.parents[i]->edge_children.begin() + pos); + } + + // remove all edges pointing to this node from its children + for (unsigned long i = 0; i < n.children.size(); ++i) + { + // remove the edge from this specific child + unsigned long pos = find(n.children[i]->parents.begin(), + n.children[i]->parents.end(), + &n) - n.children[i]->parents.begin(); + + n.children[i]->parents.erase(n.children[i]->parents.begin() + pos); + n.children[i]->edge_parents.erase(n.children[i]->edge_parents.begin() + pos); + } + + // now remove this node by replacing it with the last node in the nodes vector + nodes[index] = nodes[nodes.size()-1]; + + // update the index for the node we just moved + nodes[index]->idx = index; + + // now remove the duplicated node at the end of the vector + nodes.pop_back(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DIRECTED_GRAPH_KERNEl_1_ + diff --git a/dlib/directed_graph/directed_graph_kernel_abstract.h b/dlib/directed_graph/directed_graph_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..95bfc4bbc5d488e87318893ca9ef1db4b00c7a3f --- /dev/null +++ b/dlib/directed_graph/directed_graph_kernel_abstract.h @@ -0,0 +1,379 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_ +#ifdef DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_ + +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include "../noncopyable.h" + +namespace dlib +{ + + template < + typename T, + typename E = char, + typename mem_manager = memory_manager::kernel_1a + > + class directed_graph : noncopyable + { + + /*! + REQUIREMENTS ON T + T must be swappable by a global swap() and + T must have a default constructor + + REQUIREMENTS ON E + E must be swappable by a global swap() and + E must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + The only functions that invalidate pointers or references to internal data are + clear(), remove_node(), add_node(), set_number_of_nodes(), and the object's destructor. + + INITIAL VALUE + number_of_nodes() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a directed graph which is a set of nodes with directed + edges connecting various nodes. + + In this object if there is a directed edge from a node A to a node B then I say + that A is the parent of B and B is the child of A. + !*/ + + public: + + typedef T type; + typedef E edge_type; + typedef mem_manager mem_manager_type; + + template + struct rebind { + typedef directed_graph other; + }; + + directed_graph( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor. + !*/ + + virtual ~directed_graph( + ); + /*! + ensures + - all resources associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void set_number_of_nodes ( + unsigned long new_size + ); + /*! + ensures + - #number_of_nodes() == new_size + - for all i < new_size: + - number_of_parents(i) == 0 + - number_of_children(i) == 0 + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + unsigned long number_of_nodes ( + ) const; + /*! + ensures + - returns the number of nodes in this graph + !*/ + + struct node_type + { + T data; + typedef directed_graph graph_type; + + unsigned long index( + ) const; + /*! + ensures + - let G be the graph that contains the node *this + - returns a number N such that G.node(N) == *this + (i.e. returns the index of this node in the graph) + !*/ + + unsigned long number_of_parents ( + ) const; + /*! + ensures + - returns the number of parents of this node + !*/ + + unsigned long number_of_children ( + ) const; + /*! + ensures + - returns the number of children of this node + !*/ + + const node_type& parent ( + unsigned long edge_index + ) const; + /*! + requires + - edge_index < number_of_parents() + ensures + - returns a const reference to the edge_index'th parent of *this + !*/ + + node_type& parent ( + unsigned long edge_index + ); + /*! + requires + - edge_index < number_of_parents() + ensures + - returns a non-const reference to the edge_index'th parent of *this + !*/ + + const node_type& child ( + unsigned long edge_index + ) const; + /*! + requires + - edge_index < number_of_children() + ensures + - returns a const reference to the edge_index'th child of *this + !*/ + + node_type& child ( + unsigned long edge_index + ); + /*! + requires + - edge_index < number_of_children() + ensures + - returns a non-const reference to the edge_index'th child of *this + !*/ + + const E& parent_edge ( + unsigned long edge_index + ) const; + /*! + requires + - edge_index < number_of_parents() + ensures + - returns a const reference to the edge_index'th edge data for the + edge connecting to node this->parent(edge_index) + !*/ + + E& parent_edge ( + unsigned long edge_index + ); + /*! + requires + - edge_index < number_of_parents() + ensures + - returns a non-const reference to the edge_index'th edge data for the + edge connecting to node this->parent(edge_index) + !*/ + + const E& child_edge ( + unsigned long edge_index + ) const; + /*! + requires + - edge_index < number_of_children() + ensures + - returns a const reference to the edge_index'th edge data for the + edge connecting to node this->child(edge_index) + !*/ + + E& child_edge ( + unsigned long edge_index + ); + /*! + requires + - edge_index < number_of_children() + ensures + - returns a non-const reference to the edge_index'th edge data for the + edge connecting to node this->child(edge_index) + !*/ + }; + + node_type& node ( + unsigned long index + ); + /*! + requires + - index < number_of_nodes() + ensures + - returns a non-const reference to the node with the given index + !*/ + + const node_type& node ( + unsigned long index + ) const; + /*! + requires + - index < number_of_nodes() + ensures + - returns a const reference to the node with the given index + !*/ + + bool has_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ) const; + /*! + requires + - parent_node_index < number_of_nodes() + - child_node_index < number_of_nodes() + ensures + - if (there is an edge leading from node(parent_node_index) to + node(child_node_index)) then + - returns true + - else + - returns false + !*/ + + void add_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ); + /*! + requires + - parent_node_index < number_of_nodes() + - child_node_index < number_of_nodes() + - has_edge(parent_node_index, child_node_index) == false + ensures + - #has_edge(parent_node_index, child_node_index) == true + throws + - std::bad_alloc + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + void remove_edge ( + unsigned long parent_node_index, + unsigned long child_node_index + ); + /*! + requires + - parent_node_index < number_of_nodes() + - child_node_index < number_of_nodes() + - has_edge(parent_node_index, child_node_index) == true + ensures + - #has_edge(parent_node_index, child_node_index) == false + throws + - std::bad_alloc + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + unsigned long add_node ( + ); + /*! + ensures + - adds a node with index N == number_of_nodes() such that: + - #node(N).number_of_parents() == 0 + - #node(N).number_of_children() == 0 + - #number_of_nodes() == number_of_nodes() + 1 + - returns N + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + void remove_node ( + unsigned long index + ); + /*! + requires + - index < number_of_nodes() + ensures + - removes the node with the given index from the graph. + - removes all edges linking the removed node to the rest + of the graph. + - the remaining node indexes are remapped so that they remain + contiguous. (This means that for all valid N, node(N) doesn't + necessarily reference the same node as #node(N)) + - #number_of_nodes() == number_of_nodes() - 1 + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + void swap ( + directed_graph& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + directed_graph& a, + directed_graph& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename mem_manager + > + void serialize ( + const directed_graph& item, + std::ostream& out + ); + /*! + provides deserialization support + !*/ + + template < + typename T, + typename mem_manager + > + void deserialize ( + directed_graph& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_ + + diff --git a/dlib/dlib_include_path_tutorial.txt b/dlib/dlib_include_path_tutorial.txt new file mode 100644 index 0000000000000000000000000000000000000000..b73a0d642a5c960dd3f7617be93f268d2b37676f --- /dev/null +++ b/dlib/dlib_include_path_tutorial.txt @@ -0,0 +1,20 @@ +#error "Don't put the dlib folder in your include path" +/* + You are getting this error because you have added the dlib folder to your + compiler's include search path. + + You should *NOT* add the dlib folder itself to your compiler's include path. + Doing so will cause the build to fail because of name collisions (such as + dlib/string.h and string.h from the standard library). Instead you should + add the folder that contains the dlib folder to your include search path + and then use include statements of the form #include . + This will ensure that everything builds correctly. + + XCode: + The XCode IDE often puts all folders that it knows about into + the compiler search path. So if you are using XCode then don't + drag the dlib folder into the project (or modify your XCode project + settings to not auto-add all folders to the include path. + Instead just make sure that the dlib folder is itself inside + a folder in your include path. +*/ diff --git a/dlib/enable_if.h b/dlib/enable_if.h new file mode 100644 index 0000000000000000000000000000000000000000..d72ae57b8ad4d8e6f681d26114846d8b3f511211 --- /dev/null +++ b/dlib/enable_if.h @@ -0,0 +1,140 @@ +// Boost enable_if library + +// Copyright 2003 (C) The Trustees of Indiana University. + +// Use, modification, and distribution is subject to 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) + +// Authors: Jaakko Jarvi (jajarvi at osl.iu.edu) +// Jeremiah Willcock (jewillco at osl.iu.edu) +// Andrew Lumsdaine (lums at osl.iu.edu) + +#ifndef DLIB_BOOST_UTILITY_ENABLE_IF_HPP +#define DLIB_BOOST_UTILITY_ENABLE_IF_HPP + + +#ifndef BOOST_UTILITY_ENABLE_IF_HPP +#define BOOST_UTILITY_ENABLE_IF_HPP + +// Even the definition of enable_if causes problems on some compilers, +// so it's macroed out for all compilers that do not support SFINAE + +#ifndef BOOST_NO_SFINAE + +namespace boost +{ + + template + struct enable_if_c { + typedef T type; + }; + + template + struct enable_if_c {}; + + template + struct enable_if : public enable_if_c {}; + + template + struct lazy_enable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_enable_if_c {}; + + template + struct lazy_enable_if : public lazy_enable_if_c {}; + + + template + struct disable_if_c { + typedef T type; + }; + + template + struct disable_if_c {}; + + template + struct disable_if : public disable_if_c {}; + + template + struct lazy_disable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_disable_if_c {}; + + template + struct lazy_disable_if : public lazy_disable_if_c {}; + +} // namespace boost + +#else + +namespace boost +{ + + namespace detail { typedef void enable_if_default_T; } + + template + struct enable_if_does_not_work_on_this_compiler; + + template + struct enable_if_c : enable_if_does_not_work_on_this_compiler + { }; + + template + struct disable_if_c : enable_if_does_not_work_on_this_compiler + { }; + + template + struct lazy_enable_if_c : enable_if_does_not_work_on_this_compiler + { }; + + template + struct lazy_disable_if_c : enable_if_does_not_work_on_this_compiler + { }; + + template + struct enable_if : enable_if_does_not_work_on_this_compiler + { }; + + template + struct disable_if : enable_if_does_not_work_on_this_compiler + { }; + + template + struct lazy_enable_if : enable_if_does_not_work_on_this_compiler + { }; + + template + struct lazy_disable_if : enable_if_does_not_work_on_this_compiler + { }; + +} // namespace boost + +#endif // BOOST_NO_SFINAE + +#endif // BOOST_UTILITY_ENABLE_IF_HPP + +namespace dlib +{ + using boost::enable_if_c; + using boost::enable_if_c; + using boost::enable_if; + using boost::lazy_enable_if_c; + using boost::lazy_enable_if_c; + using boost::lazy_enable_if; + using boost::disable_if_c; + using boost::disable_if_c; + using boost::disable_if; + using boost::lazy_disable_if_c; + using boost::lazy_disable_if_c; + using boost::lazy_disable_if; +} + +#endif // DLIB_BOOST_UTILITY_ENABLE_IF_HPP + diff --git a/dlib/entropy_decoder.h b/dlib/entropy_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..dedf5170a33a01638d31e0955c656286b4ba363e --- /dev/null +++ b/dlib/entropy_decoder.h @@ -0,0 +1,44 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODEr_ +#define DLIB_ENTROPY_DECODEr_ + +#include "entropy_decoder/entropy_decoder_kernel_1.h" +#include "entropy_decoder/entropy_decoder_kernel_2.h" +#include "entropy_decoder/entropy_decoder_kernel_c.h" + + + + +namespace dlib +{ + + + class entropy_decoder + { + entropy_decoder() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef entropy_decoder_kernel_1 + kernel_1a; + typedef entropy_decoder_kernel_c + kernel_1a_c; + + + // kernel_2a + typedef entropy_decoder_kernel_2 + kernel_2a; + typedef entropy_decoder_kernel_c + kernel_2a_c; + + + }; +} + +#endif // DLIB_ENTROPY_DECODEr_ + diff --git a/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp b/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b149880f048ca6910c290775cc944be89626a4d --- /dev/null +++ b/dlib/entropy_decoder/entropy_decoder_kernel_1.cpp @@ -0,0 +1,220 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_KERNEL_1_CPp_ +#define DLIB_ENTROPY_DECODER_KERNEL_1_CPp_ +#include "entropy_decoder_kernel_1.h" +#include +#include +#include + +#include "../assert.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + entropy_decoder_kernel_1:: + entropy_decoder_kernel_1( + ) : + initial_low(0x00000001), + initial_high(0xffffffff), + in(0), + low(initial_low), + high(initial_high), + buf(0), + buf_used(0), + target(0x00000000), + r(0) + { + } + +// ---------------------------------------------------------------------------------------- + + entropy_decoder_kernel_1:: + ~entropy_decoder_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + void entropy_decoder_kernel_1:: + clear( + ) + { + in = 0; + buf_used = 0; + buf = 0; + r = 0; + low = initial_low; + high = initial_high; + target = 0x00000000; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_decoder_kernel_1:: + set_stream ( + std::istream& in_ + ) + { + buf_used = 0; + buf = 0; + r = 0; + low = initial_low; + high = initial_high; + target = 0x00000000; + + in = &in_; + streambuf = in_.rdbuf(); + + + + unsigned char ch; + + + streambuf->sgetn((char*)&ch,1); + target = ch; + + target <<= 8; + if (streambuf->sgetn((char*)&ch,1)) + target += ch; + + + target <<= 8; + if (streambuf->sgetn((char*)&ch,1)) + target += ch; + + + target <<= 8; + if (streambuf->sgetn((char*)&ch,1)) + target += ch; + + } + +// ---------------------------------------------------------------------------------------- + + bool entropy_decoder_kernel_1:: + stream_is_set ( + ) const + { + if (in != 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + std::istream& entropy_decoder_kernel_1:: + get_stream ( + ) const + { + return *in; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_decoder_kernel_1:: + decode ( + uint32 low_count, + uint32 high_count + ) + { + // note that we must subtract 1 to preserve the convention that + // high == the real upper range - 1 + high = low + r*high_count - 1; + low = low + r*low_count; + r = 0; + + + + while (true) + { + + // if the highest order bit in high and low is the same + if ( low >= 0x80000000 || high < 0x80000000) + { + // make sure buf isn't empty + if (buf_used == 0) + { + buf_used = 8; + if (streambuf->sgetn(reinterpret_cast(&buf),1)==0) + { + // if there isn't anything else in the streambuffer then just + // make buf zero. + buf = 0; + } + } + + // we will be taking one bit from buf to replace the one we threw away + --buf_used; + + // roll off the bit in target + target <<= 1; + + // roll off the bit + high <<= 1; + low <<= 1; + high |= 1; // note that it is ok to add one to high here because + // of the convention that high == real upper range - 1. + // so that means that if we want to shift the upper range + // left by one then we must shift a one into high also + // since real upper range == high + 0.999999999... + + // make sure low is never zero + if (low == 0) + low = 1; + + // take a bit from buf to fill in the one we threw away + target += (buf>>buf_used)&0x01; + } + // if the distance between high and low is small and there aren't + // any bits we can roll off then round low up or high down. + else if (high-low < 0x10000) + { + if (high == 0x80000000) + high = 0x7fffffff; + else + low = 0x80000000; + } + else + { + break; + } + } // while (true) + + } + +// ---------------------------------------------------------------------------------------- + + bool entropy_decoder_kernel_1:: + get_target_called ( + ) const + { + return (r != 0); + } + +// ---------------------------------------------------------------------------------------- + + uint32 entropy_decoder_kernel_1:: + get_target ( + uint32 total + ) + { + // note that we must add one because of the convention that + // high == the real upper range minus 1 + r = (high-low+1)/total; + uint32 temp = (target-low)/r; + if (temp < total) + return temp; + else + return total-1; + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_ENTROPY_DECODER_KERNEL_1_CPp_ + diff --git a/dlib/entropy_decoder/entropy_decoder_kernel_1.h b/dlib/entropy_decoder/entropy_decoder_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..c3536d36924fa1830bf97c362e9a6eeb45d83297 --- /dev/null +++ b/dlib/entropy_decoder/entropy_decoder_kernel_1.h @@ -0,0 +1,132 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_KERNEl_1_ +#define DLIB_ENTROPY_DECODER_KERNEl_1_ + +#include "../algs.h" +#include "entropy_decoder_kernel_abstract.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + class entropy_decoder_kernel_1 + { + /*! + GENERAL NOTES + this decoder is implemented using arithmetic coding + + INITIAL VALUE + in == 0 + buf_used == 0 + buf == 0 + initial_low == 0x00000001 (slightly more than zero) + initial_high == 0xffffffff (slightly less than one, 0.99999999976717) + target == 0x00000000 (zero) + low == initial_low + high == initial_high + r == 0 + + CONVENTION + if (in != 0) + *in == get_stream() + true == stream_is_set() + streambuf == in->rdbuf() + else + false == stream_is_set() + + buf == used to hold fractional byte values which are fed to target. + buf_used == the number of low order bits in buf that are currently + in use + low == the low end of the range used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so it is + always in the range [0,1) + + low is also never allowed to be zero to avoid overflow + in the calculation (high-low+1)/total. + + high == the high end of the range - 1 used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so when we + interpret high as a real number then it is always in the + range [0,1) + + the range for arithmetic encoding is always + [low,high + 0.9999999...) the 0.9999999... is why + high == real upper range - 1 + + target == 32 bits of the fraction produced from an arithmetic encoder. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so it is + always in the range [0,1) + + r == the value (high-low+1)/total from the last call to + get_target() or 0 if get_target_called() should be false + + get_target_called() == (r != 0) + + !*/ + + public: + + entropy_decoder_kernel_1 ( + ); + + virtual ~entropy_decoder_kernel_1 ( + ); + + void clear( + ); + + void set_stream ( + std::istream& in + ); + + bool stream_is_set ( + ) const; + + std::istream& get_stream ( + ) const; + + void decode ( + uint32 low_count, + uint32 high_count + ); + + bool get_target_called ( + ) const; + + uint32 get_target ( + uint32 total + ); + + private: + + // restricted functions + entropy_decoder_kernel_1(entropy_decoder_kernel_1&); // copy constructor + entropy_decoder_kernel_1& operator=(entropy_decoder_kernel_1&); // assignment operator + + // data members + const uint32 initial_low; + const uint32 initial_high; + std::istream* in; + uint32 low; + uint32 high; + unsigned char buf; + uint32 buf_used; + uint32 target; + uint32 r; + std::streambuf* streambuf; + + }; + +} + +#ifdef NO_MAKEFILE +#include "entropy_decoder_kernel_1.cpp" +#endif + +#endif // DLIB_ENTROPY_DECODER_KERNEl_1_ + diff --git a/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp b/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0ab82f958a0810c20d0ac6556301a2235a70877 --- /dev/null +++ b/dlib/entropy_decoder/entropy_decoder_kernel_2.cpp @@ -0,0 +1,224 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_KERNEL_2_CPp_ +#define DLIB_ENTROPY_DECODER_KERNEL_2_CPp_ +#include "entropy_decoder_kernel_2.h" +#include +#include +#include + +#include "../assert.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + entropy_decoder_kernel_2:: + entropy_decoder_kernel_2( + ) : + initial_low(0x00000001), + initial_high(0xffffffff), + in(0), + low(initial_low), + high(initial_high), + target(0x00000000), + r(0) + { + } + +// ---------------------------------------------------------------------------------------- + + entropy_decoder_kernel_2:: + ~entropy_decoder_kernel_2 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + void entropy_decoder_kernel_2:: + clear( + ) + { + in = 0; + r = 0; + low = initial_low; + high = initial_high; + target = 0x00000000; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_decoder_kernel_2:: + set_stream ( + std::istream& in_ + ) + { + r = 0; + low = initial_low; + high = initial_high; + target = 0x00000000; + + in = &in_; + streambuf = in_.rdbuf(); + + + + unsigned char ch; + + + streambuf->sgetn((char*)&ch,1); + target = ch; + + target <<= 8; + if (streambuf->sgetn((char*)&ch,1)) + target += ch; + + + target <<= 8; + if (streambuf->sgetn((char*)&ch,1)) + target += ch; + + + target <<= 8; + if (streambuf->sgetn((char*)&ch,1)) + target += ch; + } + +// ---------------------------------------------------------------------------------------- + + bool entropy_decoder_kernel_2:: + stream_is_set ( + ) const + { + if (in != 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + std::istream& entropy_decoder_kernel_2:: + get_stream ( + ) const + { + return *in; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_decoder_kernel_2:: + decode ( + uint32 low_count, + uint32 high_count + ) + { + // note that we must subtract 1 to preserve the convention that + // high == the real upper range - 1 + high = low + r*high_count - 1; + low = low + r*low_count; + r = 0; + + + while (true ) + { + + // if high and low don't have the same 8 high order bits + if ((high&0xFF000000) != (low&0xFF000000)) + { + // if the distance between high and low is small and there aren't + // any bits we can roll off then force high and low to have common high + // order bits. + if ((high-low < 0x10000)) + { + if (high-low > 0x1000) + { + high>>=1; + low>>=1; + high = low = high+low; + high += 0xFF; + low -= 0xFF; + } + else /**/ + { + high>>=1; + low>>=1; + high = low = high+low; + } + } + else + { + // there are no bits to roll off and high and low are not + // too close so just quit the loop + break; + } + + } + // else if there are 8 bits we can roll off + else + { + unsigned char buf; + if (streambuf->sgetn(reinterpret_cast(&buf),1)==0) + { + // if there isn't anything else in the streambuffer then just + // make buf zero. + buf = 0; + } + + // also roll off the bits in target + target <<= 8; + + // roll off the bits + high <<= 8; + low <<= 8; + high |= 0xFF; // note that it is ok to add 0xFF to high here because + // of the convention that high == real upper range - 1. + // so that means that if we want to shift the upper range + // left by one then we must shift a one into high also + // since real upper range == high + 0.999999999... + + // make sure low is never zero + if (low == 0) + low = 1; + + + // put the new bits into target + target |= static_cast(buf); + } + + } // while (true) + } + +// ---------------------------------------------------------------------------------------- + + bool entropy_decoder_kernel_2:: + get_target_called ( + ) const + { + return (r != 0); + } + +// ---------------------------------------------------------------------------------------- + + uint32 entropy_decoder_kernel_2:: + get_target ( + uint32 total + ) + { + // note that we must add one because of the convention that + // high == the real upper range minus 1 + r = (high-low+1)/total; + uint32 temp = (target-low)/r; + if (temp < total) + return temp; + else + return total-1; + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_ENTROPY_DECODER_KERNEL_2_CPp_ + diff --git a/dlib/entropy_decoder/entropy_decoder_kernel_2.h b/dlib/entropy_decoder/entropy_decoder_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..5332b62fcbd9eeff7296d41fe03e9a91d2e71219 --- /dev/null +++ b/dlib/entropy_decoder/entropy_decoder_kernel_2.h @@ -0,0 +1,127 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_KERNEl_2_ +#define DLIB_ENTROPY_DECODER_KERNEl_2_ + +#include "../algs.h" +#include "entropy_decoder_kernel_abstract.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + class entropy_decoder_kernel_2 + { + /*! + GENERAL NOTES + this decoder is implemented using "range" coding + + INITIAL VALUE + in == 0 + initial_low == 0x00000001 (slightly more than zero) + initial_high == 0xffffffff (slightly less than one, 0.99999999976717) + target == 0x00000000 (zero) + low == initial_low + high == initial_high + r == 0 + + CONVENTION + if (in != 0) + *in == get_stream() + true == stream_is_set() + streambuf == in->rdbuf() + else + false == stream_is_set() + + + low == the low end of the range used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so it is + always in the range [0,1) + + low is also never allowed to be zero to avoid overflow + in the calculation (high-low+1)/total. + + high == the high end of the range - 1 used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so when we + interpret high as a real number then it is always in the + range [0,1) + + the range for arithmetic encoding is always + [low,high + 0.9999999...) the 0.9999999... is why + high == real upper range - 1 + + target == 32 bits of the fraction produced from an arithmetic encoder. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so it is + always in the range [0,1) + + r == the value (high-low+1)/total from the last call to + get_target() or 0 if get_target_called() should be false + + get_target_called() == (r != 0) + + !*/ + + public: + + entropy_decoder_kernel_2 ( + ); + + virtual ~entropy_decoder_kernel_2 ( + ); + + void clear( + ); + + void set_stream ( + std::istream& in + ); + + bool stream_is_set ( + ) const; + + std::istream& get_stream ( + ) const; + + void decode ( + uint32 low_count, + uint32 high_count + ); + + bool get_target_called ( + ) const; + + uint32 get_target ( + uint32 total + ); + + private: + + // restricted functions + entropy_decoder_kernel_2(entropy_decoder_kernel_2&); // copy constructor + entropy_decoder_kernel_2& operator=(entropy_decoder_kernel_2&); // assignment operator + + // data members + const uint32 initial_low; + const uint32 initial_high; + std::istream* in; + uint32 low; + uint32 high; + uint32 target; + uint32 r; + std::streambuf* streambuf; + + }; + + +} + +#ifdef NO_MAKEFILE +#include "entropy_decoder_kernel_2.cpp" +#endif + +#endif // DLIB_ENTROPY_DECODER_KERNEl_2_ + diff --git a/dlib/entropy_decoder/entropy_decoder_kernel_abstract.h b/dlib/entropy_decoder/entropy_decoder_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b277d2c7f24968f438cf278482819425d94a4042 --- /dev/null +++ b/dlib/entropy_decoder/entropy_decoder_kernel_abstract.h @@ -0,0 +1,207 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_ +#ifdef DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + class entropy_decoder + { + /*! + INITIAL VALUE + stream_is_set() == false + get_target_called() == false + + + WHAT THIS OBJECT REPRESENTS + This object represents an entropy decoder (could be implemented as an + arithmetic decoder for example). + + Note that all implementations of entropy_encoder and entropy_decoder + are paired. This means that if you use entropy_encoder_kernel_n to + encode something then you must use the corresponding + entropy_decoder_kernel_n to decode it. + + + WHERE IS EOF? + It is important to note that this object will not give any indication + that is has hit the end of the input stream when it occurs. It is + up to you to use some kind of coding scheme to detect this in the + compressed data stream. + + Another important thing to know is that decode() must be called + exactly the same number of times as encode() and with the same values + supplied for TOTAL, high_count, and low_count. Doing this ensures + that the decoder consumes exactly all the bytes from the input + stream that were written by the entropy_encoder. + + NOTATION: + At any moment each symbol has a certain probability of appearing in + the input stream. These probabilities may change as each symbol is + decoded and the probability model is updated accordingly. + + + - Before considering current symbol: + + let P(i) be a function which gives the probability of seeing the ith + symbol of an N symbol alphabet. Note that P(i) refers to the probability + of seeing the ith symbol WITHOUT considering the symbol currently given + by get_target(TOTAL). ( The domain of P(i) is from 0 to N-1. ) + + for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers + and TOTAL is the same number for all P(i) but COUNT may vary. + + let LOW_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i-1 + (note that LOW_COUNT(0) == 0) + let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i + + + - After considering current symbol: + + let #P(i) be a function which gives the probability of seeing the ith + symbol after we have updated our probability model to take the symbol + given by get_target(TOTAL) into account. + + for each i: #P(i) == #COUNT/#TOTAL where #COUNT and #TOTAL are integers + and #TOTAL is the same number for all #P(i) but #COUNT may vary. + !*/ + + public: + + entropy_decoder ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~entropy_decoder ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - if (stream_is_set()) + - clears any state accumulated in *this from decoding data from + the stream get_stream() + throws + - any exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void set_stream ( + std::istream& in + ); + /*! + ensures + - #*this will read data from in and decode it + - #stream_is_set() == true + - #get_target() == a number representing the first symbol from in + - #get_target_called() == false + - if (stream_is_set()) + - clears any state accumulated in *this from decoding data from + the stream get_stream() + throws + - any exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + bool stream_is_set ( + ) const; + /*! + ensures + - returns true if a stream has been associated with *this by calling + set_stream() + !*/ + + std::istream& get_stream ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns a reference to the istream object that *this is reading + encoded data from + !*/ + + + void decode ( + uint32 low_count, + uint32 high_count + ); + /*! + requires + - get_target_called() == true + - stream_is_set() == true + - low_count == LOW_COUNT(S) where S is the symbol represented + by get_target(TOTAL) + - high_count == HIGH_COUNT(S) where S is the symbol represented + by get_target(TOTAL) + - low_count <= get_target(TOTAL) < high_count <= TOTAL + ensures + - #get_target(#TOTAL) == a number which represents the next symbol + - #get_target_called() == false + throws + - any exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + bool get_target_called ( + ) const; + /*! + ensures + - returns true if get_target() has been called and since then decode() + and set_stream() have not been called + - returns false otherwise + !*/ + + uint32 get_target ( + uint32 total + ); + /*! + requires + - 0 < total < 65536 (2^16) + - total == TOTAL + - stream_is_set() == true + ensures + - in the next call to decode() the value of TOTAL will be + considered to be total + - #get_target_called() == true + - returns a number N such that: + - N is in the range 0 to total - 1 + - N represents a symbol S where + LOW_COUNT(S) <= N < HIGH_COUNT(S) + throws + - any exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + private: + + // restricted functions + entropy_decoder(entropy_decoder&); // copy constructor + entropy_decoder& operator=(entropy_decoder&); // assignment operator + + }; + +} + +#endif // DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_ + diff --git a/dlib/entropy_decoder/entropy_decoder_kernel_c.h b/dlib/entropy_decoder/entropy_decoder_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..5271d9f1f61630ec3a9a97884adf412aef70dd7c --- /dev/null +++ b/dlib/entropy_decoder/entropy_decoder_kernel_c.h @@ -0,0 +1,123 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_KERNEl_C_ +#define DLIB_ENTROPY_DECODER_KERNEl_C_ + +#include "entropy_decoder_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename decoder + > + class entropy_decoder_kernel_c : public decoder + { + + public: + std::istream& get_stream ( + ) const; + + void decode ( + uint32 low_count, + uint32 high_count + ); + + uint32 get_target ( + uint32 total + ); + + private: + uint32 _get_target; + uint32 TOTAL; + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename decoder + > + std::istream& entropy_decoder_kernel_c:: + get_stream ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tstd::istream& entropy_decoder::get_stream()" + << "\n\tyou must set a stream for this object before you can get it" + << "\n\tthis: " << this + ); + + // call the real function + return decoder::get_stream(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename decoder + > + void entropy_decoder_kernel_c:: + decode ( + uint32 low_count, + uint32 high_count + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (low_count <= _get_target) && (_get_target < high_count) && + (high_count <= TOTAL) && + (this->stream_is_set() == true) && (this->get_target_called() == true), + "\tvoid entropy_decoder::decode()" + << "\n\tRefer to the ensures clause for this function for further information." + << "\n\tNote that _get_target refers to get_target(TOTAL)" + << "\n\tthis: " << this + << "\n\tlow_count: " << low_count + << "\n\thigh_count: " << high_count + << "\n\tTOTAL: " << TOTAL + << "\n\tget_target(TOTAL): " << _get_target + << "\n\tis_stream_set(): " << (this->stream_is_set() ? "true" : "false" ) + << "\n\tget_target_called(): " << (this->get_target_called() ? "true" : "false" ) + ); + + // call the real function + decoder::decode(low_count,high_count); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename decoder + > + uint32 entropy_decoder_kernel_c:: + get_target ( + uint32 total + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (total > 0) && (total < 65536) && (this->stream_is_set() == true), + "\tvoid entropy_decoder::get_target()" + << "\n\tyou must set a stream for this object before you can get the " + << "\n\rnext target." + << "\n\tthis: " << this + << "\n\ttotal: " << total + ); + + // call the real function + _get_target = decoder::get_target(total); + TOTAL = total; + return _get_target; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_KERNEl_C_ + diff --git a/dlib/entropy_decoder_model.h b/dlib/entropy_decoder_model.h new file mode 100644 index 0000000000000000000000000000000000000000..4120ba8045e7613f3c41f921432cad0234c46ccc --- /dev/null +++ b/dlib/entropy_decoder_model.h @@ -0,0 +1,108 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEl_ +#define DLIB_ENTROPY_DECODER_MODEl_ + +#include "entropy_decoder_model/entropy_decoder_model_kernel_1.h" +#include "entropy_decoder_model/entropy_decoder_model_kernel_2.h" +#include "entropy_decoder_model/entropy_decoder_model_kernel_3.h" +#include "entropy_decoder_model/entropy_decoder_model_kernel_4.h" +#include "entropy_decoder_model/entropy_decoder_model_kernel_5.h" +#include "entropy_decoder_model/entropy_decoder_model_kernel_6.h" + +#include "conditioning_class.h" +#include "memory_manager.h" + +namespace dlib +{ + + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + class entropy_decoder_model + { + entropy_decoder_model() {} + + typedef typename conditioning_class::kernel_1a cc1; + typedef typename conditioning_class::kernel_2a cc2; + typedef typename conditioning_class::kernel_3a cc3; + typedef typename conditioning_class::kernel_4a cc4a; + typedef typename conditioning_class::kernel_4b cc4b; + typedef typename conditioning_class::kernel_4c cc4c; + typedef typename conditioning_class::kernel_4d cc4d; + + public: + + //----------- kernels --------------- + + // kernel_1 + typedef entropy_decoder_model_kernel_1 + kernel_1a; + + typedef entropy_decoder_model_kernel_1 + kernel_1b; + + typedef entropy_decoder_model_kernel_1 + kernel_1c; + + // -------------------- + + // kernel_2 + typedef entropy_decoder_model_kernel_2 + kernel_2a; + + typedef entropy_decoder_model_kernel_2 + kernel_2b; + + typedef entropy_decoder_model_kernel_2 + kernel_2c; + + typedef entropy_decoder_model_kernel_2 + kernel_2d; + + // -------------------- + + // kernel_3 + typedef entropy_decoder_model_kernel_3 + kernel_3a; + + typedef entropy_decoder_model_kernel_3 + kernel_3b; + + typedef entropy_decoder_model_kernel_3 + kernel_3c; + + // -------------------- + + // kernel_4 + typedef entropy_decoder_model_kernel_4 + kernel_4a; + typedef entropy_decoder_model_kernel_4 + kernel_4b; + + + // -------------------- + + // kernel_5 + typedef entropy_decoder_model_kernel_5 + kernel_5a; + typedef entropy_decoder_model_kernel_5 + kernel_5b; + typedef entropy_decoder_model_kernel_5 + kernel_5c; + + + // -------------------- + + // kernel_6 + typedef entropy_decoder_model_kernel_6 + kernel_6a; + + + }; +} + +#endif // DLIB_ENTROPY_DECODER_MODEl_ + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..86b864e9617505cd77ed3c16c8edbad2fc49937c --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h @@ -0,0 +1,173 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_ +#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_ + +#include "../algs.h" +#include "entropy_decoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc + > + class entropy_decoder_model_kernel_1 + { + /*! + REQUIREMENTS ON cc + cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc::get_alphabet_size() == alphabet_size+1 + + INITIAL VALUE + Initially this object's finite context model is empty + + CONVENTION + &get_entropy_decoder() == coder + &order_0.get_global_state() == &gs + + This is an order-0 model. The last symbol in the order-0 context is + an escape into the order minus 1 context. + !*/ + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model_kernel_1 ( + entropy_decoder& coder + ); + + virtual ~entropy_decoder_model_kernel_1 ( + ); + + inline void clear( + ); + + inline void decode ( + unsigned long& symbol + ); + + entropy_decoder& get_entropy_decoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_decoder& coder; + typename cc::global_state_type gs; + cc order_0; + + // restricted functions + entropy_decoder_model_kernel_1(entropy_decoder_model_kernel_1&); // copy constructor + entropy_decoder_model_kernel_1& operator=(entropy_decoder_model_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc + > + entropy_decoder_model_kernel_1:: + entropy_decoder_model_kernel_1 ( + entropy_decoder& coder_ + ) : + coder(coder_), + order_0(gs) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc + > + entropy_decoder_model_kernel_1:: + ~entropy_decoder_model_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc + > + void entropy_decoder_model_kernel_1:: + clear( + ) + { + order_0.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc + > + void entropy_decoder_model_kernel_1:: + decode ( + unsigned long& symbol + ) + { + unsigned long current_symbol, low_count, high_count, target; + + // look in the order-0 context + target = coder.get_target(order_0.get_total()); + order_0.get_symbol(target,current_symbol,low_count,high_count); + + + // have coder decode the next symbol + coder.decode(low_count,high_count); + + // if current_symbol is not an escape from the order-0 context + if (current_symbol != alphabet_size) + { + // update the count for this symbol + order_0.increment_count(current_symbol,2); + + symbol = current_symbol; + return; + } + + // update the count for the escape symbol + order_0.increment_count(alphabet_size); + + + // go into the order minus one context + target = coder.get_target(alphabet_size); + coder.decode(target,target+1); + + + // update the count for this symbol in the order-0 context + order_0.increment_count(target,2); + + symbol = target; + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_ + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..b6781fe4fe47fbd90a7087e6e27a660cd266d91b --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h @@ -0,0 +1,245 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_ +#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_ + +#include "../algs.h" +#include "entropy_decoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename ccbig + > + class entropy_decoder_model_kernel_2 + { + /*! + REQUIREMENTS ON cc + cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc::get_alphabet_size() == alphabet_size+1 + this will be used for the order-0 context + + REQUIREMENTS ON ccbig + ccbig is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + ccbig::get_alphabet_size() == alphabet_size+1 + this will be used for the order-1 context + + INITIAL VALUE + Initially this object's finite context model is empty + previous_symbol == 0 + + CONVENTION + &get_entropy_decoder() == coder + &order_0.get_global_state() == &gs + &order_1[i]->get_global_state() == &gsbig + + + This is an order-1-0 model. The last symbol in the order-0 and order-1 + context is an escape into the lower context. + + previous_symbol == the last symbol seen + !*/ + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model_kernel_2 ( + entropy_decoder& coder + ); + + virtual ~entropy_decoder_model_kernel_2 ( + ); + + inline void clear( + ); + + inline void decode ( + unsigned long& symbol + ); + + entropy_decoder& get_entropy_decoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_decoder& coder; + typename cc::global_state_type gs; + typename ccbig::global_state_type gsbig; + cc order_0; + ccbig* order_1[alphabet_size]; + unsigned long previous_symbol; + + + // restricted functions + entropy_decoder_model_kernel_2(entropy_decoder_model_kernel_2&); // copy constructor + entropy_decoder_model_kernel_2& operator=(entropy_decoder_model_kernel_2&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename ccbig + > + entropy_decoder_model_kernel_2:: + entropy_decoder_model_kernel_2 ( + entropy_decoder& coder_ + ) : + coder(coder_), + order_0(gs), + previous_symbol(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535); + + unsigned long i; + try + { + for (i = 0; i < alphabet_size; ++i) + { + order_1[i] = new ccbig(gsbig); + } + } + catch (...) + { + for (unsigned long j = 0; j < i; ++j) + { + delete order_1[j]; + } + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename ccbig + > + entropy_decoder_model_kernel_2:: + ~entropy_decoder_model_kernel_2 ( + ) + { + for (unsigned long i = 0; i < alphabet_size; ++i) + { + delete order_1[i]; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename ccbig + > + void entropy_decoder_model_kernel_2:: + clear( + ) + { + previous_symbol = 0; + order_0.clear(); + for (unsigned long i = 0; i < alphabet_size; ++i) + { + order_1[i]->clear(); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename ccbig + > + void entropy_decoder_model_kernel_2:: + decode ( + unsigned long& symbol + ) + { + unsigned long current_symbol, low_count, high_count, target; + + // look in the order-1 context + target = coder.get_target(order_1[previous_symbol]->get_total()); + order_1[previous_symbol]->get_symbol(target,current_symbol,low_count,high_count); + + // have the coder decode the next symbol + coder.decode(low_count,high_count); + + // if the current_symbol is not an escape from the order-1 context + if (current_symbol != alphabet_size) + { + symbol = current_symbol; + order_1[previous_symbol]->increment_count(current_symbol,2); + previous_symbol = current_symbol; + return; + } + + // since this is an escape to order-0 we should increment + // the escape symbol + order_1[previous_symbol]->increment_count(alphabet_size); + + + + // look in the order-0 context + target = coder.get_target(order_0.get_total()); + order_0.get_symbol(target,current_symbol,low_count,high_count); + + // have coder decode the next symbol + coder.decode(low_count,high_count); + + // if current_symbol is not an escape from the order-0 context + if (current_symbol != alphabet_size) + { + // update the count for this symbol + order_1[previous_symbol]->increment_count(current_symbol,2); + order_0.increment_count(current_symbol,2); + + symbol = current_symbol; + previous_symbol = current_symbol; + return; + } + + // update the count for the escape symbol + order_0.increment_count(current_symbol); + + + // go into the order minus one context + target = coder.get_target(alphabet_size); + coder.decode(target,target+1); + + + // update the count for this symbol + order_1[previous_symbol]->increment_count(target,2); + order_0.increment_count(target,2); + + symbol = target; + previous_symbol = target; + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_ + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h new file mode 100644 index 0000000000000000000000000000000000000000..f98cb3be2f672b7055cf10a5927a7836fee37043 --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h @@ -0,0 +1,335 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_ +#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_ + +#include "../algs.h" +#include "entropy_decoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename cc_high + > + class entropy_decoder_model_kernel_3 + { + /*! + REQUIREMENTS ON cc + cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc::get_alphabet_size() == alphabet_size+1 + + REQUIREMENTS ON cc_high + cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc_high::get_alphabet_size() == alphabet_size+1 + + INITIAL VALUE + - Initially this object's finite context model is empty + - previous_symbol == 0 + - previous_symbol2 == 0 + - order_1 == pointer to an array of alphabet_size elements + - order_2 == pointer to an array of alphabet_size*alphabet_size elements + - for all values of i: order_2[i] == 0 + + CONVENTION + &get_entropy_encoder() == coder + &order_0.get_global_state() == &gs + &order_1[i]->get_global_state() == &gs + + if (order_2[i] != 0) then + &order_2[i]->get_global_state() == &gs_high + + This is an order-2-1-0 model. The last symbol in the order-2, order-1 and + order-0 contexts is an escape into the lower context. + + previous_symbol == the last symbol seen + previous_symbol2 == the symbol we saw before previous_symbol + !*/ + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model_kernel_3 ( + entropy_decoder& coder + ); + + virtual ~entropy_decoder_model_kernel_3 ( + ); + + inline void clear( + ); + + inline void decode ( + unsigned long& symbol + ); + + entropy_decoder& get_entropy_decoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_decoder& coder; + typename cc::global_state_type gs; + typename cc_high::global_state_type gs_high; + cc order_0; + cc** order_1; + unsigned long previous_symbol; + cc_high** order_2; + unsigned long previous_symbol2; + + // restricted functions + entropy_decoder_model_kernel_3(entropy_decoder_model_kernel_3&); // copy constructor + entropy_decoder_model_kernel_3& operator=(entropy_decoder_model_kernel_3&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename cc_high + > + entropy_decoder_model_kernel_3:: + entropy_decoder_model_kernel_3 ( + entropy_decoder& coder_ + ) : + coder(coder_), + order_0(gs), + order_1(0), + previous_symbol(0), + order_2(0), + previous_symbol2(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535); + + try + { + order_1 = new cc*[alphabet_size]; + order_2 = new cc_high*[alphabet_size*alphabet_size]; + } + catch (...) + { + if (order_1) delete [] order_1; + if (order_2) delete [] order_2; + throw; + } + + + unsigned long i; + + for (i = 0; i < alphabet_size*alphabet_size; ++i) + { + order_2[i] = 0; + } + + try + { + for (i = 0; i < alphabet_size; ++i) + { + order_1[i] = new cc(gs); + } + } + catch (...) + { + for (unsigned long j = 0; j < i; ++j) + { + delete order_1[j]; + } + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename cc_high + > + entropy_decoder_model_kernel_3:: + ~entropy_decoder_model_kernel_3 ( + ) + { + for (unsigned long i = 0; i < alphabet_size; ++i) + { + delete order_1[i]; + } + + for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i) + { + if (order_2[i] != 0) + delete order_2[i]; + } + delete [] order_1; + delete [] order_2; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename cc_high + > + void entropy_decoder_model_kernel_3:: + clear( + ) + { + previous_symbol = 0; + previous_symbol2 = 0; + order_0.clear(); + for (unsigned long i = 0; i < alphabet_size; ++i) + { + order_1[i]->clear(); + } + + for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i) + { + if (order_2[i] != 0) + { + delete order_2[i]; + order_2[i] = 0; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + typename cc, + typename cc_high + > + void entropy_decoder_model_kernel_3:: + decode ( + unsigned long& symbol + ) + { + unsigned long current_symbol, low_count, high_count, target; + + + // look in the order-2 context + unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size); + if (order_2[temp] != 0) + { + target = coder.get_target(order_2[temp]->get_total()); + order_2[temp]->get_symbol(target,current_symbol,low_count,high_count); + + // have the coder decode the next symbol + coder.decode(low_count,high_count); + + // if the current_symbol is not an escape from the order-2 context + if (current_symbol != alphabet_size) + { + symbol = current_symbol; + order_2[temp]->increment_count(current_symbol,2); + previous_symbol2 = previous_symbol; + previous_symbol = current_symbol; + return; + } + + // since this is an escape to order-1 we should increment + // the escape symbol + order_2[temp]->increment_count(alphabet_size); + } + else + { + order_2[temp] = new cc_high(gs_high); + } + + + + + + + // look in the order-1 context + target = coder.get_target(order_1[previous_symbol]->get_total()); + order_1[previous_symbol]->get_symbol(target,current_symbol,low_count,high_count); + + // have the coder decode the next symbol + coder.decode(low_count,high_count); + + // if the current_symbol is not an escape from the order-1 context + if (current_symbol != alphabet_size) + { + symbol = current_symbol; + order_2[temp]->increment_count(current_symbol,2); + order_1[previous_symbol]->increment_count(current_symbol,2); + previous_symbol2 = previous_symbol; + previous_symbol = current_symbol; + return; + } + + // since this is an escape to order-0 we should increment + // the escape symbol + order_1[previous_symbol]->increment_count(alphabet_size); + + + + // look in the order-0 context + target = coder.get_target(order_0.get_total()); + order_0.get_symbol(target,current_symbol,low_count,high_count); + + // have coder decode the next symbol + coder.decode(low_count,high_count); + + // if current_symbol is not an escape from the order-0 context + if (current_symbol != alphabet_size) + { + // update the count for this symbol + order_2[temp]->increment_count(current_symbol,2); + order_1[previous_symbol]->increment_count(current_symbol,2); + order_0.increment_count(current_symbol,2); + + + symbol = current_symbol; + previous_symbol2 = previous_symbol; + previous_symbol = current_symbol; + return; + } + + // update the count for the escape symbol + order_0.increment_count(current_symbol); + + + // go into the order minus one context + target = coder.get_target(alphabet_size); + coder.decode(target,target+1); + + + // update the count for this symbol + order_2[temp]->increment_count(target,2); + order_1[previous_symbol]->increment_count(target,2); + order_0.increment_count(target,2); + + + symbol = target; + previous_symbol2 = previous_symbol; + previous_symbol = target; + + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_ + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h new file mode 100644 index 0000000000000000000000000000000000000000..23442ff2d55f5be23f220cbe02ee0e40a75769d6 --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h @@ -0,0 +1,622 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_ +#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_ + +#include "../algs.h" +#include "entropy_decoder_model_kernel_abstract.h" +#include "../assert.h" + + +namespace dlib +{ + + namespace edmk4 + { + struct node + { + node* next; + node* child_context; + node* parent_context; + + unsigned short symbol; + unsigned short count; + unsigned short total; + unsigned short escapes; + }; + } + + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + class entropy_decoder_model_kernel_4 + { + /*! + REQUIREMENTS ON total_nodes + - 4096 < total_nodes + - this is the total number of nodes that we will use in the tree + + REQUIREMENTS ON order + - 0 <= order + - this is the maximum depth-1 the tree will be allowed to go (note + that the root level is depth 0). + + + GENERAL NOTES + This implementation follows more or less the implementation + strategy laid out by Alistair Moffat in his paper + Implementing the PPM data compression scheme. Published in IEEE + Transactions on Communications, 38(11):1917-1921, 1990. + + The escape method used will be method D. + + + INITIAL VALUE + - root == pointer to an array of total_nodes nodes + - next_node == 1 + - cur == root + - cur_order = 0 + - root->next == 0 + - root->parent_context == 0 + - root->child_context == 0 + - root->escapes == 0 + - root->total == 0 + - stack_size == 0 + + CONVENTION + - pop() == stack[stack_size-1] + - &get_entropy_decoder() == coder + - root == pointer to an array of total_nodes nodes. + this is also the root of the tree. + + - if (next_node < total_nodes) then + - next_node == the next node in root that has not yet been allocated + + + - root->next == 0 + - root->parent_context == 0 + + + - for every node in the tree: + { + - NOTATION: + - The "context" of a node is the string of symbols seen + when you go from the root of the tree down (down though + child context pointers) to the node, including the symbol at + the node itself. (note that the context of the root node + is "" or the empty string) + - A set of nodes is in the same "context set" if all the node's + contexts are of length n and all the node's contexts share + the same prefix of length n-1. + - The "child context set" of a node is a set of nodes with + contexts that are one symbol longer and prefixed by the node's + context. For example, if a node has a context "abc" then the + nodes for contexts "abca", "abcb", "abcc", etc... are all in + the child context set of the node. + - The "parent context" of a node is the context that is one + symbol shorter than the node's context and includes the + symbol in the node. So the parent context of a node with + context "abcd" would be the context "bcd". + + + - if (next != 0) then + - next == pointer to the next node in the same context set + - if (child_context != 0) then + - child_context == pointer to the first node of the child + context set for this node. + - if (parent_context != 0) then + - parent_context == pointer to the parent context of this node. + - else + - this node is the root node of the tree + + + - if (this is not the root node) then + - symbol == the symbol represented with this node + - count == the number of times this symbol has been seen in its + parent context. + - else + - the root doesn't have a symbol. i.e. the context for the + root node is "" or the empty string. + + - total == The sum of the counts of all the nodes + in the child context set + escapes. + - escapes == the escape count for the context represented + by the node. + } + + + - cur_order < order + - cur_order == the depth of the node cur in the tree. + (note that the root node has depth 0) + - cur == pointer to the node in the tree who's context matches + the most recent symbols we have seen. + + + !*/ + + typedef edmk4::node node; + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model_kernel_4 ( + entropy_decoder& coder + ); + + virtual ~entropy_decoder_model_kernel_4 ( + ); + + inline void clear( + ); + + inline void decode ( + unsigned long& symbol + ); + + entropy_decoder& get_entropy_decoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + + inline void push ( + edmk4::node* n + ); + /*! + requires + - stack_size <= order + ensures + - #pop() == n + !*/ + + inline edmk4::node* pop ( + ); + /*! + requires + - stack_size > 0 + ensures + - returns the node at the top of the stack + !*/ + + inline edmk4::node* allocate_node ( + ); + /*! + requires + - space_left() == true + ensures + - returns a pointer to a new node + !*/ + + inline void destroy_tree ( + ); + /*! + ensures + - deallocates all nodes except the root + - #root->child_context == 0 + - #root->escapes == 0 + - #root->total == 0 + - #cur == root + - #cur_order == 0 + - #stack_size == 0 + !*/ + + + inline bool space_left ( + ) const; + /*! + ensures + - returns true if there is at least 1 free node left. + - returns false otherwise + !*/ + + + inline void scale_counts ( + node* n + ); + /*! + ensures + - divides all the counts in the child context set of n by 2. + - none of the nodes in the child context set will have a count of 0 + !*/ + + + entropy_decoder& coder; + unsigned long next_node; + node* root; + node* cur; + unsigned long cur_order; + node* stack[order+1]; + unsigned long stack_size; + + // restricted functions + entropy_decoder_model_kernel_4(entropy_decoder_model_kernel_4&); // copy constructor + entropy_decoder_model_kernel_4& operator=(entropy_decoder_model_kernel_4&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + entropy_decoder_model_kernel_4:: + entropy_decoder_model_kernel_4 ( + entropy_decoder& coder_ + ) : + coder(coder_), + next_node(1), + cur_order(0), + stack_size(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535); + COMPILE_TIME_ASSERT( 4096 < total_nodes ); + + root = new node[total_nodes]; + cur = root; + + root->child_context = 0; + root->escapes = 0; + root->next = 0; + root->parent_context = 0; + root->total = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + entropy_decoder_model_kernel_4:: + ~entropy_decoder_model_kernel_4 ( + ) + { + delete [] root; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_4:: + clear( + ) + { + destroy_tree(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_4:: + decode ( + unsigned long& symbol + ) + { + node* temp = cur; + cur = 0; + unsigned long low_count, high_count, total_count; + unsigned long target; + node* new_node = 0; + + // local_order will track the level of temp in the tree + unsigned long local_order = cur_order; + + + while (true) + { + high_count = 0; + if (space_left()) + { + total_count = temp->total; + + if (total_count > 0) + { + // check if we need to scale the counts + if (total_count > 10000) + { + scale_counts(temp); + total_count = temp->total; + } + + target = coder.get_target(total_count); + + // find either the symbol we are looking for or the + // end of the context set + node* n = temp->child_context; + node* last = 0; + while (true) + { + high_count += n->count; + + if (high_count > target || n->next == 0) + break; + last = n; + n = n->next; + } + + low_count = high_count - n->count; + + // if we found the symbol + if (high_count > target) + { + if (new_node != 0) + { + new_node->parent_context = n; + } + + symbol = n->symbol; + + coder.decode(low_count,high_count); + n->count += 8; + temp->total += 8; + + // move this node to the front + if (last) + { + last->next = n->next; + n->next = temp->child_context; + temp->child_context = n; + } + + + if (cur == 0) + { + if (local_order < order) + { + cur_order = local_order+1; + cur = n; + } + else + { + cur = n->parent_context; + cur_order = local_order; + } + } + + break; + + } + // if we hit the end of the context set without finding the symbol + else + { + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + n->next = new_node; + + // get the escape code + coder.decode(high_count,total_count); + } + + } + else // if (total_count == 0) + { + // this means that temp->child_context == 0 so we should make + // a new node here. + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + temp->child_context = new_node; + } + + if (cur == 0 && local_order < order) + { + cur = new_node; + cur_order = local_order+1; + } + + // fill out the new node + new_node->child_context = 0; + new_node->count = 4; + new_node->escapes = 0; + new_node->next = 0; + push(new_node); + new_node->total = 0; + temp->escapes += 4; + temp->total += 8; + + + if (temp != root) + { + temp = temp->parent_context; + --local_order; + continue; + } + + // since this is the root we are going to the order-(-1) context + // so we can just take care of that here. + target = coder.get_target(alphabet_size); + new_node->parent_context = root; + coder.decode(target,target+1); + symbol = target; + + if (cur == 0) + { + cur = root; + cur_order = 0; + } + break; + } + else + { + // there isn't enough space so we should rebuild the tree + destroy_tree(); + temp = cur; + local_order = cur_order; + cur = 0; + new_node = 0; + } + } // while (true) + + while (stack_size > 0) + { + pop()->symbol = static_cast(symbol); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + edmk4::node* entropy_decoder_model_kernel_4:: + allocate_node ( + ) + { + node* temp; + temp = root + next_node; + ++next_node; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_4:: + destroy_tree ( + ) + { + next_node = 1; + root->child_context = 0; + root->escapes = 0; + root->total = 0; + cur = root; + cur_order = 0; + stack_size = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_decoder_model_kernel_4:: + space_left ( + ) const + { + return (next_node < total_nodes); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_4:: + push ( + edmk4::node* n + ) + { + stack[stack_size] = n; + ++stack_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + edmk4::node* entropy_decoder_model_kernel_4:: + pop ( + ) + { + --stack_size; + return stack[stack_size]; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_4:: + scale_counts ( + node* temp + ) + { + if (temp->escapes > 1) + temp->escapes >>= 1; + temp->total = temp->escapes; + + node* n = temp->child_context; + while (n != 0) + { + if (n->count > 1) + n->count >>= 1; + + temp->total += n->count; + n = n->next; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_ + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h new file mode 100644 index 0000000000000000000000000000000000000000..1243b3529bf74ba5f6d8ddbbd0cd6e84635d34cf --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h @@ -0,0 +1,793 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_ +#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_ + +#include "../algs.h" +#include "entropy_decoder_model_kernel_abstract.h" +#include "../assert.h" + + +namespace dlib +{ + + namespace edmk5 + { + struct node + { + node* next; + node* child_context; + node* parent_context; + + unsigned short symbol; + unsigned short count; + unsigned short total; + unsigned short escapes; + }; + } + + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + class entropy_decoder_model_kernel_5 + { + /*! + REQUIREMENTS ON total_nodes + - 4096 < total_nodes + - this is the total number of nodes that we will use in the tree + + REQUIREMENTS ON order + - 0 <= order + - this is the maximum depth-1 the tree will be allowed to go (note + that the root level is depth 0). + + + GENERAL NOTES + This implementation follows more or less the implementation + strategy laid out by Alistair Moffat in his paper + Implementing the PPM data compression scheme. Published in IEEE + Transactions on Communications, 38(11):1917-1921, 1990. + + The escape method used will be method D. + + This also uses Dmitry Shkarin's Information Inheritance scheme. + (described in "PPM: one step to practicality" and "Improving the + Efficiency of the PPM Algorithm") + + + INITIAL VALUE + - root == pointer to an array of total_nodes nodes + - next_node == 1 + - cur == root + - cur_order = 0 + - root->next == 0 + - root->parent_context == 0 + - root->child_context == 0 + - root->escapes == 0 + - root->total == 0 + - stack_size == 0 + - exc_used == false + - for all i: exc[i] == 0 + + CONVENTION + - exc_used == something_is_excluded() + - pop() == stack[stack_size-1].n and stack[stack_size-1].nc + - is_excluded(symbol) == bit symbol&0x1F from exc[symbol>>5] + - &get_entropy_decoder() == coder + - root == pointer to an array of total_nodes nodes. + this is also the root of the tree. + - if (next_node < total_nodes) then + - next_node == the next node in root that has not yet been allocated + + - root->next == 0 + - root->parent_context == 0 + + + - for every node in the tree: + { + - NOTATION: + - The "context" of a node is the string of symbols seen + when you go from the root of the tree down (down though + child context pointers) to the node, including the symbol at + the node itself. (note that the context of the root node + is "" or the empty string) + - A set of nodes is in the same "context set" if all the node's + contexts are of length n and all the node's contexts share + the same prefix of length n-1. + - The "child context set" of a node is a set of nodes with + contexts that are one symbol longer and prefixed by the node's + context. For example, if a node has a context "abc" then the + nodes for contexts "abca", "abcb", "abcc", etc... are all in + the child context set of the node. + - The "parent context" of a node is the context that is one + symbol shorter than the node's context and includes the + symbol in the node. So the parent context of a node with + context "abcd" would be the context "bcd". + + + - if (next != 0) then + - next == pointer to the next node in the same context set + - if (child_context != 0) then + - child_context == pointer to the first node of the child + context set for this node. + - escapes > 0 + - if (parent_context != 0) then + - parent_context == pointer to the parent context of this node. + - else + - this node is the root node of the tree + + + - if (this is not the root node) then + - symbol == the symbol represented with this node + - count == the number of times this symbol has been seen in its + parent context. + - else + - the root doesn't have a symbol. i.e. the context for the + root node is "" or the empty string. + + - total == The sum of the counts of all the nodes + in the child context set + escapes. + - escapes == the escape count for the context represented + by the node. + - count > 0 + } + + + - cur_order < order + - cur_order == the depth of the node cur in the tree. + (note that the root node has depth 0) + - cur == pointer to the node in the tree who's context matches + the most recent symbols we have seen. + + + !*/ + + typedef edmk5::node node; + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model_kernel_5 ( + entropy_decoder& coder + ); + + virtual ~entropy_decoder_model_kernel_5 ( + ); + + inline void clear( + ); + + inline void decode ( + unsigned long& symbol + ); + + entropy_decoder& get_entropy_decoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + + inline void push ( + node* n, + node* nc + ); + /*! + requires + - stack_size < order + ensures + - #pop(a,b): a == n && b == nc + !*/ + + inline void pop ( + node*& n, + node*& nc + ); + /*! + requires + - stack_size > 0 + ensures + - returns the two nodes at the top of the stack + !*/ + + inline edmk5::node* allocate_node ( + ); + /*! + requires + - space_left() == true + ensures + - returns a pointer to a new node + !*/ + + inline bool space_left ( + ) const; + /*! + ensures + - returns true if there is at least 1 free node left. + - returns false otherwise + !*/ + + inline void exclude ( + unsigned short symbol + ); + /*! + ensures + - #is_excluded(symbol) == true + - #something_is_excluded() == true + !*/ + + inline bool is_excluded ( + unsigned short symbol + ); + /*! + ensures + - if (symbol has been excluded) then + - returns true + - else + - returns false + !*/ + + inline bool something_is_excluded ( + ); + /*! + ensures + - returns true if some symbol has been excluded. + returns false otherwise + !*/ + + inline void clear_exclusions ( + ); + /*! + ensures + - for all symbols #is_excluded(symbol) == false + - #something_is_excluded() == false + !*/ + + inline void scale_counts ( + node* n + ); + /*! + ensures + - divides all the counts in the child context set of n by 2. + - none of the nodes in the child context set will have a count of 0 + !*/ + + struct nodes + { + node* n; + node* nc; + }; + + entropy_decoder& coder; + unsigned long next_node; + node* root; + node* cur; + unsigned long cur_order; + unsigned long exc[alphabet_size/32+1]; + nodes stack[order+1]; + unsigned long stack_size; + bool exc_used; + + // restricted functions + entropy_decoder_model_kernel_5(entropy_decoder_model_kernel_5&); // copy constructor + entropy_decoder_model_kernel_5& operator=(entropy_decoder_model_kernel_5&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + entropy_decoder_model_kernel_5:: + entropy_decoder_model_kernel_5 ( + entropy_decoder& coder_ + ) : + coder(coder_), + next_node(1), + cur_order(0), + stack_size(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535); + COMPILE_TIME_ASSERT( 4096 < total_nodes ); + + root = new node[total_nodes]; + cur = root; + + root->child_context = 0; + root->escapes = 0; + root->next = 0; + root->parent_context = 0; + root->total = 0; + + clear_exclusions(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + entropy_decoder_model_kernel_5:: + ~entropy_decoder_model_kernel_5 ( + ) + { + delete [] root; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + clear( + ) + { + next_node = 1; + root->child_context = 0; + root->escapes = 0; + root->total = 0; + cur = root; + cur_order = 0; + stack_size = 0; + + clear_exclusions(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + decode ( + unsigned long& symbol + ) + { + node* temp = cur; + cur = 0; + unsigned long low_count, high_count, total_count; + unsigned long target; + node* new_node = 0; + + // local_order will track the level of temp in the tree + unsigned long local_order = cur_order; + + + unsigned short c; // c == t(a|sk) + unsigned short t; // t == T(sk) + + + if (something_is_excluded()) + clear_exclusions(); + + while (true) + { + high_count = 0; + if (space_left()) + { + total_count = temp->total; + + if (total_count > 0) + { + // check if we need to scale the counts + if (total_count > 10000) + { + scale_counts(temp); + total_count = temp->total; + } + + if (something_is_excluded()) + { + node* n = temp->child_context; + total_count = temp->escapes; + while (true) + { + if (is_excluded(n->symbol) == false) + { + total_count += n->count; + } + if (n->next == 0) + break; + n = n->next; + } + } + + + + target = coder.get_target(total_count); + + // find either the symbol we are looking for or the + // end of the context set + node* n = temp->child_context; + node* last = 0; + while (true) + { + if (is_excluded(n->symbol) == false) + { + high_count += n->count; + exclude(n->symbol); + } + + + if (high_count > target || n->next == 0) + break; + last = n; + n = n->next; + } + + + // if we found the symbol + if (high_count > target) + { + low_count = high_count - n->count; + + if (new_node != 0) + { + new_node->parent_context = n; + } + + symbol = n->symbol; + + coder.decode(low_count,high_count); + c = n->count += 8; + t = temp->total += 8; + + + // move this node to the front + if (last) + { + last->next = n->next; + n->next = temp->child_context; + temp->child_context = n; + } + + if (cur == 0) + { + if (local_order < order) + { + cur_order = local_order+1; + cur = n; + } + else + { + cur = n->parent_context; + cur_order = local_order; + } + } + + break; + + + } + // if we hit the end of the context set without finding the symbol + else + { + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + n->next = new_node; + + // get the escape code + coder.decode(high_count,total_count); + } + + } + else // if (total_count == 0) + { + // this means that temp->child_context == 0 so we should make + // a new node here. + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + temp->child_context = new_node; + } + + if (cur == 0 && local_order < order) + { + cur = new_node; + cur_order = local_order+1; + } + + // fill out the new node + new_node->child_context = 0; + new_node->escapes = 0; + new_node->next = 0; + push(new_node,temp); + new_node->total = 0; + + + + if (temp != root) + { + temp = temp->parent_context; + --local_order; + continue; + } + + t = 2056; + c = 8; + + // since this is the root we are going to the order-(-1) context + // so we can just take care of that here. + target = coder.get_target(alphabet_size); + new_node->parent_context = root; + coder.decode(target,target+1); + symbol = target; + + if (cur == 0) + { + cur = root; + cur_order = 0; + } + break; + } + else + { + // there isn't enough space so we should rebuild the tree + clear(); + temp = cur; + local_order = cur_order; + cur = 0; + new_node = 0; + } + } // while (true) + + // initialize the counts and symbol for any new nodes we have added + // to the tree. + node* n, *nc; + while (stack_size > 0) + { + pop(n,nc); + + n->symbol = static_cast(symbol); + + // if nc is not a determnistic context + if (nc->total) + { + unsigned long temp2 = t-c+nc->total - nc->escapes - nc->escapes; + unsigned long temp = nc->total; + temp *= c; + temp /= (temp2|1); // this oring by 1 is just to make sure that temp2 is never zero + temp += 2; + if (temp > 50000) temp = 50000; + n->count = static_cast(temp); + + + nc->escapes += 4; + nc->total += static_cast(temp) + 4; + } + else + { + n->count = 3 + 5*(c)/(t-c); + + nc->escapes = 4; + nc->total = n->count + 4; + } + + while (nc->total > 10000) + { + scale_counts(nc); + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + edmk5::node* entropy_decoder_model_kernel_5:: + allocate_node ( + ) + { + node* temp; + temp = root + next_node; + ++next_node; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_decoder_model_kernel_5:: + space_left ( + ) const + { + return (next_node < total_nodes); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + exclude ( + unsigned short symbol + ) + { + exc_used = true; + unsigned long temp = 1; + temp <<= symbol&0x1F; + exc[symbol>>5] |= temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_decoder_model_kernel_5:: + is_excluded ( + unsigned short symbol + ) + { + unsigned long temp = 1; + temp <<= symbol&0x1F; + return ((exc[symbol>>5]&temp) != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + clear_exclusions ( + ) + { + exc_used = false; + for (unsigned long i = 0; i < alphabet_size/32+1; ++i) + { + exc[i] = 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + push ( + node* n, + node* nc + ) + { + stack[stack_size].n = n; + stack[stack_size].nc = nc; + ++stack_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + pop ( + node*& n, + node*& nc + ) + { + --stack_size; + n = stack[stack_size].n; + nc = stack[stack_size].nc; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_decoder_model_kernel_5:: + something_is_excluded ( + ) + { + return exc_used; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_decoder_model_kernel_5:: + scale_counts ( + node* temp + ) + { + if (temp->escapes > 1) + temp->escapes >>= 1; + temp->total = temp->escapes; + + node* n = temp->child_context; + while (n != 0) + { + if (n->count > 1) + n->count >>= 1; + + temp->total += n->count; + n = n->next; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_ + + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h new file mode 100644 index 0000000000000000000000000000000000000000..5004d72117d7d188f5a712ea59f6198f06554726 --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h @@ -0,0 +1,131 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_ +#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_ + +#include "../algs.h" +#include "entropy_decoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + class entropy_decoder_model_kernel_6 + { + /*! + INITIAL VALUE + This object has no state + + CONVENTION + &get_entropy_decoder() == coder + + This is an order-(-1) model. So it doesn't really do anything. + Every symbol has the same probability. + !*/ + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model_kernel_6 ( + entropy_decoder& coder + ); + + virtual ~entropy_decoder_model_kernel_6 ( + ); + + inline void clear( + ); + + inline void decode ( + unsigned long& symbol + ); + + entropy_decoder& get_entropy_decoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_decoder& coder; + + // restricted functions + entropy_decoder_model_kernel_6(entropy_decoder_model_kernel_6&); // copy constructor + entropy_decoder_model_kernel_6& operator=(entropy_decoder_model_kernel_6&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + entropy_decoder_model_kernel_6:: + entropy_decoder_model_kernel_6 ( + entropy_decoder& coder_ + ) : + coder(coder_) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + entropy_decoder_model_kernel_6:: + ~entropy_decoder_model_kernel_6 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + void entropy_decoder_model_kernel_6:: + clear( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + void entropy_decoder_model_kernel_6:: + decode ( + unsigned long& symbol + ) + { + unsigned long target; + + target = coder.get_target(alphabet_size); + coder.decode(target,target+1); + + symbol = target; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_ + diff --git a/dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..e9c595b3e77486a9adb00b03983e3ddf230aa6a7 --- /dev/null +++ b/dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h @@ -0,0 +1,116 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_ +#ifdef DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_decoder + > + class entropy_decoder_model + { + /*! + REQUIREMENTS ON alphabet_size + 1 < alphabet_size < 65535 + + REQUIREMENTS ON entropy_decoder + is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h + + INITIAL VALUE + Initially this object is at some predefined empty or ground state. + + WHAT THIS OBJECT REPRESENTS + This object represents some kind of statistical model. You + can use it to read symbols from an entropy_decoder and it will calculate + the cumulative counts/probabilities and manage contexts for you. + + Note that all implementations of entropy_encoder_model and + entropy_decoder_model are paired. This means that if you use + entropy_encoder_model_kernel_n to encode something then you must + use the corresponding entropy_decoder_model_kernel_n to decode it. + + Also note that this object does not perform any buffering of symbols. It + reads them from its associated entropy_decoder simply as it needs them. + This makes it safe to use multiple entropy_decoder_model objects with + a single entropy_decoder without them trampling each other. + !*/ + + public: + + typedef entropy_decoder entropy_decoder_type; + + entropy_decoder_model ( + entropy_decoder& coder + ); + /*! + ensures + - #*this is properly initialized + - &#get_entropy_decoder() == &coder + throws + - any exception + !*/ + + virtual ~entropy_decoder_model ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - does not modify get_entropy_decoder() + throws + - any exception + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void decode ( + unsigned long& symbol + ); + /*! + ensures + - decodes the next symbol + - #symbol == the next symbol + - #symbol < alphabet_size + throws + - any exception + If this exception is thrown then #*this is unusable until + clear() is called and succeeds. + !*/ + + entropy_decoder& get_entropy_decoder ( + ); + /*! + ensures + - returns a reference to the entropy_decoder used by *this + !*/ + + static unsigned long get_alphabet_size ( + ); + /*! + ensures + - returns alphabet_size + !*/ + + private: + + // restricted functions + entropy_decoder_model(entropy_decoder_model&); // copy constructor + entropy_decoder_model& operator=(entropy_decoder_model&); // assignment operator + + }; + +} + +#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_ + diff --git a/dlib/entropy_encoder.h b/dlib/entropy_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..df068cd56e169f8307abc11ce04a3d6cdaf54cc0 --- /dev/null +++ b/dlib/entropy_encoder.h @@ -0,0 +1,43 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODEr_ +#define DLIB_ENTROPY_ENCODEr_ + +#include "entropy_encoder/entropy_encoder_kernel_1.h" +#include "entropy_encoder/entropy_encoder_kernel_2.h" +#include "entropy_encoder/entropy_encoder_kernel_c.h" + + + + +namespace dlib +{ + + + class entropy_encoder + { + entropy_encoder() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef entropy_encoder_kernel_1 + kernel_1a; + typedef entropy_encoder_kernel_c + kernel_1a_c; + + + // kernel_2a + typedef entropy_encoder_kernel_2 + kernel_2a; + typedef entropy_encoder_kernel_c + kernel_2a_c; + + }; +} + +#endif // DLIB_ENTROPY_ENCODEr_ + diff --git a/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp b/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92e34252350749b5a9487e9d146607e3a0583e0b --- /dev/null +++ b/dlib/entropy_encoder/entropy_encoder_kernel_1.cpp @@ -0,0 +1,239 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ +#define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ +#include "entropy_encoder_kernel_1.h" +#include +#include + +namespace dlib +{ + + +// ---------------------------------------------------------------------------------------- + + entropy_encoder_kernel_1:: + entropy_encoder_kernel_1( + ) : + initial_low(0x00000001), + initial_high(0xffffffff), + out(0), + low(initial_low), + high(initial_high), + buf(0), + buf_used(0) + { + } + +// ---------------------------------------------------------------------------------------- + + entropy_encoder_kernel_1:: + ~entropy_encoder_kernel_1 ( + ) + { + try { + if (out != 0) + { + flush(); + } + } catch (...) {} + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_1:: + clear( + ) + { + if (out != 0) + { + flush(); + } + out = 0; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_1:: + set_stream ( + std::ostream& out_ + ) + { + if (out != 0) + { + // if a stream is currently set then flush the buffers to it before + // we switch to the new stream + flush(); + } + + out = &out_; + streambuf = out_.rdbuf(); + + // reset the encoder state + buf_used = 0; + buf = 0; + low = initial_low; + high = initial_high; + } + +// ---------------------------------------------------------------------------------------- + + bool entropy_encoder_kernel_1:: + stream_is_set ( + ) const + { + if (out != 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + std::ostream& entropy_encoder_kernel_1:: + get_stream ( + ) const + { + return *out; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_1:: + encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ) + { + // note that we must add one because of the convention that + // high == the real upper range minus 1 + uint32 r = (high-low+1)/total; + + // note that we must subtract 1 to preserve the convention that + // high == the real upper range - 1 + high = low + r*high_count-1; + low = low + r*low_count; + + + while (true) + { + + // if the highest order bit in high and low is the same + if ( low >= 0x80000000 || high < 0x80000000) + { + // if buf is full then write it out + if (buf_used == 8) + { + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + { + throw std::ios_base::failure("error occured in the entropy_encoder object"); + } + buf = 0; + buf_used = 0; + } + + + // write the high order bit from low into buf + buf <<= 1; + ++buf_used; + if (low&0x80000000) + buf |= 0x1; + + // roll off the bit we just wrote to buf + low <<= 1; + high <<= 1; + high |= 1; // note that it is ok to add one to high here because + // of the convention that high == real upper range - 1. + // so that means that if we want to shift the upper range + // left by one then we must shift a one into high also + // since real upper range == high + 0.999999999... + + // make sure low is never zero + if (low == 0) + low = 1; + } + // if the distance between high and low is small and there aren't + // any bits we can roll off then round low up or high down. + else if (high-low < 0x10000) + { + if (high == 0x80000000) + high = 0x7fffffff; + else + low = 0x80000000; + } + else + { + break; + } + } // while (true) + + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_1:: + flush ( + ) + { + // flush the next 4 or 5 bytes that are buffered + // thats whatever is contained in buf and then all of low plus any extra + // bits needed to pad that to be an even 4 or 5 bytes + + + if (buf_used != 8) + { + buf <<= (8-buf_used); + buf |= static_cast(low>>(24+buf_used)); + low <<= (8-buf_used); + } + + if (streambuf->sputn(reinterpret_cast(&buf),1) == 0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + buf = static_cast((low >> 24)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1) == 0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + + buf = static_cast((low >> 16)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + buf = static_cast((low >> 8)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + if (buf_used != 0) + { + buf = static_cast((low)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + } + + + + // make sure the stream buffer flushes to its I/O channel + streambuf->pubsync(); + + + // reset the encoder state + buf_used = 0; + buf = 0; + low = initial_low; + high = initial_high; + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ + diff --git a/dlib/entropy_encoder/entropy_encoder_kernel_1.h b/dlib/entropy_encoder/entropy_encoder_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..fc343d392869f3ce082b65004d46d6f55d8b190f --- /dev/null +++ b/dlib/entropy_encoder/entropy_encoder_kernel_1.h @@ -0,0 +1,119 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_KERNEl_1_ +#define DLIB_ENTROPY_ENCODER_KERNEl_1_ + +#include "../algs.h" +#include "entropy_encoder_kernel_abstract.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + class entropy_encoder_kernel_1 + { + /*! + GENERAL NOTES + this encoder is implemented using arithmetic coding + + INITIAL VALUE + out == 0 + buf_used == 0 + buf == 0 + initial_low == 0x00000001 (slightly more than zero) + initial_high == 0xffffffff (slightly less than one, 0.99999999976717) + low == initial_low + high == initial_high + + CONVENTION + if (out != 0) + *out == get_stream() + true == stream_is_set() + streambuf == out->rdbuf() + else + false == stream_is_set() + + buf == used to accumulate bits before writing them to out. + buf_used == the number of low order bits in buf that are currently + in use + low == the low end of the range used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so it is + always in the range [0,1) + + low is also never allowed to be zero to avoid overflow + in the calculation (high-low+1)/total. + + high == the high end of the range - 1 used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so when we + interpret high as a real number then it is always in the + range [0,1) + + the range for arithmetic encoding is always + [low,high + 0.9999999...) the 0.9999999... is why + high == real upper range - 1 + + !*/ + + public: + + entropy_encoder_kernel_1 ( + ); + + virtual ~entropy_encoder_kernel_1 ( + ); + + void clear( + ); + + void set_stream ( + std::ostream& out + ); + + bool stream_is_set ( + ) const; + + std::ostream& get_stream ( + ) const; + + void encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ); + + private: + + void flush ( + ); + /*! + requires + out != 0 (i.e. there is a stream object to flush the data to + !*/ + + // restricted functions + entropy_encoder_kernel_1(entropy_encoder_kernel_1&); // copy constructor + entropy_encoder_kernel_1& operator=(entropy_encoder_kernel_1&); // assignment operator + + // data members + const uint32 initial_low; + const uint32 initial_high; + std::ostream* out; + uint32 low; + uint32 high; + unsigned char buf; + uint32 buf_used; + std::streambuf* streambuf; + + }; + +} + +#ifdef NO_MAKEFILE +#include "entropy_encoder_kernel_1.cpp" +#endif + +#endif // DLIB_ENTROPY_ENCODER_KERNEl_1_ + diff --git a/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp b/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5009c263248dd98b0b0745a44b508c48c2020018 --- /dev/null +++ b/dlib/entropy_encoder/entropy_encoder_kernel_2.cpp @@ -0,0 +1,233 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ +#define DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ +#include "entropy_encoder_kernel_2.h" +#include +#include + +namespace dlib +{ + + +// ---------------------------------------------------------------------------------------- + + entropy_encoder_kernel_2:: + entropy_encoder_kernel_2( + ) : + initial_low(0x00000001), + initial_high(0xffffffff), + out(0), + low(initial_low), + high(initial_high) + { + } + +// ---------------------------------------------------------------------------------------- + + entropy_encoder_kernel_2:: + ~entropy_encoder_kernel_2 ( + ) + { + try { + if (out != 0) + { + flush(); + } + } catch (...) {} + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_2:: + clear( + ) + { + if (out != 0) + { + flush(); + } + out = 0; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_2:: + set_stream ( + std::ostream& out_ + ) + { + if (out != 0) + { + // if a stream is currently set then flush the buffers to it before + // we switch to the new stream + flush(); + } + + out = &out_; + streambuf = out_.rdbuf(); + + // reset the encoder state + low = initial_low; + high = initial_high; + } + +// ---------------------------------------------------------------------------------------- + + bool entropy_encoder_kernel_2:: + stream_is_set ( + ) const + { + if (out != 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + std::ostream& entropy_encoder_kernel_2:: + get_stream ( + ) const + { + return *out; + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_2:: + encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ) + { + // note that we must add one because of the convention that + // high == the real upper range minus 1 + uint32 r = (high-low+1)/total; + + // note that we must subtract 1 to preserve the convention that + // high == the real upper range - 1 + high = low + r*high_count-1; + low = low + r*low_count; + + + + while (true ) + { + + // if high and low don't have the same 8 high order bits + if ((high&0xFF000000) != (low&0xFF000000)) + { + // if the distance between high and low is small and there aren't + // any bits we can roll off then force high and low to have common high + // order bits. + if ((high-low < 0x10000)) + { + if (high-low > 0x1000) + { + high>>=1; + low>>=1; + high = low = high+low; + high += 0xFF; + low -= 0xFF; + } + else /**/ + { + high>>=1; + low>>=1; + high = low = high+low; + } + } + else + { + // there are no bits to roll off and high and low are not + // too close so just quit the loop + break; + } + + } + // else if there are 8 bits we can roll off + else + { + // write the 8 high order bits from low into buf + unsigned char buf = static_cast(low>>24); + + + // roll off the bits we just wrote to buf + high <<= 8; + low <<= 8; + high |= 0xFF; // note that it is ok to add 0xFF to high here because + // of the convention that high == real upper range - 1. + // so that means that if we want to shift the upper range + // left by one then we must shift a one into high also + // since real upper range == high + 0.999999999... + + // make sure low is never zero + if (low == 0) + low = 1; + + // write buf to the output stream + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + { + throw std::ios_base::failure("error occured in the entropy_encoder object"); + } + + } + + } // while (true) + + } + +// ---------------------------------------------------------------------------------------- + + void entropy_encoder_kernel_2:: + flush ( + ) + { + + // flush low to the output stream + + + unsigned char buf; + + + buf = static_cast((low >> 24)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1) == 0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + + buf = static_cast((low >> 16)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + buf = static_cast((low >> 8)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + buf = static_cast((low)&0xFF); + if (streambuf->sputn(reinterpret_cast(&buf),1)==0) + throw std::ios_base::failure("error occured in the entropy_encoder object"); + + + + + // make sure the stream buffer flushes to its I/O channel + streambuf->pubsync(); + + + // reset the encoder state + low = initial_low; + high = initial_high; + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ + diff --git a/dlib/entropy_encoder/entropy_encoder_kernel_2.h b/dlib/entropy_encoder/entropy_encoder_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..16505b67022e42ad32caaef75bab84a0cb873f0c --- /dev/null +++ b/dlib/entropy_encoder/entropy_encoder_kernel_2.h @@ -0,0 +1,112 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_KERNEl_2_ +#define DLIB_ENTROPY_ENCODER_KERNEl_2_ + +#include "../algs.h" +#include "entropy_encoder_kernel_abstract.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + class entropy_encoder_kernel_2 + { + /*! + GENERAL NOTES + this encoder is implemented using "range" coding + + INITIAL VALUE + out == 0 + initial_low == 0x00000001 (slightly more than zero) + initial_high == 0xffffffff (slightly less than one, 0.99999999976717) + low == initial_low + high == initial_high + + CONVENTION + if (out != 0) + *out == get_stream() + true == stream_is_set() + streambuf == out->rdbuf() + else + false == stream_is_set() + + + low == the low end of the range used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so it is + always in the range [0,1) + + low is also never allowed to be zero to avoid overflow + in the calculation (high-low+1)/total. + + high == the high end of the range - 1 used for arithmetic encoding. + this number is used as a 32bit fixed point real number. + the point is fixed just before the first bit, so when we + interpret high as a real number then it is always in the + range [0,1) + + the range for arithmetic encoding is always + [low,high + 0.9999999...) the 0.9999999... is why + high == real upper range - 1 + !*/ + + public: + + entropy_encoder_kernel_2 ( + ); + + virtual ~entropy_encoder_kernel_2 ( + ); + + void clear( + ); + + void set_stream ( + std::ostream& out + ); + + bool stream_is_set ( + ) const; + + std::ostream& get_stream ( + ) const; + + void encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ); + + private: + + void flush ( + ); + /*! + requires + out != 0 (i.e. there is a stream object to flush the data to + !*/ + + // restricted functions + entropy_encoder_kernel_2(entropy_encoder_kernel_2&); // copy constructor + entropy_encoder_kernel_2& operator=(entropy_encoder_kernel_2&); // assignment operator + + // data members + const uint32 initial_low; + const uint32 initial_high; + std::ostream* out; + uint32 low; + uint32 high; + std::streambuf* streambuf; + + }; + +} + +#ifdef NO_MAKEFILE +#include "entropy_encoder_kernel_2.cpp" +#endif + +#endif // DLIB_ENTROPY_ENCODER_KERNEl_2_ + diff --git a/dlib/entropy_encoder/entropy_encoder_kernel_abstract.h b/dlib/entropy_encoder/entropy_encoder_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..9037538abe993a0b22554f8aced623ba5a17a737 --- /dev/null +++ b/dlib/entropy_encoder/entropy_encoder_kernel_abstract.h @@ -0,0 +1,161 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_ +#ifdef DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + class entropy_encoder + { + /*! + INITIAL VALUE + stream_is_set() == false + + + WHAT THIS OBJECT REPRESENTS + This object represents an entropy encoder (could be implemented as an + arithmetic encoder for example). + + Note that all implementations of entropy_encoder and entropy_decoder + are paired. This means that if you use entropy_encoder_kernel_n to + encode something then you must use the corresponding + entropy_decoder_kernel_n to decode it. + + NOTATION: + At any moment each symbol has a certain probability of appearing in + the input stream. These probabilities may change as each symbol is + encountered and the probability model is updated accordingly. + + + let P(i) be a function which gives the probability of seeing the ith + symbol of an N symbol alphabet BEFORE the probability model is updated + to account for the current symbol. ( The domain of P(i) is from 0 to N-1. ) + + for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers. + and TOTAL is the same number for all P(i) but COUNT may vary. + + let LOW_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i-1 + (note that LOW_COUNT(0) == 0) + let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i + !*/ + + public: + + entropy_encoder ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~entropy_encoder ( + ); + /*! + ensures + - all memory associated with *this has been released + - if (stream_is_set()) then + - any buffered data in *this will be written to get_stream() + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - if (stream_is_set()) then + - any buffered data in *this will be written to get_stream() + - clears any memory of all previous calls to encode() from #*this + throws + - std::ios_base::failure + if (stream_is_set() && there was a problem writing to get_stream()) + then this exception will be thrown. #*this will be unusable until + clear() is called and succeeds + - any other exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + + void set_stream ( + std::ostream& out + ); + /*! + ensures + - #get_stream() == out + - #stream_is_set() == true + - if (stream_is_set()) then + - any buffered data in *this will be written to get_stream() + - clears any memory of all previous calls to encode() from #*this + throws + - std::ios_base::failure + if (stream_is_set() && there was a problem writing to get_stream()) + then this exception will be thrown. #*this will be unusable until + clear() is called and succeeds + - any other exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + bool stream_is_set ( + ) const; + /*! + ensures + - returns true if a stream has been associated with *this by calling + set_stream() + !*/ + + std::ostream& get_stream ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns a reference to the ostream object that *this writes its + encoded data to + !*/ + + void encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ); + /*! + requires + - 0 < total < 65536 (2^16) + - total == TOTAL + - low_count < high_count <= total + - stream_is_set() == true + ensures + - encodes the symbol S where: + - LOW_COUNT(S) == low_count + - HIGH_COUNT(S) == high_count + throws + - std::ios_base::failure + if (there was a problem writing to get_stream()) then + this exception will be thrown. #*this will be unusable until + clear() is called and succeeds + - any other exception + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + + private: + + // restricted functions + entropy_encoder(entropy_encoder&); // copy constructor + entropy_encoder& operator=(entropy_encoder&); // assignment operator + + }; + +} + +#endif // DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_ + diff --git a/dlib/entropy_encoder/entropy_encoder_kernel_c.h b/dlib/entropy_encoder/entropy_encoder_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..c5687911b0c92b14c3c704c7b313ec6ef29cd99e --- /dev/null +++ b/dlib/entropy_encoder/entropy_encoder_kernel_c.h @@ -0,0 +1,112 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_KERNEl_C_ +#define DLIB_ENTROPY_ENCODER_KERNEl_C_ + +#include "entropy_encoder_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename encoder + > + class entropy_encoder_kernel_c : public encoder + { + + public: + std::ostream& get_stream ( + ) const; + + void encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ); + + void flush ( + ); + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename encoder + > + std::ostream& entropy_encoder_kernel_c:: + get_stream ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tstd::ostream& entropy_encoder::get_stream()" + << "\n\tyou must set a stream for this object before you can get it" + << "\n\tthis: " << this + ); + + // call the real function + return encoder::get_stream(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename encoder + > + void entropy_encoder_kernel_c:: + encode ( + uint32 low_count, + uint32 high_count, + uint32 total + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (0 < total) && (total < 65536) && (low_count < high_count) && (high_count <= total) && + (this->stream_is_set() == true), + "\tvoid entropy_encoder::encode()" + << "\n\trefer to the ensures clause for this function for further information" + << "\n\tthis: " << this + << "\n\ttotal: " << total + << "\n\tlow_count: " << low_count + << "\n\thigh_count: " << high_count + << "\n\tis_stream_set(): " << (this->stream_is_set() ? "true" : "false" ) + ); + + // call the real function + encoder::encode(low_count,high_count,total); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename encoder + > + void entropy_encoder_kernel_c:: + flush ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tvoid entropy_encoder::flush()" + << "\n\tyou must set a stream for this object before you can flush to it" + << "\n\tthis: " << this + ); + + // call the real function + encoder::flush(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_KERNEl_C_ + diff --git a/dlib/entropy_encoder_model.h b/dlib/entropy_encoder_model.h new file mode 100644 index 0000000000000000000000000000000000000000..7fe4dd5debbb3fb726efc4c8321d7288f41b1983 --- /dev/null +++ b/dlib/entropy_encoder_model.h @@ -0,0 +1,146 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEl_ +#define DLIB_ENTROPY_ENCODER_MODEl_ + +#include "entropy_encoder_model/entropy_encoder_model_kernel_1.h" +#include "entropy_encoder_model/entropy_encoder_model_kernel_2.h" +#include "entropy_encoder_model/entropy_encoder_model_kernel_3.h" +#include "entropy_encoder_model/entropy_encoder_model_kernel_4.h" +#include "entropy_encoder_model/entropy_encoder_model_kernel_5.h" +#include "entropy_encoder_model/entropy_encoder_model_kernel_6.h" +#include "entropy_encoder_model/entropy_encoder_model_kernel_c.h" + +#include "conditioning_class.h" +#include "memory_manager.h" +#include "sliding_buffer.h" + + +namespace dlib +{ + + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + class entropy_encoder_model + { + entropy_encoder_model() {} + + typedef typename conditioning_class::kernel_1a cc1; + typedef typename conditioning_class::kernel_2a cc2; + typedef typename conditioning_class::kernel_3a cc3; + typedef typename conditioning_class::kernel_4a cc4a; + typedef typename conditioning_class::kernel_4b cc4b; + typedef typename conditioning_class::kernel_4c cc4c; + typedef typename conditioning_class::kernel_4d cc4d; + + + public: + + //----------- kernels --------------- + + // kernel_1 + typedef entropy_encoder_model_kernel_1 + kernel_1a; + typedef entropy_encoder_model_kernel_c + kernel_1a_c; + + typedef entropy_encoder_model_kernel_1 + kernel_1b; + typedef entropy_encoder_model_kernel_c + kernel_1b_c; + + typedef entropy_encoder_model_kernel_1 + kernel_1c; + typedef entropy_encoder_model_kernel_c + kernel_1c_c; + + // -------------------- + + // kernel_2 + typedef entropy_encoder_model_kernel_2 + kernel_2a; + typedef entropy_encoder_model_kernel_c + kernel_2a_c; + + typedef entropy_encoder_model_kernel_2 + kernel_2b; + typedef entropy_encoder_model_kernel_c + kernel_2b_c; + + typedef entropy_encoder_model_kernel_2 + kernel_2c; + typedef entropy_encoder_model_kernel_c + kernel_2c_c; + + typedef entropy_encoder_model_kernel_2 + kernel_2d; + typedef entropy_encoder_model_kernel_c + kernel_2d_c; + + // -------------------- + + // kernel_3 + typedef entropy_encoder_model_kernel_3 + kernel_3a; + typedef entropy_encoder_model_kernel_c + kernel_3a_c; + + typedef entropy_encoder_model_kernel_3 + kernel_3b; + typedef entropy_encoder_model_kernel_c + kernel_3b_c; + + typedef entropy_encoder_model_kernel_3 + kernel_3c; + typedef entropy_encoder_model_kernel_c + kernel_3c_c; + + // -------------------- + + // kernel_4 + typedef entropy_encoder_model_kernel_4 + kernel_4a; + typedef entropy_encoder_model_kernel_c + kernel_4a_c; + + typedef entropy_encoder_model_kernel_4 + kernel_4b; + typedef entropy_encoder_model_kernel_c + kernel_4b_c; + + // -------------------- + + // kernel_5 + typedef entropy_encoder_model_kernel_5 + kernel_5a; + typedef entropy_encoder_model_kernel_c + kernel_5a_c; + + typedef entropy_encoder_model_kernel_5 + kernel_5b; + typedef entropy_encoder_model_kernel_c + kernel_5b_c; + + typedef entropy_encoder_model_kernel_5 + kernel_5c; + typedef entropy_encoder_model_kernel_c + kernel_5c_c; + + // -------------------- + + // kernel_6 + typedef entropy_encoder_model_kernel_6 + kernel_6a; + typedef entropy_encoder_model_kernel_c + kernel_6a_c; + + + + }; +} + +#endif // DLIB_ENTROPY_ENCODER_MODEl_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..d4404e4e47ee4f123b1ccc8ca370700327ea808f --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h @@ -0,0 +1,167 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_ + +#include "../algs.h" +#include "entropy_encoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc + > + class entropy_encoder_model_kernel_1 + { + /*! + REQUIREMENTS ON cc + cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc::get_alphabet_size() == alphabet_size+1 + + INITIAL VALUE + Initially this object's finite context model is empty + + CONVENTION + &get_entropy_encoder() == coder + &order_0.get_global_state() == &gs + + This is an order-0 model. The last symbol in the order-0 context is + an escape into the order minus 1 context. + !*/ + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model_kernel_1 ( + entropy_encoder& coder + ); + + virtual ~entropy_encoder_model_kernel_1 ( + ); + + inline void clear( + ); + + inline void encode ( + unsigned long symbol + ); + + entropy_encoder& get_entropy_encoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_encoder& coder; + typename cc::global_state_type gs; + cc order_0; + + // restricted functions + entropy_encoder_model_kernel_1(entropy_encoder_model_kernel_1&); // copy constructor + entropy_encoder_model_kernel_1& operator=(entropy_encoder_model_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc + > + entropy_encoder_model_kernel_1:: + entropy_encoder_model_kernel_1 ( + entropy_encoder& coder_ + ) : + coder(coder_), + order_0(gs) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc + > + entropy_encoder_model_kernel_1:: + ~entropy_encoder_model_kernel_1 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc + > + void entropy_encoder_model_kernel_1:: + clear( + ) + { + order_0.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc + > + void entropy_encoder_model_kernel_1:: + encode ( + unsigned long symbol + ) + { + unsigned long low_count = 0, high_count = 0, total_count = 0; + + // if we have seen this symbol in the order-0 context + if (order_0.get_range(symbol,low_count,high_count,total_count)) + { + // update the count for this symbol + order_0.increment_count(symbol,2); + // encode this symbol + coder.encode(low_count,high_count,total_count); + return; + } + + // if we are here then the symbol does not appear in the order-0 context + + + // since we have never seen the current symbol in this context + // escape from order-0 context + order_0.get_range(alphabet_size,low_count,high_count,total_count); + coder.encode(low_count,high_count,total_count); + // increment the count for the escape symbol + order_0.increment_count(alphabet_size); + + // update the count for this symbol + order_0.increment_count(symbol,2); + + // use order minus one context + coder.encode(symbol,symbol+1,alphabet_size); + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..c72736ba6404be6ed7c7dcf13be9c4d0389cd8b7 --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h @@ -0,0 +1,246 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_ + +#include "../algs.h" +#include "entropy_encoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename ccbig + > + class entropy_encoder_model_kernel_2 + { + /*! + REQUIREMENTS ON cc + cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc::get_alphabet_size() == alphabet_size+1 + this will be used for the order-0 context + + REQUIREMENTS ON ccbig + ccbig is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + ccbig::get_alphabet_size() == alphabet_size+1 + this will be used for the order-1 context + + INITIAL VALUE + Initially this object's finite context model is empty + previous_symbol == 0 + + CONVENTION + &get_entropy_encoder() == coder + &order_0.get_global_state() == &gs + &order_1[i]->get_global_state() == &gsbig + + + This is an order-1-0 model. The last symbol in the order-0 and order-1 + context is an escape into the lower context. + + previous_symbol == the last symbol seen + !*/ + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model_kernel_2 ( + entropy_encoder& coder + ); + + virtual ~entropy_encoder_model_kernel_2 ( + ); + + inline void clear( + ); + + inline void encode ( + unsigned long symbol + ); + + entropy_encoder& get_entropy_encoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_encoder& coder; + typename cc::global_state_type gs; + typename ccbig::global_state_type gsbig; + cc order_0; + ccbig* order_1[alphabet_size]; + unsigned long previous_symbol; + + + // restricted functions + entropy_encoder_model_kernel_2(entropy_encoder_model_kernel_2&); // copy constructor + entropy_encoder_model_kernel_2& operator=(entropy_encoder_model_kernel_2&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename ccbig + > + entropy_encoder_model_kernel_2:: + entropy_encoder_model_kernel_2 ( + entropy_encoder& coder_ + ) : + coder(coder_), + order_0(gs), + previous_symbol(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + + unsigned long i; + try + { + for (i = 0; i < alphabet_size; ++i) + { + order_1[i] = new ccbig(gsbig); + } + } + catch (...) + { + for (unsigned long j = 0; j < i; ++j) + { + delete order_1[j]; + } + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename ccbig + > + entropy_encoder_model_kernel_2:: + ~entropy_encoder_model_kernel_2 ( + ) + { + for (unsigned long i = 0; i < alphabet_size; ++i) + { + delete order_1[i]; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename ccbig + > + void entropy_encoder_model_kernel_2:: + clear( + ) + { + previous_symbol = 0; + order_0.clear(); + for (unsigned long i = 0; i < alphabet_size; ++i) + { + order_1[i]->clear(); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename ccbig + > + void entropy_encoder_model_kernel_2:: + encode ( + unsigned long symbol + ) + { + unsigned long low_count = 0, high_count = 0, total_count = 0; + + + ccbig& context = *order_1[previous_symbol]; + + // if we have seen this symbol in the order-1 context + if (context.get_range(symbol,low_count,high_count,total_count)) + { + // update the count for this symbol + context.increment_count(symbol,2); + // encode this symbol + coder.encode(low_count,high_count,total_count); + previous_symbol = symbol; + return; + } + + // we didn't find the symbol in the order-1 context so we must escape to a + // lower context. + + // escape to the order-0 context + context.get_range(alphabet_size,low_count,high_count,total_count); + coder.encode(low_count,high_count,total_count); + + + // increment counts for the escape symbol and the current symbol + context.increment_count(alphabet_size); + context.increment_count(symbol,2); + + previous_symbol = symbol; + + + + + + // if we have seen this symbol in the order-0 context + if (order_0.get_range(symbol,low_count,high_count,total_count)) + { + // update the count for this symbol + order_0.increment_count(symbol,2); + // encode this symbol + coder.encode(low_count,high_count,total_count); + return; + } + + // if we are here then the symbol does not appear in the order-0 context + + + // since we have never seen the current symbol in this context + // escape from order-0 context + order_0.get_range(alphabet_size,low_count,high_count,total_count); + coder.encode(low_count,high_count,total_count); + // increment the count for the escape symbol + order_0.increment_count(alphabet_size); + + // update the count for this symbol + order_0.increment_count(symbol,2); + + // use order minus one context + coder.encode(symbol,symbol+1,alphabet_size); + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h new file mode 100644 index 0000000000000000000000000000000000000000..05d0fcc5a1e7c32c56489ca94d250fb75683d45b --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h @@ -0,0 +1,341 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_ + +#include "../algs.h" +#include "entropy_encoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename cc_high + > + class entropy_encoder_model_kernel_3 + { + /*! + REQUIREMENTS ON cc + cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc::get_alphabet_size() == alphabet_size+1 + + REQUIREMENTS ON cc_high + cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + cc_high::get_alphabet_size() == alphabet_size+1 + + INITIAL VALUE + - Initially this object's finite context model is empty + - previous_symbol == 0 + - previous_symbol2 == 0 + - order_1 == pointer to an array of alphabet_size elements + - order_2 == pointer to an array of alphabet_size*alphabet_size elements + - order_2[i] == 0 + + CONVENTION + &get_entropy_encoder() == coder + &order_0.get_global_state() == &gs + &order_1[i]->get_global_state() == &gs + + if (order_2[i] != 0) then + &order_2[i]->get_global_state() == &gs_high + + This is an order-2-1-0 model. The last symbol in the order-2, order-1 and + order-0 contexts is an escape into the lower context. + + previous_symbol == the last symbol seen + previous_symbol2 == the symbol we saw before previous_symbol + !*/ + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model_kernel_3 ( + entropy_encoder& coder + ); + + virtual ~entropy_encoder_model_kernel_3 ( + ); + + inline void clear( + ); + + inline void encode ( + unsigned long symbol + ); + + entropy_encoder& get_entropy_encoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_encoder& coder; + typename cc::global_state_type gs; + typename cc_high::global_state_type gs_high; + cc order_0; + cc** order_1; + unsigned long previous_symbol; + cc_high** order_2; + unsigned long previous_symbol2; + + + // restricted functions + entropy_encoder_model_kernel_3(entropy_encoder_model_kernel_3&); // copy constructor + entropy_encoder_model_kernel_3& operator=(entropy_encoder_model_kernel_3&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename cc_high + > + entropy_encoder_model_kernel_3:: + entropy_encoder_model_kernel_3 ( + entropy_encoder& coder_ + ) : + coder(coder_), + order_0(gs), + order_1(0), + previous_symbol(0), + order_2(0), + previous_symbol2(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + + try + { + order_1 = new cc*[alphabet_size]; + order_2 = new cc_high*[alphabet_size*alphabet_size]; + } + catch (...) + { + if (order_1) delete [] order_1; + if (order_2) delete [] order_2; + throw; + } + + unsigned long i; + + for (i = 0; i < (alphabet_size*alphabet_size); ++i) + { + order_2[i] = 0; + } + + try + { + for (i = 0; i < alphabet_size; ++i) + { + order_1[i] = new cc(gs); + } + } + catch (...) + { + for (unsigned long j = 0; j < i; ++j) + { + delete order_1[j]; + } + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename cc_high + > + entropy_encoder_model_kernel_3:: + ~entropy_encoder_model_kernel_3 ( + ) + { + for (unsigned long i = 0; i < alphabet_size; ++i) + { + delete order_1[i]; + } + + for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i) + { + if (order_2[i] != 0) + delete order_2[i]; + } + delete [] order_1; + delete [] order_2; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename cc_high + > + void entropy_encoder_model_kernel_3:: + clear( + ) + { + previous_symbol = 0; + previous_symbol2 = 0; + order_0.clear(); + for (unsigned long i = 0; i < alphabet_size; ++i) + { + order_1[i]->clear(); + } + + for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i) + { + if (order_2[i] != 0) + { + delete order_2[i]; + order_2[i] = 0; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + typename cc, + typename cc_high + > + void entropy_encoder_model_kernel_3:: + encode ( + unsigned long symbol + ) + { + unsigned long low_count = 0, high_count = 0, total_count = 0; + + + // order-2 context stuff + { + unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size); + previous_symbol2 = previous_symbol; + + if (order_2[temp] != 0) + { + if (order_2[temp]->get_range(symbol,low_count,high_count,total_count)) + { + // there was an entry for this symbol in this context + + // update the count for this symbol + order_2[temp]->increment_count(symbol,2); + // encode this symbol + coder.encode(low_count,high_count,total_count); + previous_symbol = symbol; + return; + } + + // there was no entry for this symbol in this context so we must + // escape to order-1 + + // escape to the order-1 context + order_2[temp]->get_range(alphabet_size,low_count,high_count,total_count); + coder.encode(low_count,high_count,total_count); + + // increment the count for the escape symbol + order_2[temp]->increment_count(alphabet_size); + + } + else + { + order_2[temp] = new cc_high(gs_high); + + // in this case the decoder knows to escape to order-1 because + // there was no conditioning_class object in this context yet. + // so we don't need to actually write the escape symbol + } + + // update the count for this symbol in this context + order_2[temp]->increment_count(symbol,2); + } + + + + + // order-1 context stuff + { + cc& context = *order_1[previous_symbol]; + + // if we have seen this symbol in the order-1 context + if (context.get_range(symbol,low_count,high_count,total_count)) + { + // update the count for this symbol + context.increment_count(symbol,2); + // encode this symbol + coder.encode(low_count,high_count,total_count); + previous_symbol = symbol; + return; + } + + // we didn't find the symbol in the order-1 context so we must escape to a + // lower context. + + // escape to the order-0 context + context.get_range(alphabet_size,low_count,high_count,total_count); + coder.encode(low_count,high_count,total_count); + + + // increment counts for the escape symbol and the current symbol + context.increment_count(alphabet_size); + context.increment_count(symbol,2); + } + + previous_symbol = symbol; + + + + + + // if we have seen this symbol in the order-0 context + if (order_0.get_range(symbol,low_count,high_count,total_count)) + { + // update the count for this symbol + order_0.increment_count(symbol,2); + // encode this symbol + coder.encode(low_count,high_count,total_count); + return; + } + + // if we are here then the symbol does not appear in the order-0 context + + + // since we have never seen the current symbol in this context + // escape from order-0 context + order_0.get_range(alphabet_size,low_count,high_count,total_count); + coder.encode(low_count,high_count,total_count); + // increment the count for the escape symbol + order_0.increment_count(alphabet_size); + + // update the count for this symbol + order_0.increment_count(symbol,2); + + // use order minus one context + coder.encode(symbol,symbol+1,alphabet_size); + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h new file mode 100644 index 0000000000000000000000000000000000000000..3a9fec407d9172374d49ce1b557904273ce1448e --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h @@ -0,0 +1,553 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_ + +#include "../algs.h" +#include "entropy_encoder_model_kernel_abstract.h" +#include "../assert.h" + + + +namespace dlib +{ + + namespace eemk4 + { + struct node + { + node* next; + node* child_context; + node* parent_context; + + unsigned short symbol; + unsigned short count; + unsigned short total; + unsigned short escapes; + }; + } + + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + class entropy_encoder_model_kernel_4 + { + /*! + REQUIREMENTS ON total_nodes + - 4096 < total_nodes + - this is the total number of nodes that we will use in the tree + + REQUIREMENTS ON order + - 0 <= order + - this is the maximum depth-1 the tree will be allowed to go (note + that the root level is depth 0). + + GENERAL NOTES + This implementation follows more or less the implementation + strategy laid out by Alistair Moffat in his paper + Implementing the PPM data compression scheme. Published in IEEE + Transactions on Communications, 38(11):1917-1921, 1990. + + The escape method used will be method D. + + + INITIAL VALUE + - root == pointer to an array of total_nodes nodes + - next_node == 1 + - cur == root + - cur_order = 0 + - root->next == 0 + - root->parent_context == 0 + - root->child_context == 0 + - root->escapes == 0 + - root->total == 0 + + CONVENTION + - &get_entropy_encoder() == coder + - root == pointer to an array of total_nodes nodes. + this is also the root of the tree. + + - if (next_node < total_nodes) then + - next_node == the next node in root that has not yet been allocated + + - root->next == 0 + - root->parent_context == 0 + + + - for every node in the tree: + { + - NOTATION: + - The "context" of a node is the string of symbols seen + when you go from the root of the tree down (down though + child context pointers) to the node, including the symbol at + the node itself. (note that the context of the root node + is "" or the empty string) + - A set of nodes is in the same "context set" if all the node's + contexts are of length n and all the node's contexts share + the same prefix of length n-1. + - The "child context set" of a node is a set of nodes with + contexts that are one symbol longer and prefixed by the node's + context. For example, if a node has a context "abc" then the + nodes for contexts "abca", "abcb", "abcc", etc... are all in + the child context set of the node. + - The "parent context" of a node is the context that is one + symbol shorter than the node's context and includes the + symbol in the node. So the parent context of a node with + context "abcd" would be the context "bcd". + + + - if (next != 0) then + - next == pointer to the next node in the same context set + - if (child_context != 0) then + - child_context == pointer to the first node of the child + context set for this node. + - if (parent_context != 0) then + - parent_context == pointer to the parent context of this node. + - else + - this node is the root node of the tree + + + - if (this is not the root node) then + - symbol == the symbol represented with this node + - count == the number of times this symbol has been seen in its + parent context. + - else + - the root doesn't have a symbol. i.e. the context for the + root node is "" or the empty string. + + - total == The sum of the counts of all the nodes + in the child context set + escapes. + - escapes == the escape count for the context represented + by the node. + } + + + - cur_order < order + - cur_order == the depth of the node cur in the tree. + (note that the root node has depth 0) + - cur == pointer to the node in the tree who's context matches + the most recent symbols we have seen. + + + !*/ + + typedef eemk4::node node; + + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model_kernel_4 ( + entropy_encoder& coder + ); + + virtual ~entropy_encoder_model_kernel_4 ( + ); + + inline void clear( + ); + + inline void encode ( + unsigned long symbol + ); + + entropy_encoder& get_entropy_encoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + inline eemk4::node* allocate_node ( + ); + /*! + requires + - space_left() == true + ensures + - returns a pointer to a new node + !*/ + + inline void destroy_tree ( + ); + /*! + ensures + - deallocates all nodes except the root + - #root->child_context == 0 + - #root->escapes == 0 + - #root->total == 0 + - #cur == root + - #cur_order == 0 + !*/ + + + inline bool space_left ( + ) const; + /*! + ensures + - returns true if there is at least 1 free node left. + - returns false otherwise + !*/ + + + inline void scale_counts ( + node* n + ); + /*! + ensures + - divides all the counts in the child context set of n by 2. + - none of the nodes in the child context set will have a count of 0 + !*/ + + + unsigned long next_node; + entropy_encoder& coder; + node* root; + node* cur; + unsigned long cur_order; + + + // restricted functions + entropy_encoder_model_kernel_4(entropy_encoder_model_kernel_4&); // copy constructor + entropy_encoder_model_kernel_4& operator=(entropy_encoder_model_kernel_4&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + entropy_encoder_model_kernel_4:: + entropy_encoder_model_kernel_4 ( + entropy_encoder& coder_ + ) : + next_node(1), + coder(coder_), + cur_order(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + COMPILE_TIME_ASSERT( 4096 < total_nodes ); + + root = new node[total_nodes]; + cur = root; + + root->child_context = 0; + root->escapes = 0; + root->next = 0; + root->parent_context = 0; + root->total = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + entropy_encoder_model_kernel_4:: + ~entropy_encoder_model_kernel_4 ( + ) + { + delete [] root; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_4:: + clear( + ) + { + destroy_tree(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_4:: + encode ( + unsigned long sym + ) + { + unsigned short symbol = static_cast(sym); + node* temp = cur; + cur = 0; + unsigned short low_count, high_count, total_count; + node* new_node = 0; + + // local_order will track the level of temp in the tree + unsigned long local_order = cur_order; + + while (true) + { + high_count = 0; + if (space_left()) + { + total_count = temp->total; + + if (total_count > 0) + { + // check if we need to scale the counts + if (total_count > 10000) + { + scale_counts(temp); + total_count = temp->total; + } + + // find either the symbol we are looking for or the + // end of the context set + node* n = temp->child_context; + node* last = 0; + while (true) + { + high_count += n->count; + + if (n->symbol == symbol || n->next == 0) + break; + last = n; + n = n->next; + } + + low_count = high_count - n->count; + + // if we found the symbol + if (n->symbol == symbol) + { + if (new_node != 0) + { + new_node->parent_context = n; + } + + coder.encode(low_count,high_count,total_count); + n->count += 8; + temp->total += 8; + + + // move this node to the front + if (last) + { + last->next = n->next; + n->next = temp->child_context; + temp->child_context = n; + } + + + if (cur == 0) + { + if (local_order < order) + { + cur_order = local_order+1; + cur = n; + } + else + { + cur = n->parent_context; + cur_order = local_order; + } + } + + break; + + } + // if we hit the end of the context set without finding the symbol + else + { + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + n->next = new_node; + + // write an escape to a lower context + coder.encode(high_count,total_count,total_count); + } + + } + else // if (total_count == 0) + { + // this means that temp->child_context == 0 so we should make + // a new node here. + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + temp->child_context = new_node; + } + + if (cur == 0 && local_order < order) + { + cur = new_node; + cur_order = local_order+1; + } + + // fill out the new node + new_node->child_context = 0; + new_node->count = 4; + new_node->escapes = 0; + new_node->next = 0; + new_node->symbol = static_cast(symbol); + new_node->total = 0; + temp->escapes += 4; + temp->total += 8; + + + if (temp != root) + { + temp = temp->parent_context; + --local_order; + continue; + } + + // since this is the root we are going to the order-(-1) context + // so we can just take care of that here. + new_node->parent_context = root; + coder.encode(symbol,symbol+1,alphabet_size); + + if (cur == 0) + { + cur = root; + cur_order = 0; + } + break; + } + else + { + // there isn't enough space so we should rebuild the tree + destroy_tree(); + temp = cur; + local_order = cur_order; + cur = 0; + new_node = 0; + } + } // while (true) + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + eemk4::node* entropy_encoder_model_kernel_4:: + allocate_node ( + ) + { + node* temp; + temp = root + next_node; + ++next_node; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_4:: + destroy_tree ( + ) + { + next_node = 1; + root->child_context = 0; + root->escapes = 0; + root->total = 0; + cur = root; + cur_order = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_encoder_model_kernel_4:: + space_left ( + ) const + { + return (next_node < total_nodes); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_4:: + scale_counts ( + node* temp + ) + { + if (temp->escapes > 1) + temp->escapes >>= 1; + temp->total = temp->escapes; + + node* n = temp->child_context; + while (n != 0) + { + if (n->count > 1) + n->count >>= 1; + + temp->total += n->count; + n = n->next; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h new file mode 100644 index 0000000000000000000000000000000000000000..2c0cf70d867a8840406b2fadc6af620dcd122291 --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h @@ -0,0 +1,817 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_ + +#include "../algs.h" +#include "entropy_encoder_model_kernel_abstract.h" +#include "../assert.h" + + + +namespace dlib +{ + + namespace eemk5 + { + struct node + { + node* next; + node* child_context; + node* parent_context; + + unsigned short symbol; + unsigned short count; + unsigned short total; + unsigned short escapes; + }; + } + + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + class entropy_encoder_model_kernel_5 + { + /*! + REQUIREMENTS ON total_nodes + - 4096 < total_nodes + - this is the total number of nodes that we will use in the tree + + REQUIREMENTS ON order + - 0 <= order + - this is the maximum depth-1 the tree will be allowed to go (note + that the root level is depth 0). + + GENERAL NOTES + This implementation follows more or less the implementation + strategy laid out by Alistair Moffat in his paper + Implementing the PPM data compression scheme. Published in IEEE + Transactions on Communications, 38(11):1917-1921, 1990. + + The escape method used will be method D. + + This also uses Dmitry Shkarin's Information Inheritance scheme. + (described in "PPM: one step to practicality" and "Improving the + Efficiency of the PPM Algorithm") + + + INITIAL VALUE + - root == pointer to an array of total_nodes nodes + - next_node == 1 + - cur == root + - cur_order = 0 + - root->next == 0 + - root->parent_context == 0 + - root->child_context == 0 + - root->escapes == 0 + - root->total == 0 + - stack_size == 0 + - exc_used == false + - for all i: exc[i] == 0 + + CONVENTION + - pop() == stack[stack_size-1].n and stack[stack_size-1].nc + - exc_used == something_is_excluded() + - is_excluded(symbol) == bit symbol&0x1F from exc[symbol>>5] + - &get_entropy_encoder() == coder + - root == pointer to an array of total_nodes nodes. + this is also the root of the tree. + - if (next_node < total_nodes) then + - next_node == the next node in root that has not yet been allocated + + - root->next == 0 + - root->parent_context == 0 + + + - for every node in the tree: + { + - NOTATION: + - The "context" of a node is the string of symbols seen + when you go from the root of the tree down (down though + child context pointers) to the node, including the symbol at + the node itself. (note that the context of the root node + is "" or the empty string) + - A set of nodes is in the same "context set" if all the node's + contexts are of length n and all the node's contexts share + the same prefix of length n-1. + - The "child context set" of a node is a set of nodes with + contexts that are one symbol longer and prefixed by the node's + context. For example, if a node has a context "abc" then the + nodes for contexts "abca", "abcb", "abcc", etc... are all in + the child context set of the node. + - The "parent context" of a node is the context that is one + symbol shorter than the node's context and includes the + symbol in the node. So the parent context of a node with + context "abcd" would be the context "bcd". + + + - if (next != 0) then + - next == pointer to the next node in the same context set + - if (child_context != 0) then + - child_context == pointer to the first node of the child + context set for this node. + - escapes > 0 + - if (parent_context != 0) then + - parent_context == pointer to the parent context of this node. + - else + - this node is the root node of the tree + + + - if (this is not the root node) then + - symbol == the symbol represented with this node + - count == the number of times this symbol has been seen in its + parent context. + - else + - the root doesn't have a symbol. i.e. the context for the + root node is "" or the empty string. + + - total == The sum of the counts of all the nodes + in the child context set + escapes. + - escapes == the escape count for the context represented + by the node. + - count > 0 + } + + + - cur_order < order + - cur_order == the depth of the node cur in the tree. + (note that the root node has depth 0) + - cur == pointer to the node in the tree who's context matches + the most recent symbols we have seen. + + + !*/ + + typedef eemk5::node node; + + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model_kernel_5 ( + entropy_encoder& coder + ); + + virtual ~entropy_encoder_model_kernel_5 ( + ); + + inline void clear( + ); + + inline void encode ( + unsigned long symbol + ); + + entropy_encoder& get_entropy_encoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + inline eemk5::node* allocate_node ( + ); + /*! + requires + - space_left() == true + ensures + - returns a pointer to a new node + !*/ + + inline bool space_left ( + ) const; + /*! + ensures + - returns true if there is at least 1 free node left. + - returns false otherwise + !*/ + + inline void exclude ( + unsigned short symbol + ); + /*! + ensures + - #is_excluded(symbol) == true + - #something_is_excluded() == true + !*/ + + inline bool something_is_excluded ( + ); + /*! + ensures + - returns true if some symbol has been excluded. + returns false otherwise + !*/ + + inline bool is_excluded ( + unsigned short symbol + ); + /*! + ensures + - if (symbol has been excluded) then + - returns true + - else + - returns false + !*/ + + inline void clear_exclusions ( + ); + /*! + ensures + - for all symbols #is_excluded(symbol) == false + - #something_is_excluded() == true + !*/ + + inline void scale_counts ( + node* n + ); + /*! + ensures + - divides all the counts in the child context set of n by 2. + - none of the nodes in the child context set will have a count of 0 + !*/ + + inline void push ( + node* n, + node* nc + ); + /*! + requires + - stack_size < order + ensures + - #pop(a,b): a == n && b == nc + !*/ + + inline void pop ( + node*& n, + node*& nc + ); + /*! + requires + - stack_size > 0 + ensures + - returns the two nodes at the top of the stack + !*/ + + struct nodes + { + node* n; + node* nc; + }; + + unsigned long next_node; + entropy_encoder& coder; + node* root; + node* cur; + unsigned long cur_order; + unsigned long exc[alphabet_size/32+1]; + bool exc_used; + nodes stack[order+1]; + unsigned long stack_size; + + // restricted functions + entropy_encoder_model_kernel_5(entropy_encoder_model_kernel_5&); // copy constructor + entropy_encoder_model_kernel_5& operator=(entropy_encoder_model_kernel_5&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + entropy_encoder_model_kernel_5:: + entropy_encoder_model_kernel_5 ( + entropy_encoder& coder_ + ) : + next_node(1), + coder(coder_), + cur_order(0), + stack_size(0) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + COMPILE_TIME_ASSERT( 4096 < total_nodes ); + + root = new node[total_nodes]; + cur = root; + + root->child_context = 0; + root->escapes = 0; + root->next = 0; + root->parent_context = 0; + root->total = 0; + + clear_exclusions(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + entropy_encoder_model_kernel_5:: + ~entropy_encoder_model_kernel_5 ( + ) + { + delete [] root; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + clear( + ) + { + next_node = 1; + root->child_context = 0; + root->escapes = 0; + root->total = 0; + cur = root; + cur_order = 0; + stack_size = 0; + + clear_exclusions(); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + encode ( + unsigned long sym + ) + { + unsigned short symbol = static_cast(sym); + node* temp = cur; + cur = 0; + unsigned short low_count, high_count, total_count; + node* new_node = 0; + + // local_order will track the level of temp in the tree + unsigned long local_order = cur_order; + + + unsigned short c; // c == t(a|sk) + unsigned short t; // t == T(sk) + + + if (something_is_excluded()) + clear_exclusions(); + + while (true) + { + low_count = 0; + high_count = 0; + if (space_left()) + { + total_count = temp->total; + + if (total_count > 0) + { + // check if we need to scale the counts + if (total_count > 10000) + { + scale_counts(temp); + total_count = temp->total; + } + + + // find the symbol we are looking for and put a pointer to it + // into found_symbol. If it isn't found then found_symbol == 0. + // also, low_count and high_count will be correctly set. + node* n = temp->child_context; + node* found_symbol = 0; + node* last = 0; + if (something_is_excluded()) + { + node* templast = 0; + while (true) + { + if (is_excluded(n->symbol) == false) + { + exclude(n->symbol); + if (found_symbol == 0) + { + high_count += n->count; + if (n->symbol == symbol) + { + found_symbol = n; + last = templast; + low_count = high_count - n->count; + } + } + } + else + { + total_count -= n->count; + } + + if (n->next == 0) + break; + templast = n; + n = n->next; + } + } + else + { + while (true) + { + high_count += n->count; + exclude(n->symbol); + + if (n->symbol == symbol) + { + found_symbol = n; + low_count = high_count - n->count; + break; + } + + if (n->next == 0) + break; + last = n; + n = n->next; + } + } + + + + + + // if we found the symbol + if (found_symbol) + { + n = found_symbol; + if (new_node != 0) + { + new_node->parent_context = found_symbol; + } + + + coder.encode(low_count,high_count,total_count); + c = n->count += 8; + t = temp->total += 8; + + // move this node to the front + if (last) + { + last->next = n->next; + n->next = temp->child_context; + temp->child_context = n; + } + + + if (cur == 0) + { + if (local_order >= order) + { + cur = n->parent_context; + cur_order = local_order; + } + else + { + cur_order = local_order+1; + cur = n; + } + } + + break; + + } + // if we hit the end of the context set without finding the symbol + else + { + // finish excluding all the symbols + while (n->next) + { + exclude(n->symbol); + n = n->next; + } + + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + n->next = new_node; + + // write an escape to a lower context + coder.encode(high_count,total_count,total_count); + } + + } + else // if (total_count == 0) + { + // this means that temp->child_context == 0 so we should make + // a new node here. + if (new_node != 0) + { + new_node->parent_context = allocate_node(); + new_node = new_node->parent_context; + } + else + { + new_node = allocate_node(); + } + + temp->child_context = new_node; + } + + if (cur == 0 && local_order < order) + { + cur = new_node; + cur_order = local_order+1; + } + + // fill out the new node + new_node->child_context = 0; + new_node->escapes = 0; + new_node->next = 0; + new_node->total = 0; + push(new_node,temp); + + if (temp != root) + { + temp = temp->parent_context; + --local_order; + continue; + } + + t = 2056; + c = 8; + + // since this is the root we are going to the order-(-1) context + // so we can just take care of that here. + new_node->parent_context = root; + coder.encode(symbol,symbol+1,alphabet_size); + + if (cur == 0) + { + cur = root; + cur_order = 0; + } + break; + } + else + { + // there isn't enough space so we should throw away the tree + clear(); + temp = cur; + local_order = cur_order; + cur = 0; + new_node = 0; + } + } // while (true) + + + // initialize the counts and symbol for any new nodes we have added + // to the tree. + node* n, *nc; + while (stack_size > 0) + { + pop(n,nc); + + n->symbol = static_cast(symbol); + + // if nc is not a determnistic context + if (nc->total) + { + unsigned long temp2 = t-c+nc->total - nc->escapes - nc->escapes; + unsigned long temp = nc->total; + temp *= c; + temp /= (temp2|1); // this oring by 1 is just to make sure that temp2 is never zero + temp += 2; + if (temp > 50000) temp = 50000; + n->count = static_cast(temp); + + + nc->escapes += 4; + nc->total += static_cast(temp) + 4; + } + else + { + n->count = 3 + 5*(c)/(t-c); + + nc->escapes = 4; + nc->total = n->count + 4; + } + + while (nc->total > 10000) + { + scale_counts(nc); + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + eemk5::node* entropy_encoder_model_kernel_5:: + allocate_node ( + ) + { + node* temp; + temp = root + next_node; + ++next_node; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_encoder_model_kernel_5:: + space_left ( + ) const + { + return (next_node < total_nodes); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + exclude ( + unsigned short symbol + ) + { + exc_used = true; + unsigned long temp = 1; + temp <<= symbol&0x1F; + exc[symbol>>5] |= temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_encoder_model_kernel_5:: + is_excluded ( + unsigned short symbol + ) + { + unsigned long temp = 1; + temp <<= symbol&0x1F; + return ((exc[symbol>>5]&temp) != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + clear_exclusions ( + ) + { + exc_used = false; + for (unsigned long i = 0; i < alphabet_size/32+1; ++i) + { + exc[i] = 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + bool entropy_encoder_model_kernel_5:: + something_is_excluded ( + ) + { + return exc_used; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + push ( + node* n, + node* nc + ) + { + stack[stack_size].n = n; + stack[stack_size].nc = nc; + ++stack_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + pop ( + node*& n, + node*& nc + ) + { + --stack_size; + n = stack[stack_size].n; + nc = stack[stack_size].nc; + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder, + unsigned long total_nodes, + unsigned long order + > + void entropy_encoder_model_kernel_5:: + scale_counts ( + node* temp + ) + { + if (temp->escapes > 1) + temp->escapes >>= 1; + temp->total = temp->escapes; + + node* n = temp->child_context; + while (n != 0) + { + if (n->count > 1) + n->count >>= 1; + + temp->total += n->count; + n = n->next; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_ + + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h new file mode 100644 index 0000000000000000000000000000000000000000..f4e9b66f43c9de5fef01402e263cdecb75cf8ec4 --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h @@ -0,0 +1,127 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_ + +#include "../algs.h" +#include "entropy_encoder_model_kernel_abstract.h" +#include "../assert.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + class entropy_encoder_model_kernel_6 + { + /*! + INITIAL VALUE + Initially this object's finite context model is empty + + CONVENTION + &get_entropy_encoder() == coder + + This is an order-(-1) model. So it doesn't really do anything. + Every symbol has the same probability. + !*/ + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model_kernel_6 ( + entropy_encoder& coder + ); + + virtual ~entropy_encoder_model_kernel_6 ( + ); + + inline void clear( + ); + + inline void encode ( + unsigned long symbol + ); + + entropy_encoder& get_entropy_encoder ( + ) { return coder; } + + static unsigned long get_alphabet_size ( + ) { return alphabet_size; } + + private: + + entropy_encoder& coder; + + // restricted functions + entropy_encoder_model_kernel_6(entropy_encoder_model_kernel_6&); // copy constructor + entropy_encoder_model_kernel_6& operator=(entropy_encoder_model_kernel_6&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + entropy_encoder_model_kernel_6:: + entropy_encoder_model_kernel_6 ( + entropy_encoder& coder_ + ) : + coder(coder_) + { + COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 ); + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + entropy_encoder_model_kernel_6:: + ~entropy_encoder_model_kernel_6 ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + void entropy_encoder_model_kernel_6:: + clear( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + void entropy_encoder_model_kernel_6:: + encode ( + unsigned long symbol + ) + { + // use order minus one context + coder.encode(symbol,symbol+1,alphabet_size); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..449d14c03b2c590b96eaaa50ebc74bec87118772 --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h @@ -0,0 +1,118 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_ +#ifdef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + template < + unsigned long alphabet_size, + typename entropy_encoder + > + class entropy_encoder_model + { + /*! + REQUIREMENTS ON alphabet_size + 1 < alphabet_size < 65535 + + REQUIREMENTS ON entropy_encoder + is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h + + INITIAL VALUE + Initially this object is at some predefined empty or ground state. + + WHAT THIS OBJECT REPRESENTS + This object represents some kind of statistical model. You + can use it to write symbols to an entropy_encoder and it will calculate + the cumulative counts/probabilities and manage contexts for you. + + Note that all implementations of entropy_encoder_model and + entropy_decoder_model are paired. This means that if you use + entropy_encoder_model_kernel_n to encode something then you must + use the corresponding entropy_decoder_model_kernel_n to decode it. + + Also note that this object does not perform any buffering of symbols. It + writes them to its associated entropy_encoder immediately. + This makes it safe to use multiple entropy_encoder_model objects with + a single entropy_encoder without them trampling each other. + !*/ + + public: + + typedef entropy_encoder entropy_encoder_type; + + entropy_encoder_model ( + entropy_encoder& coder + ); + /*! + ensures + - #*this is properly initialized + - &#get_entropy_encoder() == &coder + throws + - any exception + !*/ + + virtual ~entropy_encoder_model ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - does not modify get_entropy_encoder() + throws + - any exception + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void encode ( + unsigned long symbol + ); + /*! + requires + - symbol < alphabet_size + ensures + - encodes and writes the symbol to get_entropy_encoder(). + This also means that there is no internal buffering. symbol is + written immediately to the entropy_encoder. + throws + - any exception + If this exception is thrown then #*this is unusable until + clear() is called and succeeds. + !*/ + + entropy_encoder& get_entropy_encoder ( + ); + /*! + ensures + - returns a reference to the entropy_encoder used by *this + !*/ + + static unsigned long get_alphabet_size ( + ); + /*! + ensures + - returns alphabet_size + !*/ + + private: + + // restricted functions + entropy_encoder_model(entropy_encoder_model&); // copy constructor + entropy_encoder_model& operator=(entropy_encoder_model&); // assignment operator + + }; + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_ + diff --git a/dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..6165f4151aae1dbe730bd33c6ec28bdd49899812 --- /dev/null +++ b/dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h @@ -0,0 +1,65 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_ +#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_ + +#include "entropy_encoder_model_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename eem_base + > + class entropy_encoder_model_kernel_c : public eem_base + { + const unsigned long alphabet_size; + typedef typename eem_base::entropy_encoder_type entropy_encoder; + + public: + + entropy_encoder_model_kernel_c ( + entropy_encoder& coder + ) : eem_base(coder), alphabet_size(eem_base::get_alphabet_size()) {} + + void encode ( + unsigned long symbol + ); + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename eem_base + > + void entropy_encoder_model_kernel_c:: + encode ( + unsigned long symbol + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(symbol < alphabet_size, + "\tvoid entropy_encoder_model::encode()" + << "\n\tthe symbol must be in the range 0 to alphabet_size-1" + << "\n\talphabet_size: " << alphabet_size + << "\n\tsymbol: " << symbol + << "\n\tthis: " << this + ); + + // call the real function + eem_base::encode(symbol); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_ + diff --git a/dlib/error.h b/dlib/error.h new file mode 100644 index 0000000000000000000000000000000000000000..8def61a77edac021ce4fadf64469eda31ee9ed23 --- /dev/null +++ b/dlib/error.h @@ -0,0 +1,355 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ERROr_ +#define DLIB_ERROr_ + +#include +#include // for std::bad_alloc + +// ------------------------------- +// ------ exception classes ------ +// ------------------------------- + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + enum error_type + { + EOTHER, + EPORT_IN_USE, + ETIMEOUT, + ECONNECTION, + ELISTENER, + ERESOLVE, + EMONITOR, + ECREATE_THREAD, + ECREATE_MUTEX, + ECREATE_SIGNALER, + EUNSPECIFIED, + EGENERAL_TYPE1, + EGENERAL_TYPE2, + EGENERAL_TYPE3, + EINVALID_OPTION, + ETOO_FEW_ARGS, + ETOO_MANY_ARGS, + ESOCKET, + ETHREAD, + EGUI, + EFATAL, + EBROKEN_ASSERT, + EIMAGE_LOAD, + EDIR_CREATE, + EINCOMPATIBLE_OPTIONS, + EMISSING_REQUIRED_OPTION, + EINVALID_OPTION_ARG, + EMULTIPLE_OCCURANCES, + ECONFIG_READER, + EIMAGE_SAVE, + ECAST_TO_STRING, + ESTRING_CAST, + EUTF8_TO_UTF32 + }; + +// ---------------------------------------------------------------------------------------- + + // the base exception class + class error : public std::exception + { + /*! + WHAT THIS OBJECT REPRESENTS + This is the base exception class for the dlib library. i.e. all + exceptions in this library inherit from this class. + !*/ + + public: + error( + error_type t, + const std::string& a + ): info(a), type(t) {} + /*! + ensures + - #type == t + - #info == a + !*/ + + error( + error_type t + ): type(t) {} + /*! + ensures + - #type == t + - #info == "" + !*/ + + error( + const std::string& a + ): info(a), type(EUNSPECIFIED) {} + /*! + ensures + - #type == EUNSPECIFIED + - #info == a + !*/ + + error( + ): type(EUNSPECIFIED) {} + /*! + ensures + - #type == EUNSPECIFIED + - #info == "" + !*/ + + virtual ~error( + ) throw() {} + /*! + ensures + - does nothing + !*/ + + const char* what( + ) const throw() + /*! + ensures + - if (info.size() != 0) then + - returns info.c_str() + - else + - returns type_to_string(type) + !*/ + { + if (info.size() > 0) + return info.c_str(); + else + return type_to_string(); + } + + const char* type_to_string ( + ) const throw() + /*! + ensures + - returns a string that names the contents of the type member. + !*/ + { + if (type == EOTHER) return "EOTHER"; + else if ( type == EPORT_IN_USE) return "EPORT_IN_USE"; + else if ( type == ETIMEOUT) return "ETIMEOUT"; + else if ( type == ECONNECTION) return "ECONNECTION"; + else if ( type == ELISTENER) return "ELISTENER"; + else if ( type == ERESOLVE) return "ERESOLVE"; + else if ( type == EMONITOR) return "EMONITOR"; + else if ( type == ECREATE_THREAD) return "ECREATE_THREAD"; + else if ( type == ECREATE_MUTEX) return "ECREATE_MUTEX"; + else if ( type == ECREATE_SIGNALER) return "ECREATE_SIGNALER"; + else if ( type == EUNSPECIFIED) return "EUNSPECIFIED"; + else if ( type == EGENERAL_TYPE1) return "EGENERAL_TYPE1"; + else if ( type == EGENERAL_TYPE2) return "EGENERAL_TYPE2"; + else if ( type == EGENERAL_TYPE3) return "EGENERAL_TYPE3"; + else if ( type == EINVALID_OPTION) return "EINVALID_OPTION"; + else if ( type == ETOO_FEW_ARGS) return "ETOO_FEW_ARGS"; + else if ( type == ETOO_MANY_ARGS) return "ETOO_MANY_ARGS"; + else if ( type == ESOCKET) return "ESOCKET"; + else if ( type == ETHREAD) return "ETHREAD"; + else if ( type == EGUI) return "EGUI"; + else if ( type == EFATAL) return "EFATAL"; + else if ( type == EBROKEN_ASSERT) return "EBROKEN_ASSERT"; + else if ( type == EIMAGE_LOAD) return "EIMAGE_LOAD"; + else if ( type == EDIR_CREATE) return "EDIR_CREATE"; + else if ( type == EINCOMPATIBLE_OPTIONS) return "EINCOMPATIBLE_OPTIONS"; + else if ( type == EMISSING_REQUIRED_OPTION) return "EMISSING_REQUIRED_OPTION"; + else if ( type == EINVALID_OPTION_ARG) return "EINVALID_OPTION_ARG"; + else if ( type == EMULTIPLE_OCCURANCES) return "EMULTIPLE_OCCURANCES"; + else if ( type == ECONFIG_READER) return "ECONFIG_READER"; + else if ( type == EIMAGE_SAVE) return "EIMAGE_SAVE"; + else if ( type == ECAST_TO_STRING) return "ECAST_TO_STRING"; + else if ( type == ESTRING_CAST) return "ESTRING_CAST"; + else if ( type == EUTF8_TO_UTF32) return "EUTF8_TO_UTF32"; + else return "undefined error type"; + } + + const std::string info; // info about the error + const error_type type; // the type of the error + + private: + const error& operator=(const error&); + }; + +// ---------------------------------------------------------------------------------------- + + class fatal_error : public error + { + /*! + WHAT THIS OBJECT REPRESENTS + As the name says, this object represents some kind of fatal error. + It is also the exception thrown by the DLIB_ASSERT and DLIB_CASSERT macros. + !*/ + + public: + fatal_error( + error_type t, + const std::string& a + ): error(t,a) {} + /*! + ensures + - #type == t + - #info == a + !*/ + + fatal_error( + error_type t + ): error(t) {} + /*! + ensures + - #type == t + - #info == "" + !*/ + + fatal_error( + const std::string& a + ): error(EFATAL,a) {} + /*! + ensures + - #type == EFATAL + - #info == a + !*/ + + fatal_error( + ): error(EFATAL) {} + /*! + ensures + - #type == EFATAL + - #info == "" + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class gui_error : public error + { + public: + gui_error( + error_type t, + const std::string& a + ): error(t,a) {} + /*! + ensures + - #type == t + - #info == a + !*/ + + gui_error( + error_type t + ): error(t) {} + /*! + ensures + - #type == t + - #info == "" + !*/ + + gui_error( + const std::string& a + ): error(EGUI,a) {} + /*! + ensures + - #type == EGUI + - #info == a + !*/ + + gui_error( + ): error(EGUI) {} + /*! + ensures + - #type == EGUI + - #info == "" + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class socket_error : public error + { + public: + socket_error( + error_type t, + const std::string& a + ): error(t,a) {} + /*! + ensures + - #type == t + - #info == a + !*/ + + socket_error( + error_type t + ): error(t) {} + /*! + ensures + - #type == t + - #info == "" + !*/ + + socket_error( + const std::string& a + ): error(ESOCKET,a) {} + /*! + ensures + - #type == ESOCKET + - #info == a + !*/ + + socket_error( + ): error(ESOCKET) {} + /*! + ensures + - #type == ESOCKET + - #info == "" + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class thread_error : public error + { + public: + thread_error( + error_type t, + const std::string& a + ): error(t,a) {} + /*! + ensures + - #type == t + - #info == a + !*/ + + thread_error( + error_type t + ): error(t) {} + /*! + ensures + - #type == t + - #info == "" + !*/ + + thread_error( + const std::string& a + ): error(ETHREAD,a) {} + /*! + ensures + - #type == ETHREAD + - #info == a + !*/ + + thread_error( + ): error(ETHREAD) {} + /*! + ensures + - #type == ETHREAD + - #info == "" + !*/ + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ERROr_ + diff --git a/dlib/fstream b/dlib/fstream new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/fstream @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/general_hash/general_hash.h b/dlib/general_hash/general_hash.h new file mode 100644 index 0000000000000000000000000000000000000000..a5c80d02fcb41fa217c7d5fce6f9dd12077d2e98 --- /dev/null +++ b/dlib/general_hash/general_hash.h @@ -0,0 +1,84 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GENERAL_HASh_ +#define DLIB_GENERAL_HASh_ + + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ----------------------- provide a general hashing function object ---------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class general_hash + { + public: + inline unsigned long operator() ( + const T& item + ) const; + }; + + /*! + Note that the default behavior of general hash is to attempt to cast + an object of type T to an unsigned long and use that as the hash. + + REQUIREMENTS ON general_hash + - must have a default constructor + - must be a function object which overloads operator() as follows: + unsigned long operator()(const T& item) + - must take item, compute a hash number and return it + - must not throw + - must define the hash in such a way that all equivalent objects have + the same hash. where equivalent means the following: + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + +// --------------- + + template < + typename T + > + unsigned long general_hash:: + operator() ( + const T& item + ) const + { + // hash any types that have a conversion to unsigned long + return static_cast(item); + } + + +// --------------- + + // std::string hash + template <> + inline unsigned long general_hash:: + operator() ( + const std::string& item + ) const + { + unsigned long hash = 0; + std::string::size_type size = item.size(); + for (std::string::size_type i = 0; i < size; ++i) + hash = hash*37 + static_cast(item[i]); + return hash; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GENERAL_HASh_ + diff --git a/dlib/geometry.h b/dlib/geometry.h new file mode 100644 index 0000000000000000000000000000000000000000..0ebae9a7d3eb675cef6985dce5d35d7b76a15dab --- /dev/null +++ b/dlib/geometry.h @@ -0,0 +1,11 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GEOMETRy_HEADER +#define DLIB_GEOMETRy_HEADER + +#include "geometry/rectangle.h" +#include "geometry/vector.h" + +#endif // DLIB_GEOMETRy_HEADER + + diff --git a/dlib/geometry/rectangle.h b/dlib/geometry/rectangle.h new file mode 100644 index 0000000000000000000000000000000000000000..e14ef1d84691c9925d6f37ee09c3df236f6a923b --- /dev/null +++ b/dlib/geometry/rectangle.h @@ -0,0 +1,491 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RECTANGLe_ +#define DLIB_RECTANGLe_ + +#include "rectangle_abstract.h" +#include "../algs.h" +#include +#include +#include "../serialize.h" +#include "vector.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class rectangle + { + /*! + INITIAL VALUE + The initial value of this object is defined by its constructor. + + CONVENTION + left() == l + top() == t + right() == r + bottom() == b + !*/ + + public: + + rectangle ( + long l_, + long t_, + long r_, + long b_ + ) : + l(l_), + t(t_), + r(r_), + b(b_) + {} + + rectangle ( + unsigned long w, + unsigned long h + ) : + l(0), + t(0), + r(static_cast(w)-1), + b(static_cast(h)-1) + { + DLIB_ASSERT(w > 0 && h > 0 || w == 0 && h == 0, + "\trectangle(width,height)" + << "\n\twidth and height must be > 0 or both == 0" + << "\n\twidth: " << w + << "\n\theight: " << h + << "\n\tthis: " << this + ); + } + + rectangle ( + const point& p + ) : + l(p.x()), + t(p.y()), + r(p.x()), + b(p.y()) + { + } + + template + rectangle ( + const vector& v + ) : + l(static_cast(v.x()+0.5)), + t(static_cast(v.y()+0.5)), + r(static_cast(v.x()+0.5)), + b(static_cast(v.y()+0.5)) + { + } + + rectangle ( + const point& p1, + const point& p2 + ) + { + *this = rectangle(p1) + rectangle(p2); + } + + template + rectangle ( + const vector& v1, + const vector& v2 + ) + { + *this = rectangle(v1) + rectangle(v2); + } + + rectangle ( + ) : + l(0), + t(0), + r(-1), + b(-1) + {} + + long top ( + ) const { return t; } + + long& top ( + ) { return t; } + + void set_top ( + long top_ + ) { t = top_; } + + long left ( + ) const { return l; } + + long& left ( + ) { return l; } + + void set_left ( + long left_ + ) { l = left_; } + + long right ( + ) const { return r; } + + long& right ( + ) { return r; } + + void set_right ( + long right_ + ) { r = right_; } + + long bottom ( + ) const { return b; } + + long& bottom ( + ) { return b; } + + void set_bottom ( + long bottom_ + ) { b = bottom_; } + + unsigned long width ( + ) const + { + if (is_empty()) + return 0; + else + return r - l + 1; + } + + unsigned long height ( + ) const + { + if (is_empty()) + return 0; + else + return b - t + 1; + } + + unsigned long area ( + ) const + { + return width()*height(); + } + + bool is_empty ( + ) const { return (t > b || l > r); } + + rectangle operator + ( + const rectangle& rhs + ) const + { + if (rhs.is_empty()) + return *this; + else if (is_empty()) + return rhs; + + return rectangle ( + std::min(l,rhs.l), + std::min(t,rhs.t), + std::max(r,rhs.r), + std::max(b,rhs.b) + ); + } + + rectangle intersect ( + const rectangle& rhs + ) const + { + return rectangle ( + std::max(l,rhs.l), + std::max(t,rhs.t), + std::min(r,rhs.r), + std::min(b,rhs.b) + ); + } + + bool contains ( + const point& p + ) const + { + if (p.x() < l || p.x() > r || p.y() < t || p.y() > b) + return false; + return true; + } + + bool contains ( + long x, + long y + ) const + { + if (x < l || x > r || y < t || y > b) + return false; + return true; + } + + bool contains ( + const rectangle& rect + ) const + { + return (rect + *this == *this); + } + + rectangle& operator+= ( + const rectangle& rect + ) + { + *this = *this + rect; + return *this; + } + + bool operator== ( + const rectangle& rect + ) const + { + return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b); + } + + bool operator!= ( + const rectangle& rect + ) const + { + return !(*this == rect); + } + + private: + long l; + long t; + long r; + long b; + }; + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const rectangle& item, + std::ostream& out + ) + { + try + { + serialize(item.left(),out); + serialize(item.top(),out); + serialize(item.right(),out); + serialize(item.bottom(),out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing an object of type rectangle"); + } + } + + inline void deserialize ( + rectangle& item, + std::istream& in + ) + { + try + { + deserialize(item.left(),in); + deserialize(item.top(),in); + deserialize(item.right(),in); + deserialize(item.bottom(),in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing an object of type rectangle"); + } + } + + inline std::ostream& operator<< ( + std::ostream& out, + const rectangle& item + ) + { + out << "[(" << item.left() << ", " << item.top() << ") (" << item.right() << ", " << item.bottom() << ")]"; + return out; + } + + inline std::istream& operator>>( + std::istream& in, + rectangle& item + ) + { + // ignore any whitespace + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n') + in.get(); + // now eat the leading '[' character + if (in.get() != '[') + { + in.setstate(in.rdstate() | std::ios::failbit); + return in; + } + + point p1, p2; + in >> p1; + in >> p2; + item = rectangle(p1) + rectangle(p2); + + // ignore any whitespace + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n') + in.get(); + // now eat the trailing ']' character + if (in.get() != ']') + { + in.setstate(in.rdstate() | std::ios::failbit); + } + return in; + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle centered_rect ( + long x, + long y, + unsigned long width, + unsigned long height + ) + { + rectangle result; + result.set_left ( x - static_cast(width) / 2 ); + result.set_top ( y - static_cast(height) / 2 ); + result.set_right ( result.left() + width - 1 ); + result.set_bottom ( result.top() + height - 1 ); + return result; + } + +// ---------------------------------------------------------------------------------------- + + inline const point nearest_point ( + const rectangle& rect, + const point& p + ) + { + point temp(p); + if (temp.x() < rect.left()) + temp.x() = rect.left(); + else if (temp.x() > rect.right()) + temp.x() = rect.right(); + + if (temp.y() < rect.top()) + temp.y() = rect.top(); + else if (temp.y() > rect.bottom()) + temp.y() = rect.bottom(); + + return temp; + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle centered_rect ( + const point& p, + unsigned long width, + unsigned long height + ) + { + return centered_rect(p.x(),p.y(),width,height); + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle centered_rect ( + const rectangle& rect, + unsigned long width, + unsigned long height + ) + { + return centered_rect((rect.left()+rect.right())/2, (rect.top()+rect.bottom())/2, width, height); + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle translate_rect ( + const rectangle& rect, + long x, + long y + ) + { + rectangle result; + result.set_top ( rect.top() + y ); + result.set_bottom ( rect.bottom() + y ); + result.set_left ( rect.left() + x ); + result.set_right ( rect.right() + x ); + return result; + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle resize_rect ( + const rectangle& rect, + unsigned long width, + unsigned long height + ) + { + return rectangle(rect.left(),rect.top(), + rect.left()+width-1, + rect.top()+height-1); + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle resize_rect_width ( + const rectangle& rect, + unsigned long width + ) + { + return rectangle(rect.left(),rect.top(), + rect.left()+width-1, + rect.bottom()); + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle resize_rect_height ( + const rectangle& rect, + unsigned long height + ) + { + return rectangle(rect.left(),rect.top(), + rect.right(), + rect.top()+height-1); + } + +// ---------------------------------------------------------------------------------------- + + inline const rectangle move_rect ( + const rectangle& rect, + long x, + long y + ) + { + return rectangle(x, y, x+rect.width()-1, y+rect.height()-1); + } + +// ---------------------------------------------------------------------------------------- + +} + +namespace std +{ + /*! + Define std::less so that you can use rectangles in the associative containers. + !*/ + template<> + struct less : public binary_function + { + inline bool operator() (const dlib::rectangle& a, const dlib::rectangle& b) const + { + if (a.left() < b.left()) return true; + else if (a.left() > b.left()) return false; + else if (a.top() < b.top()) return true; + else if (a.top() > b.top()) return false; + else if (a.right() < b.right()) return true; + else if (a.right() > b.right()) return false; + else if (a.bottom() < b.bottom()) return true; + else if (a.bottom() > b.bottom()) return false; + else return false; + } + }; +} + +#endif // DLIB_RECTANGLe_ + + diff --git a/dlib/geometry/rectangle_abstract.h b/dlib/geometry/rectangle_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b8ecd41366f031352be99b0e948938ca2857cfd2 --- /dev/null +++ b/dlib/geometry/rectangle_abstract.h @@ -0,0 +1,574 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RECTANGLe_ABSTRACT_ +#ifdef DLIB_RECTANGLe_ABSTRACT_ + +#include "vector_abstract.h" +#include +#include "../serialize.h" + +namespace dlib +{ + + class rectangle + { + /*! + INITIAL VALUE + The initial value of this object is defined by its constructor. + + WHAT THIS OBJECT REPRESENTS + This object represents a rectangular region inside a Cartesian + coordinate system. The region is the rectangle with its upper + left corner at position (left(),top()) and its lower right corner + at (right(),bottom()). + + Note that the origin of the coordinate system, i.e. (0,0), is located + at the upper left corner. That is, points such as (1,1) or (3,5) + represent locations that are below and to the right of the origin. + + Also note that rectangles where top() > bottom() or left() > right() + represent empty rectangles. + !*/ + + public: + + rectangle ( + const rectangle& rect + ); + /*! + ensures + - #*this represents the same rectangle as rect + !*/ + + rectangle ( + ); + /*! + ensures + - #left() == 0 + - #top() == 0 + - #right() == -1 + - #bottom() == -1 + - #is_empty() == true + !*/ + + rectangle ( + long left_, + long top_, + long right_, + long bottom_ + ); + /*! + ensures + - #left() == left_ + - #top() == top_ + - #right() == right_ + - #bottom() == bottom_ + !*/ + + rectangle ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - #left() == 0 + - #top() == 0 + - #width() == width_ + - #height() == height_ + !*/ + + rectangle ( + const point& p + ); + /*! + ensures + - #left() == p.x() + - #top() == p.y() + - #right() == p.x() + - #bottom() == p.y() + !*/ + + template + rectangle ( + const vector& v + ); + /*! + ensures + - #left() == static_cast(floor(v.x()+0.5)) + - #top() == static_cast(floor(v.y()+0.5)) + - #right() == static_cast(floor(v.x()+0.5)) + - #bottom() == static_cast(floor(v.y()+0.5)) + !*/ + + rectangle ( + const point& p1, + const point& p2 + ); + /*! + ensures + - #*this == rectangle(p1) + rectangle(p2) + !*/ + + template + rectangle ( + const vector& v1, + const vector& v2 + ); + /*! + ensures + - #*this == rectangle(v1) + rectangle(v2) + !*/ + + long left ( + ) const; + /*! + ensures + - returns the x coordinate for the left side of this rectangle + !*/ + + long& left ( + ); + /*! + ensures + - returns a non-const reference to the x coordinate for the left side + of this rectangle + !*/ + + void set_left ( + long left_ + ); + /*! + ensures + - #left() == left_ + !*/ + + long top ( + ) const; + /*! + ensures + - returns the y coordinate for the top of this rectangle + !*/ + + long& top ( + ); + /*! + ensures + - returns a non-const reference to the y coordinate for the + top of this rectangle + !*/ + + void set_top ( + long top_ + ); + /*! + ensures + - #top() == top_ + !*/ + + long right ( + ) const; + /*! + ensures + - returns the x coordinate for the right side of this rectangle + !*/ + + long& right ( + ); + /*! + ensures + - returns a non-const reference to the x coordinate for the right + side of this rectangle + !*/ + + void set_right ( + long right_ + ); + /*! + ensures + - #right() == right_ + !*/ + + long bottom ( + ) const; + /*! + ensures + - returns the y coordinate for the bottom of this rectangle + !*/ + + long& bottom ( + ); + /*! + ensures + - returns a non-const reference to the y coordinate for the bottom + of this rectangle + !*/ + + void set_bottom ( + long bottom_ + ); + /*! + ensures + - #bottom() == bottom_ + !*/ + + bool is_empty ( + ) const; + /*! + ensures + - if (top() > bottom() || left() > right()) then + - returns true + - else + - returns false + !*/ + + unsigned long width ( + ) const; + /*! + ensures + - if (is_empty()) then + - returns 0 + - else + - returns the width of this rectangle. + (i.e. right() - left() + 1) + !*/ + + unsigned long height ( + ) const; + /*! + ensures + - if (is_empty()) then + - returns 0 + - else + - returns the height of this rectangle. + (i.e. bottom() - top() + 1) + !*/ + + unsigned long area ( + ) const; + /*! + ensures + - returns width()*height() + !*/ + + rectangle operator + ( + const rectangle& rhs + ) const; + /*! + ensures + - if (rhs.is_empty() == false && this->is_empty() == false) then + - returns the smallest rectangle that contains both *this and + rhs. + - if (rhs.is_empty() == true && this->is_empty() == false) then + - returns *this + - if (rhs.is_empty() == false && this->is_empty() == true) then + - returns rhs + - if (rhs.is_empty() == true && this->is_empty() == true) then + - returns a rectangle that has is_empty() == true + !*/ + + rectangle intersect ( + const rectangle& rhs + ) const; + /*! + ensures + - if (there is a region of intersection between *this and rhs) then + - returns a rectangle that represents the intersection of *this + and rhs. + - else + - returns a rectangle where is_empty() == true + !*/ + + bool contains ( + long x, + long y + ) const; + /*! + ensures + - if (the point (x,y) is contained in this rectangle) then + - returns true + - else + - returns false + !*/ + + bool contains ( + const point& p + ) const; + /*! + ensures + - if (the point (p.x(),p.y()) is contained in this rectangle) then + - returns true + - else + - returns false + !*/ + + bool contains ( + const rectangle& rect + ) const; + /*! + ensures + - if (rect + *this == *this) then + - returns true + (i.e. returns true if *this contains the given rectangle) + - else + - returns false + !*/ + + rectangle& operator= ( + const rectangle& rect + ); + /*! + ensures + - #*this represents the same rectangle as rect + - returns #*this + !*/ + + rectangle& operator+= ( + const rectangle& rect + ); + /*! + ensures + - #*this == *this + rect + - returns #*this + !*/ + + bool operator== ( + const rectangle& rect + ) const; + /*! + ensures + - if (top() == rect.top() && left() == rect.left() && + right() == rect.right() && bottom() == rect.bottom()) then + - returns true + - else + - returns false + !*/ + + bool operator!= ( + const rectangle& rect + ) const; + /*! + ensures + - returns !(*this == rect) + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const rectangle& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + void deserialize ( + rectangle& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + + std::ostream& operator<< ( + std::ostream& out, + const rectangle& item + ); + /*! + ensures + - writes item to out in the form "[(left, top) (right, bottom)]" + !*/ + + std::istream& operator>>( + std::istream& in, + rectangle& item + ); + /*! + ensures + - reads a rectangle from the input stream in and stores it in #item. + The data in the input stream should be of the form [(left, top) (right, bottom)] + !*/ + +// ---------------------------------------------------------------------------------------- + + inline const rectangle centered_rect ( + const point& p, + unsigned long width, + unsigned long height + ); + /*! + ensures + - returns a rectangle R such that: + - if (width == 0 || height == 0) + - R.width() == 0 + - R.height() == 0 + - else + - R.width() == width + - R.height() == height + - The center of R is a the point p + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle centered_rect ( + long x, + long y, + unsigned long width, + unsigned long height + ); + /*! + ensures + - returns a rectangle R such that: + - if (width == 0 || height == 0) + - R.width() == 0 + - R.height() == 0 + - else + - R.width() == width + - R.height() == height + - The center of R is a the point (x,y) + !*/ + +// ---------------------------------------------------------------------------------------- + + inline const rectangle centered_rect ( + const rectangle& rect, + unsigned long width, + unsigned long height + ); + /*! + ensures + - returns a rectangle R such that: + - if (width == 0 || height == 0) + - R.width() == 0 + - R.height() == 0 + - else + - R.width() == width + - R.height() == height + - The center of R is at the center of rect + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle translate_rect ( + const rectangle& rect, + long x, + long y + ); + /*! + ensures + - returns a rectangle R such that: + - R.left() == rect.left() + x + - R.right() == rect.right() + x + - R.top() == rect.top() + y + - R.bottom() == rect.bottom() + y + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle resize_rect ( + const rectangle& rect, + unsigned long width, + unsigned long height + ); + /*! + ensures + - returns a rectangle R such that: + - if (width == 0 || height == 0) + - R.width() == 0 + - R.height() == 0 + - else + - R.width() == width + - R.height() == height + - R.left() == rect.left() + - R.top() == rect.top() + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle resize_rect_width ( + const rectangle& rect, + unsigned long width + ); + /*! + ensures + - returns a rectangle R such that: + - R.width() == width + - R.left() == rect.left() + - R.top() == rect.top() + - R.bottom() == rect.bottom() + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle resize_rect_height ( + const rectangle& rect, + unsigned long height + ); + /*! + ensures + - returns a rectangle R such that: + - R.height() == height + - R.left() == rect.left() + - R.top() == rect.top() + - R.right() == rect.right() + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle move_rect ( + const rectangle& rect, + long x, + long y + ); + /*! + ensures + - returns a rectangle R such that: + - R.width() == rect.width() + - R.height() == rect.height() + - R.left() == x + - R.top() == y + !*/ + +// ---------------------------------------------------------------------------------------- + + inline const point nearest_point ( + const rectangle& rect, + const point& p + ); + /*! + ensures + - if (rect.contains(p)) then + - returns p + - else + - returns the point in rect that is closest to p + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +namespace std +{ + /*! + Define std::less so that you can use rectangles in the associative containers. + !*/ + template<> + struct less : public binary_function + { + inline bool operator() (const dlib::rectangle& a, const dlib::rectangle& b) const + { + if (a.left() < b.left()) return true; + else if (a.left() > b.left()) return false; + else if (a.top() < b.top()) return true; + else if (a.top() > b.top()) return false; + else if (a.right() < b.right()) return true; + else if (a.right() > b.right()) return false; + else if (a.bottom() < b.bottom()) return true; + else if (a.bottom() > b.bottom()) return false; + else return false; + } + }; +} + +#endif // DLIB_RECTANGLe_ABSTRACT_ + diff --git a/dlib/geometry/vector.h b/dlib/geometry/vector.h new file mode 100644 index 0000000000000000000000000000000000000000..47cc86e3d71793a1c49a09b3726c9a0900bc084e --- /dev/null +++ b/dlib/geometry/vector.h @@ -0,0 +1,728 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_VECTOr_H_ +#define DLIB_VECTOr_H_ + +#include +#include "vector_abstract.h" +#include "../algs.h" +#include "../serialize.h" +#include +#include + +namespace dlib +{ + class point; + + template < + typename T + > + class vector + { + /*! + INITIAL VALUE + - x_value == 0 + - y_value == 0 + - z_value == 0 + + CONVENTION + - x_value == x() + - y_value == y() + - z_value == z() + + !*/ + + public: + + typedef T type; + + vector ( + ) : + x_value(0.0), + y_value(0.0), + z_value(0.0) + {} + + // --------------------------------------- + + vector ( + const T _x, + const T _y, + const T _z + ) : + x_value(_x), + y_value(_y), + z_value(_z) + {} + + // --------------------------------------- + + vector ( + const vector& v + ) : + x_value(v.x_value), + y_value(v.y_value), + z_value(v.z_value) + {} + + // --------------------------------------- + + inline vector ( + const point& p + ); + + // --------------------------------------- + + ~vector ( + ){} + + // --------------------------------------- + + T length( + ) const + { + return (T)std::sqrt((double)(x_value*x_value + y_value*y_value + z_value*z_value)); + } + + // --------------------------------------- + + vector normalize ( + ) const + { + T tmp = (T)std::sqrt((double)(x_value*x_value + y_value*y_value + z_value*z_value)); + return vector ( x_value/tmp, + y_value/tmp, + z_value/tmp + ); + } + + // --------------------------------------- + + T& x ( + ) + { + return x_value; + } + + // --------------------------------------- + + T& y ( + ) + { + return y_value; + } + + // --------------------------------------- + + T& z ( + ) + { + return z_value; + } + + // --------------------------------------- + + const T& x ( + ) const + { + return x_value; + } + + // --------------------------------------- + + const T& y ( + ) const + { + return y_value; + } + + // --------------------------------------- + + const T& z ( + ) const + { + return z_value; + } + + // --------------------------------------- + + T dot ( + const vector& rhs + ) const + { + return x_value*rhs.x_value + y_value*rhs.y_value + z_value*rhs.z_value; + } + + // --------------------------------------- + + vector cross ( + const vector& rhs + ) const + { + return vector ( + y_value*rhs.z_value - z_value*rhs.y_value, + z_value*rhs.x_value - x_value*rhs.z_value, + x_value*rhs.y_value - y_value*rhs.x_value + ); + } + + // --------------------------------------- + + vector operator+ ( + const vector& rhs + ) const + { + return vector ( + x_value+rhs.x_value, + y_value+rhs.y_value, + z_value+rhs.z_value + ); + } + + // --------------------------------------- + + vector operator- ( + const vector& rhs + ) const + { + return vector ( + x_value-rhs.x_value, + y_value-rhs.y_value, + z_value-rhs.z_value + ); + } + + // --------------------------------------- + + vector& operator= ( + const vector& rhs + ) + { + x_value = rhs.x_value; + y_value = rhs.y_value; + z_value = rhs.z_value; + return *this; + } + + // --------------------------------------- + + vector operator/ ( + const T rhs + ) const + { + return vector ( + x_value/rhs, + y_value/rhs, + z_value/rhs + ); + } + + // --------------------------------------- + + vector& operator += ( + const vector& rhs + ) + { + x_value += rhs.x_value; + y_value += rhs.y_value; + z_value += rhs.z_value; + return *this; + } + + // --------------------------------------- + + vector& operator -= ( + const vector& rhs + ) + { + x_value -= rhs.x_value; + y_value -= rhs.y_value; + z_value -= rhs.z_value; + return *this; + } + + // --------------------------------------- + + vector& operator *= ( + const T rhs + ) + { + x_value *= rhs; + y_value *= rhs; + z_value *= rhs; + return *this; + } + + // --------------------------------------- + + vector& operator /= ( + const T rhs + ) + { + x_value /= rhs; + y_value /= rhs; + z_value /= rhs; + return *this; + } + + // --------------------------------------- + + bool operator== ( + const vector& rhs + ) const + { + return (x_value == rhs.x_value && + y_value == rhs.y_value && + z_value == rhs.z_value ); + } + + // --------------------------------------- + + bool operator!= ( + const vector& rhs + ) const + { + return !((*this) == rhs); + } + + // --------------------------------------- + + void swap ( + vector& item + ) + { + exchange(x_value,item.x_value); + exchange(y_value,item.y_value); + exchange(z_value,item.z_value); + } + + // --------------------------------------- + + private: + T x_value; + T y_value; + T z_value; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + inline vector operator* ( + const vector & lhs, + const U rhs + ) + { + return vector ( + lhs.x()*rhs, + lhs.y()*rhs, + lhs.z()*rhs + ); + } + +// ---------------------------------------------------------------------------------------- + + template + inline vector operator* ( + const U lhs, + const vector & rhs + ) { return rhs*lhs; } + +// ---------------------------------------------------------------------------------------- + + template + inline void swap ( + vector & a, + vector & b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template + inline void serialize ( + const vector & item, + std::ostream& out + ) + { + try + { + serialize(item.x(),out); + serialize(item.y(),out); + serialize(item.z(),out); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type vector"); + } + } + + template + inline void deserialize ( + vector & item, + std::istream& in + ) + { + try + { + deserialize(item.x(),in); + deserialize(item.y(),in); + deserialize(item.z(),in); + } + catch (serialization_error e) + { + item.x() = 0; + item.y() = 0; + item.z() = 0; + throw serialization_error(e.info + "\n while deserializing object of type vector"); + } + } + +// ---------------------------------------------------------------------------------------- + + template + std::ostream& operator<< ( + std::ostream& out, + const vector& item + ) + { + out << "(" << item.x() << ", " << item.y() << ", " << item.z() << ")"; + return out; + } + + template + std::istream& operator>>( + std::istream& in, + vector& item + ) + { + + // eat all the crap up to the '(' + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n') + in.get(); + + // there should be a '(' if not then this is an error + if (in.get() != '(') + { + in.setstate(in.rdstate() | std::ios::failbit); + return in; + } + + // eat all the crap up to the first number + while (in.peek() == ' ' || in.peek() == '\t') + in.get(); + in >> item.x(); + + if (!in.good()) + return in; + + // eat all the crap up to the next number + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',') + in.get(); + in >> item.y(); + + if (!in.good()) + return in; + + // eat all the crap up to the next number + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',') + in.get(); + in >> item.z(); + + if (!in.good()) + return in; + + // eat all the crap up to the ')' + while (in.peek() == ' ' || in.peek() == '\t') + in.get(); + + // there should be a ')' if not then this is an error + if (in.get() != ')') + in.setstate(in.rdstate() | std::ios::failbit); + return in; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class point + { + /*! + INITIAL VALUE + The initial value of this object is defined by its constructor. + + CONVENTION + - x_ == x() + - y_ == y() + !*/ + + public: + + point ( + ) : x_(0), y_(0) {} + + point ( + long x__, + long y__ + ) + { + x_ = x__; + y_ = y__; + } + + point ( + const point& p + ) + { + x_ = p.x_; + y_ = p.y_; + } + + template + point ( + const vector& v + ) : + x_(static_cast(v.x()+0.5)), + y_(static_cast(v.y()+0.5)) + {} + + long x ( + ) const { return x_; } + + long y ( + ) const { return y_; } + + long& x ( + ) { return x_; } + + long& y ( + ) { return y_; } + + const point operator+ ( + const point& rhs + ) const + { + return point(x()+rhs.x(), y()+rhs.y()); + } + + const point operator- ( + const point& rhs + ) const + { + return point(x()-rhs.x(), y()-rhs.y()); + } + + point& operator= ( + const point& p + ) + { + x_ = p.x_; + y_ = p.y_; + return *this; + } + + point& operator+= ( + const point& rhs + ) + { + x_ += rhs.x_; + y_ += rhs.y_; + return *this; + } + + point& operator-= ( + const point& rhs + ) + { + x_ -= rhs.x_; + y_ -= rhs.y_; + return *this; + } + + bool operator== ( + const point& p + ) const { return p.x_ == x_ && p.y_ == y_; } + + bool operator!= ( + const point& p + ) const { return p.x_ != x_ || p.y_ != y_; } + + private: + long x_; + long y_; + }; + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const point& item, + std::ostream& out + ) + { + try + { + serialize(item.x(),out); + serialize(item.y(),out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing an object of type point"); + } + } + + inline void deserialize ( + point& item, + std::istream& in + ) + { + try + { + deserialize(item.x(),in); + deserialize(item.y(),in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing an object of type point"); + } + } + + inline std::ostream& operator<< ( + std::ostream& out, + const point& item + ) + { + out << "(" << item.x() << ", " << item.y() << ")"; + return out; + } + + inline std::istream& operator>>( + std::istream& in, + point& item + ) + { + // eat all the crap up to the '(' + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\r' || in.peek() == '\n') + in.get(); + + // there should be a '(' if not then this is an error + if (in.get() != '(') + { + in.setstate(in.rdstate() | std::ios::failbit); + return in; + } + + // eat all the crap up to the first number + while (in.peek() == ' ' || in.peek() == '\t') + in.get(); + + bool is_negative = false; + if (in.peek() == '-') + { + in.get(); + is_negative = true; + } + + // read in the number and store it in item.x() + item.x() = 0; + while (in.peek() >= '0' && in.peek() <= '9') + { + long temp = in.get()-'0'; + item.x() = item.x()*10 + temp; + } + if (is_negative) + item.x() *= -1; + + if (!in.good()) + return in; + + // eat all the crap up to the next number + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == ',') + in.get(); + + is_negative = false; + if (in.peek() == '-') + { + in.get(); + is_negative = true; + } + + + // read in the number and store it in item.y() + item.y() = 0; + while (in.peek() >= '0' && in.peek() <= '9') + { + long temp = in.get()-'0'; + item.y() = item.y()*10 + temp; + } + if (is_negative) + item.y() *= -1; + + if (!in.good()) + return in; + + // eat all the crap up to the ')' + while (in.peek() == ' ' || in.peek() == '\t') + in.get(); + + // there should be a ')' if not then this is an error + if (in.get() != ')') + in.setstate(in.rdstate() | std::ios::failbit); + return in; + } + +// ---------------------------------------------------------------------------------------- + + template + vector::vector ( + const point& p + ) : + x_value(p.x()), + y_value(p.y()), + z_value(0) + {} + +// ---------------------------------------------------------------------------------------- + +} + +namespace std +{ + /*! + Define std::less > so that you can use vectors in the associative containers. + !*/ + template + struct less > : public binary_function ,dlib::vector ,bool> + { + inline bool operator() (const dlib::vector & a, const dlib::vector & b) const + { + if (a.x() < b.x()) return true; + else if (a.x() > b.x()) return false; + else if (a.y() < b.y()) return true; + else if (a.y() > b.y()) return false; + else if (a.z() < b.z()) return true; + else if (a.z() > b.z()) return false; + else return false; + } + }; + + /*! + Define std::less so that you can use points in the associative containers. + !*/ + template<> + struct less : public binary_function + { + inline bool operator() (const dlib::point& a, const dlib::point& b) const + { + if (a.x() < b.x()) return true; + else if (a.x() > b.x()) return false; + else if (a.y() < b.y()) return true; + else if (a.y() > b.y()) return false; + else return false; + } + }; +} + +#endif // DLIB_VECTOr_H_ + diff --git a/dlib/geometry/vector_abstract.h b/dlib/geometry/vector_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..3be990fd39689879bafd25b0b39541ce21d9901b --- /dev/null +++ b/dlib/geometry/vector_abstract.h @@ -0,0 +1,557 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_VECTOR_ABSTRACT_ +#ifdef DLIB_VECTOR_ABSTRACT_ + +#include "../serialize.h" +#include +#include + +namespace dlib +{ + class point; + + template < + typename T + > + class vector + { + /*! + REQUIREMENTS ON T + T should be some object that provides an interface that is + compatible with double, float and the like. + + INITIAL VALUE + x() == 0 + y() == 0 + z() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a three dimensional vector. + + THREAD SAFETY + Note that the vector object is not allowed to be reference counted. + This is to ensure a minimum amount of thread safety. + !*/ + + public: + + typedef T type; + + vector ( + ); + /*! + ensures + - #*this has been properly initialized + !*/ + + vector ( + const T _x, + const T _y, + const T _z + ); + /*! + ensures + - #*this properly initialized + - #x() == _x + - #y() == _y + - #z() == _z + !*/ + + vector ( + const point& p + ); + /*! + ensures + - #*this properly initialized + - #x() == p.x() + - #y() == p.y() + - #z() == 0 + !*/ + + vector ( + const vector& v + ); + /*! + ensures + - #*this properly initialized + - #x() == v.x() + - #y() == v.y() + - #z() == v.z() + !*/ + + ~vector ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + + T length( + ) const; + /*! + ensures + - returns the length of the vector + !*/ + + T& x ( + ); + /*! + ensures + - returns a reference to the x component of the vector + !*/ + + T& y ( + ); + /*! + ensures + - returns a reference to the y component of the vector + !*/ + + T& z ( + ); + /*! + ensures + - returns a reference to the z component of the vector + !*/ + + const T& x ( + ) const; + /*! + ensures + - returns a const reference to the x component of the vector + !*/ + + const T& y ( + ) const; + /*! + ensures + - returns a const reference to the y component of the vector + !*/ + + const T& z ( + ) const; + /*! + ensures + - returns a const reference to the z component of the vector + !*/ + + T dot ( + const vector& rhs + ) const; + /*! + ensures + - returns the result of the dot product between *this and rhs + !*/ + + vector cross ( + const vector& rhs + ) const; + /*! + ensures + - returns the result of the cross product between *this and rhs + !*/ + + vector normalize ( + ) const; + /*! + ensures + - returns a vector with length() == 1 and in the same direction as *this + !*/ + + vector operator+ ( + const vector& rhs + ) const; + /*! + ensures + - returns the result of adding *this to rhs + !*/ + + vector operator- ( + const vector& rhs + ) const; + /*! + ensures + - returns the result of subtracting rhs from *this + !*/ + + vector operator/ ( + const T rhs + ) const; + /*! + ensures + - returns the result of dividing *this by rhs + !*/ + + vector& operator= ( + const vector& rhs + ); + /*! + ensures + - #x() == rhs.x() + - #y() == rhs.y() + - #z() == rhs.z() + - returns #*this + !*/ + + vector& operator += ( + const vector& rhs + ); + /*! + ensures + - #*this == *this + rhs + - returns #*this + !*/ + + vector& operator -= ( + const vector& rhs + ); + /*! + ensures + - #*this == *this - rhs + - returns #*this + !*/ + + vector& operator *= ( + const T rhs + ); + /*! + ensures + - #*this == *this * rhs + - returns #*this + !*/ + + vector& operator /= ( + const T rhs + ); + /*! + ensures + - #*this == *this / rhs + - returns #*this + !*/ + + bool operator== ( + const vector& rhs + ) const; + /*! + ensures + - if (x() == rhs.x() && y() == rhs.y() && z() == rhs.z()) then + - returns true + - else + - returns false + !*/ + + bool operator!= ( + const vector& rhs + ) const; + /*! + ensures + - returns !((*this) == rhs) + !*/ + + void swap ( + vector& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + template + vector operator* ( + const vector & lhs, + const U rhs + ); + /*! + ensures + - returns the result of multiplying the scalar rhs by lhs + !*/ + + template + vector operator* ( + const U lhs, + const vector & rhs + ); + /*! + ensures + - returns the result of multiplying the scalar lhs by rhs + !*/ + + template + inline void swap ( + vector & a, + vector & b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template + void serialize ( + const vector & item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + template + void deserialize ( + vector & item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + + template + std::ostream& operator<< ( + std::ostream& out, + const vector& item + ); + /*! + ensures + - writes item to out in the form "(x, y, z)" + !*/ + + template + std::istream& operator>>( + std::istream& in, + vector& item + ); + /*! + ensures + - reads a vector from the input stream in and stores it in #item. + The data in the input stream should be of the form (x, y, z) + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class point + { + /*! + INITIAL VALUE + The initial value of this object is defined by its constructor. + + WHAT THIS OBJECT REPRESENTS + This object represents a point inside a Cartesian coordinate system. + !*/ + + public: + + point ( + ); + /*! + ensures + - #x() == 0 + - #y() == 0 + !*/ + + point ( + long x_ + long y_ + ); + /*! + ensures + - #x() == x_ + - #y() == y_ + !*/ + + point ( + const point& p + ); + /*! + ensures + - #x() == p.x() + - #y() == p.y() + !*/ + + template + point ( + const vector& v + ); + /*! + ensures + - #x() == floor(v.x()+0.5) + - #y() == floor(v.y()+0.5) + !*/ + + long x ( + ) const; + /*! + ensures + - returns the x coordinate of this point + !*/ + + long y ( + ) const; + /*! + ensures + - returns the y coordinate of this point + !*/ + + long& x ( + ); + /*! + ensures + - returns a non-const reference to the x coordinate of + this point + !*/ + + long& y ( + ); + /*! + ensures + - returns a non-const reference to the y coordinate of + this point + !*/ + + const point operator+ ( + const point& rhs + ) const; + /*! + ensures + - returns point(x()+rhs.x(), y()+rhs.y()) + !*/ + + const point operator- ( + const point& rhs + ) const; + /*! + ensures + - returns point(x()-rhs.x(), y()-rhs.y()) + !*/ + + point& operator= ( + const point& p + ); + /*! + ensures + - #x() == p.x() + - #y() == p.y() + - returns #*this + !*/ + + point& operator+= ( + const point& rhs + ); + /*! + ensures + - #*this = *this + rhs + - returns #*this + !*/ + + point& operator-= ( + const point& rhs + ); + /*! + ensures + - #*this = *this - rhs + - returns #*this + !*/ + + bool operator== ( + const point& p + ) const; + /*! + ensures + - if (x() == p.x() && y() == p.y()) then + - returns true + - else + - returns false + !*/ + + bool operator!= ( + const point& p + ) const; + /*! + ensures + - returns !(*this == p) + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const point& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + void deserialize ( + point& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + + std::ostream& operator<< ( + std::ostream& out, + const point& item + ); + /*! + ensures + - writes item to out in the form "(x, y)" + !*/ + + std::istream& operator>>( + std::istream& in, + point& item + ); + /*! + ensures + - reads a point from the input stream in and stores it in #item. + The data in the input stream should be of the form (x, y) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +namespace std +{ + /*! + Define std::less > so that you can use vectors in the associative containers. + !*/ + template + struct less > : public binary_function ,dlib::vector ,bool> + { + inline bool operator() (const dlib::vector & a, const dlib::vector & b) const + { + if (a.x() < b.x()) return true; + else if (a.x() > b.x()) return false; + else if (a.y() < b.y()) return true; + else if (a.y() > b.y()) return false; + else if (a.z() < b.z()) return true; + else if (a.z() > b.z()) return false; + else return false; + } + }; + + /*! + Define std::less so that you can use points in the associative containers. + !*/ + template<> + struct less : public binary_function + { + inline bool operator() (const dlib::point& a, const dlib::point& b) const + { + if (a.x() < b.x()) return true; + else if (a.x() > b.x()) return false; + else if (a.y() < b.y()) return true; + else if (a.y() > b.y()) return false; + else return false; + } + }; +} + +#endif // DLIB_VECTOR_ABSTRACT_ + diff --git a/dlib/graph.h b/dlib/graph.h new file mode 100644 index 0000000000000000000000000000000000000000..558b8ef945faf6ae0b35cc0afb5739071eec1036 --- /dev/null +++ b/dlib/graph.h @@ -0,0 +1,37 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GRAPh_ +#define DLIB_GRAPh_ + +#include "graph/graph_kernel_1.h" + +#include "memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename E = char, + typename mem_manager = memory_manager::kernel_1a + > + class graph + { + graph() {} + public: + + + //----------- kernels --------------- + + // kernel_1a + typedef graph_kernel_1 + kernel_1a; + typedef graph_kernel_1 + kernel_1a_c; + + }; +} + +#endif // DLIB_GRAPh_ + + diff --git a/dlib/graph/graph_kernel_1.h b/dlib/graph/graph_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..e5fb28f884cebf05eba70d86b01a1bef59de59d1 --- /dev/null +++ b/dlib/graph/graph_kernel_1.h @@ -0,0 +1,629 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GRAPH_KERNEl_1_ +#define DLIB_GRAPH_KERNEl_1_ + +#include "../serialize.h" +#include "../noncopyable.h" +#include "../std_allocator.h" +#include "../smart_pointers.h" +#include "../algs.h" +#include +#include "../memory_manager.h" +#include "graph_kernel_abstract.h" +#include "../is_kind.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + struct graph_checker_helper + { + /*! + This object is used to check preconditions based on the value of is_checked + !*/ + + static void check_neighbor ( + unsigned long edge_index, + const node_type& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(edge_index < self.number_of_neighbors(), + "\tnode_type& graph::node_type::neighbor(edge_index)" + << "\n\tYou have specified an invalid index" + << "\n\tedge_index: " << edge_index + << "\n\tnumber_of_neighbors(): " << self.number_of_neighbors() + << "\n\tthis: " << &self + ); + } + + static void check_edge ( + unsigned long edge_index, + const node_type& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(edge_index < self.number_of_neighbors(), + "\tE& graph::node_type::edge(edge_index)" + << "\n\tYou have specified an invalid index" + << "\n\tedge_index: " << edge_index + << "\n\tnumber_of_neighbors(): " << self.number_of_neighbors() + << "\n\tthis: " << &self + ); + } + + static void check_node ( + unsigned long index, + const graph& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(index < self.number_of_nodes(), + "\tnode_type& graph::node(index)" + << "\n\tYou have specified an invalid index" + << "\n\tindex: " << index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + } + + static void check_has_edge ( + unsigned long node_index1, + unsigned long node_index2, + const graph& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(node_index1 < self.number_of_nodes() && + node_index2 < self.number_of_nodes(), + "\tvoid graph::has_edge(node_index1, node_index2)" + << "\n\tYou have specified an invalid index" + << "\n\tnode_index1: " << node_index1 + << "\n\tnode_index2: " << node_index2 + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + } + + static void check_add_edge ( + unsigned long node_index1, + unsigned long node_index2, + const graph& self + ) + { + DLIB_CASSERT(node_index1 < self.number_of_nodes() && + node_index2 < self.number_of_nodes(), + "\tvoid graph::add_edge(node_index1, node_index2)" + << "\n\tYou have specified an invalid index" + << "\n\tnode_index1: " << node_index1 + << "\n\tnode_index2: " << node_index2 + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + DLIB_CASSERT( self.has_edge(node_index1, node_index2) == false, + "\tvoid graph::add_edge(node_index1, node_index2)" + << "\n\tYou can't add an edge if it already exists in the graph" + << "\n\tnode_index1: " << node_index1 + << "\n\tnode_index2: " << node_index2 + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + } + + static void check_remove_edge ( + unsigned long node_index1, + unsigned long node_index2, + const graph& self + ) + { + DLIB_CASSERT(node_index1 < self.number_of_nodes() && + node_index2 < self.number_of_nodes(), + "\tvoid graph::remove_edge(node_index1, node_index2)" + << "\n\tYou have specified an invalid index" + << "\n\tnode_index1: " << node_index1 + << "\n\tnode_index2: " << node_index2 + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + DLIB_CASSERT( self.has_edge(node_index1, node_index2) == true, + "\tvoid graph::remove_edge(node_index1, node_index2)" + << "\n\tYou can't remove an edge if it isn't in the graph" + << "\n\tnode_index1: " << node_index1 + << "\n\tnode_index2: " << node_index2 + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + + } + + static void check_remove_node ( + unsigned long index, + const graph& self + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(index < self.number_of_nodes(), + "\tvoid graph::remove_node(index)" + << "\n\tYou have specified an invalid index" + << "\n\tindex: " << index + << "\n\tnumber_of_nodes(): " << self.number_of_nodes() + << "\n\tthis: " << &self + ); + } + }; + + template + struct graph_checker_helper + { + static inline void check_edge ( unsigned long edge_index, const node_type& self) { } + static inline void check_neighbor ( unsigned long edge_index, const node_type& self) { } + static inline void check_node ( unsigned long index, const graph& self) { } + static inline void check_has_edge ( unsigned long , unsigned long , const graph& ) { } + static inline void check_add_edge ( unsigned long , unsigned long , const graph& ) { } + static inline void check_remove_edge ( unsigned long , unsigned long , const graph& ) { } + static inline void check_remove_node ( unsigned long index, const graph& self) { } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E = char, + typename mem_manager = memory_manager::kernel_1a, + bool is_checked = true + > + class graph_kernel_1 : noncopyable + { + + /*! + INITIAL VALUE + - nodes.size() == 0 + + CONVENTION + - nodes.size() == number_of_nodes() + - for all valid i: + - *nodes[i] == node(i) + - nodes[i]->neighbors.size() == nodes[i]->number_of_neighbors(i) + - nodes[i]->idx == i == nodes[i]->index() + - for all valid n: + - nodes[i]->neighbors[n] == pointer to the n'th parent node of i + - *nodes[i]->neighbors[n] == node(i).neighbor(n) + - *nodes[i]->edges[n] == node(i).edge(n) + !*/ + + public: + struct node_type; + + private: + typedef graph_checker_helper checker; + + + public: + + typedef T type; + typedef E edge_type; + typedef mem_manager mem_manager_type; + + graph_kernel_1( + ) {} + + virtual ~graph_kernel_1( + ) {} + + void clear( + ) { nodes.clear(); } + + void set_number_of_nodes ( + unsigned long new_size + ); + + unsigned long number_of_nodes ( + ) const { return nodes.size(); } + + node_type& node ( + unsigned long index + ) { checker::check_node(index,*this); return *nodes[index]; } + + const node_type& node ( + unsigned long index + ) const { checker::check_node(index,*this); return *nodes[index]; } + + bool has_edge ( + unsigned long node_index1, + unsigned long node_index2 + ) const; + + void add_edge ( + unsigned long node_index1, + unsigned long node_index2 + ); + + void remove_edge ( + unsigned long node_index1, + unsigned long node_index2 + ); + + unsigned long add_node ( + ); + + void remove_node ( + unsigned long index + ); + + void swap ( + graph_kernel_1& item + ) { nodes.swap(item.nodes); } + + public: + + struct node_type + { + T data; + typedef graph_kernel_1 graph_type; + + unsigned long index( + ) const { return idx; } + + unsigned long number_of_neighbors ( + ) const { return neighbors.size(); } + + const node_type& neighbor ( + unsigned long edge_index + ) const { checker::check_neighbor(edge_index,*this); return *neighbors[edge_index]; } + + node_type& neighbor ( + unsigned long edge_index + ) { checker::check_neighbor(edge_index,*this); return *neighbors[edge_index]; } + + const E& edge ( + unsigned long edge_index + ) const { checker::check_edge(edge_index,*this); return *edges[edge_index]; } + + E& edge ( + unsigned long edge_index + ) { checker::check_edge(edge_index,*this); return *edges[edge_index]; } + + private: + friend class graph_kernel_1; + typedef std_allocator alloc_type; + typedef std_allocator,mem_manager> alloc_edge_type; + std::vector neighbors; + std::vector,alloc_edge_type> edges; + unsigned long idx; + }; + + private: + + typedef std_allocator,mem_manager> alloc_type; + typedef std::vector, alloc_type> vector_type; + vector_type nodes; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + inline void swap ( + graph_kernel_1& a, + graph_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + struct is_graph > + { + static const bool value = true; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void serialize ( + const graph_kernel_1& item, + std::ostream& out + ) + { + try + { + serialize(item.number_of_nodes(), out); + + // serialize each node + for (unsigned long i = 0; i < item.number_of_nodes(); ++i) + { + serialize(item.node(i).data, out); + + // serialize all the edges + for (unsigned long n = 0; n < item.node(i).number_of_neighbors(); ++n) + { + // only serialize edges that we haven't already serialized + if (item.node(i).neighbor(n).index() >= i) + { + serialize(item.node(i).neighbor(n).index(), out); + serialize(item.node(i).edge(n), out); + } + } + const unsigned long stop_mark = 0xFFFFFFFF; + serialize(stop_mark, out); + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type graph_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void deserialize ( + graph_kernel_1& item, + std::istream& in + ) + { + try + { + unsigned long size; + deserialize(size, in); + + item.clear(); + item.set_number_of_nodes(size); + + // deserialize each node + for (unsigned long i = 0; i < item.number_of_nodes(); ++i) + { + deserialize(item.node(i).data, in); + + const unsigned long stop_mark = 0xFFFFFFFF; + // Add all the edges going to this node's neighbors + unsigned long index; + deserialize(index, in); + while (index != stop_mark) + { + item.add_edge(i, index); + // find the edge + unsigned long j = 0; + for (j = 0; j < item.node(i).number_of_neighbors(); ++j) + if (item.node(i).neighbor(j).index() == index) + break; + + deserialize(item.node(i).edge(j), in); + deserialize(index, in); + } + + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type graph_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void graph_kernel_1:: + set_number_of_nodes ( + unsigned long new_size + ) + { + try + { + nodes.resize(new_size); + for (unsigned long i = 0; i < nodes.size(); ++i) + { + nodes[i].reset(new node_type); + nodes[i]->idx = i; + } + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + bool graph_kernel_1:: + has_edge ( + unsigned long node_index1, + unsigned long node_index2 + ) const + { + checker::check_has_edge(node_index1, node_index2, *this); + + node_type& n = *nodes[node_index1]; + + // search all the child nodes to see if there is a link to the right node + for (unsigned long i = 0; i < n.neighbors.size(); ++i) + { + if (n.neighbors[i]->idx == node_index2) + return true; + } + + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void graph_kernel_1:: + add_edge ( + unsigned long node_index1, + unsigned long node_index2 + ) + { + checker::check_add_edge(node_index1, node_index2, *this); + try + { + node_type& n1 = *nodes[node_index1]; + node_type& n2 = *nodes[node_index2]; + + n1.neighbors.push_back(&n2); + + shared_ptr e(new E); + n1.edges.push_back(e); + + // don't add this twice if this is an edge from node_index1 back to itself + if (node_index1 != node_index2) + { + n2.neighbors.push_back(&n1); + n2.edges.push_back(e); + } + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void graph_kernel_1:: + remove_edge ( + unsigned long node_index1, + unsigned long node_index2 + ) + { + checker::check_remove_edge(node_index1, node_index2, *this); + + node_type& n1 = *nodes[node_index1]; + node_type& n2 = *nodes[node_index2]; + + // remove the record of the link from n1 + unsigned long pos = find(n1.neighbors.begin(), n1.neighbors.end(), &n2) - n1.neighbors.begin(); + n1.neighbors.erase(n1.neighbors.begin() + pos); + n1.edges.erase(n1.edges.begin() + pos); + + // check if this is an edge that goes from node_index1 back to itself + if (node_index1 != node_index2) + { + // remove the record of the link from n2 + unsigned long pos = find(n2.neighbors.begin(), n2.neighbors.end(), &n1) - n2.neighbors.begin(); + n2.neighbors.erase(n2.neighbors.begin() + pos); + n2.edges.erase(n2.edges.begin() + pos); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + unsigned long graph_kernel_1:: + add_node ( + ) + { + try + { + shared_ptr n(new node_type); + n->idx = nodes.size(); + nodes.push_back(n); + return n->idx; + } + catch (...) + { + clear(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename E, + typename mem_manager, + bool is_checked + > + void graph_kernel_1:: + remove_node ( + unsigned long index + ) + { + checker::check_remove_node(index,*this); + + node_type& n = *nodes[index]; + + // remove all edges pointing to this node from its neighbors + for (unsigned long i = 0; i < n.neighbors.size(); ++i) + { + // remove the edge from this specific parent + unsigned long pos = find(n.neighbors[i]->neighbors.begin(), n.neighbors[i]->neighbors.end(), &n) - + n.neighbors[i]->neighbors.begin(); + n.neighbors[i]->neighbors.erase(n.neighbors[i]->neighbors.begin() + pos); + n.neighbors[i]->edges.erase(n.neighbors[i]->edges.begin() + pos); + } + + // now remove this node by replacing it with the last node in the nodes vector + nodes[index] = nodes[nodes.size()-1]; + + // update the index for the node we just moved + nodes[index]->idx = index; + + // now remove the duplicated node at the end of the vector + nodes.pop_back(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GRAPH_KERNEl_1_ + diff --git a/dlib/graph/graph_kernel_abstract.h b/dlib/graph/graph_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c8662f9a012a4033e3dbcdd0a3b5198c7ad505db --- /dev/null +++ b/dlib/graph/graph_kernel_abstract.h @@ -0,0 +1,325 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_GRAPH_KERNEl_ABSTRACT_ +#ifdef DLIB_GRAPH_KERNEl_ABSTRACT_ + +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include "../noncopyable.h" + +namespace dlib +{ + + template < + typename T, + typename E = char, + typename mem_manager = memory_manager::kernel_1a + > + class graph : noncopyable + { + + /*! + REQUIREMENTS ON T + T must be swappable by a global swap() and + T must have a default constructor + + REQUIREMENTS ON E + E must be swappable by a global swap() and + E must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + The only functions that invalidate pointers or references to internal data are + clear(), remove_node(), add_node(), set_number_of_nodes(), and the object's destructor. + + INITIAL VALUE + number_of_nodes() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents an undirected graph which is a set of nodes with undirected + edges connecting various nodes. + !*/ + + public: + + typedef T type; + typedef E edge_type; + typedef mem_manager mem_manager_type; + + graph( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor. + !*/ + + virtual ~graph( + ); + /*! + ensures + - all resources associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void set_number_of_nodes ( + unsigned long new_size + ); + /*! + ensures + - #number_of_nodes() == new_size + - for all i < new_size: + - number_of_neighbors(i) == 0 + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + unsigned long number_of_nodes ( + ) const; + /*! + ensures + - returns the number of nodes in this graph + !*/ + + struct node_type + { + T data; + typedef graph graph_type; + + unsigned long index( + ) const; + /*! + ensures + - let G be the graph that contains the node *this + - returns a number N such that G.node(N) == *this + (i.e. returns the index of this node in the graph) + !*/ + + unsigned long number_of_neighbors ( + ) const; + /*! + ensures + - returns the number of nodes in this graph that are + adjacent to this node. I.e. the number of nodes + that are directly connected to this node via an edge. + !*/ + + const node_type& neighbor ( + unsigned long edge_index + ) const; + /*! + requires + - edge_index < number_of_neighbors() + ensures + - returns a const reference to the edge_index'th neighbor of *this + !*/ + + node_type& neighbor ( + unsigned long edge_index + ); + /*! + requires + - edge_index < number_of_neighbors() + ensures + - returns a non-const reference to the edge_index'th neighbor of *this + !*/ + + const E& edge ( + unsigned long edge_index + ) const; + /*! + requires + - edge_index < number_of_neighbors() + ensures + - returns a const reference to the edge_index'th edge data for the + edge connecting to neighbor this->neighbor(edge_index) + !*/ + + E& edge ( + unsigned long edge_index + ); + /*! + requires + - edge_index < number_of_neighbors() + ensures + - returns a non-const reference to the edge_index'th edge data for the + edge connecting to neighbor this->neighbor(edge_index) + !*/ + + }; + + node_type& node ( + unsigned long index + ); + /*! + requires + - index < number_of_nodes() + ensures + - returns a non-const reference to the node with the given index + !*/ + + const node_type& node ( + unsigned long index + ) const; + /*! + requires + - index < number_of_nodes() + ensures + - returns a const reference to the node with the given index + !*/ + + bool has_edge ( + unsigned long node_index1, + unsigned long node_index2 + ) const; + /*! + requires + - node_index1 < number_of_nodes() + - node_index2 < number_of_nodes() + ensures + - if (there is an edge connecting node(node_index1) and node(node_index2)) then + - returns true + - else + - returns false + !*/ + + void add_edge ( + unsigned long node_index1, + unsigned long node_index2 + ); + /*! + requires + - node_index1 < number_of_nodes() + - node_index2 < number_of_nodes() + - has_edge(node_index1, node_index2) == false + ensures + - #has_edge(node_index1, node_index2) == true + throws + - std::bad_alloc + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + void remove_edge ( + unsigned long node_index1, + unsigned long node_index2 + ); + /*! + requires + - node_index1 < number_of_nodes() + - node_index2 < number_of_nodes() + - has_edge(node_index1, node_index2) == true + ensures + - #has_edge(node_index1, node_index2) == false + throws + - std::bad_alloc + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + unsigned long add_node ( + ); + /*! + ensures + - adds a node with index N == number_of_nodes() such that: + - #node(N).number_of_neighbors() == 0 + - #number_of_nodes() == number_of_nodes() + 1 + - returns N + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + void remove_node ( + unsigned long index + ); + /*! + requires + - index < number_of_nodes() + ensures + - removes the node with the given index from the graph. + - removes all edges linking the removed node to the rest + of the graph. + - the remaining node indexes are remapped so that they remain + contiguous. (This means that for all valid N, node(N) doesn't + necessarily reference the same node as #node(N)) + - #number_of_nodes() == number_of_nodes() - 1 + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then this object reverts back + to its initial state. + !*/ + + void swap ( + graph& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + template < + typename T, + typename E, + typename mem_manager + > + inline void swap ( + graph& a, + graph& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename E, + typename mem_manager + > + void serialize ( + const graph& item, + std::ostream& out + ); + /*! + provides deserialization support + !*/ + + template < + typename T, + typename E, + typename mem_manager + > + void deserialize ( + graph& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_GRAPH_KERNEl_ABSTRACT_ + + diff --git a/dlib/graph_utils.h b/dlib/graph_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..47177927efbb078a9f8b3c627ab47036337dd101 --- /dev/null +++ b/dlib/graph_utils.h @@ -0,0 +1,10 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GRAPH_UTILs_H_ +#define DLIB_GRAPH_UTILs_H_ + +#include "graph_utils/graph_utils.h" + +#endif // DLIB_GRAPH_UTILs_H_ + + diff --git a/dlib/graph_utils/graph_utils.h b/dlib/graph_utils/graph_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..f5390bb7bdd0533386a4616fb6d366133596ca2e --- /dev/null +++ b/dlib/graph_utils/graph_utils.h @@ -0,0 +1,1071 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GRAPH_UTILs_ +#define DLIB_GRAPH_UTILs_ + +#include "../algs.h" +#include +#include "graph_utils_abstract.h" +#include "../is_kind.h" +#include "../enable_if.h" +#include +#include "../set.h" +#include "../memory_manager.h" +#include "../set_utils.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + typename T::edge_type& edge( + T& g, + unsigned long idx, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(g.has_edge(idx,n) == true, + "\tT::edge_type& edge(g, i, j)" + << "\n\tyou have requested an invalid edge" + << "\n\ti: " << idx + << "\n\tj: " << n + ); + + for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i) + { + if (g.node(idx).neighbor(i).index() == n) + return g.node(idx).edge(i); + } + + // put this here just so compilers don't complain about a lack of + // a return here + DLIB_CASSERT(false, + "\tT::edge_type& edge(g, i, j)" + << "\n\tyou have requested an invalid edge" + << "\n\ti: " << idx + << "\n\tj: " << n + ); + } + + template + const typename T::edge_type& edge( + const T& g, + unsigned long idx, + unsigned long n + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(g.has_edge(idx,n) == true, + "\tT::edge_type& edge(g, i, j)" + << "\n\tyou have requested an invalid edge" + << "\n\ti: " << idx + << "\n\tj: " << n + ); + + for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i) + { + if (g.node(idx).neighbor(i).index() == n) + return g.node(idx).edge(i); + } + + // put this here just so compilers don't complain about a lack of + // a return here + DLIB_CASSERT(false, + "\tT::edge_type& edge(g, i, j)" + << "\n\tyou have requested an invalid edge" + << "\n\ti: " << idx + << "\n\tj: " << n + ); + } + +// ---------------------------------------------------------------------------------------- + + namespace graph_helpers + { + template + inline bool is_same_object ( + const T& a, + const U& b + ) + { + if (is_same_type::value == false) + return false; + if ((void*)&a == (void*)&b) + return true; + else + return false; + } + + template < + typename T + > + bool search_for_directed_cycles ( + const T& node, + std::vector& visited, + std::vector& temp + ) + /*! + requires + - visited.size() >= number of nodes in the graph that contains the given node + - temp.size() >= number of nodes in the graph that contains the given node + - for all i in temp: + - temp[i] == false + ensures + - checks the connected subgraph containing the given node for directed cycles + and returns true if any are found and false otherwise. + - for all nodes N in the connected subgraph containing the given node: + - #visited[N.index()] == true + - for all i in temp: + - #temp[i] == false + !*/ + { + if (temp[node.index()] == true) + return true; + + visited[node.index()] = true; + temp[node.index()] = true; + + for (unsigned long i = 0; i < node.number_of_children(); ++i) + { + if (search_for_directed_cycles(node.child(i), visited, temp)) + return true; + } + + temp[node.index()] = false; + + return false; + } + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + typename enable_if,bool>::type search_for_undirected_cycles ( + const T& node, + std::vector& visited, + unsigned long prev = -1 + ) + /*! + requires + - visited.size() >= number of nodes in the graph that contains the given node + - for all nodes N in the connected subgraph containing the given node: + - visited[N.index] == false + ensures + - checks the connected subgraph containing the given node for directed cycles + and returns true if any are found and false otherwise. + - for all nodes N in the connected subgraph containing the given node: + - #visited[N.index()] == true + !*/ + { + using namespace std; + if (visited[node.index()] == true) + return true; + + visited[node.index()] = true; + + for (unsigned long i = 0; i < node.number_of_children(); ++i) + { + if (node.child(i).index() != prev && + search_for_undirected_cycles(node.child(i), visited, node.index())) + return true; + } + + for (unsigned long i = 0; i < node.number_of_parents(); ++i) + { + if (node.parent(i).index() != prev && + search_for_undirected_cycles(node.parent(i), visited, node.index())) + return true; + } + + return false; + } + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + typename enable_if,bool>::type search_for_undirected_cycles ( + const T& node, + std::vector& visited, + unsigned long prev = -1 + ) + /*! + requires + - visited.size() >= number of nodes in the graph that contains the given node + - for all nodes N in the connected subgraph containing the given node: + - visited[N.index] == false + ensures + - checks the connected subgraph containing the given node for directed cycles + and returns true if any are found and false otherwise. + - for all nodes N in the connected subgraph containing the given node: + - #visited[N.index()] == true + !*/ + { + using namespace std; + if (visited[node.index()] == true) + return true; + + visited[node.index()] = true; + + for (unsigned long i = 0; i < node.number_of_neighbors(); ++i) + { + if (node.neighbor(i).index() != prev && + search_for_undirected_cycles(node.neighbor(i), visited, node.index())) + return true; + } + + return false; + } + + } + +// ------------------------------------------------------------------------------------ + + template < + typename graph_type1, + typename graph_type2 + > + typename enable_if >::type copy_graph_structure ( + const graph_type1& src, + graph_type2& dest + ) + { + COMPILE_TIME_ASSERT(is_graph::value); + COMPILE_TIME_ASSERT(is_graph::value); + if (graph_helpers::is_same_object(src,dest)) + return; + + dest.clear(); + dest.set_number_of_nodes(src.number_of_nodes()); + + // copy all the edges from src into dest + for (unsigned long i = 0; i < src.number_of_nodes(); ++i) + { + for (unsigned long j = 0; j < src.node(i).number_of_neighbors(); ++j) + { + const unsigned long nidx = src.node(i).neighbor(j).index(); + if (nidx >= i) + { + dest.add_edge(i,nidx); + } + } + } + } + + template < + typename graph_type1, + typename graph_type2 + > + typename enable_if >::type copy_graph_structure ( + const graph_type1& src, + graph_type2& dest + ) + { + COMPILE_TIME_ASSERT(is_directed_graph::value); + COMPILE_TIME_ASSERT(is_directed_graph::value || is_graph::value ); + if (graph_helpers::is_same_object(src,dest)) + return; + + dest.clear(); + dest.set_number_of_nodes(src.number_of_nodes()); + + // copy all the edges from src into dest + for (unsigned long i = 0; i < src.number_of_nodes(); ++i) + { + for (unsigned long j = 0; j < src.node(i).number_of_children(); ++j) + { + const unsigned long nidx = src.node(i).child(j).index(); + if (dest.has_edge(i,nidx) == false) + { + dest.add_edge(i,nidx); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename S + > + typename enable_if >::type find_connected_nodes ( + const T& n, + S& visited + ) + { + if (visited.is_member(n.index()) == false) + { + unsigned long temp = n.index(); + visited.add(temp); + + for (unsigned long i = 0; i < n.number_of_neighbors(); ++i) + find_connected_nodes(n.neighbor(i), visited); + } + } + + template < + typename T, + typename S + > + typename enable_if >::type find_connected_nodes ( + const T& n, + S& visited + ) + { + if (visited.is_member(n.index()) == false) + { + unsigned long temp = n.index(); + visited.add(temp); + + for (unsigned long i = 0; i < n.number_of_parents(); ++i) + find_connected_nodes(n.parent(i), visited); + for (unsigned long i = 0; i < n.number_of_children(); ++i) + find_connected_nodes(n.child(i), visited); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_is_connected ( + const T& g + ) + { + if (g.number_of_nodes() == 0) + return true; + + set::kernel_1b_c visited; + find_connected_nodes(g.node(0), visited); + return (visited.size() == g.number_of_nodes()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_contains_directed_cycle ( + const T& graph + ) + { + using namespace std; + using namespace graph_helpers; + std::vector visited(graph.number_of_nodes(), false); + std::vector temp(graph.number_of_nodes(), false); + + while (true) + { + // find the first node that hasn't been visited yet + unsigned long i; + for (i = 0; i < visited.size(); ++i) + { + if (visited[i] == false) + break; + } + + // if we didn't find any non-visited nodes then we are done + if (i == visited.size()) + return false; + + if (search_for_directed_cycles(graph.node(i), visited, temp)) + return true; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_contains_undirected_cycle ( + const T& graph + ) + { + using namespace std; + using namespace graph_helpers; + std::vector visited(graph.number_of_nodes(), false); + + while (true) + { + // find the first node that hasn't been visited yet + unsigned long i; + for (i = 0; i < visited.size(); ++i) + { + if (visited[i] == false) + break; + } + + // if we didn't find any non-visited nodes then we are done + if (i == visited.size()) + return false; + + if (search_for_undirected_cycles(graph.node(i), visited)) + return true; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename directed_graph_type, + typename graph_type + > + void create_moral_graph ( + const directed_graph_type& g, + graph_type& moral_graph + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(graph_contains_directed_cycle(g) == false, + "\tvoid create_moral_graph(g, moral_graph)" + << "\n\tYou can only make moral graphs if g doesn't have directed cycles" + ); + COMPILE_TIME_ASSERT(is_graph::value); + COMPILE_TIME_ASSERT(is_directed_graph::value); + + copy_graph_structure(g, moral_graph); + + // now marry all the parents (i.e. add edges between parent nodes) + for (unsigned long i = 0; i < g.number_of_nodes(); ++i) + { + // loop over all combinations of parents of g.node(i) + for (unsigned long j = 0; j < g.node(i).number_of_parents(); ++j) + { + for (unsigned long k = 0; k < g.node(i).number_of_parents(); ++k) + { + const unsigned long p1 = g.node(i).parent(j).index(); + const unsigned long p2 = g.node(i).parent(k).index(); + if (p1 == p2) + continue; + + if (moral_graph.has_edge(p1,p2) == false) + moral_graph.add_edge(p1,p2); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename sets_of_int + > + bool is_clique ( + const graph_type& g, + const sets_of_int& clique + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(graph_contains_length_one_cycle(g) == false, + "\tvoid is_clique(g, clique)" + << "\n\tinvalid graph" + ); +#ifdef ENABLE_ASSERTS + clique.reset(); + while (clique.move_next()) + { + const unsigned long x = clique.element(); + DLIB_ASSERT( x < g.number_of_nodes(), + "\tvoid is_clique(g, clique)" + << "\n\tthe clique set contained an invalid node index" + << "\n\tx: " << x + << "\n\tg.number_of_nodes(): " << g.number_of_nodes() + ); + } +#endif + + COMPILE_TIME_ASSERT(is_graph::value); + + std::vector v; + v.reserve(clique.size()); + clique.reset(); + while (clique.move_next()) + { + v.push_back(clique.element()); + } + + for (unsigned long i = 0; i < v.size(); ++i) + { + for (unsigned long j = 0; j < v.size(); ++j) + { + if (v[i] == v[j]) + continue; + if (g.has_edge(v[i], v[j]) == false) + return false; + } + } + + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename sets_of_int + > + bool is_maximal_clique ( + const graph_type& g, + const sets_of_int& clique + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(graph_contains_length_one_cycle(g) == false, + "\tvoid is_maximal_clique(g, clique)" + << "\n\tinvalid graph" + ); + DLIB_ASSERT(is_clique(g,clique) == true, + "\tvoid is_maximal_clique(g, clique)" + << "\n\tinvalid graph" + ); +#ifdef ENABLE_ASSERTS + clique.reset(); + while (clique.move_next()) + { + const unsigned long x = clique.element(); + DLIB_ASSERT( x < g.number_of_nodes(), + "\tvoid is_maximal_clique(g, clique)" + << "\n\tthe clique set contained an invalid node index" + << "\n\tx: " << x + << "\n\tg.number_of_nodes(): " << g.number_of_nodes() + ); + } +#endif + + COMPILE_TIME_ASSERT(is_graph::value); + + if (clique.size() == 0) + return true; + + // get an element in the clique and make sure that + // none of its neighbors that aren't in the clique are connected + // to all the elements of the clique. + clique.reset(); + clique.move_next(); + const unsigned long idx = clique.element(); + + for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i) + { + const unsigned long n = g.node(idx).neighbor(i).index(); + if (clique.is_member(n)) + continue; + + // now loop over all the clique members and make sure they don't all + // share an edge with node n + bool all_share_edge = true; + clique.reset(); + while (clique.move_next()) + { + if (g.has_edge(clique.element(), n) == false) + { + all_share_edge = false; + break; + } + } + + if (all_share_edge == true) + return false; + } + + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename enable_if,bool>::type graph_contains_length_one_cycle ( + const T& graph + ) + { + for (unsigned long i = 0; i < graph.number_of_nodes(); ++i) + { + // make sure none of this guys children are actually itself + for (unsigned long n = 0; n < graph.node(i).number_of_children(); ++n) + { + if (graph.node(i).child(n).index() == i) + return true; + } + } + + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename enable_if,bool>::type graph_contains_length_one_cycle ( + const T& graph + ) + { + for (unsigned long i = 0; i < graph.number_of_nodes(); ++i) + { + // make sure none of this guys neighbors are actually itself + for (unsigned long n = 0; n < graph.node(i).number_of_neighbors(); ++n) + { + if (graph.node(i).neighbor(n).index() == i) + return true; + } + } + + return false; + } + +// ---------------------------------------------------------------------------------------- + + namespace graph_helpers + { + struct pair + { + unsigned long index; + unsigned long num_neighbors; + + bool operator< (const pair& p) const { return num_neighbors < p.num_neighbors; } + }; + + template < + typename T, + typename S, + typename V + > + void search_graph_for_triangulate ( + const T& n, + S& visited, + V& order_visited + ) + { + // base case of recursion. stop when we hit a node we have + // already visited. + if (visited.is_member(n.index())) + return; + + // record that we have visited this node + order_visited.push_back(n.index()); + unsigned long temp = n.index(); + visited.add(temp); + + // we want to visit all the neighbors of this node but do + // so by visiting the nodes with the most neighbors first. So + // lets make a vector that lists the nodes in the order we + // want to visit them + std::vector neighbors; + for (unsigned long i = 0; i < n.number_of_neighbors(); ++i) + { + pair p; + p.index = i; + p.num_neighbors = n.neighbor(i).number_of_neighbors(); + neighbors.push_back(p); + } + + // now sort the neighbors array so that the neighbors with the + // most neighbors come first. + std::sort(neighbors.rbegin(), neighbors.rend()); + + // now visit all the nodes + for (unsigned long i = 0; i < neighbors.size(); ++i) + { + search_graph_for_triangulate(n.neighbor(neighbors[i].index), visited, order_visited); + } + } + } // end namespace graph_helpers + + template < + typename graph_type, + typename set_of_sets_of_int + > + void triangulate_graph_and_find_cliques ( + graph_type& g, + set_of_sets_of_int& cliques + ) + { + + // make sure requires clause is not broken + DLIB_ASSERT(graph_contains_length_one_cycle(g) == false, + "\tvoid triangulate_graph_and_find_cliques(g, cliques)" + << "\n\tInvalid graph" + ); + DLIB_ASSERT(graph_is_connected(g) == true, + "\tvoid triangulate_graph_and_find_cliques(g, cliques)" + << "\n\tInvalid graph" + ); + + COMPILE_TIME_ASSERT(is_graph::value); + + + using namespace graph_helpers; + using namespace std; + typedef typename set_of_sets_of_int::type set_of_int; + + cliques.clear(); + + // first we find the node with the most neighbors + unsigned long max_index = 0; + unsigned long num_neighbors = 0; + for (unsigned long i = 0; i < g.number_of_nodes(); ++i) + { + if (g.node(i).number_of_neighbors() > num_neighbors) + { + max_index = i; + num_neighbors = g.node(i).number_of_neighbors(); + } + } + + // now we do a depth first search of the entire graph starting + // with the node we just found. We record the order in which + // we visit each node in the vector order_visited. + std::vector order_visited; + set_of_int visited; + search_graph_for_triangulate(g.node(max_index), visited, order_visited); + + set_of_int clique; + + // now add edges to the graph to make it triangulated + while (visited.size() > 0) + { + // we are going to enumerate over the nodes in the reverse of the + // order in which they were visited. So get the last node out. + const unsigned long idx = order_visited.back(); + order_visited.pop_back(); + visited.destroy(idx); + + // as a start add this node to our current clique + unsigned long temp = idx; + clique.clear(); + clique.add(temp); + + // now we want to make a clique that contains node g.node(idx) and + // all of its neighbors that are still recorded in the visited set + // (except for neighbors that have only one edge). + for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i) + { + // get the index of the i'th neighbor + unsigned long nidx = g.node(idx).neighbor(i).index(); + + // add it to the clique if it is still in visited and it isn't + // a node with only one neighbor + if (visited.is_member(nidx) == true && + g.node(nidx).number_of_neighbors() != 1) + { + // add edges between this new node and all the nodes + // that are already in the clique + clique.reset(); + while (clique.move_next()) + { + if (g.has_edge(nidx, clique.element()) == false) + g.add_edge(nidx, clique.element()); + } + + // now also record that we added this node to the clique + clique.add(nidx); + } + } + + if (cliques.is_member(clique) == false && is_maximal_clique(g,clique) ) + { + cliques.add(clique); + } + + // now it is possible that we are missing some cliques of size 2 since + // above we didn't add nodes with only one edge to any of our cliques. + // Now lets make sure all these nodes are accounted for + for (unsigned long i = 0; i < g.number_of_nodes(); ++i) + { + clique.clear(); + if (g.node(i).number_of_neighbors() == 1) + { + unsigned long temp = i; + clique.add(temp); + temp = g.node(i).neighbor(0).index(); + clique.add(temp); + + if (cliques.is_member(clique) == false) + cliques.add(clique); + } + } + } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename join_tree_type + > + void create_join_tree ( + const graph_type& g, + join_tree_type& join_tree + ) + { + // make sure requires clause is not broken + DLIB_ASSERT(graph_contains_length_one_cycle(g) == false, + "\tvoid create_join_tree(g, join_tree)" + << "\n\tInvalid graph" + ); + DLIB_ASSERT(graph_is_connected(g) == true, + "\tvoid create_join_tree(g, join_tree)" + << "\n\tInvalid graph" + ); + + COMPILE_TIME_ASSERT(is_graph::value); + COMPILE_TIME_ASSERT(is_graph::value); + + + + typedef typename join_tree_type::type set_of_int; + typedef typename join_tree_type::edge_type set_of_int_edge; + typedef typename set::kernel_1b_c set_of_sets_of_int; + + copy_graph_structure(g, join_tree); + + // don't even bother in this case + if (g.number_of_nodes() == 0) + return; + + set_of_sets_of_int cliques; + set_of_int s; + + triangulate_graph_and_find_cliques(join_tree, cliques); + + join_tree.set_number_of_nodes(cliques.size()); + + // copy the cliques into each of the nodes of tree + for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i) + { + cliques.remove_any(s); + s.swap(join_tree.node(i).data); + } + + set_of_int_edge e; + + // add all possible edges to the join_tree + for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i) + { + for (unsigned long j = i+1; j < join_tree.number_of_nodes(); ++j) + { + set_intersection( + join_tree.node(i).data, + join_tree.node(j).data, + e); + + if (e.size() > 0) + { + join_tree.add_edge(i,j); + edge(join_tree,i,j).swap(e); + } + } + } + + // now we just need to remove the unnecessary edges so that we get a + // proper join tree + s.clear(); + set_of_int& good = s; // rename s to something slightly more meaningful + // good will contain nodes that have been "approved" + unsigned long n = 0; + good.add(n); + + std::vector vtemp; + + while (good.size() < join_tree.number_of_nodes()) + { + // figure out which of the neighbors of nodes in good has the best edge + unsigned long best_bad_idx = 0; + unsigned long best_good_idx = 0; + unsigned long best_overlap = 0; + good.reset(); + while (good.move_next()) + { + // loop over all the neighbors of the current node in good + for (unsigned long i = 0; i < join_tree.node(good.element()).number_of_neighbors(); ++i) + { + const unsigned long idx = join_tree.node(good.element()).neighbor(i).index(); + if (!good.is_member(idx)) + { + const unsigned long overlap = join_tree.node(good.element()).edge(i).size(); + + if (overlap > best_overlap) + { + best_overlap = overlap; + best_bad_idx = idx; + best_good_idx = good.element(); + } + } + } + } + + // now remove all the edges from best_bad_idx to the nodes in good except for the + // edge to best_good_idx. + for (unsigned long i = 0; i < join_tree.node(best_bad_idx).number_of_neighbors(); ++i) + { + const unsigned long idx = join_tree.node(best_bad_idx).neighbor(i).index(); + if (idx != best_good_idx && good.is_member(idx)) + { + vtemp.push_back(idx); + } + } + + for (unsigned long i = 0; i < vtemp.size(); ++i) + join_tree.remove_edge(vtemp[i], best_bad_idx); + + vtemp.clear(); + + + // and finally add this bad index into the good set + good.add(best_bad_idx); + } + } + +// ---------------------------------------------------------------------------------------- + + namespace graph_helpers + { + template < + typename T, + typename U + > + bool validate_join_tree ( + const T& n, + U& deads, + unsigned long parent = 0xffffffff + ) + /*! + this function makes sure that a join tree satisfies the following criterion for paths starting at the given node: + - for all valid i and j such that i and j are both < #join_tree.number_of_nodes() + - let X be the set of numbers that is contained in both #join_tree.node(i).data + and #join_tree.node(j).data + - It is the case that all nodes on the unique path between #join_tree.node(i) + and #join_tree.node(j) contain the numbers from X in their sets. + + returns true if validation passed and false if there is a problem with the tree + !*/ + { + n.data.reset(); + while (n.data.move_next()) + { + if (deads.is_member(n.data.element())) + return false; + } + + + for (unsigned long i = 0; i < n.number_of_neighbors(); ++i) + { + if (n.neighbor(i).index() == parent) + continue; + + // add anything to dead stuff + n.data.reset(); + while (n.data.move_next()) + { + if (n.neighbor(i).data.is_member(n.data.element()) == false) + { + unsigned long temp = n.data.element(); + deads.add(temp); + } + } + + if (validate_join_tree(n.neighbor(i), deads, n.index()) == false) + return false; + + // remove this nodes stuff from dead stuff + n.data.reset(); + while (n.data.move_next()) + { + if (n.neighbor(i).data.is_member(n.data.element()) == false) + { + unsigned long temp = n.data.element(); + deads.destroy(temp); + } + } + } + + return true; + } + } + + template < + typename graph_type, + typename join_tree_type + > + bool is_join_tree ( + const graph_type& g, + const join_tree_type& join_tree + ) + { + + // make sure requires clause is not broken + DLIB_ASSERT(graph_contains_length_one_cycle(g) == false, + "\tvoid create_join_tree(g, join_tree)" + << "\n\tInvalid graph" + ); + DLIB_ASSERT(graph_is_connected(g) == true, + "\tvoid create_join_tree(g, join_tree)" + << "\n\tInvalid graph" + ); + + COMPILE_TIME_ASSERT(is_graph::value || is_directed_graph::value); + COMPILE_TIME_ASSERT(is_graph::value); + + + if (graph_contains_undirected_cycle(join_tree)) + return false; + + if (graph_is_connected(join_tree) == false) + return false; + + // verify that the path condition of the join tree is valid + for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i) + { + typename join_tree_type::type deads; + if (graph_helpers::validate_join_tree(join_tree.node(i), deads) == false) + return false; + } + + typename join_tree_type::edge_type e; + typename join_tree_type::edge_type all; + // now make sure that the edges contain correct intersections + for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i) + { + set_union(all,join_tree.node(i).data, all); + for (unsigned long j = 0; j < join_tree.node(i).number_of_neighbors(); ++j) + { + set_intersection(join_tree.node(i).data, + join_tree.node(i).neighbor(j).data, + e); + + if (!(e == join_tree.node(i).edge(j))) + return false; + } + } + + // and finally check that all the nodes in g show up in the join tree + if (all.size() != g.number_of_nodes()) + return false; + all.reset(); + while (all.move_next()) + { + if (all.element() >= g.number_of_nodes()) + return false; + } + + + return true; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GRAPH_UTILs_ + + diff --git a/dlib/graph_utils/graph_utils_abstract.h b/dlib/graph_utils/graph_utils_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..991a8caf2759cf6994514e7a6299700ecf2f19e3 --- /dev/null +++ b/dlib/graph_utils/graph_utils_abstract.h @@ -0,0 +1,373 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_GRAPH_UTILs_ABSTRACT_ +#ifdef DLIB_GRAPH_UTILs_ABSTRACT_ + +#include "../directed_graph.h" +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename T::edge_type& edge( + T& g, + unsigned long i, + unsigned long j + ); + /*! + requires + - T is an implementation of graph/graph_kernel_abstract.h + - g.has_edge(i,j) + ensures + - returns a reference to the edge data for the edge connecting nodes i and j + (i.e. returns g.node(i).edge(x) such that g.node(i).neighbor(x).index() == j) + !*/ + + template < + typename T + > + typename const T::edge_type& edge( + const T& g, + unsigned long i, + unsigned long j + ); + /*! + requires + - T is an implementation of graph/graph_kernel_abstract.h + - g.has_edge(i,j) + ensures + - returns a const reference to the edge data for the edge connecting nodes i and j + (i.e. returns g.node(i).edge(x) such that g.node(i).neighbor(x).index() == j) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_contains_directed_cycle ( + const T& graph + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h + ensures + - if (there is a directed cycle in the given graph) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_contains_undirected_cycle ( + const T& graph + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or + T is an implementation of graph/graph_kernel_abstract.h + ensures + - if (there is an undirected cycle in the given graph) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_contains_length_one_cycle ( + const T& graph + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or + T is an implementation of graph/graph_kernel_abstract.h + ensures + - if (it is the case that graph.has_edge(i,i) == true for some i) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename src_type, + typename dest_type + > + void copy_graph_structure ( + const src_type& src, + dest_type& dest + ); + /*! + requires + - src_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or + src_type is an implementation of graph/graph_kernel_abstract.h + - dest_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or + dest_type is an implementation of graph/graph_kernel_abstract.h + - dest_type is not a directed_graph when src_type is a graph + ensures + - this function copies the graph structure from src into dest + - #dest.number_of_nodes() == src.number_of_nodes() + - for all valid i: #dest.node(i).item has an initial value for its type + - for all valid i and j: + - if (src.has_edge(i,j) == true) then + - #dest.has_edge(i,j) == true + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename directed_graph_type, + typename graph_type + > + void create_moral_graph ( + const directed_graph_type& g, + graph_type& moral_graph + ); + /*! + requires + - directed_graph_type is an implementation of directed_graph/directed_graph_kernel_abstract.h + - graph_type is an implementation of graph/graph_kernel_abstract.h + - graph_contains_directed_cycle(g) == false + ensures + - #moral_graph == the moralized version of the directed graph g + - #moral_graph.number_of_nodes() == g.number_of_nodes() + - for all valid i and j: + - if (g.has_edge(i,j) == true) then + - #moral_graph.has_edge(i,j) == true + (i.e. all the edges that are in g are also in moral_graph) + - for all valid i: + - for all pairs p1 and p2 such that p1 != p2 and g.node(p1) and g.node(p2) are both + parents of node g.node(i): + - #moral_graph.has_edge(p1,p2) == true + (i.e. all the parents of a node are connected in the moral graph) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename S + > + void find_connected_nodes ( + const T& n, + S& visited + ); + /*! + requires + - T is a node_type from an implementation of directed_graph/directed_graph_kernel_abstract.h or + T is a node_type from an implementation of graph/graph_kernel_abstract.h + - S is an implementation of set/set_kernel_abstract.h + ensures + - let G be the graph that contains node n + - #visited.is_member(n.index()) == true + - for all i such that there is an undirected path from n to G.node(i): + - #visited.is_member(i) == true + - for all i such that visited.is_member(i): + - #visited.is_member(i) == true + (i.e. this function doesn't remove anything from visited. So if + it contains stuff when you call this function then it will still + contain those things once the function ends) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool graph_is_connected ( + const T& g + ); + /*! + requires + - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or + T is an implementation of graph/graph_kernel_abstract.h + ensures + - every node in g has an undirected path to every other node in g. + I.e. g is a connected graph + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename sets_of_int + > + bool is_clique ( + const graph_type& g, + const sets_of_int& clique + ); + /*! + requires + - graph_type is an implementation of graph/graph_kernel_abstract.h + - sets_of_int is an implementation of set/set_kernel_abstract.h + and it contains unsigned long objects. + - graph_contains_length_one_cycle(g) == false + - for all x such that clique.is_member(x): + - x < g.number_of_nodes() + ensures + - if (it is true that for all i and j such that clique.is_member(i) and + clique.is_member(j) then g.has_edge(i,j) == true) then + - returns true + - else + - returns false + - if (clique.size() == 0) then + - returns true + (this is just a special case of the above condition) + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename sets_of_int + > + bool is_maximal_clique ( + const graph_type& g, + const sets_of_int& clique + ); + /*! + requires + - graph_type is an implementation of graph/graph_kernel_abstract.h + - sets_of_int is an implementation of set/set_kernel_abstract.h + and it contains unsigned long objects. + - graph_contains_length_one_cycle(g) == false + - for all x such that clique.is_member(x): + - x < g.number_of_nodes() + - is_clique(g,clique) == true + ensures + - if (there is no x such that clique.is_member(x) == false + and g.has_edge(i,x) for all i such that cliques.is_member(i)) then + - returns true + - else + - returns false + - if (clique.size() == 0) then + - returns true + (this is just a special case of the above condition) + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename set_of_sets_of_int + > + void triangulate_graph_and_find_cliques ( + graph_type& g, + set_of_sets_of_int& cliques + ); + /*! + requires + - graph_type is an implementation of graph/graph_kernel_abstract.h + - set_of_sets_of_int is an implementation of set/set_kernel_abstract.h + and it contains another set object which is comparable by operator< and + itself contains unsigned long objects. + (e.g. set::compare_1a>::kernel_1a) + - graph_contains_length_one_cycle(g) == false + - graph_is_connected(g) == true + ensures + - #g.number_of_nodes() == g.number_of_nodes() + - all this function does to g is add edges to it until g becomes a + chordal graph where a chordal graph is a graph where each cycle + in the graph of 4 or more nodes has an edge joining two nodes + that are not adjacent in the cycle. + - #cliques.size() == the number of maximal cliques in the graph #g + - for all valid sets S such that #cliques.is_member(S): + - for all valid integers i and j such that S.is_member(i) == true + and S.is_member(j) == true and i != j: + - #g.has_edge(i,j) == true + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename join_tree_type + > + bool is_join_tree ( + const graph_type& g, + const join_tree_type& join_tree + ); + /*! + requires + - graph_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or + graph_type is an implementation of graph/graph_kernel_abstract.h + - join_tree_type is an implementation of graph/graph_kernel_abstract.h + - join_tree_type::type is an implementation of set/set_compare_abstract.h and + this set type contains unsigned long objects. + - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and + this set type contains unsigned long objects. + - graph_contains_length_one_cycle(g) == false + - graph_is_connected(g) == true + ensures + - if (join_tree is a valid join tree of graph g. That is, join_tree is a + tree decomposition of g) then + - returns true + - else + - returns false + + - a join tree of graph g is defined as follows: + - graph_contains_undirected_cycle(join_tree) == false + - graph_is_connected(join_tree) == true + - for all valid i: + - join_tree.node(i).item == a non-empty set containing node indexes + from g. That is, this set contains all the nodes from g that are + in this cluster in the join tree + - for all valid i and j such that i and j are both < join_tree.number_of_nodes() + - let X be the set of numbers that is contained in both join_tree.node(i).item + and join_tree.node(j).item + - It is the case that all nodes on the unique path between join_tree.node(i) + and join_tree.node(j) contain the numbers from X in their sets. + - edge(join_tree,i,j) == a set containing the intersection of + join_tree.node(i).item and join_tree.node(j).item + - the node index for every node in g appears in some node in join_tree at + least once. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type, + typename join_tree_type + > + void create_join_tree ( + const graph_type& g, + join_tree_type& join_tree + ); + /*! + requires + - graph_type is an implementation of graph/graph_kernel_abstract.h + - join_tree_type is an implementation of graph/graph_kernel_abstract.h + - join_tree_type::type is an implementation of set/set_compare_abstract.h and + this set type contains unsigned long objects. + - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and + this set type contains unsigned long objects. + - graph_contains_length_one_cycle(g) == false + - graph_is_connected(g) == true + ensures + - #is_join_tree(g, join_tree) == true + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GRAPH_UTILs_ABSTRACT_ + diff --git a/dlib/gui_core.h b/dlib/gui_core.h new file mode 100644 index 0000000000000000000000000000000000000000..d7d2efdfcaafbdb33d7d01c56acc9bd944ef9028 --- /dev/null +++ b/dlib/gui_core.h @@ -0,0 +1,20 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORe_ +#define DLIB_GUI_CORe_ + + +#include "platform.h" + + + +#ifdef WIN32 +#include "gui_core/windows.h" +#else +#include "gui_core/xlib.h" +#endif + + + +#endif // DLIB_GUI_CORe_ + diff --git a/dlib/gui_core/gui_core_kernel_1.cpp b/dlib/gui_core/gui_core_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..241cc1809ef63fdd6bbe48d1dfec1210dc866d64 --- /dev/null +++ b/dlib/gui_core/gui_core_kernel_1.cpp @@ -0,0 +1,2002 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORE_KERNEL_1_CPp_ +#define DLIB_GUI_CORE_KERNEL_1_CPp_ +#include "../platform.h" + +#ifdef WIN32 + +#include "gui_core_kernel_1.h" + +// tell visual studio to link to the libraries we need if we are +// in fact using visual studio +#ifdef _MSC_VER +#pragma comment (lib, "gdi32.lib") +#pragma comment (lib, "comctl32.lib") +#pragma comment (lib, "user32.lib") +#endif + + +#include +#include "../threads.h" +#include "../assert.h" +#include "../queue.h" +#include "../sync_extension.h" +#include "../queue.h" +#include "../logger.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace gui_core_kernel_1_globals + { + + static logger dlog("dlib.gui_core"); + + static TCHAR window_class_name[] = TEXT ("w3049u6qc2d94thw9m34f4we0gvwa3-tgkser0-b9gm 05"); + static HINSTANCE hInstance; + static HWND helper_window = NULL; + + static bool core_has_been_initialized = false; + static bool quit_windows_loop = false; + static bool set_window_title_done = true; + static std::string window_title; + static bool move_window_done = true; + static HWND move_window_hwnd = NULL; + static int move_window_width = 0; + static int move_window_height = 0; + static int move_window_x = 0; + static int move_window_y = 0; + static bool request_new_window = false; + static DWORD dwStyle; + static HWND new_window = NULL; + // the window_table.get_mutex() mutex locks the above 11 variables + + + typedef sync_extension::kernel_1a>::kernel_1a + window_table_type; + + // this variable holds a mapping from window handles to the base_window + // objects which represent them. Note that this objects mutex is always locked + // when inside the event loop. + // Also, put these objects on the heap because we want to ensure that they + // aren't destroyed until the event_handler is destroyed + static window_table_type& window_table = *(new window_table_type); + static rsignaler& window_close_signaler = *(new rsignaler(window_table.get_mutex())); + static rsignaler& et_signaler = *(new rsignaler(window_table.get_mutex())); + + // note that this is the thread that will perform all the event + // processing. + thread_id_type event_thread_id; + + struct user_event_type + { + HWND w; + void* p; + int i; + }; + + typedef sync_extension::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events; + queue_of_user_events user_events; + + enum USER_OFFSETS + { + CREATE_WINDOW, + DESTROY_WINDOW, + SET_ACTIVE_WINDOW, + QUIT_EVENT_HANDLER_THREAD, + USER_EVENTS_READY, + CALL_MOVE_WINDOW, + SHOW_WINDOW_SHOW, + SHOW_WINDOW_HIDE, + CALL_SET_WINDOW_TITLE + }; + + // ---------------------------------------------------------------------------------------- + + struct ebh_param + { + std::string text; + std::string title; + }; + + static void error_box_helper(void* param) + { + ebh_param& p = *reinterpret_cast(param); + + MessageBox (NULL, TEXT (p.text.c_str()), + p.title.c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL + ); + delete &p; + } + + static void error_box ( + const char* title, + const char* text, + bool nonblocking = false + ) + { + try + { + if (nonblocking) + { + ebh_param* param = new ebh_param; + param->text = text; + param->title = title; + dlib::create_new_thread(error_box_helper,param); + } + else + { + MessageBox (NULL, TEXT (text), + title, MB_OK|MB_ICONERROR|MB_SYSTEMMODAL + ); + } + } + catch (...) + { + // we are totally screwed if this happens so just quit + exit(0); + } + } + + // ---------------------------------------------------------------------------------------- + + static bool map_keys ( + unsigned long keycode, + bool shift, + bool caps, + unsigned long& result, + bool& is_printable + ) + /*! + requires + - if (shift was down for this key) then + - shift == true + - if (caps lock was on for this key) then + - caps == true + - keycode == the keycode from windows that we are to process + - keycode < keyboard_keys_size + ensures + - if (this key should be ignored) then + - returns false + - else + - returns true + - #is_printable == true if result is a printable ascii character + - #result == the keycode converted into the proper number to tbe + returned by the event handler. + !*/ + { + is_printable = true; + + if (keycode <= '9' && keycode >= '0') + { + result = keycode; + if (shift) + { + switch (result) + { + case '0': result = ')'; break; + case '1': result = '!'; break; + case '2': result = '@'; break; + case '3': result = '#'; break; + case '4': result = '$'; break; + case '5': result = '%'; break; + case '6': result = '^'; break; + case '7': result = '&'; break; + case '8': result = '*'; break; + case '9': result = '('; break; + } + } + } + else if (keycode <= 'Z' && keycode >= 'A') + { + result = keycode; + + // make the result lower case if we need to. + if (shift && caps || !caps && !shift) + result = result - 'A' + 'a'; + } + else + { + switch (keycode) + { + case VK_BACK: + is_printable = false; + result = base_window::KEY_BACKSPACE; + break; + + case VK_SHIFT: + is_printable = false; + result = base_window::KEY_SHIFT; + break; + + case VK_CONTROL: + is_printable = false; + result = base_window::KEY_CTRL; + break; + + case VK_MENU: + is_printable = false; + result = base_window::KEY_ALT; + break; + + case VK_PAUSE: + is_printable = false; + result = base_window::KEY_PAUSE; + break; + + case VK_CAPITAL: + is_printable = false; + result = base_window::KEY_CAPS_LOCK; + break; + + case VK_ESCAPE: + is_printable = false; + result = base_window::KEY_ESC; + break; + + case VK_PRIOR: + is_printable = false; + result = base_window::KEY_PAGE_UP; + break; + + case VK_NEXT: + is_printable = false; + result = base_window::KEY_PAGE_DOWN; + break; + + case VK_END: + is_printable = false; + result = base_window::KEY_END; + break; + + case VK_HOME: + is_printable = false; + result = base_window::KEY_HOME; + break; + + case VK_LEFT: + is_printable = false; + result = base_window::KEY_LEFT; + break; + + case VK_RIGHT: + is_printable = false; + result = base_window::KEY_RIGHT; + break; + + case VK_UP: + is_printable = false; + result = base_window::KEY_UP; + break; + + case VK_DOWN: + is_printable = false; + result = base_window::KEY_DOWN; + break; + + case VK_INSERT: + is_printable = false; + result = base_window::KEY_INSERT; + break; + + case VK_DELETE: + is_printable = false; + result = base_window::KEY_DELETE; + break; + + case 0x91: + is_printable = false; + result = base_window::KEY_SCROLL_LOCK; + break; + + case VK_F1: + is_printable = false; + result = base_window::KEY_F1; + break; + + case VK_F2: + is_printable = false; + result = base_window::KEY_F2; + break; + + case VK_F3: + is_printable = false; + result = base_window::KEY_F3; + break; + + case VK_F4: + is_printable = false; + result = base_window::KEY_F4; + break; + + case VK_F5: + is_printable = false; + result = base_window::KEY_F5; + break; + + case VK_F6: + is_printable = false; + result = base_window::KEY_F6; + break; + + case VK_F7: + is_printable = false; + result = base_window::KEY_F7; + break; + + case VK_F8: + is_printable = false; + result = base_window::KEY_F8; + break; + + case VK_F9: + is_printable = false; + result = base_window::KEY_F9; + break; + + case VK_F10: + is_printable = false; + result = base_window::KEY_F10; + break; + + case VK_F11: + is_printable = false; + result = base_window::KEY_F11; + break; + + case VK_F12: + is_printable = false; + result = base_window::KEY_F12; + break; + + + case VK_SPACE: result = ' '; break; + case VK_TAB: result = '\t'; break; + case VK_RETURN: result = '\n'; break; + case VK_NUMPAD0: result = '0'; break; + case VK_NUMPAD1: result = '1'; break; + case VK_NUMPAD2: result = '2'; break; + case VK_NUMPAD3: result = '3'; break; + case VK_NUMPAD4: result = '4'; break; + case VK_NUMPAD5: result = '5'; break; + case VK_NUMPAD6: result = '6'; break; + case VK_NUMPAD7: result = '7'; break; + case VK_NUMPAD8: result = '8'; break; + case VK_NUMPAD9: result = '9'; break; + + case VK_MULTIPLY: result = '*'; break; + case VK_ADD: result = '+'; break; + case VK_SUBTRACT: result = '-'; break; + case VK_DECIMAL: result = '.'; break; + case VK_DIVIDE: result = '/'; break; + + case VK_OEM_1: + if (shift) result = ':'; + else result = ';'; + break; + + case VK_OEM_PLUS: + if (shift) result = '+'; + else result = '='; + break; + + case VK_OEM_COMMA: + if (shift) result = '<'; + else result = ','; + break; + + case VK_OEM_MINUS: + if (shift) result = '_'; + else result = '-'; + break; + + case VK_OEM_PERIOD: + if (shift) result = '>'; + else result = '.'; + break; + + case VK_OEM_2: + if (shift) result = '?'; + else result = '/'; + break; + + case VK_OEM_3: + if (shift) result = '~'; + else result = '`'; + break; + + case VK_OEM_4: + if (shift) result = '{'; + else result = '['; + break; + + case VK_OEM_5: + if (shift) result = '|'; + else result = '\\'; + break; + + case VK_OEM_6: + if (shift) result = '}'; + else result = ']'; + break; + + case VK_OEM_7: + if (shift) result = '"'; + else result = '\''; + break; + + default: + return false; + } + } + + return true; + } + + // ------------------------------------------------------------------------------------ + + LRESULT CALLBACK WndProc ( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) + { + using namespace gui_core_kernel_1_globals; + queue_of_user_events user_events_temp; + // Make the event processing thread have a priority slightly above normal. + // This makes the GUI smother if you do heavy processing in other threads. + HANDLE hand = OpenThread(THREAD_ALL_ACCESS,FALSE,GetCurrentThreadId()); + SetThreadPriority(hand,THREAD_PRIORITY_ABOVE_NORMAL); + CloseHandle(hand); + + auto_mutex M(window_table.get_mutex()); + + try + { + std::vector bitmap_buffer; + + bool is_double = false; + unsigned long btn = base_window::NONE; + + switch (message) + { + case WM_USER+QUIT_EVENT_HANDLER_THREAD: + if (hwnd == helper_window) + { + quit_windows_loop = true; + PostQuitMessage(0); + } + return 0; + + case WM_USER+DESTROY_WINDOW: + if (hwnd == helper_window) + { + DestroyWindow((HWND)wParam); + } + return 0; + + case WM_USER+CALL_MOVE_WINDOW: + if (hwnd == helper_window) + { + MoveWindow( + move_window_hwnd, + move_window_x, + move_window_y, + move_window_width, + move_window_height, + TRUE); + move_window_done = true; + et_signaler.broadcast(); + } + return 0; + + case WM_USER+USER_EVENTS_READY: + if (hwnd == helper_window) + { + // this is the signal to look in the user_events queue + user_events.lock(); + user_events.swap(user_events_temp); + user_events.unlock(); + user_events_temp.reset(); + // now dispatch all these user events + while (user_events_temp.move_next()) + { + base_window** win_ = window_table[user_events_temp.element().w]; + base_window* win; + // if this window exists in the window table then dispatch + // its event. + if (win_) + { + win = *win_; + win->on_user_event( + user_events_temp.element().p, + user_events_temp.element().i + ); + } + } + user_events_temp.clear(); + } + return 0; + + case WM_USER+SET_ACTIVE_WINDOW: + if (hwnd == helper_window) + { + SetActiveWindow((HWND)wParam); + } + return 0; + + case WM_USER+SHOW_WINDOW_SHOW: + if (hwnd == helper_window) + { + ShowWindow((HWND)wParam,SW_SHOW); + BringWindowToTop((HWND)wParam); + } + return 0; + + case WM_USER+SHOW_WINDOW_HIDE: + if (hwnd == helper_window) + { + ShowWindow((HWND)wParam,SW_HIDE); + } + return 0; + + case WM_USER+CALL_SET_WINDOW_TITLE: + if (hwnd == helper_window) + { + SetWindowText((HWND)wParam,window_title.c_str()); + set_window_title_done = true; + et_signaler.broadcast(); + } + return 0; + + + case WM_USER+CREATE_WINDOW: + if (hwnd == helper_window) + { + + // if this is stupposed to be a popup window then do the popup window thing + if (dwStyle == WS_CHILD) + { + new_window = CreateWindowEx (WS_EX_TOOLWINDOW,window_class_name, "", + dwStyle, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + helper_window, NULL, hInstance, NULL); + SetParent(new_window,NULL); + } + else + { + new_window = CreateWindow (window_class_name, "", + dwStyle, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, NULL); + } + // use the helper_window to indicate that CreateWindow failed + if (new_window == NULL) + new_window = helper_window; + et_signaler.broadcast(); + } + return 0; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + unsigned long state = 0; + + bool shift = ((GetKeyState(VK_SHIFT)&0x8000)!=0); + bool ctrl = ((GetKeyState(VK_CONTROL)&0x8000)!=0); + bool caps = ((GetKeyState(VK_CAPITAL)&0x0001)!=0); + if(shift) + state = base_window::KBD_MOD_SHIFT; + if(ctrl) + state |= base_window::KBD_MOD_CONTROL; + if(caps) + state |= base_window::KBD_MOD_CAPS_LOCK; + if((GetKeyState(VK_MENU)&0x8000)!=0) + state |= base_window::KBD_MOD_ALT; + if((GetKeyState(VK_NUMLOCK)&0x0001)!=0) + state |= base_window::KBD_MOD_NUM_LOCK; + if((GetKeyState(VK_SCROLL)&0x0001)!=0) + state |= base_window::KBD_MOD_SCROLL_LOCK; + + + bool is_printable; + unsigned long result; + + if (map_keys(wParam,shift,caps,result,is_printable)) + { + // signal the keyboard event + win->on_keydown(result,is_printable,state); + } + + } + break; + + // treat the user releasing the mouse button on the non client area (e.g. the title bar) + // like focus being lost since that is what X11 does + case WM_NCLBUTTONUP: + case WM_NCMBUTTONUP: + case WM_NCRBUTTONUP: + case WM_SETFOCUS: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + // signal that the window is gaining focus + win->on_focus_gained(); + } + break; + + // treat the user clicking on the non client area (e.g. the title bar) + // like focus being lost since that is what X11 does + case WM_NCLBUTTONDBLCLK: + case WM_NCMBUTTONDBLCLK: + case WM_NCRBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_KILLFOCUS: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + // signal that the window is gaining focus + win->on_focus_lost(); + } + break; + + case WM_SIZE: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + + // signal that the window has been resized + win->on_window_resized(); + + } + return 0; + + case WM_MOVE: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + + // signal that the window has moved + win->on_window_moved(); + + } + return 0; + + case WM_MOUSELEAVE: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + + // signal that the mouse has left the window + if (win->mouse_in) + { + win->on_mouse_leave(); + win->mouse_in = false; + } + + } + return 0; + + case WM_MOUSEWHEEL: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + + // signal the mouse wheel event + if (GET_WHEEL_DELTA_WPARAM(wParam) > 0) + { + win->on_wheel_up(); + } + else + { + win->on_wheel_down(); + } + + } + return 0; + + case WM_LBUTTONUP: + btn = base_window::LEFT; + case WM_MBUTTONUP: + if (btn == base_window::NONE) + btn = base_window::MIDDLE; + case WM_RBUTTONUP: + if (btn == base_window::NONE) + btn = base_window::RIGHT; + { + // release the mouse capture if the user isn't holding any + // other mouse buttons + if (!((wParam & MK_LBUTTON) | (wParam & MK_MBUTTON) | (wParam & MK_RBUTTON))) + ReleaseCapture(); + + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + unsigned long state = 0; + if (wParam & MK_CONTROL) + state |= base_window::CONTROL; + if (wParam & MK_LBUTTON) + state |= base_window::LEFT; + if (wParam & MK_MBUTTON) + state |= base_window::MIDDLE; + if (wParam & MK_RBUTTON) + state |= base_window::RIGHT; + if (wParam & MK_SHIFT) + state |= base_window::SHIFT; + + // remove the clicked button from the state + state &= (~btn); + + // signal the mouse click + win->on_mouse_up(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); + + } + return 0; + + + + case WM_LBUTTONDBLCLK: + if (btn == base_window::NONE) + btn = base_window::LEFT; + case WM_MBUTTONDBLCLK: + if (btn == base_window::NONE) + btn = base_window::MIDDLE; + case WM_RBUTTONDBLCLK: + if (btn == base_window::NONE) + btn = base_window::RIGHT; + is_double = true; + case WM_LBUTTONDOWN: + if (btn == base_window::NONE) + btn = base_window::LEFT; + case WM_MBUTTONDOWN: + if (btn == base_window::NONE) + btn = base_window::MIDDLE; + case WM_RBUTTONDOWN: + if (btn == base_window::NONE) + btn = base_window::RIGHT; + { + SetCapture(hwnd); + + + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + unsigned long state = 0; + if (wParam & MK_CONTROL) + state |= base_window::CONTROL; + if (wParam & MK_LBUTTON) + state |= base_window::LEFT; + if (wParam & MK_MBUTTON) + state |= base_window::MIDDLE; + if (wParam & MK_RBUTTON) + state |= base_window::RIGHT; + if (wParam & MK_SHIFT) + state |= base_window::SHIFT; + + // remove the clicked button from the state + state &= (~btn); + + // signal the mouse click + win->on_mouse_down(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),is_double); + + } + return 0; + + case WM_MOUSEMOVE: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + unsigned long state = 0; + bool mouse_button_down = false; + if (wParam & MK_CONTROL) + state |= base_window::CONTROL; + if (wParam & MK_LBUTTON) + { + state |= base_window::LEFT; + mouse_button_down = true; + } + if (wParam & MK_MBUTTON) + { + mouse_button_down = true; + state |= base_window::MIDDLE; + } + if (wParam & MK_RBUTTON) + { + state |= base_window::RIGHT; + mouse_button_down = true; + } + if (wParam & MK_SHIFT) + state |= base_window::SHIFT; + + // signal the mouse movement if this mouse event isn't identical to the + // last one we got + if ( GET_X_LPARAM(lParam) != win->prevx || + GET_Y_LPARAM(lParam) != win->prevy || + state != win->prev_state) + { + win->on_mouse_move(state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); + } + + // save the event data into the prev* member variables + win->prevx = GET_X_LPARAM(lParam); + win->prevy = GET_Y_LPARAM(lParam); + win->prev_state = state; + + // The following block of code checks if the mouse is moving + // into or out of the window. + if (mouse_button_down == false) + { + // if there isn't any mouse button down then the fact that + // we are getting a mouse move message means it is in the + // window + if (win->mouse_in == false) + { + win->on_mouse_enter(); + win->mouse_in = true; + + // set the tracker for the mouse + TRACKMOUSEEVENT tm; + tm.hwndTrack = hwnd; + tm.cbSize = sizeof(tm); + tm.dwFlags = TME_LEAVE; + _TrackMouseEvent(&tm); + } + } + else if (win->mouse_in) + { + // check if the mouse is currently outside the window + const long mouse_x = GET_X_LPARAM(lParam); + const long mouse_y = GET_Y_LPARAM(lParam); + if (mouse_x < 0 || mouse_y < 0) + { + // the mouse is not in the window + win->mouse_in = false; + win->on_mouse_leave(); + } + else + { + unsigned long width, height; + win->get_size(width,height); + if (mouse_x >= static_cast(width) || + mouse_y >= static_cast(height)) + { + // the mouse is not in the window + win->mouse_in = false; + win->on_mouse_leave(); + } + } + } + else if (win->mouse_in == false) + { + // at this point we know that the mouse is moving around + // with some of its buttons down. So it might be outside the window. + // get the window size and see if the mouse is outside + // it. + const long mouse_x = GET_X_LPARAM(lParam); + const long mouse_y = GET_Y_LPARAM(lParam); + unsigned long width, height; + win->get_size(width,height); + if (mouse_x < static_cast(width) && + mouse_y < static_cast(height) && + mouse_x >= 0 && + mouse_y >= 0) + { + // The mouse has gone inside the window + win->mouse_in = true; + win->on_mouse_enter(); + + // set the tracker for the mouse + TRACKMOUSEEVENT tm; + tm.hwndTrack = hwnd; + tm.cbSize = sizeof(tm); + tm.dwFlags = TME_LEAVE; + _TrackMouseEvent(&tm); + } + + } + + + } + return 0; + + case WM_PAINT : + { + + PAINTSTRUCT ps; + HDC hdc = NULL; + + hdc = BeginPaint (hwnd, &ps) ; + + try + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + + + + LONG x = ps.rcPaint.left; + LONG y = ps.rcPaint.top; + LONG width = ps.rcPaint.right - x; + LONG height = ps.rcPaint.bottom - y; + + if (width != 0 && height != 0) + { + + BITMAPINFO bmap_info; + bmap_info.bmiColors[0].rgbBlue = 0; + bmap_info.bmiColors[0].rgbGreen = 0; + bmap_info.bmiColors[0].rgbRed = 0; + bmap_info.bmiColors[0].rgbReserved = 0; + bmap_info.bmiHeader.biSize = sizeof(bmap_info.bmiHeader); + bmap_info.bmiHeader.biWidth = width; + bmap_info.bmiHeader.biHeight = -1*height; + bmap_info.bmiHeader.biPlanes = 1; + bmap_info.bmiHeader.biBitCount = 24; + bmap_info.bmiHeader.biCompression = BI_RGB; + bmap_info.bmiHeader.biSizeImage = 0; + bmap_info.bmiHeader.biXPelsPerMeter = 0; + bmap_info.bmiHeader.biYPelsPerMeter = 0; + bmap_info.bmiHeader.biClrUsed = 0; + bmap_info.bmiHeader.biClrImportant = 0; + + + + unsigned char* bitmap ; + unsigned long size; + unsigned long padding = 0; + if ((width*3)%sizeof(LONG) != 0) + { + padding = sizeof(LONG) - (width*3)%sizeof(LONG); + size = (width*3+padding)*height; + } + else + { + size = width*height*3; + } + + if (bitmap_buffer.size() < size) + bitmap_buffer.resize(size); + bitmap = &bitmap_buffer[0]; + + canvas bits(bitmap,padding,x,y,x+width-1,y+height-1); + + + + win->paint(bits); + + + + SetDIBitsToDevice ( + hdc, + ps.rcPaint.left, + ps.rcPaint.top, + width, + height, + 0, + 0, + 0, + height, + bitmap, + &bmap_info, + DIB_RGB_COLORS + ); + } + + EndPaint (hwnd, &ps) ; + + } + catch (...) + { + // make sure EndPaint is called even if an exception + // is thrown. + if (hdc != NULL) + EndPaint (hwnd, &ps); + throw; + } + } + return 0 ; + + case WM_ERASEBKGND: + return 1; + + + + + case WM_CLOSE: + { + base_window** win_ = window_table[hwnd]; + base_window* win; + if (win_) + win = *win_; + else + break; + + + // signal that the window is being closed + if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW) + { + DLIB_ASSERT(win->has_been_destroyed == false, + "\tYou called close_window() inside the on_window_close() event but" + << "\n\tthen returned DO_NOT_CLOSE_WINDOW. You can do one or the other but not both." + << "\n\tthis: " << win + ); + // this happens if the on_window_close() callback + // tells us to ignore the close event. + return 0; + } + else + { + if (window_table[hwnd]) + { + window_table.destroy(hwnd); + win->has_been_destroyed = true; + win->hwnd = 0; + gui_core_kernel_1_globals::window_close_signaler.broadcast(); + } + else + { + // in this case the window must have self destructed by + // calling delete this; + return 0; + } + } + + } + return DefWindowProc (hwnd, message, wParam, lParam); + + + default: + break; + + } // switch (message) + + + } + catch (std::exception& e) + { + error_box("Exception thrown in event handler",e.what()); + quit_windows_loop = true; + } + catch (...) + { + error_box("Exception thrown in event handler","Unknown Exception type."); + quit_windows_loop = true; + } + + return DefWindowProc (hwnd, message, wParam, lParam) ; + + } + + // ---------------------------------------------------------------------------------------- + + void show_window ( + HWND hwnd + ) + { + using namespace gui_core_kernel_1_globals; + PostMessage(helper_window,WM_USER+SHOW_WINDOW_SHOW,(WPARAM)hwnd,0); + } + + // ---------------------------------------------------------------------------------------- + + void hide_window ( + HWND hwnd + ) + { + using namespace gui_core_kernel_1_globals; + PostMessage(helper_window,WM_USER+SHOW_WINDOW_HIDE,(WPARAM)hwnd,0); + } + + // ---------------------------------------------------------------------------------------- + + void give_window_focus ( + HWND hwnd + ) + /*! + ensures + - calls SetActiveWindow(hwnd) from the event handling thread. + !*/ + { + using namespace gui_core_kernel_1_globals; + PostMessage(helper_window,WM_USER+SET_ACTIVE_WINDOW,(WPARAM)hwnd,0); + } + + // ---------------------------------------------------------------------------------------- + + void destroy_window ( + HWND hwnd + ) + /*! + ensures + - calls DestroyWindow(hwnd) from the event handling thread. + !*/ + { + using namespace gui_core_kernel_1_globals; + PostMessage(helper_window,WM_USER+DESTROY_WINDOW,(WPARAM)hwnd,0); + } + + // ---------------------------------------------------------------------------------------- + + HWND make_window ( + DWORD dwStyle_ + ) + /*! + ensures + - creates a window by calling CreateWindow and passes on the + dwStyle argument. + - returns the HWND that is returned by CreateWindow + - ensures that CreateWindow is called from the event handler thread + - if (it was unable to create a window) then + - returns NULL or helper_window + !*/ + { + using namespace gui_core_kernel_1_globals; + // if we are running in the event handling thread then just call + // CreateWindow directly + if (get_thread_id() == gui_core_kernel_1_globals::event_thread_id) + { + // if this is stupposed to be a popup window then do the popup window thing + if (dwStyle_ == WS_CHILD) + { + HWND tmp = CreateWindowEx (WS_EX_TOOLWINDOW|WS_EX_TOPMOST, window_class_name, "", + dwStyle_, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + helper_window, NULL, hInstance, NULL); + SetParent(tmp,NULL); + return tmp; + } + else + { + return CreateWindow (window_class_name, "", + dwStyle_, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, NULL); + } + } + else + { + auto_mutex M(window_table.get_mutex()); + // wait for our chance to make a new window request + while (request_new_window) + et_signaler.wait(); + + + dwStyle = dwStyle_; + if (PostMessage(helper_window,WM_USER+CREATE_WINDOW,0,0)==0) + { + throw gui_error("Unable to schedule function for execution in event handling thread."); + } + + // wait for our request to be serviced + while (new_window == NULL) + et_signaler.wait(); + + HWND temp = new_window; + new_window = NULL; + request_new_window = false; + et_signaler.broadcast(); + + // if make_window() returns the helper_window then it means it failed + // to make a new window + if (temp == helper_window) + temp = NULL; + + return temp; + } + } + + // ------------------------------------------------------------------------------------ + + class event_handler_thread : public threaded_object + { + public: + + enum et_state + { + uninitialized, + initialized, + failure_to_init + }; + + et_state status; + + event_handler_thread( + ) + { + status = uninitialized; + register_program_ending_handler(*this, &event_handler_thread::self_destruct); + } + + ~event_handler_thread () + { + using namespace gui_core_kernel_1_globals; + + if (is_alive()) + { + if (PostMessage(helper_window,WM_USER+QUIT_EVENT_HANDLER_THREAD,0,0)==0) + { + dlog << LERROR << "Unable to schedule function for execution in event handling thread."; + } + + wait(); + } + + delete &et_signaler; + delete &window_close_signaler; + delete &window_table; + } + + void self_destruct() + { + delete this; + } + + private: + + void thread ( + ) + { + event_thread_id = get_thread_id(); + + hInstance = GetModuleHandle(NULL); + if (hInstance == NULL) + { + dlog << LFATAL << "Error gathering needed resources"; + + // signal that an error has occurred + window_table.get_mutex().lock(); + status = failure_to_init; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + return; + } + + // register the main window class + WNDCLASS wndclass ; + + wndclass.style = CS_DBLCLKS; + wndclass.lpfnWndProc = dlib::gui_core_kernel_1_globals::WndProc ; + wndclass.cbClsExtra = 0 ; + wndclass.cbWndExtra = 0 ; + wndclass.hInstance = hInstance ; + wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; + wndclass.hbrBackground = 0; + wndclass.lpszMenuName = NULL ; + wndclass.lpszClassName = window_class_name ; + + if (!RegisterClass (&wndclass)) + { + dlog << LFATAL << "Error registering window class"; + + // signal that an error has occurred + window_table.get_mutex().lock(); + status = failure_to_init; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + return; + } + + + // make the helper window that is used to trigger events in the + // event handler loop from other threads + helper_window = CreateWindow(window_class_name,"",WS_DISABLED,0,0,0,0,HWND_MESSAGE,NULL,hInstance,NULL); + if (helper_window == NULL) + { + dlog << LFATAL << "Error gathering needed resources"; + + // signal that an error has occurred + window_table.get_mutex().lock(); + status = failure_to_init; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + return; + } + + // signal that the event thread is now up and running + window_table.get_mutex().lock(); + status = initialized; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + + // start the event handler loop. + /* + A note about this quit_windows_loop thing. If the user is holding + the mouse button down on the title bar of a window it will cause + the PostQuitMessage() function to be ignored!! This extra bool + is a work around to prevent that from happening. + */ + MSG msg; + while (GetMessage (&msg, NULL, 0, 0) && + quit_windows_loop == false) + { + TranslateMessage (&msg) ; + DispatchMessage (&msg) ; + } + } + }; + + // ---------------------------------------------------------------------------------------- + + static event_handler_thread* event_handler = new event_handler_thread; + + void init_gui_core () + { + using namespace dlib::gui_core_kernel_1_globals; + auto_mutex M(window_table.get_mutex()); + + if (core_has_been_initialized == false) + { + core_has_been_initialized = true; + + + // start up the event handler thread + event_handler->start(); + + // wait for the event thread to get up and running + while (event_handler->status == event_handler_thread::uninitialized) + et_signaler.wait(); + + if (event_handler->status == event_handler_thread::failure_to_init) + throw gui_error("Failed to start event thread"); + } + } + + } // end namespace gui_core_kernel_1_globals + +// ---------------------------------------------------------------------------------------- + + void canvas:: + fill ( + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) const + { + const unsigned long red = red_; + const unsigned long green = green_; + const unsigned long blue = blue_; + + const LONG block1 = (blue<<24) | (red<<16) | (green<<8) | blue; + const LONG block2 = (green<<24) | (blue<<16) | (red<<8) | green; + const LONG block3 = (red<<24) | (green<<16) | (blue<<8) | red; + + // remember that row_width is a multiple of 4 because windows + // requires that all bitmaps have row widths that are multiples of 4. + unsigned long size = row_width/4; + for (unsigned long i = 0; i < height_; ++i) + { + unsigned long padding = size%3; + LONG* start = reinterpret_cast(bits+row_width*i); + LONG* end = reinterpret_cast(start) + size - padding; + while (start != end) + { + *start = block1; + ++start; + *start = block2; + ++start; + *start = block3; + ++start; + } + if (padding) + { + *start = block1; + ++start; + --padding; + } + if (padding) + { + *start = block2; + } + } + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + trigger_user_event ( + void* p, + int i + ) + { + using namespace gui_core_kernel_1_globals; + + user_event_type e; + e.w = hwnd; + e.p = p; + e.i = i; + { + auto_mutex M(user_events.get_mutex()); + user_events.enqueue(e); + } + + if (PostMessage(helper_window,WM_USER+USER_EVENTS_READY,0,0)==0) + { + throw gui_error("Unable to schedule function for execution in event handling thread."); + } + } + +// ---------------------------------------------------------------------------------------- + + base_window:: + base_window ( + bool resizable, + bool undecorated + ) : + has_been_destroyed(false), + wm(gui_core_kernel_1_globals::window_table.get_mutex()), + prevx(-1), + prevy(-1), + prev_state(0) + { + DLIB_ASSERT(!(undecorated == true && resizable == true), + "\tbase_window::base_window()" + << "\n\tThere is no such thing as an undecorated window that is resizable by the user." + << "\n\tthis: " << this + ); + + gui_core_kernel_1_globals::init_gui_core(); + + if (resizable) + style = WS_OVERLAPPEDWINDOW; + else if (undecorated) + style = WS_CHILD; + else + style = WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX; + + hwnd = gui_core_kernel_1_globals::make_window(style); + + if (hwnd == NULL) + throw gui_error("unable to create base_window"); + + auto_mutex M(wm); + + mouse_in = false; + + HWND temp = hwnd; + base_window* ttemp = this; + gui_core_kernel_1_globals::window_table.add(temp,ttemp); + } + +// ---------------------------------------------------------------------------------------- + + base_window:: + ~base_window ( + ) + { + close_window(); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + close_window ( + ) + { + auto_mutex M(wm); + if (has_been_destroyed == false) + { + // do this just to make sure no one tries to call this window's + // calbacks. + gui_core_kernel_1_globals::window_table.destroy(hwnd); + gui_core_kernel_1_globals::destroy_window(hwnd); + hwnd = 0; + has_been_destroyed = true; + gui_core_kernel_1_globals::window_close_signaler.broadcast(); + } + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + wait_until_closed ( + ) const + { + auto_mutex M(wm); + while (has_been_destroyed == false) + gui_core_kernel_1_globals::window_close_signaler.wait(); + } + +// ---------------------------------------------------------------------------------------- + + bool base_window:: + is_closed ( + ) const + { + auto_mutex M(wm); + return has_been_destroyed; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + set_title ( + const std::string& title + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::set_title" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + using namespace gui_core_kernel_1_globals; + + // call the SetWindowText function with our arguments but make sure it is from + // the event thread. We have to do this because the SetWindowText() apparently blocks + // until something happens in the event thread so we have to + // do this to avoid possible deadlocks. + auto_mutex M(wm); + + if (get_thread_id() == gui_core_kernel_1_globals::event_thread_id) + { + SetWindowText(hwnd,title.c_str()); + } + else + { + window_title = title; + set_window_title_done = false; + + if (PostMessage(helper_window,WM_USER+CALL_SET_WINDOW_TITLE,(WPARAM)hwnd,0)==0) + { + throw gui_error("Unable to schedule SetWindowText function for execution in event handling thread."); + } + + // wait for any SetWindowText() calls to finish + while (set_window_title_done == false) + et_signaler.wait(); + } + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + show ( + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::show" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + using namespace gui_core_kernel_1_globals; + show_window(hwnd); + if (style != WS_CHILD) + give_window_focus(hwnd); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + hide( + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::hide" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + using namespace gui_core_kernel_1_globals; + hide_window(hwnd); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + set_size ( + int width_, + int height_ + ) + { + using namespace gui_core_kernel_1_globals; + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::set_size" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + << "\n\twidth: " << width_ + << "\n\theight: " << height_ + ); + auto_mutex M(wm); + if (get_thread_id() == gui_core_kernel_1_globals::event_thread_id) + { + RECT info; + GetWindowRect(hwnd,&info); + + int x = info.left; + int y = info.top; + int width; + int height; + + RECT rect; + rect.top = 0; + rect.left = 0; + rect.bottom = height_; + rect.right = width_; + AdjustWindowRectEx(&rect,style,FALSE,0); + + width = std::abs(rect.right - rect.left); + height = std::abs(rect.bottom - rect.top); + + MoveWindow( + hwnd, + x, + y, + width, + height, + TRUE); + } + else + { + RECT info; + GetWindowRect(hwnd,&info); + + int x = info.left; + int y = info.top; + int width; + int height; + + RECT rect; + rect.top = 0; + rect.left = 0; + rect.bottom = height_; + rect.right = width_; + AdjustWindowRectEx(&rect,style,FALSE,0); + + width = std::abs(rect.right - rect.left); + height = std::abs(rect.bottom - rect.top); + + // call the MoveWindow function with our arguments. We + // have to do this because the MoveWindow() apparently blocks + // until something happens in the event thread so we have to + // do this to avoid possible deadlocks. + move_window_hwnd = hwnd; + move_window_x = x; + move_window_y = y; + move_window_width = width; + move_window_height = height; + move_window_done = false; + + if (PostMessage(helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0) + { + throw gui_error("Unable to schedule MoveWindow function for execution in event handling thread."); + } + + // wait for any MoveWindow calls to finish + while (move_window_done == false) + et_signaler.wait(); + } + + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + set_pos ( + long x_, + long y_ + ) + { + using namespace gui_core_kernel_1_globals; + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::set_pos" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + << "\n\tx: " << x_ + << "\n\ty: " << y_ + ); + auto_mutex M(wm); + if (get_thread_id() == gui_core_kernel_1_globals::event_thread_id) + { + RECT info; + GetWindowRect(hwnd,&info); + int width = info.right - info.left; + int height = info.bottom - info.top; + + MoveWindow( + hwnd, + x_, + y_, + width, + height, + TRUE); + + } + else + { + RECT info; + GetWindowRect(hwnd,&info); + int width = info.right - info.left; + int height = info.bottom - info.top; + + + + // call the MoveWindow function with our arguments. We + // have to do this because the MoveWindow() apparently blocks + // until something happens in the event thread so we have to + // do this to avoid possible deadlocks. + move_window_hwnd = hwnd; + move_window_x = x_; + move_window_y = y_; + move_window_width = width; + move_window_height = height; + move_window_done = false; + + if (PostMessage(helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0) + { + throw gui_error("Unable to schedule MoveWindow function for execution in event handling thread."); + } + + // wait for any MoveWindow calls to finish + while (move_window_done == false) + et_signaler.wait(); + } + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + get_pos ( + long& x_, + long& y_ + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::get_pos" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + POINT p; + p.x = 0; + p.y = 0; + ClientToScreen(hwnd,&p); + + x_ = p.x; + y_ = p.y; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + get_display_size ( + unsigned long& width, + unsigned long& height + ) const + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::get_display_size" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + + RECT rc; + GetWindowRect(hwnd, &rc); + + HMONITOR hMonitor; + MONITORINFO mi; + // + // get the nearest monitor to the passed rect. + // + hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST); + + // + // get the work area or entire monitor rect. + // + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + + rc = mi.rcMonitor; + + width = static_cast(rc.right - rc.left); + height = static_cast(rc.bottom - rc.top); + + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + get_size ( + unsigned long& width, + unsigned long& height + ) const + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::get_size" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + + RECT r; + GetClientRect(hwnd,&r); + + width = r.right - r.left; + height = r.bottom - r.top; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + invalidate_rectangle ( + const rectangle& rect + ) + { + if (rect.is_empty() == false && !has_been_destroyed) + { + RECT info; + info.top = rect.top(); + info.left = rect.left(); + info.right = rect.right()+1; + info.bottom = rect.bottom()+1; + + InvalidateRect(hwnd,&info,FALSE); + } + } + +// ---------------------------------------------------------------------------------------- + + void put_on_clipboard ( + const std::string& str + ) + { + using namespace gui_core_kernel_1_globals; + using namespace std; + + init_gui_core(); + + if (OpenClipboard(helper_window)) + { + EmptyClipboard(); + auto_mutex M(window_table.get_mutex()); + + const unsigned long newlines = count(str.begin(),str.end(),'\n'); + + HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE,str.size()+newlines+1); + if (mem != NULL) + { + char* buf = reinterpret_cast(GlobalLock(mem)); + + if (buf != NULL) + { + // copy str into buf while also replacing all the \n with \r\n + for (string::size_type i = 0; i < str.size(); ++i) + { + if (str[i] != '\n') + { + *buf = str[i]; + ++buf; + } + else + { + *buf = '\r'; + ++buf; + *buf = '\n'; + ++buf; + } + } + *buf = '\0'; + GlobalUnlock(mem); + SetClipboardData(CF_TEXT,mem); + } + } + CloseClipboard(); + } + } + +// ---------------------------------------------------------------------------------------- + + void get_from_clipboard ( + std::string& str + ) + { + using namespace gui_core_kernel_1_globals; + using namespace std; + + init_gui_core(); + + auto_mutex M(window_table.get_mutex()); + if (OpenClipboard(helper_window)) + { + + HANDLE data = GetClipboardData(CF_TEXT); + if (data != NULL) + { + char* buf = reinterpret_cast(GlobalLock(data)); + if (buf != 0) + { + str.clear(); + + // copy the data from buf into str while also removing any '\r' + // characters. + while (*buf != '\0') + { + if (*buf != '\r') + str += *buf; + ++buf; + } + + GlobalUnlock(data); + } + else + { + Beep(500,500); + } + } + + CloseClipboard(); + } + } + +// ---------------------------------------------------------------------------------------- + +} + + +#endif // WIN32 + +#endif // DLIB_GUI_CORE_KERNEL_1_CPp_ + diff --git a/dlib/gui_core/gui_core_kernel_1.h b/dlib/gui_core/gui_core_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..6414fd2877d8c98587f055c3d4be2355f871ffda --- /dev/null +++ b/dlib/gui_core/gui_core_kernel_1.h @@ -0,0 +1,378 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORE_KERNEl_1_ +#define DLIB_GUI_CORE_KERNEl_1_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#ifdef DLIB_NO_GUI_SUPPORT +#error "DLIB_NO_GUI_SUPPORT is defined so you can't use the GUI code. Turn DLIB_NO_GUI_SUPPORT off if you want to use it." +#endif + +#include +#include "../windows_magic.h" + + +#include +#include +#include +#include + +#include "gui_core_kernel_abstract.h" + +#ifdef _MSC_VER +// Disable the following warnings for Visual Studio +// +// These two warnings have to do with converting points to and from the LONG +// type. But both these types are 32 bits in windows so it is fine. +#pragma warning(disable: 4244; disable: 4312) +#endif + +#include "../algs.h" +#include "../sync_extension.h" +#include "../binary_search_tree.h" +#include "../threads.h" +#include "../geometry/rectangle.h" +#include "../assert.h" +#include "../queue.h" +#include "../pixel.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class base_window; + namespace gui_core_kernel_1_globals + { + + LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); + + } + +// ---------------------------------------------------------------------------------------- + + class canvas : public rectangle + { + public: + struct pixel + { + unsigned char blue; + unsigned char green; + unsigned char red; + }; + + ~canvas() { } + + inline pixel* operator[] ( + unsigned long row + ) const + { + DLIB_ASSERT(row < height(), + "\tpixel* canvas::operator[]" + << "\n\tyou have to give a row that is less than the height()" + << "\n\tthis: " << this + << "\n\trow: " << row + << "\n\theight(): " << height() + ); + unsigned char* temp = bits + row_width*row; + return reinterpret_cast(temp); + } + + void fill ( + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) const; + + private: + + friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM); + + canvas ( + unsigned char* bits__, + unsigned long padding__, + unsigned long left__, + unsigned long top__, + unsigned long right__, + unsigned long bottom__ + ) : + rectangle(left__,top__,right__,bottom__), + bits(bits__), + width_(width()), + height_(height()), + row_width(width_*3+padding__) + {} + + // restricted functions + canvas(); // normal constructor + canvas(canvas&); // copy constructor + canvas& operator=(canvas&); // assignment operator + + unsigned char* const bits; + const unsigned long width_; + const unsigned long height_; + const unsigned long row_width; + }; + + template <> + struct pixel_traits + { + const static bool rgb = true; + const static bool rgb_alpha = false; + const static bool grayscale = false; + const static bool hsi = false; + const static long num = 3; + static unsigned long max() { return 255;} + const static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + void put_on_clipboard ( + const std::string& str + ); + +// ---------------------------------------------------------------------------------------- + + void get_from_clipboard ( + std::string& str + ); + +// ---------------------------------------------------------------------------------------- + + class base_window + { + friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM); + + HWND hwnd; + DWORD style; + bool has_been_destroyed; + + // This is true if the mouse is in this window. false otherwise. + // also note that this variable is only accessed from the event handling thread + // (except for being initialized below in the constructor, but that is inside + // the window_table mutex so it doesn't matter). + bool mouse_in; + + // this is a copy of the last inputs we sent to the on_mouse_move() event. + long prevx; + long prevy; + long prev_state; + + protected: + const rmutex& wm; + + public: + + base_window ( + bool resizable = true, + bool undecorated = false + ); + + virtual ~base_window ( + ); + + void close_window ( + ); + + bool is_closed ( + ) const; + + void set_title ( + const std::string& title + ); + + virtual void show ( + ); + + virtual void hide( + ); + + void set_size ( + int width_, + int height_ + ); + + void set_pos ( + long x_, + long y_ + ); + + void get_pos ( + long& x_, + long& y_ + ); + + void get_size ( + unsigned long& width, + unsigned long& height + ) const; + + void get_display_size ( + unsigned long& width, + unsigned long& height + ) const; + + void invalidate_rectangle ( + const rectangle& rect + ); + + void trigger_user_event ( + void* p, + int i + ); + + void wait_until_closed ( + ) const; + + enum on_close_return_code + { + DO_NOT_CLOSE_WINDOW, + CLOSE_WINDOW + }; + + enum mouse_state_masks + { + NONE = 0, + LEFT = 1, + RIGHT = 2, + MIDDLE = 4, + SHIFT = 8, + CONTROL = 16 + }; + + enum keyboard_state_masks + { + KBD_MOD_NONE = 0, + KBD_MOD_SHIFT = 1, + KBD_MOD_CONTROL = 2, + KBD_MOD_ALT = 4, + KBD_MOD_META = 8, + KBD_MOD_CAPS_LOCK = 16, + KBD_MOD_NUM_LOCK = 32, + KBD_MOD_SCROLL_LOCK = 64 + }; + + enum non_printable_keyboard_keys + { + KEY_BACKSPACE, + KEY_SHIFT, + KEY_CTRL, + KEY_ALT, + KEY_PAUSE, + KEY_CAPS_LOCK, + KEY_ESC, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_END, + KEY_HOME, + KEY_LEFT, // This is the left arrow key + KEY_RIGHT, // This is the right arrow key + KEY_UP, // This is the up arrow key + KEY_DOWN, // This is the down arrow key + KEY_INSERT, + KEY_DELETE, + KEY_SCROLL_LOCK, + + // Function Keys + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12 + }; + + protected: + + virtual on_close_return_code on_window_close( + ){return CLOSE_WINDOW;} + + virtual void on_user_event ( + void* p, + int i + ){} + + virtual void on_window_resized( + ){} + + virtual void on_window_moved( + ){} + + virtual void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ){} + + virtual void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ){} + + virtual void on_mouse_move ( + unsigned long state, + long x, + long y + ){} + + virtual void on_mouse_leave ( + ){} + + virtual void on_mouse_enter ( + ){} + + virtual void on_wheel_up ( + ){} + + virtual void on_wheel_down ( + ){} + + virtual void on_focus_gained ( + ){} + + virtual void on_focus_lost ( + ){} + + virtual void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ){} + + private: + + virtual void paint ( + const canvas& c + ) =0; + + base_window(base_window&); // copy constructor + base_window& operator=(base_window&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + + +#ifdef NO_MAKEFILE +#include "gui_core_kernel_1.cpp" +#endif + +#endif // DLIB_GUI_CORE_KERNEl_1_ + diff --git a/dlib/gui_core/gui_core_kernel_2.cpp b/dlib/gui_core/gui_core_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e085b3cc9f7a7d50bf3a7b389b39449ab5997926 --- /dev/null +++ b/dlib/gui_core/gui_core_kernel_2.cpp @@ -0,0 +1,1733 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORE_KERNEL_2_CPp_ +#define DLIB_GUI_CORE_KERNEL_2_CPp_ +#include "../platform.h" + +#ifdef POSIX + +#include "gui_core_kernel_2.h" + + +#include +#include +#include +#include +#include "../assert.h" +#include "../queue.h" +#include +#include +#include +#include "../sync_extension.h" +#include "../logger.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace gui_core_kernel_2_globals + { + static logger dlog("dlib.gui_core"); + void event_handler (); + void trigger_user_event_threadproc (void*); + + struct x11_base_windowstuff + { + Window hwnd; + Time last_click_time; + }; + + typedef sync_extension::kernel_1a>::kernel_1a + window_table_type; + + int depth; + Display* disp; + static Screen* screen; + + Atom delete_window; + static Window exit_window; + static std::string clipboard; + static bool core_has_been_initialized = false; + + static int alt_mask = 0; + static int meta_mask = 0; + static int num_lock_mask = 0; + static int scroll_lock_mask = 0; + + // put these objects on the heap because we want to ensure that they + // aren't destroyed until the event_handler_thread_object is destroyed + static window_table_type& window_table = *(new window_table_type); + static rsignaler& window_close_signaler = *(new rsignaler(window_table.get_mutex())); + static rsignaler& et_signaler = *(new rsignaler(window_table.get_mutex())); + + struct user_event_type + { + Window w; + void* p; + int i; + }; + + typedef sync_extension::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events; + queue_of_user_events user_events; + queue_of_user_events user_events_temp; + + // ---------------------------------------------------------------------------------------- + + Bool XCheckIfEventPredicate ( + Display* disp, + XEvent* event, + XPointer arg + ) + /*! + ensures + - if (event is an Expose event for the window pointed to by arg) then + - returns true + - else + - returns false + !*/ + { + if (event->type == Expose) + { + XExposeEvent* e = reinterpret_cast(event); + Window* win= reinterpret_cast(arg); + if (e->window == *win) + { + return 1; + } + } + return 0; + } + + // ---------------------------------------------------------------------------------------- + + static bool map_keys ( + KeySym keycode, + bool shift, + bool caps, + unsigned long& result, + bool& is_printable + ) + /*! + requires + - if (shift was down for this key) then + - shift == true + - if (caps lock was on for this key) then + - caps == true + - keycode == the keycode from windows that we are to process + - keycode < keyboard_keys_size + ensures + - if (this key should be ignored) then + - returns false + - else + - returns true + - #is_printable == true if result is a printable ascii character + - #result == the keycode converted into the proper number to tbe + returned by the event handler. + !*/ + { + is_printable = true; + if (keycode <= 'z' && keycode >= 'a' || + keycode <= 'Z' && keycode >= 'A' || + keycode <= '9' && keycode >= '0') + { + result = keycode; + } + else + { + is_printable = false; + switch (keycode) + { + case XK_Home: result = base_window::KEY_HOME; break; + case XK_Left: result = base_window::KEY_LEFT; break; + case XK_Right: result = base_window::KEY_RIGHT; break; + case XK_Down: result = base_window::KEY_DOWN; break; + case XK_Up: result = base_window::KEY_UP; break; + case XK_Prior: result = base_window::KEY_PAGE_UP; break; + case XK_Next: result = base_window::KEY_PAGE_DOWN; break; + case XK_End: result = base_window::KEY_END; break; + case XK_Escape: result = base_window::KEY_ESC; break; + + case XK_KP_Delete: result = base_window::KEY_DELETE; break; + case XK_KP_Prior: result = base_window::KEY_PAGE_UP; break; + case XK_KP_Next: result = base_window::KEY_PAGE_DOWN; break; + + + case XK_F1: result = base_window::KEY_F1; break; + case XK_F2: result = base_window::KEY_F2; break; + case XK_F3: result = base_window::KEY_F3; break; + case XK_F4: result = base_window::KEY_F4; break; + case XK_F5: result = base_window::KEY_F5; break; + case XK_F6: result = base_window::KEY_F6; break; + case XK_F7: result = base_window::KEY_F7; break; + case XK_F8: result = base_window::KEY_F8; break; + case XK_F9: result = base_window::KEY_F9; break; + case XK_F10: result = base_window::KEY_F10; break; + case XK_F11: result = base_window::KEY_F11; break; + case XK_F12: result = base_window::KEY_F12; break; + + + case XK_Shift_L: result = base_window::KEY_SHIFT; break; + case XK_Shift_R: result = base_window::KEY_SHIFT; break; + case XK_Control_L: result = base_window::KEY_CTRL; break; + case XK_Control_R: result = base_window::KEY_CTRL; break; + case XK_Caps_Lock: result = base_window::KEY_CAPS_LOCK; break; + case XK_Alt_L: result = base_window::KEY_ALT; break; + case XK_Alt_R: result = base_window::KEY_ALT; break; + + + case XK_BackSpace: result = base_window::KEY_BACKSPACE; break; + case XK_Delete: result = base_window::KEY_DELETE; break; + case XK_Scroll_Lock: result = base_window::KEY_SCROLL_LOCK; break; + case XK_Pause: result = base_window::KEY_PAUSE; break; + case XK_Insert: result = base_window::KEY_INSERT; break; + case XK_KP_Insert: result = base_window::KEY_INSERT; break; + + + + + case XK_exclam: + is_printable = true; + result = '!'; break; + case XK_quotedbl: + is_printable = true; + result = '"'; break; + case XK_numbersign: + is_printable = true; + result = '#'; break; + case XK_dollar: + is_printable = true; + result = '$'; break; + case XK_percent: + is_printable = true; + result = '%'; break; + case XK_ampersand: + is_printable = true; + result = '&'; break; + case XK_apostrophe: + is_printable = true; + result = '\''; break; + case XK_parenleft: + is_printable = true; + result = '('; break; + case XK_parenright: + is_printable = true; + result = ')'; break; + case XK_asterisk: + is_printable = true; + result = '*'; break; + case XK_plus: + is_printable = true; + result = '+'; break; + case XK_comma: + is_printable = true; + result = ','; break; + case XK_minus: + is_printable = true; + result = '-'; break; + case XK_period: + is_printable = true; + result = '.'; break; + case XK_slash: + is_printable = true; + result = '/'; break; + case XK_colon: + is_printable = true; + result = ':'; break; + case XK_semicolon: + is_printable = true; + result = ';'; break; + case XK_less: + is_printable = true; + result = '<'; break; + case XK_equal: + is_printable = true; + result = '='; break; + case XK_greater: + is_printable = true; + result = '>'; break; + case XK_question: + is_printable = true; + result = '?'; break; + case XK_at: + is_printable = true; + result = '@'; break; + case XK_grave: + is_printable = true; + result = '`'; break; + case XK_underscore: + is_printable = true; + result = '_'; break; + case XK_asciicircum: + is_printable = true; + result = '^'; break; + case XK_bracketleft: + is_printable = true; + result = '['; break; + case XK_backslash: + is_printable = true; + result = '\\'; break; + case XK_bracketright: + is_printable = true; + result = ']'; break; + case XK_asciitilde: + is_printable = true; + result = '~'; break; + case XK_braceleft: + is_printable = true; + result = '{'; break; + case XK_bar: + is_printable = true; + result = '|'; break; + case XK_braceright: + is_printable = true; + result = '}'; break; + + + + + case XK_space: + is_printable = true; + result = ' '; break; + case XK_Return: + is_printable = true; + result = '\n'; break; + case XK_Tab: + is_printable = true; + result = '\t'; break; + case XK_KP_Divide: + is_printable = true; + result = '/'; break; + case XK_KP_Decimal: + is_printable = true; + result = '.'; break; + case XK_KP_Subtract: + is_printable = true; + result = '-'; break; + case XK_KP_Add: + is_printable = true; + result = '+'; break; + case XK_KP_Multiply: + is_printable = true; + result = '*'; break; + case XK_KP_Equal: + is_printable = true; + result = '='; break; + + case XK_KP_0: + is_printable = true; + result = '0'; break; + case XK_KP_1: + is_printable = true; + result = '1'; break; + case XK_KP_2: + is_printable = true; + result = '2'; break; + case XK_KP_3: + is_printable = true; + result = '3'; break; + case XK_KP_4: + is_printable = true; + result = '4'; break; + case XK_KP_5: + is_printable = true; + result = '5'; break; + case XK_KP_6: + is_printable = true; + result = '6'; break; + case XK_KP_7: + is_printable = true; + result = '7'; break; + case XK_KP_8: + is_printable = true; + result = '8'; break; + case XK_KP_9: + is_printable = true; + result = '9'; break; + + default: + return false; + } + } + + return true; + } + + // ---------------------------------------------------------------------------------------- + + void event_handler ( + ) + /*! + ensures + - will handle all events and event dispatching + !*/ + { + try + { + std::vector bitmap_buffer; + bool quit_event_loop = false; + while (quit_event_loop == false) + { + XEvent ev; + XNextEvent(disp,&ev); + + + // get a lock on the window_table's mutex + auto_mutex window_table_locker(window_table.get_mutex()); + + // if this event is for one of the windows in the window_table + // then get that window out of the table and put it into win. + XAnyEvent* _ae = reinterpret_cast(&ev); + base_window** win_ = window_table[_ae->window]; + base_window* win = 0; + if (win_) + win = *win_; + + + // ignore messages for unmapped windows + if (ev.type != MapNotify && win != 0) + { + if (win->is_mapped == false) + continue; + } + + + switch (ev.type) + { + + case SelectionRequest: + { + XSelectionRequestEvent* req = reinterpret_cast(&ev.xselectionrequest); + XEvent respond; + + if (req->target == XA_STRING) + { + XChangeProperty (disp, + req->requestor, + req->property, + XA_STRING, + 8, + PropModeReplace, + reinterpret_cast(clipboard.c_str()), + clipboard.size()+1); + respond.xselection.property=req->property; + } + else + { + respond.xselection.property= None; + } + respond.xselection.type= SelectionNotify; + respond.xselection.display= req->display; + respond.xselection.requestor= req->requestor; + respond.xselection.selection=req->selection; + respond.xselection.target= req->target; + respond.xselection.time = req->time; + XSendEvent (disp, req->requestor,0,0,&respond); + XFlush (disp); + + } break; + + case MapNotify: + { + if (win == 0) + break; + + win->is_mapped = true; + + if (win->resizable == false) + { + XSizeHints* hints = XAllocSizeHints(); + hints->flags = PMinSize|PMaxSize; + hints->min_width = win->width; + hints->max_width = win->width; + hints->max_height = win->height; + hints->min_height = win->height; + XSetNormalHints(gui_core_kernel_2_globals::disp,win->x11_stuff.hwnd,hints); + XFree(hints); + } + + XResizeWindow(gui_core_kernel_2_globals::disp,win->x11_stuff.hwnd,win->width,win->height); + + XMoveWindow(gui_core_kernel_2_globals::disp,win->x11_stuff.hwnd,win->x,win->y); + XFlush(gui_core_kernel_2_globals::disp); + + if (win->has_been_resized) + { + win->has_been_resized = false; + win->on_window_resized(); + } + + if (win->has_been_moved) + { + win->has_been_moved = false; + win->on_window_moved(); + } + + + } break; + + + case KeyPress: + { + XKeyPressedEvent* e = reinterpret_cast(&ev); + + if (win == 0) + break; + + unsigned long state = 0; + bool shift = ((e->state & ShiftMask)!=0); + bool ctrl = ((e->state & ControlMask)!=0); + bool caps = ((e->state & LockMask)!=0); + if(shift) + state |= base_window::KBD_MOD_SHIFT; + if(ctrl) + state |= base_window::KBD_MOD_CONTROL; + if(caps) + state |= base_window::KBD_MOD_CAPS_LOCK; + if((e->state & alt_mask)!=0) + state |= base_window::KBD_MOD_ALT; + if((e->state & meta_mask)!=0) + state |= base_window::KBD_MOD_META; + if((e->state & num_lock_mask)!=0) + state |= base_window::KBD_MOD_NUM_LOCK; + if((e->state & scroll_lock_mask)!=0) + state |= base_window::KBD_MOD_SCROLL_LOCK; + + char buffer[2]; + KeySym key; + XLookupString(e,buffer,2,&key,NULL); + + bool is_printable; + unsigned long result; + + if (map_keys(key,shift,caps,result,is_printable)) + { + // signal the keyboard event + win->on_keydown(result,is_printable,state); + } + + } break; + + case FocusIn: + { + if (win == 0) + break; + + // signal the focus event + win->on_focus_gained(); + } break; + + case FocusOut: + { + if (win == 0) + break; + + // signal the focus event + win->on_focus_lost(); + } break; + + case ButtonPress: + case ButtonRelease: + { + XButtonEvent* e = reinterpret_cast(&ev); + + if (win == 0) + break; + + unsigned long btn = base_window::NONE; + if (e->button == Button1) + btn = base_window::LEFT; + else if (e->button == Button3) + btn = base_window::RIGHT; + else if (e->button == Button2) + btn = base_window::MIDDLE; + + + // only send the event if this is a button we support + if (btn != (unsigned long)base_window::NONE) + { + + unsigned long state = 0; + if (e->state & ControlMask) + state |= base_window::CONTROL; + if (e->state & Button1Mask) + state |= base_window::LEFT; + if (e->state & Button2Mask) + state |= base_window::MIDDLE; + if (e->state & Button3Mask) + state |= base_window::RIGHT; + if (e->state & ShiftMask) + state |= base_window::SHIFT; + + if (ev.type == ButtonPress) + { + bool is_double_click = false; + if (win->last_click_button == btn && + std::abs((long)win->last_click_x - (long)e->x) < 5 && + std::abs((long)win->last_click_y - (long)e->y) < 5 && + e->time - win->x11_stuff.last_click_time <= 400) + { + // this is a double click + is_double_click = true; + // set this to make sure the next click can't be + // interpreted as a double click + win->last_click_button = base_window::NONE; + } + else + { + win->last_click_button = btn; + win->last_click_x = e->x; + win->last_click_y = e->y; + win->x11_stuff.last_click_time = e->time; + } + + // remove the clicked button from the state + state &= (~btn); + win->on_mouse_down(btn,state,e->x,e->y,is_double_click); + + } + else + { + // remove the clicked button from the state + state &= (~btn); + win->on_mouse_up(btn,state,e->x,e->y); + } + } + else if (e->button == Button4 && ev.type == ButtonPress) + { + win->on_wheel_up(); + } + else if (e->button == Button5 && ev.type == ButtonPress) + { + win->on_wheel_down(); + } + + } break; + + case LeaveNotify: + { + if (win == 0) + break; + + win->on_mouse_leave(); + + } break; + + case EnterNotify: + { + if (win == 0) + break; + + win->on_mouse_enter(); + } break; + + case MotionNotify: + { + XMotionEvent* e = reinterpret_cast(&ev); + + if (win == 0) + break; + + unsigned long state = 0; + if (e->state & ControlMask) + state |= base_window::CONTROL; + if (e->state & Button1Mask) + state |= base_window::LEFT; + if (e->state & Button2Mask) + state |= base_window::MIDDLE; + if (e->state & Button3Mask) + state |= base_window::RIGHT; + if (e->state & ShiftMask) + state |= base_window::SHIFT; + + win->on_mouse_move(state,e->x,e->y); + + } break; + + case ConfigureNotify: + { + XConfigureEvent* e = reinterpret_cast(&ev); + if (e->window == exit_window) + { + // this is the signal to quit the event handler + quit_event_loop = true; + break; + } + + if (win == 0) + break; + + if (win->width != e->width || + win->height != e->height || + win->has_been_resized) + { + win->has_been_resized = false; + // this is a resize + win->width = e->width; + win->height = e->height; + win->on_window_resized(); + } + if (win->x != e->x || + win->y != e->y || + win->has_been_moved) + { + win->has_been_moved = false; + // this is a move + win->x = e->x; + win->y = e->y; + win->on_window_moved(); + } + + } break; + + case ClientMessage: + { + XClientMessageEvent* e = reinterpret_cast(&ev); + if ((Atom)e->data.l[0] == delete_window) + { + if (win == 0) + break; + + + if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW) + { + DLIB_ASSERT(win->has_been_destroyed == false, + "\tYou called close_window() inside the on_window_close() event but" + << "\n\tthen returned DO_NOT_CLOSE_WINDOW. You can do one or the other but not both." + << "\n\tthis: " << win + ); + // the client has decided not to close the window + // after all + } + else + { + if (window_table[e->window]) + { + window_table.destroy(e->window); + XDestroyWindow(disp,e->window); + win->has_been_destroyed = true; + gui_core_kernel_2_globals::window_close_signaler.broadcast(); + } + else + { + // in this case the window must have self destructed by + // calling delete this; so we don't have to do anything. + } + } + } + } break; + + case Expose: + { + XExposeEvent* e = reinterpret_cast(&ev); + + if (win == 0) + break; + + // take all the expose events for this window out + XEvent etemp; + int x = e->x; + int y = e->y; + int width = e->width; + int height = e->height; + + + + // What we are doing here with this loop is we are combining + // all of the Expose events for this window that are + // currently in the queue. + while (XCheckIfEvent(disp,&etemp,XCheckIfEventPredicate,reinterpret_cast(&(e->window)))) + { + XExposeEvent* e2 = reinterpret_cast(&etemp); + if (e2->x < x) + { + width += x - e2->x; + x = e2->x; + } + if (e2->y < y) + { + height += y - e2->y; + y = e2->y; + } + if (e2->width + e2->x > width + x) + { + width = e2->width + e2->x - x; + } + if (e2->height + e2->y > height + y) + { + height = e2->height + e2->y - y; + } + } + + // I'm not sure if this sort of thing can happen but + // if it does then just ignore this entire event. + if (width == 0 || height == 0) + { + break; + } + + if (bitmap_buffer.size() < static_cast(width*height*4)) + bitmap_buffer.resize(width*height*4); + + unsigned char* const bitmap = &bitmap_buffer[0]; + unsigned char* const end = bitmap + width*height*4; + + unsigned char* temp; + canvas c(bitmap,x,y,x+width-1,y+height-1); + + + win->paint(c); + + // the user might have called win->close_window() and if they did + // then just stop right here. We don't want to paint the window. + if (win->has_been_destroyed) + break; + + // if the color depth we are working with isn't 24bits then we need + // to transform our image into whatever it is supposed to be. + if (depth != 24) + { + // convert this image into an 8 bit image + unsigned int red_bits; + unsigned int green_bits; + unsigned int blue_bits; + if (depth != 16) + { + unsigned int bits = depth/3; + unsigned int extra = depth%3; + red_bits = bits; + green_bits = bits; + blue_bits = bits; + if (extra) + { + ++red_bits; + --extra; + } + if (extra) + { + ++green_bits; + } + } + else if (depth == 16) + { + red_bits = 5; + green_bits = 6; + blue_bits = 5; + } + + if (depth == 16) + { + temp = bitmap; + unsigned char *red, *green, *blue; + while (temp != end) + { + blue = temp; + ++temp; + green = temp; + ++temp; + red = temp; + ++temp; + ++temp; + + const unsigned long r = static_cast(*red)>>(8-red_bits); + const unsigned long g = static_cast(*green)>>(8-green_bits); + const unsigned long b = static_cast(*blue)>>(8-blue_bits); + + unsigned long color = (r<<(depth-red_bits))| (g<<(depth-red_bits-green_bits))| b; + + *blue = (color>>0)&0xFF; + *green = (color>>8)&0xFF; + } + } + else if (depth < 24) + { + temp = bitmap; + unsigned char *red, *green, *blue; + while (temp != end) + { + blue = temp; + ++temp; + green = temp; + ++temp; + red = temp; + ++temp; + ++temp; + + const unsigned long r = static_cast(*red)>>(8-red_bits); + const unsigned long g = static_cast(*green)>>(8-green_bits); + const unsigned long b = static_cast(*blue)>>(8-blue_bits); + + unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r; + + *blue = (color>>0)&0xFF; + *green = (color>>8)&0xFF; + *red = (color>>16)&0xFF; + } + } + else if (depth > 24) + { + temp = bitmap; + unsigned char *red, *green, *blue, *four; + while (temp != end) + { + blue = temp; + ++temp; + green = temp; + ++temp; + red = temp; + ++temp; + four = temp; + ++temp; + + const unsigned long r = static_cast(*red)<<(red_bits-8); + const unsigned long g = static_cast(*green)<<(green_bits-8); + const unsigned long b = static_cast(*blue)<<(blue_bits-8); + + unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r; + + *blue = (color>>0)&0xFF; + *green = (color>>8)&0xFF; + *red = (color>>16)&0xFF; + *four = (color>>24)&0xFF; + } + } + } // if (depth != 24) + + + + XImage img; + memset(&img,0,sizeof(img)); + img.width = width; + img.height = height; + img.depth = depth; + img.data = reinterpret_cast(bitmap); + img.bitmap_bit_order = LSBFirst; + img.byte_order = LSBFirst; + img.format = ZPixmap; + img.bitmap_pad = 32; + img.bitmap_unit = 32; + img.bits_per_pixel = 32; + + + XInitImage(&img); + + GC gc = XCreateGC(disp, e->window, 0, NULL); + + XPutImage(disp,e->window,gc,&img,0,0,x,y,width,height); + + XFreeGC(disp,gc); + } break; + } // switch (ev.type) + } + } + catch (std::exception& e) + { + dlog << LFATAL << "Exception thrown in event handler: " << e.what(); + } + catch (...) + { + dlog << LFATAL << "Unknown exception thrown in event handler."; + } + } + + // ---------------------------------------------------------------------------------------- + + class event_handler_thread : public threaded_object + { + public: + + enum et_state + { + uninitialized, + initialized, + failure_to_init + }; + + et_state status; + + event_handler_thread( + ) + { + register_program_ending_handler(*this, &event_handler_thread::self_destruct); + status = uninitialized; + } + + ~event_handler_thread () + { + using namespace gui_core_kernel_2_globals; + + if (is_alive()) + { + + if (status != failure_to_init) + { + using namespace gui_core_kernel_2_globals; + XConfigureEvent event; + event.type = ConfigureNotify; + event.send_event = True; + event.display = disp; + event.window = exit_window; + event.x = 1; + XFlush(disp); + XPutBackEvent(disp,reinterpret_cast(&event)); + XFlush(disp); + + // This should cause XNextEvent() to unblock so that it will see + // this ConfigureNotify event we are putting onto the event queue. + XSendEvent(disp,exit_window,False,0,reinterpret_cast(&event)); + XFlush(disp); + + wait(); + XCloseDisplay(disp); + } + else + { + + wait(); + } + } + + delete &et_signaler; + delete &window_close_signaler; + delete &window_table; + } + + void self_destruct ( + ) + { + delete this; + } + + private: + + void thread ( + ) + { + using namespace std; + using namespace dlib; + using namespace gui_core_kernel_2_globals; + try + { + if (XInitThreads() == 0) + { + dlog << LFATAL << "Unable to initialize threading support."; + // signal that an error has occurred + window_table.get_mutex().lock(); + status = failure_to_init; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + return; + } + + + disp = XOpenDisplay(NULL); + if (disp == 0) + { + disp = XOpenDisplay(":0.0"); + if (disp == 0) + { + dlog << LFATAL << "Unable to connect to the X display."; + // signal that an error has occurred + window_table.get_mutex().lock(); + status = failure_to_init; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + return; + } + } + + screen = DefaultScreenOfDisplay(disp); + depth = DefaultDepthOfScreen(screen); + delete_window = XInternAtom(disp,"WM_DELETE_WINDOW",1); + + + // make this window just so we can send messages to it and trigger + // events in the event thread + XSetWindowAttributes attr; + exit_window = XCreateWindow( + disp, + DefaultRootWindow(disp), + 0, + 0, + 10, // this is the default width of a window + 10, // this is the default width of a window + 0, + depth, + InputOutput, + CopyFromParent, + 0, + &attr + ); + + // signal that the event thread is now up and running + window_table.get_mutex().lock(); + status = initialized; + et_signaler.broadcast(); + window_table.get_mutex().unlock(); + + // start the event handler + event_handler(); + } + catch (std::exception& e) + { + cout << "\nEXCEPTION THROWN: \n" << e.what() << endl; + abort(); + } + catch (...) + { + cout << "UNKNOWN EXCEPTION THROWN.\n" << endl; + abort(); + } + } + }; + + // ---------------------------------------------------------------------------------------- + + int index_to_modmask(unsigned long n) + { + switch ( n ) + { + case 0: + return Mod1Mask; + case 1: + return Mod2Mask; + case 2: + return Mod3Mask; + case 3: + return Mod4Mask; + } + return Mod5Mask; + } + + void init_keyboard_mod_masks() + { + XModifierKeymap* map = XGetModifierMapping( disp ); + KeyCode* codes = map->modifiermap + map->max_keypermod * Mod1MapIndex; + for (int n = 0; n < 5 * map->max_keypermod; n++ ) + { + if ( codes[n] == 0 ) + continue; + switch(XKeycodeToKeysym( disp, codes[n], 0 )) + { + case XK_Alt_L: + alt_mask = index_to_modmask(n / map->max_keypermod); + continue; + case XK_Alt_R: + if(alt_mask == 0) + alt_mask = index_to_modmask(n / map->max_keypermod); + continue; + case XK_Meta_L: + case XK_Meta_R: + meta_mask = index_to_modmask(n / map->max_keypermod); + continue; + case XK_Scroll_Lock: + scroll_lock_mask = index_to_modmask(n / map->max_keypermod); + continue; + case XK_Num_Lock: + num_lock_mask = index_to_modmask(n / map->max_keypermod); + default: + continue; + } + } + XFreeModifiermap( map ); + if ( alt_mask == 0 ) + { + dlog << LWARN << "Search for Alt-key faild."; + if ( meta_mask != 0 ) + alt_mask = meta_mask; + else + alt_mask = Mod1Mask; // resort to guessing + } + } + + // ---------------------------------------------------------------------------------------- + + static event_handler_thread* event_handler_thread_object = new event_handler_thread; + + void init_gui_core () + { + using namespace dlib::gui_core_kernel_2_globals; + auto_mutex M(window_table.get_mutex()); + + if (core_has_been_initialized == false) + { + core_has_been_initialized = true; + + + // start up the event handler thread + event_handler_thread_object->start(); + + // wait for the event thread to get up and running + while (event_handler_thread_object->status == event_handler_thread::uninitialized) + et_signaler.wait(); + + if (event_handler_thread_object->status == event_handler_thread::failure_to_init) + throw gui_error("Failed to initialize X11 resources"); + + init_keyboard_mod_masks(); + } + } + + + + } // namespace gui_core_kernel_2_globals + +// ---------------------------------------------------------------------------------------- + + void canvas:: + fill ( + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) const + { + pixel pixel_value; + pixel_value.red = red_; + pixel_value.green = green_; + pixel_value.blue = blue_; + pixel_value._padding = 0; + + pixel* start = reinterpret_cast(bits); + pixel* end = start + width_*height_; + + while (start != end) + { + *start = pixel_value; + ++start; + } + } + +// ---------------------------------------------------------------------------------------- + + void put_on_clipboard ( + const std::string& str + ) + { + using namespace gui_core_kernel_2_globals; + init_gui_core(); + auto_mutex M(window_table.get_mutex()); + clipboard = str; + clipboard[0] = clipboard[0]; + + XSetSelectionOwner(disp,XA_PRIMARY,exit_window,CurrentTime); + } + +// ---------------------------------------------------------------------------------------- + + Bool clip_peek_helper ( + Display *display, + XEvent *event, + XPointer arg + ) + { + if ( event->type == SelectionNotify) + { + return True; + } + else + { + return False; + } + } + + void get_from_clipboard ( + std::string& str + ) + { + using namespace gui_core_kernel_2_globals; + init_gui_core(); + auto_mutex M(window_table.get_mutex()); + str.clear(); + unsigned char *data = 0; + Window sown; + Atom type; + int format, result; + unsigned long len, bytes_left, dummy; + XEvent e; + + try + { + sown = XGetSelectionOwner (disp, XA_PRIMARY); + if (sown == exit_window) + { + // if we are copying from ourselfs then don't fool with the Xwindows junk. + str = clipboard; + str[0] = str[0]; + } + else if (sown != None) + { + // request that the selection be copied into the XA_PRIMARY property + // of the exit_window. It doesn't matter what window we put it in + // so long as it is one under the control of this process and exit_window + // is easy to use here so that is what I'm using. + XConvertSelection (disp, XA_PRIMARY, XA_STRING, XA_PRIMARY, + exit_window, CurrentTime); + + // This will wait until we get a SelectionNotify event which should happen + // really soon. + XPeekIfEvent(disp,&e,clip_peek_helper,0); + + // See how much data we got + XGetWindowProperty (disp, exit_window, + XA_PRIMARY, // Tricky.. + 0, 0, // offset - len + 0, // Delete 0==FALSE + AnyPropertyType, //flag + &type, // return type + &format, // return format + &len, &bytes_left, //that + &data); + if (data) + { + XFree(data); + data = 0; + } + if (bytes_left > 0 && type == XA_STRING) + { + result = XGetWindowProperty (disp, exit_window, + XA_PRIMARY, 0,bytes_left,0, + AnyPropertyType, &type,&format, + &len, &dummy, &data); + if (result == Success && type == XA_STRING) + { + str = (char*)data; + } + if (data) + { + XFree(data); + data = 0; + } + } + } + } + catch (...) + { + if (data) + XFree(data); + } + } + +// ---------------------------------------------------------------------------------------- + + namespace gui_core_kernel_2_globals + { + void trigger_user_event_threadproc ( + void* + ) + { + auto_mutex M(window_table.get_mutex()); + + user_events.lock(); + user_events.swap(user_events_temp); + user_events.unlock(); + + + user_events_temp.reset(); + // now dispatch all these user events + while (user_events_temp.move_next()) + { + base_window** win_ = window_table[user_events_temp.element().w]; + base_window* win; + // if this window exists in the window table then dispatch + // its event. + if (win_) + { + win = *win_; + win->on_user_event( + user_events_temp.element().p, + user_events_temp.element().i + ); + } + } + user_events_temp.clear(); + } + } + + void base_window:: + trigger_user_event ( + void* p, + int i + ) + { + using namespace gui_core_kernel_2_globals; + user_event_type e; + e.w = x11_stuff.hwnd; + e.p = p; + e.i = i; + { + auto_mutex M(user_events.get_mutex()); + user_events.enqueue(e); + + // we only need to start a thread to deal with this if there isn't already + // one out working on the queue + if (user_events.size() == 1) + create_new_thread (trigger_user_event_threadproc,0); + } + } + +// ---------------------------------------------------------------------------------------- + + base_window:: + base_window ( + bool resizable_, + bool undecorated + ) : + x11_stuff(*(new gui_core_kernel_2_globals::x11_base_windowstuff)), + is_mapped(false), + resizable(resizable_), + has_been_destroyed(false), + has_been_resized(false), + has_been_moved(false), + wm(gui_core_kernel_2_globals::window_table.get_mutex()) + { + DLIB_ASSERT(!(undecorated == true && resizable_ == true), + "\tbase_window::base_window()" + << "\n\tThere is no such thing as an undecorated window that is resizable by the user." + << "\n\tthis: " << this + ); + + gui_core_kernel_2_globals::init_gui_core(); + + auto_mutex M(wm); + + x11_stuff.last_click_time = 0; + last_click_x = 0; + last_click_y = 0; + last_click_button = NONE; + + XSetWindowAttributes attr; + memset(&attr,'\0',sizeof(attr)); + + unsigned long valuemask = 0; + if (undecorated) + { + attr.override_redirect = True; + valuemask = CWOverrideRedirect; + } + + x11_stuff.hwnd = XCreateWindow( + gui_core_kernel_2_globals::disp, + DefaultRootWindow(gui_core_kernel_2_globals::disp), + 0, + 0, + 10, // this is the default width of a window + 10, // this is the default width of a window + 0, + gui_core_kernel_2_globals::depth, + InputOutput, + CopyFromParent, + valuemask, + &attr + ); + + Window temp = x11_stuff.hwnd; + base_window* ttemp = this; + gui_core_kernel_2_globals::window_table.add(temp,ttemp); + + XSelectInput( + gui_core_kernel_2_globals::disp, + x11_stuff.hwnd, + StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask| + PointerMotionMask|LeaveWindowMask|EnterWindowMask|KeyPressMask| + KeyReleaseMask| FocusChangeMask + ); + + XSetWMProtocols( + gui_core_kernel_2_globals::disp, + x11_stuff.hwnd, + &gui_core_kernel_2_globals::delete_window, + 1 + ); + + + // these are just default values + x = 0; + y = 0; + width = 10; + height = 10; + + if (resizable == false) + { + XSizeHints* hints = XAllocSizeHints(); + hints->flags = PMinSize|PMaxSize; + hints->min_width = width; + hints->max_width = width; + hints->max_height = height; + hints->min_height = height; + XSetNormalHints(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,hints); + XFree(hints); + } + } + +// ---------------------------------------------------------------------------------------- + + base_window:: + ~base_window ( + ) + { + close_window(); + delete &x11_stuff; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + close_window ( + ) + { + auto_mutex M(wm); + if (has_been_destroyed == false) + { + has_been_destroyed = true; + + gui_core_kernel_2_globals::window_table.destroy(x11_stuff.hwnd); + + XDestroyWindow(gui_core_kernel_2_globals::disp,x11_stuff.hwnd); + x11_stuff.hwnd = 0; + gui_core_kernel_2_globals::window_close_signaler.broadcast(); + } + } + +// ---------------------------------------------------------------------------------------- + + bool base_window:: + is_closed ( + ) const + { + auto_mutex M(wm); + return has_been_destroyed; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + set_title ( + const std::string& title_ + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::set_title" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + // I'm pretty sure the pointer won't be modified even though + // it isn't const anymore. + char *title = const_cast(title_.c_str()); + XTextProperty property; + XStringListToTextProperty(&title,1,&property); + XSetWMName(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,&property); + XFree(property.value); + XFlush(gui_core_kernel_2_globals::disp); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + show ( + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::show" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + XMapRaised(gui_core_kernel_2_globals::disp,x11_stuff.hwnd); + XFlush(gui_core_kernel_2_globals::disp); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + wait_until_closed ( + ) const + { + auto_mutex M(wm); + while (has_been_destroyed == false) + gui_core_kernel_2_globals::window_close_signaler.wait(); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + hide ( + ) + { + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::hide" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + XUnmapWindow(gui_core_kernel_2_globals::disp,x11_stuff.hwnd); + XFlush(gui_core_kernel_2_globals::disp); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + set_size ( + int width_, + int height_ + ) + { + auto_mutex a(wm); + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::set_size" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + << "\n\twidth: " << width_ + << "\n\theight: " << height_ + ); + + // do some sanity checking on these values + if (width_ < 1) + width_ = 1; + if (height_ < 1) + height_ = 1; + + width = width_; + height = height_; + has_been_resized = true; + + if (resizable == false) + { + XSizeHints* hints = XAllocSizeHints(); + hints->flags = PMinSize|PMaxSize; + hints->min_width = width; + hints->max_width = width; + hints->max_height = height; + hints->min_height = height; + XSetNormalHints(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,hints); + XFree(hints); + } + + XResizeWindow(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,width,height); + + XFlush(gui_core_kernel_2_globals::disp); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + set_pos ( + long x_, + long y_ + ) + { + auto_mutex a(wm); + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::set_pos" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + << "\n\tx: " << x_ + << "\n\ty: " << y_ + ); + + x = x_; + y = y_; + + has_been_moved = true; + + XMoveWindow(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,x,y); + XFlush(gui_core_kernel_2_globals::disp); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + get_pos ( + long& x_, + long& y_ + ) + { + auto_mutex a(wm); + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::get_pos" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + + // we can't really trust the values we have for x and y because some window managers + // will have reported bogus values back in the ConfigureNotify event. So just to be + // on the safe side we will use XTranslateCoordinates() + int rx, ry; + Window desktop_window = DefaultRootWindow(gui_core_kernel_2_globals::disp); + Window junk; + XTranslateCoordinates(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,desktop_window,0,0,&rx, &ry, &junk); + x_ = rx; + y_ = ry; + x = rx; + y = ry; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + get_size ( + unsigned long& width_, + unsigned long& height_ + ) const + { + auto_mutex M(wm); + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::get_size" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + + width_ = width; + height_ = height; + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + get_display_size ( + unsigned long& width_, + unsigned long& height_ + ) const + { + auto_mutex M(wm); + DLIB_ASSERT(is_closed() == false, + "\tvoid base_window::get_display_size" + << "\n\tYou can't do this to a window that has been closed." + << "\n\tthis: " << this + ); + + using namespace gui_core_kernel_2_globals; + int screen_number = XScreenNumberOfScreen(screen); + width_ = DisplayWidth(disp, screen_number); + height_ = DisplayHeight(disp, screen_number); + } + +// ---------------------------------------------------------------------------------------- + + void base_window:: + invalidate_rectangle ( + const rectangle& rect + ) + { + auto_mutex a(wm); + if (is_mapped == false) + return; + + if (rect.is_empty() == false && !has_been_destroyed) + { + const long x = rect.left(); + const long y = rect.top(); + const unsigned long width = rect.width(); + const unsigned long height = rect.height(); + + XClearArea(gui_core_kernel_2_globals::disp,x11_stuff.hwnd,x,y,width,height,1); + XFlush(gui_core_kernel_2_globals::disp); + } + } + +} + +// ---------------------------------------------------------------------------------------- + +#endif // POSIX + +#endif // DLIB_GUI_CORE_KERNEL_2_CPp_ + diff --git a/dlib/gui_core/gui_core_kernel_2.h b/dlib/gui_core/gui_core_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..a525a49c2361861244402185e72287b3220e57dd --- /dev/null +++ b/dlib/gui_core/gui_core_kernel_2.h @@ -0,0 +1,379 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORE_KERNEl_2_ +#define DLIB_GUI_CORE_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#ifdef DLIB_NO_GUI_SUPPORT +#error "DLIB_NO_GUI_SUPPORT is defined so you can't use the GUI code. Turn DLIB_NO_GUI_SUPPORT off if you want to use it." +#error "Also make sure you have libx11-dev installed on your system" +#endif + +#include + +#include "gui_core_kernel_abstract.h" +#include "../algs.h" +#include "../threads.h" +#include "../geometry/rectangle.h" +#include "../binary_search_tree.h" +#include +#include "../pixel.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace gui_core_kernel_2_globals + { + void event_handler (); + void trigger_user_event_threadproc (void*); + + // This is a forward declaration for a struct that contains any + // X11 variables. This allows me to avoid having any dlib header files + // include the X11 headers. Which in turn speeds build times and simplifies + // build setups. + struct x11_base_windowstuff; + } + +// ---------------------------------------------------------------------------------------- + + void put_on_clipboard ( + const std::string& str + ); + +// ---------------------------------------------------------------------------------------- + + void get_from_clipboard ( + std::string& str + ); + +// ---------------------------------------------------------------------------------------- + + class canvas : public rectangle + { + public: + struct pixel + { + unsigned char blue; + unsigned char green; + unsigned char red; + private: + friend class canvas; + unsigned char _padding; + }; + + ~canvas() {} + + inline pixel* operator[] ( + unsigned long row + ) const + { + DLIB_ASSERT(row < height(), + "\tpixel* canvas::operator[]" + << "\n\tyou have to give a row that is less than the height()" + << "\n\tthis: " << this + << "\n\trow: " << row + << "\n\theight(): " << height() + ); + unsigned char* temp = bits + row_width*row; + return reinterpret_cast(temp); + } + + void fill ( + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) const; + + private: + + friend void gui_core_kernel_2_globals::event_handler (); + + canvas ( + unsigned char* bits__, + unsigned long left__, + unsigned long top__, + unsigned long right__, + unsigned long bottom__ + ) : + rectangle(left__,top__,right__,bottom__), + bits(bits__), + width_(width()), + height_(height()), + row_width(width_*4) + {} + + // restricted functions + canvas(); // normal constructor + canvas(canvas&); // copy constructor + canvas& operator=(canvas&); // assignment operator + + unsigned char* const bits; + const unsigned long width_; + const unsigned long height_; + const unsigned long row_width; + }; + + template <> + struct pixel_traits + { + const static bool rgb = true; + const static bool rgb_alpha = false; + const static bool grayscale = false; + const static bool hsi = false; + const static long num = 3; + static unsigned long max() { return 255;} + const static bool has_alpha = false; + }; + +// ----------------- + + class base_window + { + friend void gui_core_kernel_2_globals::event_handler (); + friend void gui_core_kernel_2_globals::trigger_user_event_threadproc (void*); + + public: + + enum mouse_state_masks + { + NONE = 0, + LEFT = 1, + RIGHT = 2, + MIDDLE = 4, + SHIFT = 8, + CONTROL = 16 + }; + + enum keyboard_state_masks + { + KBD_MOD_NONE = 0, + KBD_MOD_SHIFT = 1, + KBD_MOD_CONTROL = 2, + KBD_MOD_ALT = 4, + KBD_MOD_META = 8, + KBD_MOD_CAPS_LOCK = 16, + KBD_MOD_NUM_LOCK = 32, + KBD_MOD_SCROLL_LOCK = 64 + }; + + enum on_close_return_code + { + DO_NOT_CLOSE_WINDOW, + CLOSE_WINDOW + }; + + enum non_printable_keyboard_keys + { + KEY_BACKSPACE, + KEY_SHIFT, + KEY_CTRL, + KEY_ALT, + KEY_PAUSE, + KEY_CAPS_LOCK, + KEY_ESC, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_END, + KEY_HOME, + KEY_LEFT, // This is the left arrow key + KEY_RIGHT, // This is the right arrow key + KEY_UP, // This is the up arrow key + KEY_DOWN, // This is the down arrow key + KEY_INSERT, + KEY_DELETE, + KEY_SCROLL_LOCK, + + // Function Keys + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12 + }; + + private: + + gui_core_kernel_2_globals::x11_base_windowstuff& x11_stuff; + + int x, y, width, height; + bool is_mapped; + + const bool resizable; + bool has_been_destroyed; + bool has_been_resized; // true if someone called set_size() and the on_window_resized() event + // hasn't yet occurred. + bool has_been_moved; // true if someone called set_pos() and the on_window_moved() event + // hasn't yet occurred. + + + // The following 3 variables (and x11_stuff.last_click_time) are only accessed from the + // event handling loop (except for being initialized below). They record the last + // mouse click event details. + long last_click_x, last_click_y; + unsigned long last_click_button; + + + protected: + const rmutex& wm; + + public: + + base_window ( + bool resizable_ = true, + bool undecorated = false + ); + + virtual ~base_window ( + ); + + void close_window ( + ); + + void wait_until_closed ( + ) const; + + bool is_closed ( + ) const; + + void set_title ( + const std::string& title_ + ); + + virtual void show ( + ); + + virtual void hide( + ); + + void set_size ( + int width_, + int height_ + ); + + void set_pos ( + long x_, + long y_ + ); + + void get_pos ( + long& x_, + long& y_ + ); + + void get_size ( + unsigned long& width_, + unsigned long& height_ + ) const; + + void get_display_size ( + unsigned long& width, + unsigned long& height + ) const; + + void invalidate_rectangle ( + const rectangle& rect + ); + + void trigger_user_event ( + void* p, + int i + ); + + protected: + + virtual on_close_return_code on_window_close( + ){return CLOSE_WINDOW;} + + virtual void on_window_resized( + ){} + + virtual void on_window_moved( + ){} + virtual void on_user_event ( + void* p, + int i + ){} + + virtual void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ){} + + virtual void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ){} + + virtual void on_mouse_move ( + unsigned long state, + long x, + long y + ){} + + virtual void on_mouse_leave ( + ){} + + virtual void on_mouse_enter ( + ){} + + virtual void on_wheel_up ( + ){} + + virtual void on_wheel_down ( + ){} + + virtual void on_focus_gained ( + ){} + + virtual void on_focus_lost ( + ){} + + virtual void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ){} + + private: + + virtual void paint ( + const canvas& c + ) =0; + + + + base_window(base_window&); // copy constructor + base_window& operator=(base_window&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + + +} + + +#ifdef NO_MAKEFILE +#include "gui_core_kernel_2.cpp" +#endif + +#endif // DLIB_GUI_CORE_KERNEl_2_ + diff --git a/dlib/gui_core/gui_core_kernel_abstract.h b/dlib/gui_core/gui_core_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c79c37b80b93ffe9356c89a58c87943d645e4ec4 --- /dev/null +++ b/dlib/gui_core/gui_core_kernel_abstract.h @@ -0,0 +1,738 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_GUI_CORE_KERNEl_ABSTRACT_ +#ifdef DLIB_GUI_CORE_KERNEl_ABSTRACT_ + +#include +#include "../algs.h" +#include "../geometry/rectangle_abstract.h" + +namespace dlib +{ + + /*! + OVERVIEW: + This is a set of objects and functions which provide a very basic + framework for manipulating windows. It is intended to provide a + portable interface which can be used to build a more complex windowing + toolkit. + + EXCEPTIONS + Do not let an exception leave any of the base_window event handlers. + The results of doing so are undefined. + + THREAD SAFETY + Event Handlers + All event handlers are executed in a special event handling thread. + This means that you must not do anything that will take a long time or + block while in an event handler. Doing so will freeze all event + processing. + + Also, don't rely on get_thread_id() always returning the same ID from + inside event handlers. + + canvas + Never access a canvas object outside of the paint() callback + that supplied it. Only access a canvas object from the event + handling thread. After the paint() event handler has returned do + not access that canvas object again. + + base_window + All methods for this class are thread safe. You may call them + from any thread and do not need to serialize access. + + GENERAL WARNING + You can't make base_window objects before main() has been entered or + call get_from_clipboard() or put_on_clipboard() before + main() has been entered. + !*/ + +// ---------------------------------------------------------------------------------------- + + void put_on_clipboard ( + const std::string& str + ); + /*! + ensures + - posts the contents of str to the system clipboard + throws + - std::bad_alloc + - dlib::gui_error + - dlib::thread_error + !*/ + +// ---------------------------------------------------------------------------------------- + + void get_from_clipboard ( + std::string& str + ); + /*! + ensures + - if (there is string data on the system clipboard) then + - #str == the data from the clipboard + - else + - #str == "" + throws + - std::bad_alloc + - dlib::gui_error + - dlib::thread_error + !*/ + +// ---------------------------------------------------------------------------------------- + + + class canvas : public rectangle + { + /*! + POINTERS AND REFERENCES TO INTERNAL DATA + All functions of this object may invalidate pointers and references + to internal data. + + INITIAL VALUE + The initial value of each pixel is undefined. + is_empty() == false + + WHAT THIS OBJECT REPRESENTS + This object represents a rectangular area of a window that you + can draw on. + + Each pixel can be accessed with the following syntax: + canvas_instance[y][x].red == the red value for this pixel + canvas_instance[y][x].blue == the blue value for this pixel + canvas_instance[y][x].green == the green value for this pixel + + The origin, i.e. (0,0), of the x,y coordinate plane of the canvas is in + the upper left corner of the canvas. Note that the upper left corner + of the canvas appears at the point (left(),top()) in its window. + !*/ + + public: + + struct pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a single pixel. Each pixel's value + ranges from 0 to 255 with 0 indicating that the color is not + present in the pixel at all and 255 indicating that the color + is present in the pixel with maximum intensity. + + Note that the structure, order, and size of of this struct are + implementation dependent. It will always contain fields called + red, green, and blue but they may not be in that order and there + may be padding. + + Also note that pixel_traits<> is defined for this pixel type, + thus you can use it in assign_pixel() calls. + !*/ + unsigned char red; + unsigned char green; + unsigned char blue; + }; + + + pixel* operator[] ( + unsigned long row + ) const; + /*! + requires + - row < height() + ensures + - returns an array of width() pixel structs that represents the given + row of pixels in the canvas. + !*/ + + void fill ( + unsigned char red, + unsigned char green, + unsigned char blue + ) const; + /*! + ensures + - for all valid values of x and y: + - (#*this)[y][x].red = red + - (#*this)[y][x].green = green + - (#*this)[y][x].blue = blue + !*/ + + private: + + // restricted functions + canvas(); // normal constructor + canvas(canvas&); // copy constructor + canvas& operator=(canvas&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + class base_window + { + + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a window on the desktop. A window has a "client + area" that is a region of the screen that you can draw whatever you like + on. You implement the paint() callback and use the canvas object to do + this drawing. + + INITIAL STATE + - The initial state of the window is to be hidden. This means you need + to call show() to make it appear. + - is_closed() == false + + paint() callback: + This is where you will do all your drawing. It is triggered when + part of the window needs to be drawn/redrawn. + + mouse events: + It is important to note a few things about the mouse events. First, + the on_mouse_move() event is not triggered for each pixel the mouse crosses + but rather its frequency and precision is implementation dependent. + + Second, it is possible that a mouse button may be depressed but the + corresponding button release event does not go to the window. For instance, + if the mouse is outside the window and some other application jumps to the + top it is possible that the new application will receive any mouse button + release events rather than the original window. But the point is that + you should not rely on always getting a button up event for every button + down event. + + keydown event: + Note that the existence of a typematic action (holding down a key + and having it start to repeat itself after a moment) for each key is + totally implementation dependent. So don't rely on it for any key + and conversely don't assume it isn't present either. + + The base_window::wm mutex + This is a reference to a global rmutex. All instances of base_window make + reference to the same global rmutex. It is used to synchronize access to + the base_window to make it thread safe. It is also always locked before + an event handler is called. + !*/ + + public: + + enum on_close_return_code + { + DO_NOT_CLOSE_WINDOW, + CLOSE_WINDOW + }; + + enum mouse_state_masks + { + /*! + These constants represent the various buttons referenced by + mouse events. + !*/ + NONE = 0, + LEFT = 1, + RIGHT = 2, + MIDDLE = 4, + SHIFT = 8, + CONTROL = 16 + }; + + enum keyboard_state_masks + { + /*! + These constants represent the various modifier buttons that + could be in effect during a key press on the keyboard + !*/ + KBD_MOD_NONE = 0, + KBD_MOD_SHIFT = 1, + KBD_MOD_CONTROL = 2, + KBD_MOD_ALT = 4, + KBD_MOD_META = 8, + KBD_MOD_CAPS_LOCK = 16, + KBD_MOD_NUM_LOCK = 32, + KBD_MOD_SCROLL_LOCK = 64 + }; + + enum non_printable_keyboard_keys + { + KEY_BACKSPACE, + KEY_SHIFT, + KEY_CTRL, + KEY_ALT, + KEY_PAUSE, + KEY_CAPS_LOCK, + KEY_ESC, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_END, + KEY_HOME, + KEY_LEFT, // This is the left arrow key + KEY_RIGHT, // This is the right arrow key + KEY_UP, // This is the up arrow key + KEY_DOWN, // This is the down arrow key + KEY_INSERT, + KEY_DELETE, + KEY_SCROLL_LOCK, + + // Function Keys + KEY_F1, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12 + }; + + base_window ( + bool resizable = true, + bool undecorated = false + ); + /*! + requires + - if (undecorated == true) then + - resizable == false + ensures + - #*this has been properly initialized + - if (resizable == true) then + - this window will be resizable by the user + - else + - this window will not be resizable by the user + - if (undecorated == true) then + - this window will not have any graphical elements outside + of its drawable area or appear in the system task bar. It + also won't take the input focus from other windows. + (it is suitable for making things such as popup menus) + throws + - std::bad_alloc + - dlib::thread_error + - dlib::gui_error + This exception is thrown if there is an error while + creating this window. + !*/ + + virtual ~base_window ( + ); + /*! + ensures + - does NOT trigger the on_window_close() event + - all resources associated with *this have been released + - closes this window + !*/ + + void close_window ( + ); + /*! + ensures + - #is_closed() == true + (i.e. permanently closes this window. The window is removed from the + screen and no more events will be dispatched to this window. ) + - does NOT trigger the on_window_close() event + !*/ + + void wait_until_closed ( + ) const; + /*! + ensures + - blocks until is_closed() == true + !*/ + + bool is_closed ( + ) const; + /*! + ensures + - returns true if this window has been closed, false otherwise. + (Note that closed windows do not receive any callbacks at all. + They are also not visible on the screen.) + !*/ + + void set_title ( + const std::string& title + ); + /*! + requires + - is_closed() == false + ensures + - sets the title of the window + !*/ + + virtual void show ( + ); + /*! + requires + - is_closed() == false + ensures + - this window will appear on the screen + !*/ + + virtual void hide( + ); + /*! + requires + - is_closed() == false + ensures + - the window does not appear on the screen + !*/ + + void set_size ( + int width, + int height + ); + /*! + requires + - is_closed() == false + ensures + - The width of the client area of this window is at least width + pixels. + - The height of the client area of this window is at least height + pixels. + - if (the window wasn't already this size) then + - triggers the on_window_resized() callback + !*/ + + void set_pos ( + long x, + long y + ); + /*! + requires + - is_closed() == false + ensures + - sets the upper left corner of this window to the position (x,y) + on the desktop. Note that the origin (0,0) is at the upper left + corner of the desktop. + !*/ + + void get_pos ( + long& x, + long& y + ) const; + /*! + requires + - is_closed() == false + ensures + - #x == the x coordinate of the upper left corner of the client area of + this window. + - #y == the y coordinate of the upper left corner of the client area of + this window. + - i.e. the point (#x,#y) on the desktop is coincident with the point + (0,0) in the client area of this window. + !*/ + + void get_size ( + unsigned long& width, + unsigned long& height + ) const; + /*! + requires + - is_closed() == false + ensures + - #width == the width of the client area of this window in pixels + - #height == the height of the client area of this window in pixels + !*/ + + void get_display_size ( + unsigned long& width, + unsigned long& height + ) const; + /*! + requires + - is_closed() == false + ensures + - #width == the width in pixels of the display device that contains this window + - #height == the height in pixels of the display device that contains this window + !*/ + + void invalidate_rectangle ( + const rectangle& rect + ); + /*! + ensures + - if (is_closed() == false) then + - causes the area of this window defined by rect to become invalid. + This means that a paint() message will be dispatched to repaint + this area of the window. Note that it is possible that the + resulting paint() message may include a bigger rectangle than + the one defined by rect. + !*/ + + void trigger_user_event ( + void* p, + int i + ); + /*! + ensures + - will never block (even if some other thread has a lock on the + global mutex referenced by wm.) + - if (is_closed() == false) then + - causes the on_user_event() event to be called with + the given arguments. + !*/ + + protected: + const rmutex& wm; + + // let the window close by default + virtual on_close_return_code on_window_close( + ){return CLOSE_WINDOW;} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when the user attempts to close this window + - if (this function returns CLOSE_WINDOW) then + - #is_closed() == true (i.e. this window will be closed) + - it is safe to call "delete this;" inside on_window_close() + if *this was allocated on the heap and no one will try to + access *this anymore. + - else + - this window will not be closed and the attempt to close it + by the user will have no effect. + - #is_closed() == false + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_user_event ( + void* p, + int i + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called whenever someone calls trigger_user_event() + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_window_resized( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when this window is resized + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_window_moved( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when this window's position changes + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when the user depresses one of the mouse buttons + - btn == the button that was depressed. (either LEFT, MIDDLE, or RIGHT) + - state == the bitwise OR of the buttons that are currently depressed + excluding the button given by btn. (from the mouse_state_masks enum) + - (x,y) == the position of the mouse (relative to the upper left corner + of the window) when this event occurred. Note that the mouse may be + outside the window. + - if (this is the second button press of a double click) then + - is_double_click == true + - else + - is_double_click == false + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when the user releases one of the mouse buttons + - btn == the button that was released. (either LEFT, MIDDLE, or RIGHT) + - state == the bitwise OR of the buttons that are currently depressed + (from the mouse_state_masks enum) + - (x,y) == the position of the mouse (relative to the upper left corner + of the window) when this event occurred. Note that the mouse may be + outside the window. + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_mouse_move ( + unsigned long state, + long x, + long y + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when the user moves the mouse + - state == the bitwise OR of the buttons that are currently depressed + (from the mouse_state_masks enum) + - (x,y) == the position of the mouse (relative to the upper left corner + of the window) when this event occurred. + - if (the user is holding down one or more of the mouse buttons) then + - the mouse move events will continue to track the mouse even if + it goes out of the window. This will continue until the user + releases all the mouse buttons. + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_mouse_leave ( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when the mouse leaves this window + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_mouse_enter ( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when the mouse enters this window + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_focus_gained ( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when this window gains input focus + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_focus_lost ( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when this window loses input focus + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_wheel_up ( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called every time the mouse wheel is scrolled up one notch + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_wheel_down ( + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called every time the mouse wheel is scrolled down one notch + ensures + - does not change the state of mutex wm + !*/ + + // do nothing by default + virtual void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ){} + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when a keyboard key is pressed or if a key is held + down then this is called repeatedly at a certain rate once the + typematic action begins (note that some keys might not have any + typematic action on some platforms). + - if (is_printable) then + - key == the character that was pressed. (e.g. 'a', 'b', '1' etc...) + - this is a printable character. Note that ' ', '\t', and + '\n' (this is the return/enter key) are all considered printable. + - else + - key == one of the non_printable_keyboard_keys enums. + - state == the bitwise OR of the keyboard modifiers that are currently + depressed (taken from keyboard_state_masks). + - if (key is not in the range 'a' to 'z' or 'A' to 'Z') then + - if (the shift key was down when this key was pressed) then + - (state & KBD_MOD_SHIFT) != 0 + - else + - (state & KBD_MOD_SHIFT) == 0 + - else + - the state of the shift key is implementation defined + ensures + - does not change the state of mutex wm + !*/ + + private: + + virtual void paint ( + const canvas& c + ) =0; + /*! + requires + - is_closed() == false + - mutex wm is locked + - is called when part of the window needs to be repainted for + any reason. + - c == a canvas object that represents the invalid area of this + window which needs to be painted. + ensures + - does not change the state of mutex wm + !*/ + + base_window(base_window&); // copy constructor + base_window& operator=(base_window&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GUI_CORE_KERNEl_ABSTRACT_ + diff --git a/dlib/gui_core/windows.h b/dlib/gui_core/windows.h new file mode 100644 index 0000000000000000000000000000000000000000..d9bba7d4fa9d33027db12da338f77387911ed624 --- /dev/null +++ b/dlib/gui_core/windows.h @@ -0,0 +1,6 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORE_KERNEl_2_ +#include "gui_core_kernel_1.h" +#endif + diff --git a/dlib/gui_core/xlib.h b/dlib/gui_core/xlib.h new file mode 100644 index 0000000000000000000000000000000000000000..5f9de962bd17ca0efb9a26468cd608b0de515257 --- /dev/null +++ b/dlib/gui_core/xlib.h @@ -0,0 +1,6 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_CORE_KERNEl_1_ +#include "gui_core_kernel_2.h" +#endif + diff --git a/dlib/gui_widgets.h b/dlib/gui_widgets.h new file mode 100644 index 0000000000000000000000000000000000000000..ddc4db9e1a6681b2841e6cef18a7c980edbf3b0c --- /dev/null +++ b/dlib/gui_widgets.h @@ -0,0 +1,13 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_GUI_WIDGETs_ +#define DLIB_GUI_WIDGETs_ + + + +#include "gui_widgets/widgets.h" + + + +#endif // DLIB_GUI_WIDGETs_ + diff --git a/dlib/gui_widgets/base_widgets.cpp b/dlib/gui_widgets/base_widgets.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37cc6d175e231c19930a63d0604c4c6a594bf6e9 --- /dev/null +++ b/dlib/gui_widgets/base_widgets.cpp @@ -0,0 +1,1372 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BASE_WIDGETs_CPP_ +#define DLIB_BASE_WIDGETs_CPP_ + +#include "base_widgets.h" +#include "../assert.h" +#include + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // dragable object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + dragable::~dragable() {} + +// ---------------------------------------------------------------------------------------- + + void dragable:: + on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (drag && (state & base_window::LEFT) && enabled && !hidden) + { + // the user is trying to drag this object. we should calculate the new + // x and y positions for the upper left corner of this object's rectangle + + long new_x = x - this->x; + long new_y = y - this->y; + + // make sure these points are inside the dragable area. + if (new_x < area.left()) + new_x = area.left(); + if (new_x + static_cast(rect.width()) - 1 > area.right()) + new_x = area.right() - rect.width() + 1; + + if (new_y + static_cast(rect.height()) - 1 > area.bottom()) + new_y = area.bottom() - rect.height() + 1; + if (new_y < area.top()) + new_y = area.top(); + + // now make the new rectangle for this object + rectangle new_rect( + new_x, + new_y, + new_x + rect.width() - 1, + new_y + rect.height() - 1 + ); + + // only do anything if this is a new rectangle and it is inside area + if (new_rect != rect && area.intersect(new_rect) == new_rect) + { + parent.invalidate_rectangle(new_rect + rect); + rect = new_rect; + + // call the on_drag() event handler + on_drag(); + } + } + else + { + drag = false; + } + } + +// ---------------------------------------------------------------------------------------- + + void dragable:: + on_mouse_down ( + unsigned long btn, + unsigned long , + long x, + long y, + bool + ) + { + if (enabled && !hidden && rect.contains(x,y) && btn == base_window::LEFT) + { + drag = true; + this->x = x - rect.left(); + this->y = y - rect.top(); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // mouse_over_event object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + mouse_over_event::~mouse_over_event() {} + +// ---------------------------------------------------------------------------------------- + + void mouse_over_event:: + on_mouse_leave ( + ) + { + if (enabled && !hidden && is_mouse_over_) + { + is_mouse_over_ = false; + on_mouse_not_over(); + } + } + +// ---------------------------------------------------------------------------------------- + + void mouse_over_event:: + on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (enabled == false || hidden == true) + return; + + if (rect.contains(x,y) == false) + { + if (is_mouse_over_) + { + is_mouse_over_ = false; + on_mouse_not_over(); + } + } + else if (is_mouse_over_ == false) + { + is_mouse_over_ = true; + on_mouse_over(); + } + } + +// ---------------------------------------------------------------------------------------- + + bool mouse_over_event:: + is_mouse_over ( + ) const + { + // check if the mouse is still really over this button + if (enabled && !hidden && is_mouse_over_ && rect.contains(lastx,lasty) == false) + { + // trigger a user event to call on_mouse_not_over() and repaint this object. + // we must do this in another event because someone might call is_mouse_over() + // from draw() and you don't want this function to end up calling + // parent.invalidate_rectangle(). It would lead to draw() being called over + // and over. + parent.trigger_user_event((void*)this,drawable::next_free_user_event_number()); + return false; + } + + return is_mouse_over_; + } + +// ---------------------------------------------------------------------------------------- + + void mouse_over_event:: + on_user_event ( + int num + ) + { + if (is_mouse_over_ && num == drawable::next_free_user_event_number()) + { + is_mouse_over_ = false; + on_mouse_not_over(); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // button_action object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + button_action::~button_action() {} + +// ---------------------------------------------------------------------------------------- + + void button_action:: + on_mouse_down ( + unsigned long btn, + unsigned long , + long x, + long y, + bool + ) + { + if (enabled && !hidden && btn == base_window::LEFT && rect.contains(x,y)) + { + is_depressed_ = true; + seen_click = true; + parent.invalidate_rectangle(rect); + on_button_down(); + } + } + +// ---------------------------------------------------------------------------------------- + + void button_action:: + on_mouse_not_over ( + ) + { + if (is_depressed_) + { + is_depressed_ = false; + parent.invalidate_rectangle(rect); + on_button_up(false); + } + } + +// ---------------------------------------------------------------------------------------- + + void button_action:: + on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + // forward event to the parent class so it can do it's thing as well as us + mouse_over_event::on_mouse_move(state,x,y); + + if (enabled == false || hidden == true) + return; + + + if ((state & base_window::LEFT) == 0) + { + seen_click = false; + if (is_depressed_) + { + is_depressed_ = false; + parent.invalidate_rectangle(rect); + on_button_up(false); + } + + // the left button isn't down so we don't care about anything else + return; + } + + if (rect.contains(x,y) == false) + { + if (is_depressed_) + { + is_depressed_ = false; + parent.invalidate_rectangle(rect); + on_button_up(false); + } + } + else if (is_depressed_ == false && seen_click) + { + is_depressed_ = true; + parent.invalidate_rectangle(rect); + on_button_down(); + } + } + +// ---------------------------------------------------------------------------------------- + + void button_action:: + on_mouse_up ( + unsigned long btn, + unsigned long, + long x, + long y + ) + { + if (enabled && !hidden && btn == base_window::LEFT) + { + if (is_depressed_) + { + is_depressed_ = false; + parent.invalidate_rectangle(rect); + + if (rect.contains(x,y)) + { + on_button_up(true); + } + else + { + on_button_up(false); + } + } + else if (seen_click && rect.contains(x,y)) + { + // this case here covers the unlikly event that you click on a button, + // move the mouse off the button and then move it back very quickly and + // release the mouse button. It is possible that this mouse up event + // will occurr before any mouse move event so you might not have set + // that the button is depressed yet. + + // So we should say that this triggers an on_button_down() event and + // then an on_button_up(true) event. + + parent.invalidate_rectangle(rect); + + on_button_down(); + on_button_up(true); + } + + seen_click = false; + } + } + +// ---------------------------------------------------------------------------------------- + + bool button_action:: + is_depressed ( + ) const + { + // check if the mouse is still really over this button + if (enabled && !hidden && is_depressed_ && rect.contains(lastx,lasty) == false) + { + // trigger a user event to call on_button_up() and repaint this object. + // we must do this in another event because someone might call is_depressed() + // from draw() and you don't want this function to end up calling + // parent.invalidate_rectangle(). It would lead to draw() being called over + // and over. + parent.trigger_user_event((void*)this,mouse_over_event::next_free_user_event_number()); + return false; + } + + return is_depressed_; + } + +// ---------------------------------------------------------------------------------------- + + void button_action:: + on_user_event ( + int num + ) + { + // forward event to the parent class so it can do it's thing as well as us + mouse_over_event::on_user_event(num); + + if (is_depressed_ && num == mouse_over_event::next_free_user_event_number()) + { + is_depressed_ = false; + parent.invalidate_rectangle(rect); + on_button_up(false); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // arrow_button object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void arrow_button:: + set_size ( + unsigned long width, + unsigned long height + ) + { + auto_mutex M(m); + + rectangle old(rect); + const unsigned long x = rect.left(); + const unsigned long y = rect.top(); + rect.set_right(x+width-1); + rect.set_bottom(y+height-1); + + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + void arrow_button:: + draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + fill_rect(c,rect,rgb_pixel(212,208,200)); + + const long height = rect.height(); + const long width = rect.width(); + + const long smallest = (width < height) ? width : height; + + const long rows = (smallest+3)/4; + const long start = rows + rows/2-1; + long dep; + + long tip_x = 0; + long tip_y = 0; + long wy = 0; + long hy = 0; + long wx = 0; + long hx = 0; + + if (button_action::is_depressed()) + { + dep = 0; + + // draw the button's border + draw_button_down(c,rect); + } + else + { + dep = -1; + + // draw the button's border + draw_button_up(c,rect); + } + + + switch (dir) + { + case UP: + tip_x = width/2 + rect.left() + dep; + tip_y = (height - start)/2 + rect.top() + dep + 1; + wy = 0; + hy = 1; + wx = 1; + hx = 0; + break; + + case DOWN: + tip_x = width/2 + rect.left() + dep; + tip_y = rect.bottom() - (height - start)/2 + dep; + wy = 0; + hy = -1; + wx = 1; + hx = 0; + break; + + case LEFT: + tip_x = rect.left() + (width - start)/2 + dep + 1; + tip_y = height/2 + rect.top() + dep; + wy = 1; + hy = 0; + wx = 0; + hx = 1; + break; + + case RIGHT: + tip_x = rect.right() - (width - start)/2 + dep; + tip_y = height/2 + rect.top() + dep; + wy = 1; + hy = 0; + wx = 0; + hx = -1; + break; + } + + + rgb_pixel color; + if (enabled) + { + color.red = 0; + color.green = 0; + color.blue = 0; + } + else + { + color.red = 128; + color.green = 128; + color.blue = 128; + } + + + + for (long i = 0; i < rows; ++i) + { + draw_line(c,point(tip_x + wx*i + hx*i, tip_y + wy*i + hy*i), + point(tip_x + wx*i*-1 + hx*i, tip_y + wy*i*-1 + hy*i), + color); + } + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // scroll_bar object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + scroll_bar:: + scroll_bar( + drawable_window& w, + bar_orientation orientation + ) : + drawable(w), + width_(16), + b1(w,arrow_button::UP), + b2(w,arrow_button::DOWN), + slider(w,*this,&scroll_bar::on_slider_drag), + ori(orientation), + top_filler(w,*this,&scroll_bar::top_filler_down,&scroll_bar::top_filler_up), + bottom_filler(w,*this,&scroll_bar::bottom_filler_down,&scroll_bar::bottom_filler_up), + pos(0), + max_pos(0), + js(10), + b1_timer(*this,&scroll_bar::b1_down_t), + b2_timer(*this,&scroll_bar::b2_down_t), + top_filler_timer(*this,&scroll_bar::top_filler_down_t), + bottom_filler_timer(*this,&scroll_bar::bottom_filler_down_t) + { + if (ori == HORIZONTAL) + { + b1.set_direction(arrow_button::LEFT); + b2.set_direction(arrow_button::RIGHT); + } + + // don't show the slider when there is no place it can move. + slider.hide(); + + set_length(100); + + b1.set_button_down_handler(*this,&scroll_bar::b1_down); + b2.set_button_down_handler(*this,&scroll_bar::b2_down); + + b1.set_button_up_handler(*this,&scroll_bar::b1_up); + b2.set_button_up_handler(*this,&scroll_bar::b2_up); + b1.disable(); + b2.disable(); + enable_events(); + } + +// ---------------------------------------------------------------------------------------- + + scroll_bar:: + ~scroll_bar( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + // wait for all the timers to be stopped + b1_timer.stop_and_wait(); + b2_timer.stop_and_wait(); + top_filler_timer.stop_and_wait(); + bottom_filler_timer.stop_and_wait(); + } + +// ---------------------------------------------------------------------------------------- + + scroll_bar::bar_orientation scroll_bar:: + orientation ( + ) const + { + auto_mutex M(m); + return ori; + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + set_orientation ( + bar_orientation new_orientation + ) + { + auto_mutex M(m); + unsigned long length; + + if (ori == HORIZONTAL) + length = rect.width(); + else + length = rect.height(); + + rectangle old_rect = rect; + + if (new_orientation == HORIZONTAL) + { + rect.set_right(rect.left() + length - 1 ); + rect.set_bottom(rect.top() + width_ - 1 ); + b1.set_direction(arrow_button::LEFT); + b2.set_direction(arrow_button::RIGHT); + + } + else + { + rect.set_right(rect.left() + width_ - 1); + rect.set_bottom(rect.top() + length - 1); + b1.set_direction(arrow_button::UP); + b2.set_direction(arrow_button::DOWN); + } + ori = new_orientation; + + parent.invalidate_rectangle(old_rect); + parent.invalidate_rectangle(rect); + + // call this to put everything is in the right spot. + set_pos (rect.left(),rect.top()); + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + set_length ( + unsigned long length + ) + { + // make the min length be at least 1 + if (length == 0) + { + length = 1; + } + + auto_mutex M(m); + + parent.invalidate_rectangle(rect); + + if (ori == HORIZONTAL) + { + rect.set_right(rect.left() + length - 1); + rect.set_bottom(rect.top() + width_ - 1); + + // if the length is too small then we have to smash up the arrow buttons + // and hide the slider. + if (length <= width_*2) + { + b1.set_size(length/2,width_); + b2.set_size(length/2,width_); + } + else + { + b1.set_size(width_,width_); + b2.set_size(width_,width_); + + // now adjust the slider + if (max_pos != 0) + { + slider.set_size(get_slider_size(),width_); + } + } + + } + else + { + rect.set_right(rect.left() + width_ - 1); + rect.set_bottom(rect.top() + length - 1); + + // if the length is too small then we have to smush up the arrow buttons + // and hide the slider. + if (length <= width_*2) + { + b1.set_size(width_,length/2); + b2.set_size(width_,length/2); + } + else + { + + b1.set_size(width_,width_); + b2.set_size(width_,width_); + + // now adjust the slider + if (max_pos != 0) + { + slider.set_size(width_,get_slider_size()); + } + } + + + } + + // call this to put everything is in the right spot. + set_pos (rect.left(),rect.top()); + + if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) || + (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) || + max_pos == 0) + { + hide_slider(); + } + else if (enabled && !hidden) + { + show_slider(); + } + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + drawable::set_pos(x,y); + + b1.set_pos(rect.left(),rect.top()); + if (ori == HORIZONTAL) + { + // make the b2 button appear at the end of the scroll_bar + b2.set_pos(rect.right()-b2.get_rect().width() + 1,rect.top()); + + if (max_pos != 0) + { + double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1; + double slider_pos = pos; + slider_pos /= max_pos; + slider_pos *= range; + slider.set_pos( + static_cast(slider_pos)+rect.left() + b1.get_rect().width(), + rect.top() + ); + + // move the dragable area for the slider to the new location + rectangle area = rect; + area.set_left(area.left() + width_); + area.set_right(area.right() - width_); + slider.set_dragable_area(area); + + } + + + } + else + { + // make the b2 button appear at the end of the scroll_bar + b2.set_pos(rect.left(), rect.bottom() - b2.get_rect().height() + 1); + + if (max_pos != 0) + { + double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1; + double slider_pos = pos; + slider_pos /= max_pos; + slider_pos *= range; + slider.set_pos( + rect.left(), + static_cast(slider_pos) + rect.top() + b1.get_rect().height() + ); + + // move the dragable area for the slider to the new location + rectangle area = rect; + area.set_top(area.top() + width_); + area.set_bottom(area.bottom() - width_); + slider.set_dragable_area(area); + } + } + + adjust_fillers(); + } + +// ---------------------------------------------------------------------------------------- + + unsigned long scroll_bar:: + get_slider_size ( + ) const + { + double range; + if (ori == HORIZONTAL) + { + range = rect.width() - b2.get_rect().width() - b1.get_rect().width(); + } + else + { + range = rect.height() - b2.get_rect().height() - b1.get_rect().height(); + } + + double scale_factor = 30.0/(max_pos + 30.0); + + if (scale_factor < 0.1) + scale_factor = 0.1; + + + double fraction = range/(max_pos + range)*scale_factor; + double result = fraction * range; + unsigned long res = static_cast(result); + if (res < 8) + res = 8; + return res; + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + adjust_fillers ( + ) + { + rectangle top(rect), bottom(rect); + + if (ori == HORIZONTAL) + { + if (slider.is_hidden()) + { + top.set_left(b1.get_rect().right()+1); + top.set_right(b2.get_rect().left()-1); + bottom.set_left(1); + bottom.set_right(-1); + } + else + { + top.set_left(b1.get_rect().right()+1); + top.set_right(slider.get_rect().left()-1); + bottom.set_left(slider.get_rect().right()+1); + bottom.set_right(b2.get_rect().left()-1); + } + } + else + { + if (slider.is_hidden()) + { + top.set_top(b1.get_rect().bottom()+1); + top.set_bottom(b2.get_rect().top()-1); + bottom.set_top(1); + bottom.set_bottom(-1); + } + else + { + top.set_top(b1.get_rect().bottom()+1); + top.set_bottom(slider.get_rect().top()-1); + bottom.set_top(slider.get_rect().bottom()+1); + bottom.set_bottom(b2.get_rect().top()-1); + } + } + + top_filler.rect = top; + bottom_filler.rect = bottom; + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + hide_slider ( + ) + { + rectangle top(rect), bottom(rect); + slider.hide(); + top_filler.disable(); + bottom_filler.disable(); + bottom_filler.hide(); + if (ori == HORIZONTAL) + { + top.set_left(b1.get_rect().right()+1); + top.set_right(b2.get_rect().left()-1); + } + else + { + top.set_top(b1.get_rect().bottom()+1); + top.set_bottom(b2.get_rect().top()-1); + } + top_filler.rect = top; + bottom_filler.rect = bottom; + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + show_slider ( + ) + { + if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) || + (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) || + max_pos == 0) + return; + + rectangle top(rect), bottom(rect); + slider.show(); + top_filler.enable(); + bottom_filler.enable(); + bottom_filler.show(); + if (ori == HORIZONTAL) + { + top.set_left(b1.get_rect().right()+1); + top.set_right(slider.get_rect().left()-1); + bottom.set_left(slider.get_rect().right()+1); + bottom.set_right(b2.get_rect().left()-1); + } + else + { + top.set_top(b1.get_rect().bottom()+1); + top.set_bottom(slider.get_rect().top()-1); + bottom.set_top(slider.get_rect().bottom()+1); + bottom.set_bottom(b2.get_rect().top()-1); + } + top_filler.rect = top; + bottom_filler.rect = bottom; + } + +// ---------------------------------------------------------------------------------------- + long scroll_bar:: + max_slider_pos ( + ) const + { + auto_mutex M(m); + return max_pos; + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + set_max_slider_pos ( + long mpos + ) + { + auto_mutex M(m); + max_pos = mpos; + if (pos > mpos) + pos = mpos; + + if (ori == HORIZONTAL) + set_length(rect.width()); + else + set_length(rect.height()); + + if (mpos != 0 && enabled) + { + b1.enable(); + b2.enable(); + } + else + { + b1.disable(); + b2.disable(); + } + + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + set_slider_pos ( + long pos + ) + { + auto_mutex M(m); + if (pos < 0) + pos = 0; + if (pos > max_pos) + pos = max_pos; + + this->pos = pos; + + // move the slider object to its new position + set_pos(rect.left(),rect.top()); + } + +// ---------------------------------------------------------------------------------------- + + long scroll_bar:: + slider_pos ( + ) const + { + auto_mutex M(m); + return pos; + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + on_slider_drag ( + ) + { + if (ori == HORIZONTAL) + { + double slider_pos = slider.get_rect().left() - b1.get_rect().right() - 1; + double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1; + slider_pos /= range; + slider_pos *= max_pos; + pos = static_cast(slider_pos); + } + else + { + double slider_pos = slider.get_rect().top() - b1.get_rect().bottom() - 1; + double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1; + slider_pos /= range; + slider_pos *= max_pos; + pos = static_cast(slider_pos); + } + + adjust_fillers(); + + if (scroll_handler.is_set()) + scroll_handler(); + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + draw ( + const canvas& + ) const + { + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + b1_down ( + ) + { + if (pos != 0) + { + set_slider_pos(pos-1); + if (scroll_handler.is_set()) + scroll_handler(); + + if (b1_timer.delay_time() == 1000) + b1_timer.set_delay_time(500); + else + b1_timer.set_delay_time(50); + b1_timer.start(); + } + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + b1_up ( + bool + ) + { + b1_timer.stop(); + b1_timer.set_delay_time(1000); + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + b2_down ( + ) + { + if (pos != max_pos) + { + set_slider_pos(pos+1); + if (scroll_handler.is_set()) + scroll_handler(); + + if (b2_timer.delay_time() == 1000) + b2_timer.set_delay_time(500); + else + b2_timer.set_delay_time(50); + b2_timer.start(); + } + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + b2_up ( + bool + ) + { + b2_timer.stop(); + b2_timer.set_delay_time(1000); + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + top_filler_down ( + ) + { + // ignore this if the mouse is now outside this object. This could happen + // since the timers are also calling this function. + if (top_filler.rect.contains(lastx,lasty) == false) + { + top_filler_up(false); + return; + } + + if (pos != 0) + { + if (pos < js) + { + // if there is less than jump_size() space left then jump the remaining + // amount. + delayed_set_slider_pos(0); + } + else + { + delayed_set_slider_pos(pos-js); + } + + if (top_filler_timer.delay_time() == 1000) + top_filler_timer.set_delay_time(500); + else + top_filler_timer.set_delay_time(50); + top_filler_timer.start(); + } + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + top_filler_up ( + bool + ) + { + top_filler_timer.stop(); + top_filler_timer.set_delay_time(1000); + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + bottom_filler_down ( + ) + { + // ignore this if the mouse is now outside this object. This could happen + // since the timers are also calling this function. + if (bottom_filler.rect.contains(lastx,lasty) == false) + { + bottom_filler_up(false); + return; + } + + if (pos != max_pos) + { + if (max_pos - pos < js) + { + // if there is less than jump_size() space left then jump the remaining + // amount. + delayed_set_slider_pos(max_pos); + } + else + { + delayed_set_slider_pos(pos+js); + } + + if (bottom_filler_timer.delay_time() == 1000) + bottom_filler_timer.set_delay_time(500); + else + bottom_filler_timer.set_delay_time(50); + bottom_filler_timer.start(); + } + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + bottom_filler_up ( + bool + ) + { + bottom_filler_timer.stop(); + bottom_filler_timer.set_delay_time(1000); + } + +// ---------------------------------------------------------------------------------------- + + void scroll_bar:: + set_jump_size ( + long js_ + ) + { + auto_mutex M(m); + if (js_ < 1) + js = 1; + else + js = js_; + } + +// ---------------------------------------------------------------------------------------- + + long scroll_bar:: + jump_size ( + ) const + { + auto_mutex M(m); + return js; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// widget_group object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void widget_group:: + empty ( + ) + { + auto_mutex M(m); + widgets.clear(); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + add ( + drawable& widget, + unsigned long x, + unsigned long y + ) + { + auto_mutex M(m); + drawable* w = &widget; + relpos rp; + rp.x = x; + rp.y = y; + if (widgets.is_in_domain(w)) + { + widgets[w].x = x; + widgets[w].y = y; + } + else + { + widgets.add(w,rp); + } + if (is_hidden()) + widget.hide(); + else + widget.show(); + + if (is_enabled()) + widget.enable(); + else + widget.disable(); + + widget.set_z_order(z_order()); + widget.set_pos(x+rect.left(),y+rect.top()); + } + +// ---------------------------------------------------------------------------------------- + + bool widget_group:: + is_member ( + const drawable& widget + ) const + { + auto_mutex M(m); + drawable* w = const_cast(&widget); + return widgets.is_in_domain(w); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + remove ( + const drawable& widget + ) + { + auto_mutex M(m); + drawable* w = const_cast(&widget); + if (widgets.is_in_domain(w)) + { + relpos junk; + drawable* junk2; + widgets.remove(w,junk2,junk); + } + } + +// ---------------------------------------------------------------------------------------- + + unsigned long widget_group:: + size ( + ) const + { + auto_mutex M(m); + return widgets.size(); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + widgets.reset(); + while (widgets.move_next()) + { + const unsigned long rx = widgets.element().value().x; + const unsigned long ry = widgets.element().value().y; + widgets.element().key()->set_pos(x+rx,y+ry); + } + drawable::set_pos(x,y); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + set_z_order ( + long order + ) + { + auto_mutex M(m); + widgets.reset(); + while (widgets.move_next()) + widgets.element().key()->set_z_order(order); + drawable::set_z_order(order); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + show ( + ) + { + auto_mutex M(m); + widgets.reset(); + while (widgets.move_next()) + widgets.element().key()->show(); + drawable::show(); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + hide ( + ) + { + auto_mutex M(m); + widgets.reset(); + while (widgets.move_next()) + widgets.element().key()->hide(); + drawable::hide(); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + enable ( + ) + { + auto_mutex M(m); + widgets.reset(); + while (widgets.move_next()) + widgets.element().key()->enable(); + drawable::enable(); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + disable ( + ) + { + auto_mutex M(m); + widgets.reset(); + while (widgets.move_next()) + widgets.element().key()->disable(); + drawable::disable(); + } + +// ---------------------------------------------------------------------------------------- + + void widget_group:: + fit_to_contents ( + ) + { + auto_mutex M(m); + rectangle r; + widgets.reset(); + while (widgets.move_next()) + r = r + widgets.element().key()->get_rect(); + + if (r.is_empty()) + { + // make sure it is still empty after we set it at the correct position + r.set_right(rect.left()-1); + r.set_bottom(rect.top()-1); + } + + r.set_left(rect.left()); + r.set_top(rect.top()); + rect = r; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BASE_WIDGETs_CPP_ + diff --git a/dlib/gui_widgets/base_widgets.h b/dlib/gui_widgets/base_widgets.h new file mode 100644 index 0000000000000000000000000000000000000000..f21725af0298c1512b5391fb3e1ff4a2d57cb1d0 --- /dev/null +++ b/dlib/gui_widgets/base_widgets.h @@ -0,0 +1,3023 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_BASE_WIDGETs_ +#define DLIB_BASE_WIDGETs_ + +#include "base_widgets_abstract.h" +#include "drawable.h" +#include "../gui_core.h" +#include "../algs.h" +#include "../member_function_pointer.h" +#include "../timer.h" +#include "../map.h" +#include "../array2d.h" +#include "../pixel.h" +#include "../image_transforms.h" +#include "../array.h" +#include "../smart_pointers.h" +#include + + +namespace dlib +{ + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class dragable +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class dragable : public drawable + { + /*! + INITIAL VALUE + - drag == false + + CONVENTION + - if (the user is holding the left button down over this object) then + - drag == true + - x == the x position of the mouse relative to the upper left corner + of this object. + - y == the y position of the mouse relative to the upper left corner + of this object. + - else + - drag == false + !*/ + + public: + + dragable( + drawable_window& w, + unsigned long events = 0 + ) : + drawable(w,events | MOUSE_MOVE | MOUSE_CLICK), + drag(false) + {} + + virtual ~dragable( + ) = 0; + + rectangle dragable_area ( + ) const { auto_mutex M(m); return area; } + + void set_dragable_area ( + const rectangle& area_ + ) { auto_mutex M(m); area = area_; } + + protected: + + virtual void on_drag ( + ){} + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + void on_mouse_down ( + unsigned long btn, + unsigned long , + long x, + long y, + bool + ); + + private: + + rectangle area; + bool drag; + long x, y; + + // restricted functions + dragable(dragable&); // copy constructor + dragable& operator=(dragable&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class mouse_over_event +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class mouse_over_event : public drawable + { + /*! + INITIAL VALUE + - is_mouse_over_ == false + + CONVENTION + - is_mouse_over_ == is_mouse_over() + !*/ + + public: + + mouse_over_event( + drawable_window& w, + unsigned long events = 0 + ) : + drawable(w,events | MOUSE_MOVE), + is_mouse_over_(false) + {} + + + virtual ~mouse_over_event( + ) = 0; + + int next_free_user_event_number() const + { + return drawable::next_free_user_event_number()+1; + } + + protected: + + bool is_mouse_over ( + ) const; + + virtual void on_mouse_over ( + ){} + + virtual void on_mouse_not_over ( + ){} + + void on_mouse_leave ( + ); + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + void on_user_event ( + int num + ); + + private: + mutable bool is_mouse_over_; + + // restricted functions + mouse_over_event(mouse_over_event&); // copy constructor + mouse_over_event& operator=(mouse_over_event&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class button_action +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class button_action : public mouse_over_event + { + /*! + INITIAL VALUE + - is_depressed_ == false + - seen_click == false + + CONVENTION + - is_depressed_ == is_depressed() + - if (the user has clicked the button but hasn't yet released the + left mouse button) then + - seen_click == true + - else + - seen_click == false + !*/ + + public: + + button_action( + drawable_window& w, + unsigned long events = 0 + ) : + mouse_over_event(w,events | MOUSE_MOVE | MOUSE_CLICK), + is_depressed_(false), + seen_click(false) + {} + + + virtual ~button_action( + ) = 0; + + int next_free_user_event_number() const + { + return mouse_over_event::next_free_user_event_number()+1; + } + + protected: + + bool is_depressed ( + ) const; + + virtual void on_button_down ( + ){} + + virtual void on_button_up ( + bool mouse_over + ){} + + void on_mouse_not_over ( + ); + + void on_mouse_down ( + unsigned long btn, + unsigned long , + long x, + long y, + bool + ); + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + void on_mouse_up ( + unsigned long btn, + unsigned long, + long x, + long y + ); + + + private: + mutable bool is_depressed_; + bool seen_click; + + void on_user_event ( + int num + ); + + // restricted functions + button_action(button_action&); // copy constructor + button_action& operator=(button_action&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class arrow_button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class arrow_button : public button_action + { + /*! + INITIAL VALUE + dir == whatever is given to the constructor + + CONVENTION + - dir == direction() + !*/ + + public: + enum arrow_direction + { + UP, + DOWN, + LEFT, + RIGHT + }; + + arrow_button( + drawable_window& w, + arrow_direction dir_ + ) : + button_action(w), + dir(dir_) + { + enable_events(); + } + + virtual ~arrow_button( + ){ disable_events(); parent.invalidate_rectangle(rect); } + + arrow_direction direction ( + ) const + { + auto_mutex M(m); + return dir; + } + + void set_direction ( + arrow_direction new_direction + ) + { + auto_mutex M(m); + dir = new_direction; + parent.invalidate_rectangle(rect); + } + + void set_size ( + unsigned long width, + unsigned long height + ); + + bool is_depressed ( + ) const + { + auto_mutex M(m); + return button_action::is_depressed(); + } + + template < + typename T + > + void set_button_down_handler ( + T& object, + void (T::*event_handler)() + ) + { + auto_mutex M(m); + button_down_handler.set(object,event_handler); + } + + template < + typename T + > + void set_button_up_handler ( + T& object, + void (T::*event_handler)(bool mouse_over) + ) + { + auto_mutex M(m); + button_up_handler.set(object,event_handler); + } + + protected: + + void draw ( + const canvas& c + ) const; + + void on_button_down ( + ) + { + if (button_down_handler.is_set()) + button_down_handler(); + } + + void on_button_up ( + bool mouse_over + ) + { + if (button_up_handler.is_set()) + button_up_handler(mouse_over); + } + + private: + + arrow_direction dir; + member_function_pointer<>::kernel_1a button_down_handler; + member_function_pointer::kernel_1a button_up_handler; + + // restricted functions + arrow_button(arrow_button&); // copy constructor + arrow_button& operator=(arrow_button&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class scroll_bar +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class scroll_bar : public drawable + { + /*! + INITIAL VALUE + - ori == a value given by the constructor + - width_ == 16 + - pos == 0 + - max_pos == 0 + - js == 10 + + CONVENTION + - ori == orientation() + - b1 == the button that is near the 0 end of the scroll bar + - b2 == the button that is near the max_pos() end of the scroll bar + + - max_pos == max_slider_pos() + - pos == slider_pos() + - js == jump_size() + !*/ + + public: + enum bar_orientation + { + HORIZONTAL, + VERTICAL + }; + + scroll_bar( + drawable_window& w, + bar_orientation orientation_ + ); + + virtual ~scroll_bar( + ); + + bar_orientation orientation ( + ) const; + + void set_orientation ( + bar_orientation new_orientation + ); + + void set_length ( + unsigned long length + ); + + long max_slider_pos ( + ) const; + + void set_max_slider_pos ( + long mpos + ); + + void set_slider_pos ( + long pos + ); + + long slider_pos ( + ) const; + + template < + typename T + > + void set_scroll_handler ( + T& object, + void (T::*eh)() + ) { scroll_handler.set(object,eh); } + + void set_pos ( + long x, + long y + ); + + void enable ( + ) + { + if (!hidden) + show_slider(); + if (max_pos != 0) + { + b1.enable(); + b2.enable(); + } + drawable::enable(); + } + + void disable ( + ) + { + hide_slider(); + b1.disable(); + b2.disable(); + drawable::disable(); + } + + void hide ( + ) + { + hide_slider(); + top_filler.hide(); + bottom_filler.hide(); + b1.hide(); + b2.hide(); + drawable::hide(); + } + + void show ( + ) + { + b1.show(); + b2.show(); + drawable::show(); + top_filler.show(); + if (enabled) + show_slider(); + } + + void set_z_order ( + long order + ) + { + slider.set_z_order(order); + top_filler.set_z_order(order); + bottom_filler.set_z_order(order); + b1.set_z_order(order); + b2.set_z_order(order); + drawable::set_z_order(order); + } + + void set_jump_size ( + long js + ); + + long jump_size ( + ) const; + + + private: + + void hide_slider ( + ); + /*! + ensures + - hides the slider and makes any other changes needed so that the + scroll_bar still looks right. + !*/ + + void show_slider ( + ); + /*! + ensures + - shows the slider and makes any other changes needed so that the + scroll_bar still looks right. + !*/ + + + void on_slider_drag ( + ); + /*! + requires + - is called whenever the user drags the slider + !*/ + + void draw ( + const canvas& c + ) const; + + void b1_down ( + ); + + void b1_up ( + bool mouse_over + ); + + void b2_down ( + ); + + void b2_up ( + bool mouse_over + ); + + void top_filler_down ( + ); + + void top_filler_up ( + bool mouse_over + ); + + void bottom_filler_down ( + ); + + void bottom_filler_up ( + bool mouse_over + ); + + void on_user_event ( + int i + ) + { + switch (i) + { + case 0: + b1_down(); + break; + case 1: + b2_down(); + break; + case 2: + top_filler_down(); + break; + case 3: + bottom_filler_down(); + break; + case 4: + // if the position we are supposed to switch the slider too isn't + // already set + if (delayed_pos != pos) + { + set_slider_pos(delayed_pos); + if (scroll_handler.is_set()) + scroll_handler(); + } + break; + default: + break; + } + } + + void delayed_set_slider_pos ( + unsigned long dpos + ) + { + delayed_pos = dpos; + parent.trigger_user_event(this,4); + } + + void b1_down_t ( + ) { parent.trigger_user_event(this,0); } + + void b2_down_t ( + ) { parent.trigger_user_event(this,1); } + + void top_filler_down_t ( + ) { parent.trigger_user_event(this,2); } + + void bottom_filler_down_t ( + ) { parent.trigger_user_event(this,3); } + + + class filler : public button_action + { + friend class scroll_bar; + public: + filler ( + drawable_window& w, + scroll_bar& object, + void (scroll_bar::*down)(), + void (scroll_bar::*up)(bool) + ): + button_action(w) + { + bup.set(object,up); + bdown.set(object,down); + + enable_events(); + } + + ~filler ( + ) + { + disable_events(); + } + + void set_size ( + unsigned long width, + unsigned long height + ) + { + rectangle old(rect); + const unsigned long x = rect.left(); + const unsigned long y = rect.top(); + rect.set_right(x+width-1); + rect.set_bottom(y+height-1); + + parent.invalidate_rectangle(rect+old); + } + + private: + + void draw ( + const canvas& c + ) const + { + if (is_depressed()) + draw_checkered(c, rect,rgb_pixel(0,0,0),rgb_pixel(43,47,55)); + else + draw_checkered(c, rect,rgb_pixel(255,255,255),rgb_pixel(212,208,200)); + } + + void on_button_down ( + ) { bdown(); } + + void on_button_up ( + bool mouse_over + ) { bup(mouse_over); } + + member_function_pointer<>::kernel_1a bdown; + member_function_pointer::kernel_1a bup; + }; + + class slider_class : public dragable + { + friend class scroll_bar; + public: + slider_class ( + drawable_window& w, + scroll_bar& object, + void (scroll_bar::*handler)() + ) : + dragable(w) + { + mfp.set(object,handler); + enable_events(); + } + + ~slider_class ( + ) + { + disable_events(); + } + + void set_size ( + unsigned long width, + unsigned long height + ) + { + rectangle old(rect); + const unsigned long x = rect.left(); + const unsigned long y = rect.top(); + rect.set_right(x+width-1); + rect.set_bottom(y+height-1); + + parent.invalidate_rectangle(rect+old); + } + + private: + void on_drag ( + ) + { + mfp(); + } + + void draw ( + const canvas& c + ) const + { + fill_rect(c, rect, rgb_pixel(212,208,200)); + draw_button_up(c, rect); + } + + member_function_pointer<>::kernel_1a mfp; + }; + + + void adjust_fillers ( + ); + /*! + ensures + - top_filler and bottom_filler appear in their correct positions + relative to the current positions of the slider and the b1 and + b2 buttons + !*/ + + unsigned long get_slider_size ( + ) const; + /*! + ensures + - returns the length in pixels the slider should have based on the current + state of this scroll bar + !*/ + + + const unsigned long width_; + arrow_button b1, b2; + slider_class slider; + bar_orientation ori; + filler top_filler, bottom_filler; + member_function_pointer<>::kernel_1a scroll_handler; + + long pos; + long max_pos; + long js; + + timer::kernel_2a b1_timer; + timer::kernel_2a b2_timer; + timer::kernel_2a top_filler_timer; + timer::kernel_2a bottom_filler_timer; + long delayed_pos; + + // restricted functions + scroll_bar(scroll_bar&); // copy constructor + scroll_bar& operator=(scroll_bar&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class widget_group +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class widget_group : public drawable + { + /*! + INITIAL VALUE + widgets.size() == 0 + + CONVENTION + Widgets contains all the drawable objects and their relative positions + that are in *this. + !*/ + + struct relpos + { + unsigned long x; + unsigned long y; + }; + + public: + widget_group( + drawable_window& w + ) : drawable(w) { rect = rectangle(0,0,-1,-1); enable_events();} + + virtual ~widget_group( + ){ disable_events(); } + + void empty ( + ); + + void add ( + drawable& widget, + unsigned long x, + unsigned long y + ); + + bool is_member ( + const drawable& widget + ) const; + + void remove ( + const drawable& widget + ); + + unsigned long size ( + ) const; + + void set_pos ( + long x, + long y + ); + + void set_z_order ( + long order + ); + + void show ( + ); + + void hide ( + ); + + void enable ( + ); + + void disable ( + ); + + void fit_to_contents ( + ); + + protected: + + // this object doesn't draw anything but also isn't abstract + void draw ( + const canvas& c + ) const {} + + private: + + map::kernel_1a_c widgets; + + // restricted functions + widget_group(widget_group&); // copy constructor + widget_group& operator=(widget_group&); // assignment operator + }; + + +// ---------------------------------------------------------------------------------------- + + class image_widget : public dragable + { + /*! + INITIAL VALUE + - img.size() == 0 + + CONVENTION + - img == the image this object displays + !*/ + + public: + + image_widget( + drawable_window& w + ): dragable(w) { enable_events(); } + + ~image_widget( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + } + + template < + typename image_type + > + void set_image ( + const image_type& new_img + ) + { + auto_mutex M(m); + assign_image(img,new_img); + rectangle old(rect); + rect.set_right(rect.left()+img.nc()-1); + rect.set_bottom(rect.top()+img.nr()-1); + parent.invalidate_rectangle(rect+old); + } + + private: + + void draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + draw_image(c, point(rect.left(),rect.top()), img); + } + + array2d::kernel_1a img; + + // restricted functions + image_widget(image_widget&); // copy constructor + image_widget& operator=(image_widget&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class tooltip +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class tooltip : public mouse_over_event + { + /*! + INITIAL VALUE + - stuff.get() == 0 + - events_are_enabled() == false + + CONVENTION + - if (events_are_enabled() == true) then + - stuff.get() != 0 + !*/ + + public: + + tooltip( + drawable_window& w + ) : + mouse_over_event(w,MOUSE_CLICK) + {} + + ~tooltip( + ){ disable_events();} + + void set_size ( + long width, + long height + ) + { + auto_mutex M(m); + rect = resize_rect(rect,width,height); + } + + + void set_text ( + const std::string& str + ) + { + auto_mutex M(m); + if (!stuff) + { + stuff.reset(new data(*this)); + enable_events(); + } + + stuff->win.set_text(str); + } + + const std::string text ( + ) const + { + auto_mutex M(m); + std::string temp; + if (stuff) + { + temp = stuff->win.text; + } + return temp.c_str(); + } + + void hide ( + ) + { + mouse_over_event::hide(); + if (stuff) + { + stuff->tt_timer.stop(); + stuff->win.hide(); + } + } + + void disable ( + ) + { + mouse_over_event::disable(); + if (stuff) + { + stuff->tt_timer.stop(); + stuff->win.hide(); + } + } + + protected: + + void on_mouse_over() + { + stuff->x = lastx; + stuff->y = lasty; + stuff->tt_timer.start(); + } + + void on_mouse_not_over () + { + stuff->tt_timer.stop(); + stuff->win.hide(); + } + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ) + { + mouse_over_event::on_mouse_down(btn,state,x,y,is_double_click); + stuff->tt_timer.stop(); + stuff->win.hide(); + } + + void draw ( + const canvas& + ) const{} + + private: + + class tooltip_window : public base_window + { + public: + tooltip_window (const font* f) : base_window(false,true), pad(3), mfont(f) + { + } + + std::string text; + rectangle rect_all; + rectangle rect_text; + const unsigned long pad; + const font* mfont; + + void set_text ( + const std::string& str + ) + { + text = str.c_str(); + + unsigned long width, height; + mfont->compute_size(text,width,height); + + set_size(width+pad*2, height+pad*2); + rect_all.set_left(0); + rect_all.set_top(0); + rect_all.set_right(width+pad*2-1); + rect_all.set_bottom(height+pad*2-1); + + rect_text = move_rect(rectangle(width,height),pad,pad); + } + + void paint(const canvas& c) + { + c.fill(255,255,150); + draw_rectangle(c, rect_all); + mfont->draw_string(c,rect_text,text); + } + }; + + void show_tooltip ( + ) + { + auto_mutex M(m); + long x, y; + // if the mouse has moved since we started the timer then + // keep waiting until the user stops moving it + if (lastx != stuff->x || lasty != stuff->y) + { + stuff->x = lastx; + stuff->y = lasty; + return; + } + + unsigned long display_width, display_height; + // stop the timer + stuff->tt_timer.stop(); + parent.get_pos(x,y); + x += lastx+15; + y += lasty+15; + + // make sure the tooltip isn't going to be off the screen + parent.get_display_size(display_width, display_height); + rectangle wrect(move_rect(stuff->win.rect_all,x,y)); + rectangle srect(display_width, display_height); + if (srect.contains(wrect) == false) + { + rectangle temp(srect.intersect(wrect)); + x -= wrect.width()-temp.width(); + y -= wrect.height()-temp.height(); + } + + stuff->win.set_pos(x,y); + stuff->win.show(); + } + + // put all this stuff in data so we can arrange to only + // construct it when someone is actually using the tooltip widget + // rather than just instantiating it. + struct data + { + data( + tooltip& self + ) : + x(-1), + y(-1), + win(self.mfont), + tt_timer(self,&tooltip::show_tooltip) + { + tt_timer.set_delay_time(400); + } + + long x, y; + tooltip_window win; + timer::kernel_2a tt_timer; + + }; + friend struct data; + scoped_ptr stuff; + + + + // restricted functions + tooltip(tooltip&); // copy constructor + tooltip& operator=(tooltip&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class popup_menu +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class menu_item + { + public: + virtual ~menu_item() {} + + virtual rectangle get_left_size ( + ) const { return rectangle(); } + virtual rectangle get_middle_size ( + ) const = 0; + virtual rectangle get_right_size ( + ) const { return rectangle(); } + + virtual unichar get_hot_key ( + ) const { return 0; } + + virtual void draw_background ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const {} + + virtual void draw_left ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const {} + + virtual void draw_middle ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const = 0; + + virtual void draw_right ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const {} + + virtual void on_click ( + ) const {} + + virtual bool has_click_event ( + ) const { return false; } + + }; + +// ---------------------------------------------------------------------------------------- + + class menu_item_submenu : public menu_item + { + public: + menu_item_submenu ( + const std::string& str, + unichar hk = 0 + ) : + text(str), + f(default_font::get_font()), + hotkey(hk) + { + if (hk != 0) + { + std::string::size_type pos = str.find_first_of(hk); + if (pos != std::string::npos) + { + // now compute the location of the underline bar + rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos); + rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1); + + underline_p1.x() = r1.left()+1; + underline_p2.x() = r2.left()-1; + underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2; + underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2; + } + } + } + + virtual unichar get_hot_key ( + ) const { return hotkey; } + + virtual rectangle get_middle_size ( + ) const + { + unsigned long width, height; + f->compute_size(text,width,height); + return rectangle(width+30,height); + } + + virtual rectangle get_right_size ( + ) const + { + return rectangle(15, 5); + } + + virtual void draw_background ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + if (c.intersect(rect).is_empty()) + return; + + if (enabled && is_selected) + { + fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100)); + draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100)); + } + } + + virtual void draw_right ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + if (c.intersect(rect).is_empty()) + return; + + unsigned char color = 0; + + if (enabled == false) + color = 128; + + long x, y; + x = rect.right() - 7; + y = rect.top() + rect.height()/2; + + for ( unsigned long i = 0; i < 5; ++i) + draw_line (c, point(x - i, y + i), point(x - i, y - i), color); + } + + virtual void draw_middle ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + if (c.intersect(rect).is_empty()) + return; + + if (enabled) + { + f->draw_string(c,rect,text); + } + else + { + f->draw_string(c,rect,text,128); + } + + if (underline_p1 != underline_p2) + { + point base(rect.left(),rect.top()); + draw_line(c, base+underline_p1, base+underline_p2); + } + } + + private: + std::string text; + const font* f; + member_function_pointer<>::kernel_1a action; + unichar hotkey; + point underline_p1; + point underline_p2; + }; + +// ---------------------------------------------------------------------------------------- + + class menu_item_text : public menu_item + { + public: + template + menu_item_text ( + const std::string& str, + T& object, + void (T::*event_handler_)(), + unichar hk = 0 + ) : + text(str), + f(default_font::get_font()), + hotkey(hk) + { + action.set(object,event_handler_); + + if (hk != 0) + { + std::string::size_type pos = str.find_first_of(hk); + if (pos != std::string::npos) + { + // now compute the location of the underline bar + rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos); + rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1); + + underline_p1.x() = r1.left()+1; + underline_p2.x() = r2.left()-1; + underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2; + underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2; + } + } + } + + virtual unichar get_hot_key ( + ) const { return hotkey; } + + virtual rectangle get_middle_size ( + ) const + { + unsigned long width, height; + f->compute_size(text,width,height); + return rectangle(width,height); + } + + virtual void draw_background ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + if (c.intersect(rect).is_empty()) + return; + + if (enabled && is_selected) + { + fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100)); + draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100)); + } + } + + virtual void draw_middle ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + if (c.intersect(rect).is_empty()) + return; + + if (enabled) + { + f->draw_string(c,rect,text); + } + else + { + f->draw_string(c,rect,text,128); + } + + if (underline_p1 != underline_p2) + { + point base(rect.left(),rect.top()); + draw_line(c, base+underline_p1, base+underline_p2); + } + } + + virtual void on_click ( + ) const + { + action(); + } + + virtual bool has_click_event ( + ) const { return true; } + + private: + std::string text; + const font* f; + member_function_pointer<>::kernel_1a action; + unichar hotkey; + point underline_p1; + point underline_p2; + }; + +// ---------------------------------------------------------------------------------------- + + class menu_item_separator : public menu_item + { + public: + virtual rectangle get_middle_size ( + ) const + { + return rectangle(10,4); + } + + virtual void draw_background ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + if (c.intersect(rect).is_empty()) + return; + + point p1(rect.left(),rect.top()+rect.height()/2-1); + point p2(rect.right(),rect.top()+rect.height()/2-1); + + point p3(rect.left(),rect.top()+rect.height()/2); + point p4(rect.right(),rect.top()+rect.height()/2); + draw_line(c, p1,p2,128); + draw_line(c, p3,p4,255); + } + + virtual void draw_middle ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const + { + } + }; + +// ---------------------------------------------------------------------------------------- + + class popup_menu : public base_window + { + /*! + INITIAL VALUE + - pad == 2 + - item_pad == 3 + - cur_rect == rectangle(pad,pad,pad-1,pad-1) + - left_width == 0 + - middle_width == 0 + - selected_item == 0 + - submenu_open == false + - items.size() == 0 + - item_enabled.size() == 0 + - left_rects.size() == 0 + - middle_rects.size() == 0 + - right_rects.size() == 0 + - line_rects.size() == 0 + - submenus.size() == 0 + - hide_handlers.size() == 0 + + CONVENTION + - pad = 2 + - item_pad = 3 + - all of the following arrays have the same size: + - items.size() + - item_enabled.size() + - left_rects.size() + - middle_rects.size() + - right_rects.size() + - line_rects.size() + - submenus.size() + + - win_rect == a rectangle that is the exact size of this window and with + its upper left corner at (0,0) + - cur_rect == the rect inside which all the menu items are drawn + + - if (a menu_item is supposed to be selected) then + - selected_item == the index in menus of the menu_item + - else + - selected_item == submenus.size() + + - if (there is a selected submenu and it is currently open) then + - submenu_open == true + - else + - submenu_open == false + + - for all valid i: + - items[i] == a pointer to the ith menu_item + - item_enabled[i] == true if the ith menu_item is enabled, false otherwise + - left_rects[i] == the left rectangle for the ith menu item + - middle_rects[i] == the middle rectangle for the ith menu item + - right_rects[i] == the right rectangle for the ith menu item + - line_rects[i] == the rectangle for the entire line on which the ith menu + item appears. + - if (submenus[i] != 0) then + - the ith menu item has a submenu and it is pointed to by submenus[i] + + - hide_handlers == an array of all the on_hide events registered for + this popup_menu + !*/ + + public: + + popup_menu ( + ) : + base_window(false,true), + pad(2), + item_pad(3), + cur_rect(pad,pad,pad-1,pad-1), + left_width(0), + middle_width(0), + selected_item(0), + submenu_open(false) + { + } + + template < + typename menu_item_type + > + unsigned long add_menu_item ( + const menu_item_type& new_item + ) + { + auto_mutex M(wm); + bool t = true; + scoped_ptr item(new menu_item_type(new_item)); + items.push_back(item); + item_enabled.push_back(t); + + // figure out how big the window should be now and what not + rectangle left = new_item.get_left_size(); + rectangle middle = new_item.get_middle_size(); + rectangle right = new_item.get_right_size(); + + bool recalc_rect_positions = false; + const rectangle all = left+middle+right; + + + // make sure left_width contains the max of all the left rectangles + if (left.width() > left_width) + { + left_width = left.width(); + recalc_rect_positions = true; + } + // make sure middle_width contains the max of all the middle rectangles + if (middle.width() > middle_width) + { + middle_width = middle.width(); + recalc_rect_positions = true; + } + + // make the current rectangle wider if necessary + if (cur_rect.width() < left_width + middle_width + right.width() + 2*item_pad) + { + cur_rect = resize_rect_width(cur_rect, left_width + middle_width + right.width() + 2*item_pad); + recalc_rect_positions = true; + } + + const long y = cur_rect.bottom()+1 + item_pad; + const long x = cur_rect.left() + item_pad; + + // make the current rectangle taller to account for this new menu item + cur_rect.set_bottom(cur_rect.bottom()+all.height() + 2*item_pad); + + // adjust all the saved rectangles since the width of the window changed + // or left_width changed + if (recalc_rect_positions) + { + long y = cur_rect.top() + item_pad; + for (unsigned long i = 0; i < left_rects.size(); ++i) + { + middle_rects[i] = move_rect(middle_rects[i], x+left_width, y); + right_rects[i] = move_rect(right_rects[i], x+cur_rect.width()-right_rects[i].width()-item_pad, y); + line_rects[i] = resize_rect_width(line_rects[i], cur_rect.width()); + + y += line_rects[i].height(); + } + } + + // save the rectangles for later use. Also position them at the + // right spots + left = move_rect(left,x,y); + middle = move_rect(middle,x+left_width,y); + right = move_rect(right,x+cur_rect.width()-right.width()-item_pad,y); + rectangle line(move_rect(rectangle(cur_rect.width(),all.height()+2*item_pad), x-item_pad, y-item_pad)); + + // make sure the left, middle, and right rectangles are centered in the + // line. + if (left.height() < all.height()) + left = translate_rect(left,0, (all.height()-left.height())/2); + if (middle.height() < all.height()) + middle = translate_rect(middle,0, (all.height()-middle.height())/2); + if (right.height() < all.height()) + right = translate_rect(right,0, (all.height()-right.height())/2); + + left_rects.push_back(left); + middle_rects.push_back(middle); + right_rects.push_back(right); + line_rects.push_back(line); + + popup_menu* junk = 0; + submenus.push_back(junk); + + win_rect.set_right(cur_rect.right()+pad); + win_rect.set_bottom(cur_rect.bottom()+pad); + set_size(win_rect.width(),win_rect.height()); + + // make it so that nothing is selected + selected_item = submenus.size(); + + return items.size()-1; + } + + template < + typename menu_item_type + > + unsigned long add_submenu ( + const menu_item_type& new_item, + popup_menu& submenu + ) + { + auto_mutex M(wm); + + submenus[add_menu_item(new_item)] = &submenu; + + submenu.set_on_hide_handler(*this,&popup_menu::on_submenu_hide); + + return items.size()-1; + } + + void enable_menu_item ( + unsigned long idx + ) + { + DLIB_ASSERT ( idx < size() , + "\tvoid popup_menu::enable_menu_item()" + << "\n\tidx: " << idx + << "\n\tsize(): " << size() + ); + auto_mutex M(wm); + item_enabled[idx] = true; + invalidate_rectangle(cur_rect); + } + + void disable_menu_item ( + unsigned long idx + ) + { + DLIB_ASSERT ( idx < size() , + "\tvoid popup_menu::enable_menu_item()" + << "\n\tidx: " << idx + << "\n\tsize(): " << size() + ); + auto_mutex M(wm); + item_enabled[idx] = false; + invalidate_rectangle(cur_rect); + } + + unsigned long size ( + ) const + { + auto_mutex M(wm); + return items.size(); + } + + void clear ( + ) + { + auto_mutex M(wm); + hide(); + cur_rect = rectangle(pad,pad,pad-1,pad-1); + win_rect = rectangle(); + left_width = 0; + middle_width = 0; + items.clear(); + item_enabled.clear(); + left_rects.clear(); + middle_rects.clear(); + right_rects.clear(); + line_rects.clear(); + submenus.clear(); + selected_item = 0; + submenu_open = false; + } + + void show ( + ) + { + auto_mutex M(wm); + selected_item = submenus.size(); + base_window::show(); + } + + void hide ( + ) + { + auto_mutex M(wm); + // hide ourselves + close_submenu(); + selected_item = submenus.size(); + base_window::hide(); + } + + template + void set_on_hide_handler ( + T& object, + void (T::*event_handler)() + ) + { + auto_mutex M(wm); + + member_function_pointer<>::kernel_1a temp; + temp.set(object,event_handler); + + // if this handler isn't already registered then add it + bool found_handler = false; + for (unsigned long i = 0; i < hide_handlers.size(); ++i) + { + if (hide_handlers[i] == temp) + { + found_handler = true; + break; + } + } + + if (found_handler == false) + { + hide_handlers.push_back(temp); + } + } + + void select_first_item ( + ) + { + auto_mutex M(wm); + close_submenu(); + selected_item = items.size(); + for (unsigned long i = 0; i < items.size(); ++i) + { + if ((items[i]->has_click_event() || submenus[i]) && item_enabled[i]) + { + selected_item = i; + break; + } + } + invalidate_rectangle(cur_rect); + } + + bool forwarded_on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + auto_mutex M(wm); + // do nothing if this popup menu is empty + if (items.size() == 0) + return false; + + + // check if the selected item is a submenu + if (selected_item != submenus.size() && submenus[selected_item] != 0 && submenu_open) + { + // send the key to the submenu and return if that menu used the key + if (submenus[selected_item]->forwarded_on_keydown(key,is_printable,state) == true) + return true; + } + + if (key == KEY_UP) + { + for (unsigned long i = 0; i < items.size(); ++i) + { + selected_item = (selected_item + items.size() - 1)%items.size(); + // only stop looking if this one is enabled and has a click event or is a submenu + if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item]) ) + break; + } + invalidate_rectangle(cur_rect); + return true; + } + else if (key == KEY_DOWN) + { + for (unsigned long i = 0; i < items.size(); ++i) + { + selected_item = (selected_item + 1)%items.size(); + // only stop looking if this one is enabled and has a click event or is a submenu + if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item])) + break; + } + invalidate_rectangle(cur_rect); + return true; + } + else if (key == KEY_RIGHT && submenu_open == false && display_selected_submenu()) + { + submenus[selected_item]->select_first_item(); + return true; + } + else if (key == KEY_LEFT && selected_item != submenus.size() && + submenus[selected_item] != 0 && submenu_open) + { + close_submenu(); + return true; + } + else if (key == '\n') + { + if (selected_item != submenus.size() && (items[selected_item]->has_click_event() || submenus[selected_item])) + { + const long idx = selected_item; + // only hide this popup window if this isn't a submenu + if (submenus[idx] == 0) + { + hide(); + hide_handlers.reset(); + while (hide_handlers.move_next()) + hide_handlers.element()(); + } + else + { + display_selected_submenu(); + submenus[idx]->select_first_item(); + } + items[idx]->on_click(); + return true; + } + } + else if (is_printable) + { + // check if there is a hotkey for this key + for (unsigned long i = 0; i < items.size(); ++i) + { + if (std::tolower(key) == std::tolower(items[i]->get_hot_key()) && + (items[i]->has_click_event() || submenus[i]) ) + { + // only hide this popup window if this isn't a submenu + if (submenus[i] == 0) + { + hide(); + hide_handlers.reset(); + while (hide_handlers.move_next()) + hide_handlers.element()(); + } + else + { + if (selected_item != items.size()) + invalidate_rectangle(line_rects[selected_item]); + + selected_item = i; + display_selected_submenu(); + invalidate_rectangle(line_rects[i]); + submenus[i]->select_first_item(); + } + items[i]->on_click(); + } + } + + // always say we use a printable key for hotkeys + return true; + } + + return false; + } + + private: + + void on_submenu_hide ( + ) + { + hide(); + hide_handlers.reset(); + while (hide_handlers.move_next()) + hide_handlers.element()(); + } + + void on_window_resized( + ) + { + invalidate_rectangle(win_rect); + } + + void on_mouse_up ( + unsigned long btn, + unsigned long, + long x, + long y + ) + { + if (cur_rect.contains(x,y) && btn == LEFT) + { + // figure out which item this was on + for (unsigned long i = 0; i < items.size(); ++i) + { + if (line_rects[i].contains(x,y) && item_enabled[i] && items[i]->has_click_event()) + { + // only hide this popup window if this isn't a submenu + if (submenus[i] == 0) + { + hide(); + hide_handlers.reset(); + while (hide_handlers.move_next()) + hide_handlers.element()(); + } + items[i]->on_click(); + break; + } + } + } + } + + void on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (cur_rect.contains(x,y)) + { + // check if the mouse is still in the same rect it was in last time + rectangle last_rect; + if (selected_item != submenus.size()) + { + last_rect = line_rects[selected_item]; + } + + // if the mouse isn't in the same rectangle any more + if (last_rect.contains(x,y) == false) + { + if (selected_item != submenus.size()) + { + invalidate_rectangle(last_rect); + close_submenu(); + selected_item = submenus.size(); + } + + + // figure out if we should redraw any menu items + for (unsigned long i = 0; i < items.size(); ++i) + { + if (items[i]->has_click_event() || submenus[i]) + { + if (line_rects[i].contains(x,y)) + { + selected_item = i; + break; + } + } + } + + // if we found a rectangle that contains the mouse then + // tell it to redraw itself + if (selected_item != submenus.size()) + { + display_selected_submenu(); + invalidate_rectangle(line_rects[selected_item]); + } + } + } + } + + void close_submenu ( + ) + { + if (selected_item != submenus.size() && submenus[selected_item] && submenu_open) + { + submenus[selected_item]->hide(); + submenu_open = false; + } + } + + bool display_selected_submenu ( + ) + /*! + ensures + - if (submenus[selected_item] isn't null) then + - displays the selected submenu + - returns true + - else + - returns false + !*/ + { + // show the submenu if one exists + if (selected_item != submenus.size() && submenus[selected_item]) + { + long wx, wy; + get_pos(wx,wy); + wx += line_rects[selected_item].right(); + wy += line_rects[selected_item].top(); + submenus[selected_item]->set_pos(wx+1,wy-2); + submenus[selected_item]->show(); + submenu_open = true; + return true; + } + return false; + } + + void on_mouse_leave ( + ) + { + if (selected_item != submenus.size()) + { + // only unhighlight a menu item if it isn't a submenu item + if (submenus[selected_item] == 0) + { + invalidate_rectangle(line_rects[selected_item]); + selected_item = submenus.size(); + } + } + } + + void paint ( + const canvas& c + ) + { + c.fill(200,200,200); + draw_rectangle(c, win_rect); + for (unsigned long i = 0; i < items.size(); ++i) + { + bool is_selected = false; + if (selected_item != submenus.size() && i == selected_item && + item_enabled[i]) + is_selected = true; + + items[i]->draw_background(c,line_rects[i], item_enabled[i], is_selected); + items[i]->draw_left(c,left_rects[i], item_enabled[i], is_selected); + items[i]->draw_middle(c,middle_rects[i], item_enabled[i], is_selected); + items[i]->draw_right(c,right_rects[i], item_enabled[i], is_selected); + } + } + + const long pad; + const long item_pad; + rectangle cur_rect; + rectangle win_rect; + unsigned long left_width; + unsigned long middle_width; + array >::expand_1d_c items; + array::expand_1d_c item_enabled; + array::expand_1d_c left_rects; + array::expand_1d_c middle_rects; + array::expand_1d_c right_rects; + array::expand_1d_c line_rects; + array::expand_1d_c submenus; + unsigned long selected_item; + bool submenu_open; + array::kernel_1a>::expand_1d_c hide_handlers; + + // restricted functions + popup_menu(popup_menu&); // copy constructor + popup_menu& operator=(popup_menu&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + class zoomable_region : public drawable + { + /*! + INITIAL VALUE + - min_scale == 0.15 + - max_scale == 1.0 + - zoom_increment_ == 0.02 + - scale == 1.0 + - mouse_drag_screen == false + + + CONVENTION + - zoom_increment() == zoom_increment_ + - min_zoom_scale() == min_scale + - max_zoom_scale() == max_scale + - zoom_scale() == scale + - if (the user is currently dragging the graph around via the mouse) then + - mouse_drag_screen == true + - else + - mouse_drag_screen == false + + - max_graph_point() == lr_point + - display_rect() == display_rect_ + - gui_to_graph_space(point(display_rect.left(),display_rect.top())) == gr_orig + !*/ + + public: + + zoomable_region ( + drawable_window& w, + unsigned long events = 0 + ) : + drawable(w,MOUSE_CLICK | MOUSE_WHEEL | MOUSE_MOVE | events), + min_scale(0.15), + max_scale(1.0), + zoom_increment_(0.02), + vsb(w, scroll_bar::VERTICAL), + hsb(w, scroll_bar::HORIZONTAL) + { + scale = 1; + mouse_drag_screen = false; + + hsb.set_scroll_handler(*this,&zoomable_region::on_h_scroll); + vsb.set_scroll_handler(*this,&zoomable_region::on_v_scroll); + } + + inline ~zoomable_region ( + )= 0; + + void set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + drawable::set_pos(x,y); + vsb.set_pos(rect.right()-2-vsb.width(),rect.top()+2); + hsb.set_pos(rect.left()+2,rect.bottom()-2-hsb.height()); + + display_rect_ = rectangle(rect.left()+2,rect.top()+2,rect.right()-2-vsb.width(),rect.bottom()-2-hsb.height()); + + } + + void set_zoom_increment ( + double zi + ) + { + auto_mutex M(m); + zoom_increment_ = zi; + } + + double zoom_increment ( + ) const + { + auto_mutex M(m); + return zoom_increment_; + } + + void set_max_zoom_scale ( + double ms + ) + { + auto_mutex M(m); + max_scale = ms; + if (scale > ms) + { + scale = max_scale; + lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom())); + redraw_graph(); + } + } + + void set_min_zoom_scale ( + double ms + ) + { + auto_mutex M(m); + min_scale = ms; + if (scale < ms) + { + scale = min_scale; + lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom())); + redraw_graph(); + } + } + + double min_zoom_scale ( + ) const + { + auto_mutex M(m); + return min_scale; + } + + double max_zoom_scale ( + ) const + { + auto_mutex M(m); + return max_scale; + } + + void set_size ( + long width, + long height + ) + { + auto_mutex M(m); + rectangle old(rect); + rect = resize_rect(rect,width,height); + vsb.set_pos(rect.right()-1-vsb.width(), rect.top()+2); + hsb.set_pos(rect.left()+2, rect.bottom()-1-hsb.height()); + + display_rect_ = rectangle(rect.left()+2,rect.top()+2,rect.right()-2-vsb.width(),rect.bottom()-2-hsb.height()); + vsb.set_length(display_rect_.height()); + hsb.set_length(display_rect_.width()); + parent.invalidate_rectangle(rect+old); + + const double old_scale = scale; + scale = min_scale; + lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom())); + scale = old_scale; + + // call adjust_origin() so that the scroll bars get their max slider positions + // setup right + const point rect_corner(display_rect_.left(), display_rect_.top()); + const vector rect_corner_graph(gui_to_graph_space(rect_corner)); + adjust_origin(rect_corner, rect_corner_graph); + } + + void show ( + ) + { + auto_mutex M(m); + drawable::show(); + hsb.show(); + vsb.show(); + } + + void hide ( + ) + { + auto_mutex M(m); + drawable::hide(); + hsb.hide(); + vsb.hide(); + } + + void enable ( + ) + { + auto_mutex M(m); + drawable::enable(); + hsb.enable(); + vsb.enable(); + } + + void disable ( + ) + { + auto_mutex M(m); + drawable::disable(); + hsb.disable(); + vsb.disable(); + } + + void set_z_order ( + long order + ) + { + auto_mutex M(m); + drawable::set_z_order(order); + hsb.set_z_order(order); + vsb.set_z_order(order); + } + + protected: + + point graph_to_gui_space ( + const vector& p + ) const + { + const point rect_corner(display_rect_.left(), display_rect_.top()); + const dlib::vector v(p); + return (v - gr_orig)*scale + rect_corner; + } + + vector gui_to_graph_space ( + const point& p + ) const + { + const point rect_corner(display_rect_.left(), display_rect_.top()); + const dlib::vector v(p - rect_corner); + return v/scale + gr_orig; + } + + point max_graph_point ( + ) const + { + return lr_point; + } + + rectangle display_rect ( + ) const + { + return display_rect_; + } + + double zoom_scale ( + ) const + { + return scale; + } + + void set_zoom_scale ( + double new_scale + ) + { + if (min_scale <= new_scale && new_scale <= max_scale) + { + // find the point in the center of the graph area + point center((display_rect_.left()+display_rect_.right())/2, (display_rect_.top()+display_rect_.bottom())/2); + point graph_p(gui_to_graph_space(center)); + scale = new_scale; + adjust_origin(center, graph_p); + redraw_graph(); + } + } + + void center_display_at_graph_point ( + const vector& p + ) + { + // find the point in the center of the graph area + point center((display_rect_.left()+display_rect_.right())/2, (display_rect_.top()+display_rect_.bottom())/2); + adjust_origin(center, p); + redraw_graph(); + } + + // ----------- event handlers --------------- + + void on_wheel_down ( + ) + { + // zoom out + if (enabled && !hidden && scale > min_scale && display_rect_.contains(lastx,lasty)) + { + point gui_p(lastx,lasty); + point graph_p(gui_to_graph_space(gui_p)); + scale -= zoom_increment_; + if (scale < min_scale) + scale = min_scale; + redraw_graph(); + adjust_origin(gui_p, graph_p); + } + } + + void on_wheel_up ( + ) + { + // zoom in + if (enabled && !hidden && scale < max_scale && display_rect_.contains(lastx,lasty)) + { + point gui_p(lastx,lasty); + point graph_p(gui_to_graph_space(gui_p)); + scale += zoom_increment_; + if (scale > max_scale) + scale = max_scale; + redraw_graph(); + adjust_origin(gui_p, graph_p); + } + } + + void on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (enabled && !hidden && mouse_drag_screen) + { + adjust_origin(point(x,y), drag_screen_point); + redraw_graph(); + } + + // check if the mouse isn't being dragged anymore + if ((state & base_window::LEFT) == 0) + { + mouse_drag_screen = false; + } + } + + void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ) + { + mouse_drag_screen = false; + } + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ) + { + if (enabled && !hidden && display_rect_.contains(x,y) && btn == base_window::LEFT) + { + mouse_drag_screen = true; + drag_screen_point = gui_to_graph_space(point(x,y)); + } + } + + void draw ( + const canvas& c + ) const + { + draw_sunken_rectangle(c,rect); + } + + private: + + void on_h_scroll ( + ) + { + gr_orig.x() = hsb.slider_pos(); + redraw_graph(); + } + + void on_v_scroll ( + ) + { + gr_orig.y() = vsb.slider_pos(); + redraw_graph(); + } + + void redraw_graph ( + ) + { + parent.invalidate_rectangle(display_rect_); + } + + void adjust_origin ( + const point& gui_p, + const vector& graph_p + ) + /*! + ensures + - adjusts gr_orig so that we are as close to the following as possible: + - graph_to_gui_space(graph_p) == gui_p + - gui_to_graph_space(gui_p) == graph_p + !*/ + { + const point rect_corner(display_rect_.left(), display_rect_.top()); + const dlib::vector v(gui_p - rect_corner); + gr_orig = graph_p - v/scale; + + + // make sure the origin isn't outside the point (0,0) + if (gr_orig.x() < 0) + gr_orig.x() = 0; + if (gr_orig.y() < 0) + gr_orig.y() = 0; + + // make sure the lower right corner of the display_rect_ doesn't map to a point beyond lr_point + point lr_rect_corner(display_rect_.right(), display_rect_.bottom()); + point p = graph_to_gui_space(lr_point); + vector lr_rect_corner_graph_space(gui_to_graph_space(lr_rect_corner)); + vector delta(lr_point - lr_rect_corner_graph_space); + if (lr_rect_corner.x() > p.x()) + { + gr_orig.x() += delta.x(); + } + + if (lr_rect_corner.y() > p.y()) + { + gr_orig.y() += delta.y(); + } + + + const vector ul_rect_corner_graph_space(gui_to_graph_space(rect_corner)); + lr_rect_corner_graph_space = gui_to_graph_space(lr_rect_corner); + // now adjust the scroll bars + + hsb.set_max_slider_pos((unsigned long)std::max(lr_point.x()-(lr_rect_corner_graph_space.x()-ul_rect_corner_graph_space.x()),0.0)); + vsb.set_max_slider_pos((unsigned long)std::max(lr_point.y()-(lr_rect_corner_graph_space.y()-ul_rect_corner_graph_space.y()),0.0)); + // adjust slider position now. + hsb.set_slider_pos(static_cast(ul_rect_corner_graph_space.x())); + vsb.set_slider_pos(static_cast(ul_rect_corner_graph_space.y())); + + } + + + vector gr_orig; // point in graph space such that it's gui space point is the upper left of display_rect_ + vector lr_point; // point in graph space such that it is at the lower right corner of the screen at max zoom + + mutable std::ostringstream sout; + + double scale; // 0 < scale <= 1 + double min_scale; + double max_scale; + double zoom_increment_; + rectangle display_rect_; + + bool mouse_drag_screen; // true if the user is dragging the white background area + point drag_screen_point; // the starting point the mouse was at in graph space for the background area drag + + scroll_bar vsb; + scroll_bar hsb; + + // restricted functions + zoomable_region(zoomable_region&); // copy constructor + zoomable_region& operator=(zoomable_region&); // assignment operator + + }; + zoomable_region::~zoomable_region() {} + +// ---------------------------------------------------------------------------------------- + + class scrollable_region : public drawable + { + /*! + INITIAL VALUE + - border_size == 2 + - hscroll_bar_inc == 1 + - vscroll_bar_inc == 1 + + CONVENTION + - border_size == 2 + - horizontal_scroll_increment() == hscroll_bar_inc + - vertical_scroll_increment() == vscroll_bar_inc + - vertical_scroll_pos() == vsb.slider_pos() + - horizontal_scroll_pos() == hsb.slider_pos() + - total_rect() == total_rect_ + - display_rect() == display_rect_ + !*/ + + public: + + scrollable_region ( + drawable_window& w, + unsigned long events = 0 + ) : + drawable(w, MOUSE_WHEEL|events), + hsb(w,scroll_bar::HORIZONTAL), + vsb(w,scroll_bar::VERTICAL), + border_size(2), + hscroll_bar_inc(1), + vscroll_bar_inc(1) + { + hsb.set_scroll_handler(*this,&scrollable_region::on_h_scroll); + vsb.set_scroll_handler(*this,&scrollable_region::on_v_scroll); + } + + virtual inline ~scrollable_region ( + ) = 0; + + void show ( + ) + { + auto_mutex M(m); + drawable::show(); + if (need_h_scroll()) + hsb.show(); + if (need_v_scroll()) + vsb.show(); + } + + void hide ( + ) + { + auto_mutex M(m); + drawable::hide(); + hsb.hide(); + vsb.hide(); + } + + void enable ( + ) + { + auto_mutex M(m); + drawable::enable(); + hsb.enable(); + vsb.enable(); + } + + void disable ( + ) + { + auto_mutex M(m); + drawable::disable(); + hsb.disable(); + vsb.disable(); + } + + void set_z_order ( + long order + ) + { + auto_mutex M(m); + drawable::set_z_order(order); + hsb.set_z_order(order); + vsb.set_z_order(order); + } + + void set_size ( + unsigned long width, + unsigned long height + ) + { + auto_mutex M(m); + rectangle old(rect); + rect = resize_rect(rect,width,height); + vsb.set_pos(rect.right()-border_size-vsb.width()+1, rect.top()+border_size); + hsb.set_pos(rect.left()+border_size, rect.bottom()-border_size-hsb.height()+1); + + // adjust the display_rect_ + if (need_h_scroll() && need_v_scroll()) + { + // both scroll bars aren't hidden + if (!hidden) + { + vsb.show(); + hsb.show(); + } + display_rect_ = rectangle( rect.left()+border_size, + rect.top()+border_size, + rect.right()-border_size-vsb.width(), + rect.bottom()-border_size-hsb.height()); + + // figure out how many scroll bar positions there should be + unsigned long hdelta = total_rect_.width()-display_rect_.width(); + unsigned long vdelta = total_rect_.height()-display_rect_.height(); + hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc; + vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc; + + hsb.set_max_slider_pos(hdelta); + vsb.set_max_slider_pos(vdelta); + + vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1); + hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1); + } + else if (need_h_scroll()) + { + // only hsb is hidden + if (!hidden) + { + hsb.show(); + vsb.hide(); + } + display_rect_ = rectangle( rect.left()+border_size, + rect.top()+border_size, + rect.right()-border_size, + rect.bottom()-border_size-hsb.height()); + + // figure out how many scroll bar positions there should be + unsigned long hdelta = total_rect_.width()-display_rect_.width(); + hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc; + + hsb.set_max_slider_pos(hdelta); + vsb.set_max_slider_pos(0); + + hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1); + } + else if (need_v_scroll()) + { + // only vsb is hidden + if (!hidden) + { + hsb.hide(); + vsb.show(); + } + display_rect_ = rectangle( rect.left()+border_size, + rect.top()+border_size, + rect.right()-border_size-vsb.width(), + rect.bottom()-border_size); + + unsigned long vdelta = total_rect_.height()-display_rect_.height(); + vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc; + + hsb.set_max_slider_pos(0); + vsb.set_max_slider_pos(vdelta); + + vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1); + } + else + { + // both are hidden + if (!hidden) + { + hsb.hide(); + vsb.hide(); + } + display_rect_ = rectangle( rect.left()+border_size, + rect.top()+border_size, + rect.right()-border_size, + rect.bottom()-border_size); + + hsb.set_max_slider_pos(0); + vsb.set_max_slider_pos(0); + } + + vsb.set_length(display_rect_.height()); + hsb.set_length(display_rect_.width()); + + // adjust the total_rect_ position by trigging the scroll events + on_h_scroll(); + on_v_scroll(); + + parent.invalidate_rectangle(rect+old); + } + + unsigned long horizontal_scroll_increment ( + ) const + { + auto_mutex M(m); + return hscroll_bar_inc; + } + + unsigned long vertical_scroll_increment ( + ) const + { + auto_mutex M(m); + return vscroll_bar_inc; + } + + void set_horizontal_scroll_increment ( + unsigned long inc + ) + { + auto_mutex M(m); + hscroll_bar_inc = inc; + // call set_size to reset the scroll bars + set_size(rect.width(),rect.height()); + } + + void set_vertical_scroll_increment ( + unsigned long inc + ) + { + auto_mutex M(m); + vscroll_bar_inc = inc; + // call set_size to reset the scroll bars + set_size(rect.width(),rect.height()); + } + + long horizontal_scroll_pos ( + ) const + { + auto_mutex M(m); + return hsb.slider_pos(); + } + + long vertical_scroll_pos ( + ) const + { + auto_mutex M(m); + return vsb.slider_pos(); + } + + void set_horizontal_scroll_pos ( + long pos + ) + { + auto_mutex M(m); + + hsb.set_slider_pos(pos); + on_h_scroll(); + } + + void set_vertical_scroll_pos ( + long pos + ) + { + auto_mutex M(m); + + vsb.set_slider_pos(pos); + on_v_scroll(); + } + + void set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + drawable::set_pos(x,y); + vsb.set_pos(rect.right()-border_size-vsb.width()+1, rect.top()+border_size); + hsb.set_pos(rect.left()+border_size, rect.bottom()-border_size-hsb.height()+1); + + const long delta_x = total_rect_.left() - display_rect_.left(); + const long delta_y = total_rect_.top() - display_rect_.top(); + + display_rect_ = move_rect(display_rect_, rect.left()+border_size, rect.top()+border_size); + + total_rect_ = move_rect(total_rect_, display_rect_.left()+delta_x, display_rect_.top()+delta_y); + } + + protected: + + const rectangle& display_rect ( + ) const + { + return display_rect_; + } + + void set_total_rect_size ( + unsigned long width, + unsigned long height + ) + { + total_rect_ = move_rect(rectangle(width,height), + display_rect_.left()-static_cast(hsb.slider_pos()), + display_rect_.top()-static_cast(vsb.slider_pos())); + + // call this just to reconfigure the scroll bars + set_size(rect.width(),rect.height()); + } + + const rectangle& total_rect ( + ) const + { + return total_rect_; + } + + void scroll_to_rect ( + const rectangle& r + ) + { + const rectangle old(total_rect_); + // adjust the horizontal scroll bar so that r fits as best as possible + if (r.left() < display_rect_.left()) + { + long distance = (r.left()-total_rect_.left())/hscroll_bar_inc; + hsb.set_slider_pos(distance); + } + else if (r.right() > display_rect_.right()) + { + long distance = (r.right()-total_rect_.left()-display_rect_.width()+hscroll_bar_inc)/hscroll_bar_inc; + hsb.set_slider_pos(distance); + } + + // adjust the vertical scroll bar so that r fits as best as possible + if (r.top() < display_rect_.top()) + { + long distance = (r.top()-total_rect_.top())/hscroll_bar_inc; + vsb.set_slider_pos(distance); + } + else if (r.bottom() > display_rect_.bottom()) + { + long distance = (r.bottom()-total_rect_.top()-display_rect_.height()+hscroll_bar_inc)/hscroll_bar_inc; + vsb.set_slider_pos(distance); + } + + + // adjust total_rect_ so that it matches where the scroll bars are now + total_rect_ = move_rect(total_rect_, + display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), + display_rect_.top()-vscroll_bar_inc*vsb.slider_pos()); + + // only redraw if we actually changed something + if (total_rect_ != old) + { + parent.invalidate_rectangle(display_rect_); + } + } + + void on_wheel_down ( + ) + { + if (rect.contains(lastx,lasty) && enabled && !hidden) + { + if (need_v_scroll()) + { + unsigned long pos = vsb.slider_pos(); + vsb.set_slider_pos(pos+1); + on_v_scroll(); + } + else if (need_h_scroll()) + { + unsigned long pos = hsb.slider_pos(); + hsb.set_slider_pos(pos+1); + on_h_scroll(); + } + } + } + + void on_wheel_up ( + ) + { + if (rect.contains(lastx,lasty) && enabled && !hidden) + { + if (need_v_scroll()) + { + unsigned long pos = vsb.slider_pos(); + vsb.set_slider_pos(pos-1); + on_v_scroll(); + } + else if (need_h_scroll()) + { + unsigned long pos = hsb.slider_pos(); + hsb.set_slider_pos(pos-1); + on_h_scroll(); + } + } + } + + void draw ( + const canvas& c + ) const + { + rectangle area = c.intersect(rect); + if (area.is_empty() == true) + return; + + draw_sunken_rectangle(c,rect); + } + + private: + + bool need_h_scroll ( + ) const + { + if (total_rect_.width() > rect.width()-border_size*2) + { + return true; + } + else + { + // check if we would need a vertical scroll bar and if adding one would make us need + // a horizontal one + if (total_rect_.height() > rect.height()-border_size*2 && + total_rect_.width() > rect.width()-border_size*2-vsb.width()) + return true; + else + return false; + } + } + + bool need_v_scroll ( + ) const + { + if (total_rect_.height() > rect.height()-border_size*2) + { + return true; + } + else + { + // check if we would need a horizontal scroll bar and if adding one would make us need + // a vertical_scroll_pos one + if (total_rect_.width() > rect.width()-border_size*2 && + total_rect_.height() > rect.height()-border_size*2-hsb.height()) + return true; + else + return false; + } + } + + void on_h_scroll ( + ) + { + total_rect_ = move_rect(total_rect_, display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), total_rect_.top()); + parent.invalidate_rectangle(display_rect_); + } + + void on_v_scroll ( + ) + { + total_rect_ = move_rect(total_rect_, total_rect_.left(), display_rect_.top()-vscroll_bar_inc*vsb.slider_pos()); + parent.invalidate_rectangle(display_rect_); + } + + rectangle total_rect_; + rectangle display_rect_; + scroll_bar hsb; + scroll_bar vsb; + const unsigned long border_size; + unsigned long hscroll_bar_inc; + unsigned long vscroll_bar_inc; + + }; + scrollable_region::~scrollable_region(){} + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "base_widgets.cpp" +#endif + +#endif // DLIB_BASE_WIDGETs_ + diff --git a/dlib/gui_widgets/base_widgets_abstract.h b/dlib/gui_widgets/base_widgets_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..5f2b5d8d00f07e09bede01a8adc96a8e85e149f6 --- /dev/null +++ b/dlib/gui_widgets/base_widgets_abstract.h @@ -0,0 +1,1735 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_BASE_WIDGETs_ABSTRACT_ +#ifdef DLIB_BASE_WIDGETs_ABSTRACT_ + +#include "fonts_abstract.h" +#include "drawable_abstract.h" + +#include "../gui_core.h" +#include + +namespace dlib +{ + + /*! + GENERAL REMARKS + This file contains objects that are useful for creating complex drawable + widgets. + + THREAD SAFETY + All objects and functions defined in this file are thread safe. You may + call them from any thread without serializing access to them. + + EVENT HANDLERS + If you derive from any of the drawable objects and redefine any of the on_*() + event handlers then you should ensure that your version calls the same event + handler in the base object so that the base class part of your object will also + be able to process the event. + + Also note that all event handlers, including the user registered callback + functions, are executed in the event handling thread. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class dragable +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class dragable : public drawable + { + /*! + INITIAL VALUE + dragable_area() == an initial value for its type + + WHAT THIS OBJECT REPRESENTS + This object represents a drawable object that is dragable by the mouse. + You use it by inheriting from it and defining the draw() method and any + of the on_*() event handlers you need. + + This object is dragable by the user when is_enabled() == true and + not dragable otherwise. + !*/ + + public: + + dragable( + drawable_window& w, + unsigned long events = 0 + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + - This object will not receive any events or draw() requests until + enable_events() is called + - the events flags are passed on to the drawable object's + constructor. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~dragable( + ) = 0; + /*! + ensures + - all resources associated with *this have been released + !*/ + + rectangle dragable_area ( + ) const; + /*! + ensures + - returns the area that this dragable can be dragged around in. + !*/ + + void set_dragable_area ( + const rectangle& area + ); + /*! + ensures + - #dragable_area() == area + !*/ + + protected: + + // does nothing by default + virtual void on_drag ( + ){} + /*! + requires + - enable_events() has been called + - is_enabled() == true + - is_hidden() == false + - mutex drawable::m is locked + - is called when the user drags this object + - get_rect() == the rectangle that defines the new position + of this object. + ensures + - does not change the state of mutex drawable::m. + !*/ + + private: + + // restricted functions + dragable(dragable&); // copy constructor + dragable& operator=(dragable&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class mouse_over_event +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class mouse_over_event : public drawable + { + /*! + INITIAL VALUE + is_mouse_over() == false + + WHAT THIS OBJECT REPRESENTS + This object represents a drawable object with the additoin of two events + that will alert you when the mouse enters or leaves your drawable object. + + You use it by inheriting from it and defining the draw() method and any + of the on_*() event handlers you need. + !*/ + + public: + + mouse_over_event( + drawable_window& w, + unsigned long events = 0 + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + - #*this will not receive any events or draw() requests until + enable_events() is called + - the events flags are passed on to the drawable object's + constructor. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~mouse_over_event( + ) = 0; + /*! + ensures + - all resources associated with *this have been released + !*/ + + protected: + + bool is_mouse_over ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - if (the mouse is currently over this widget) then + - returns true + - else + - returns false + !*/ + + // does nothing by default + virtual void on_mouse_over ( + ){} + /*! + requires + - enable_events() has been called + - mutex drawable::m is locked + - is_enabled() == true + - is_hidden() == false + - is called whenever this object transitions from the state where + is_mouse_over() == false to is_mouse_over() == true + ensures + - does not change the state of mutex drawable::m. + !*/ + + // does nothing by default + virtual void on_mouse_not_over ( + ){} + /*! + requires + - enable_events() has been called + - mutex drawable::m is locked + - is_enabled() == true + - is_hidden() == false + - is called whenever this object transitions from the state where + is_mouse_over() == true to is_mouse_over() == false + ensures + - does not change the state of mutex drawable::m. + !*/ + + private: + + // restricted functions + mouse_over_event(mouse_over_event&); // copy constructor + mouse_over_event& operator=(mouse_over_event&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class button_action +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class button_action : public mouse_over_event + { + /*! + INITIAL VALUE + is_depressed() == false + + WHAT THIS OBJECT REPRESENTS + This object represents the clicking action of a push button. It provides + simple callbacks that can be used to make various kinds of button + widgets. + + You use it by inheriting from it and defining the draw() method and any + of the on_*() event handlers you need. + !*/ + + public: + + button_action( + drawable_window& w, + unsigned long events = 0 + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + - #*this will not receive any events or draw() requests until + enable_events() is called + - the events flags are passed on to the drawable object's + constructor. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~button_action( + ) = 0; + /*! + ensures + - all resources associated with *this have been released + !*/ + + protected: + + bool is_depressed ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - if (this button is currently in a depressed state) then + - the user has left clicked on this drawable and is still + holding the left mouse button down over it. + - returns true + - else + - returns false + !*/ + + // does nothing by default + virtual void on_button_down ( + ){} + /*! + requires + - enable_events() has been called + - mutex drawable::m is locked + - is_enabled() == true + - is_hidden() == false + - the area in parent_window() defined by get_rect() has been invalidated. + (This means you don't have to call invalidate_rectangle()) + - is called whenever this object transitions from the state where + is_depressed() == false to is_depressed() == true + ensures + - does not change the state of mutex drawable::m. + !*/ + + // does nothing by default + virtual void on_button_up ( + bool mouse_over + ){} + /*! + requires + - enable_events() has been called + - mutex drawable::m is locked + - is_enabled() == true + - is_hidden() == false + - the area in parent_window() defined by get_rect() has been invalidated. + (This means you don't have to call invalidate_rectangle()) + - is called whenever this object transitions from the state where + is_depressed() == true to is_depressed() == false + - if (the mouse was over this button when this event occurred) then + - mouse_over == true + - else + - mouse_over == false + ensures + - does not change the state of mutex drawable::m. + !*/ + + private: + + // restricted functions + button_action(button_action&); // copy constructor + button_action& operator=(button_action&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class arrow_button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class arrow_button : public button_action + { + /*! + INITIAL VALUE + direction() == a value given to the constructor. + + WHAT THIS OBJECT REPRESENTS + This object represents a push button with an arrow in the middle. + + When this object is disabled it means it will not respond to user clicks. + !*/ + + public: + enum arrow_direction + { + UP, + DOWN, + LEFT, + RIGHT + }; + + arrow_button( + drawable_window& w, + arrow_direction dir + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #direction() == dir + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~arrow_button( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + arrow_direction direction ( + ) const; + /*! + ensures + - returns the direction that this arrow_button's arrow points + !*/ + + void set_direction ( + arrow_direction new_direction + ); + /*! + ensures + - #direction() == new_direction + !*/ + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this button stays the + same but its width and height are modified + !*/ + + bool is_depressed ( + ) const; + /*! + ensures + - if (this button is currently in a depressed state) then + - the user has left clicked on this drawable and is still + holding the left mouse button down over it. + - returns true + - else + - returns false + !*/ + + template < + typename T + > + void set_button_down_handler ( + T& object, + void (T::*event_handler)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - The event_handler function is called whenever this object transitions + from the state where is_depressed() == false to is_depressed() == true + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_button_up_handler ( + T& object, + void (T::*event_handler)(bool mouse_over) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - The event_handler function is called whenever this object transitions + from the state where is_depressed() == true to is_depressed() == false. + furthermore: + - if (the mouse was over this button when this event occurred) then + - mouse_over == true + - else + - mouse_over == false + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + arrow_button(arrow_button&); // copy constructor + arrow_button& operator=(arrow_button&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class scroll_bar +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class scroll_bar : public drawable + { + /*! + INITIAL VALUE + orientation() == a value given to the constructor. + max_slider_pos() == 0 + slider_pos() == 0 + jump_size() == 10 + + WHAT THIS OBJECT REPRESENTS + This object represents a scroll bar. The slider_pos() of the scroll bar + ranges from 0 to max_slider_pos(). The 0 position of the scroll_bar is + in the top or left side of the scroll_bar depending on its orientation. + + When this object is disabled it means it will not respond to user clicks. + !*/ + + public: + enum bar_orientation + { + HORIZONTAL, + VERTICAL + }; + + scroll_bar( + drawable_window& w, + bar_orientation orientation + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #orientation() == orientation + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~scroll_bar( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + bar_orientation orientation ( + ) const; + /*! + ensures + - returns the orientation of this scroll_bar + !*/ + + void set_orientation ( + bar_orientation new_orientation + ); + /*! + ensures + - #orientation() == new_orientation + !*/ + + void set_length ( + unsigned long length, + ); + /*! + ensures + - if (orientation() == HORIZONTAL) then + - #width() == max(length,1) + - else + - #height() == max(length,1) + !*/ + + long max_slider_pos ( + ) const; + /*! + ensures + - returns the maximum value that slider_pos() can take. + !*/ + + void set_max_slider_pos ( + long mpos + ); + /*! + ensures + - if (mpos < 0) then + - #max_slider_pos() == 0 + - else + - #max_slider_pos() == mpos + - if (slider_pos() > #max_slider_pos()) then + - #slider_pos() == #max_slider_pos() + - else + - #slider_pos() == slider_pos() + !*/ + + void set_slider_pos ( + unsigned long pos + ); + /*! + ensures + - if (pos < 0) then + - #slider_pos() == 0 + - else if (pos > max_slider_pos()) then + - #slider_pos() == max_slider_pos() + - else + - #slider_pos() == pos + !*/ + + long slider_pos ( + ) const; + /*! + ensures + - returns the current position of the slider box within the scroll bar. + !*/ + + long jump_size ( + ) const; + /*! + ensures + - returns the number of positions that the slider bar will jump when the + user clicks on the empty gaps above or below the slider bar. + (note that the slider will jump less than the jump size if it hits the + end of the scroll bar) + !*/ + + void set_jump_size ( + long js + ); + /*! + ensures + - if (js < 1) then + - #jump_size() == 1 + - else + - #jump_size() == js + !*/ + + + template < + typename T + > + void set_scroll_handler ( + T& object, + void (T::*event_handler)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - The event_handler function is called whenever the user causes the slider box + to move. + - This event is NOT triggered by calling set_slider_pos() + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + scroll_bar(scroll_bar&); // copy constructor + scroll_bar& operator=(scroll_bar&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class widget_group +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class widget_group : public drawable + { + /*! + INITIAL VALUE + size() == 0 + get_rect().is_empty() == true + left() == 0 + top() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a grouping of drawable widgets. It doesn't draw + anything itself, rather it lets you manipulate the position, enabled + status, and visibility of a set of widgets as a group. + !*/ + + public: + widget_group( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~widget_group( + ); + /*! + ensures + - all resources associated with *this have been released. + !*/ + + void empty ( + ); + /*! + ensures + - #size() == 0 + !*/ + + void fit_to_contents ( + ); + /*! + ensures + - does not change the position of this object. + (i.e. the upper left corner of get_rect() remains at the same position) + - if (size() == 0) then + - #get_rect().is_empty() == true + - else + - #get_rect() will be the smallest rectangle that contains all the + widgets in this group and the upper left corner of get_rect(). + !*/ + + unsigned long size ( + ) const; + /*! + ensures + - returns the number of widgets currently in *this. + !*/ + + void add ( + drawable& widget, + unsigned long x, + unsigned long y + ); + /*! + ensures + - #is_member(widget) == true + - if (is_member(widget) == false) then + - #size() == size() + 1 + - else + - #size() == size() + - The following conditions apply to this function as well as to all of the + following functions so long as is_member(widget) == true: + enable(), disable(), hide(), show(), set_z_order(), and set_pos(). + - #widget.left() == left()+x + - #widget.width() == widget.width() + - #widget.top() == top()+y + - #widget.height() == widget.height() + - #widget.is_hidden() == is_hidden() + - #widget.is_enabled() == is_enabled() + - #widget.z_order() == z_order() + throws + - std::bad_alloc + !*/ + + bool is_member ( + const drawable& widget + ) const; + /*! + ensures + - returns true if widget is currently in this object, returns false otherwise. + !*/ + + void remove ( + const drawable& widget + ); + /*! + ensures + - #is_member(widget) == false + - if (is_member(widget) == true) then + - #size() == size() - 1 + - else + - #size() == size() + !*/ + + protected: + + // this object doesn't draw anything but also isn't abstract + void draw ( + const canvas& c + ) const {} + + private: + + // restricted functions + widget_group(widget_group&); // copy constructor + widget_group& operator=(widget_group&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class image_widget +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class image_widget : public dragable + { + /*! + INITIAL VALUE + dragable_area() == an initial value for its type. + This object isn't displaying anything. + + WHAT THIS OBJECT REPRESENTS + This object represents a dragable image. You give it an image to display + by calling set_image(). + + Also note that initially the dragable area is empty so it won't be + dragable unless you call set_dragable_area() to some non-empty region. + + The image is drawn such that: + - the pixel img[0][0] is the upper left corner of the image. + - the pixel img[img.nr()-1][0] is the lower left corner of the image. + - the pixel img[0][img.nc()-1] is the upper right corner of the image. + - the pixel img[img.nr()-1][img.nc()-1] is the lower right corner of the image. + + !*/ + + public: + + image_widget( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~image_widget( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + template < + typename image_type + > + void set_image ( + const image_type& img + ); + /*! + requires + - image_type == an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits must be defined + ensures + - #width() == img.nc() + - #height() == img.nr() + - #*this widget is now displaying the given image img. + !*/ + + private: + + // restricted functions + image_widget(image_widget&); // copy constructor + image_widget& operator=(image_widget&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class tooltip +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class tooltip : public mouse_over_event + { + /*! + INITIAL VALUE + - text() == "" + - the tooltip is inactive until the text is changed to + a non-empty string. + + WHAT THIS OBJECT REPRESENTS + This object represents a region on a window where if the user + hovers the mouse over this region a tooltip with a message + appears. + !*/ + + public: + + tooltip( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~tooltip( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + long width_, + long height_ + ); + /*! + ensures + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this widget stays the + same but its width and height are modified + !*/ + + void set_text ( + const std::string& str + ); + /*! + ensures + - #text() == str + - activates the tooltip. i.e. after this function the tooltip + will display on the screen when the user hovers the mouse over it + !*/ + + const std::string text ( + ) const; + /*! + ensures + - returns the text that is displayed inside this + tooltip + !*/ + + private: + + // restricted functions + tooltip(tooltip&); // copy constructor + tooltip& operator=(tooltip&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // popup menu stuff +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class menu_item + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an abstract class that defines the interface a + menu item in a popup_menu must implement. + + Note that a menu_item is drawn as 3 separate pieces: + --------------------------------- + | left | middle | right | + --------------------------------- + + Also note that derived classes must be copyable via + their copy constructors. + !*/ + + public: + + virtual ~menu_item() {} + + virtual void on_click ( + ) const {} + /*! + requires + - the mutex drawable::m is locked + - if (has_click_event()) then + - this function is called when the user clicks on this menu_item + !*/ + + virtual bool has_click_event ( + ) const { return false; } + /*! + ensures + - if (this menu_item wants to receive on_click events) then + - returns true + - else + - returns false + !*/ + + virtual unichar get_hot_key ( + ) const { return 0; } + /*! + ensures + - if (this menu item has a keyboard hot key) then + - returns the unicode value of the key + - else + - returns 0 + !*/ + + virtual rectangle get_left_size ( + ) const { return rectangle(); } // return empty rect by default + /*! + ensures + - returns the dimensions of the left part of the menu_item + !*/ + + virtual rectangle get_middle_size ( + ) const = 0; + /*! + ensures + - returns the dimensions of the middle part of the menu_item + !*/ + + virtual rectangle get_right_size ( + ) const { return rectangle(); } // return empty rect by default + /*! + ensures + - returns the dimensions of the right part of the menu_item + !*/ + + virtual void draw_background ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const {} + /*! + requires + - the mutex drawable::m is locked + requires + - c == the canvas to draw on + - rect == the rectangle in which we are to draw the background + - enabled == true if the menu_item is to be drawn enabled + - is_selected == true if the menu_item is to be drawn selected + ensures + - draws the background of the menu_item on the canvas c at the location + given by rect. + !*/ + + virtual void draw_left ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const {} + /*! + requires + - the mutex drawable::m is locked + requires + - c == the canvas to draw on + - rect == the rectangle in which we are to draw the background + - enabled == true if the menu_item is to be drawn enabled + - is_selected == true if the menu_item is to be drawn selected + ensures + - draws the left part of the menu_item on the canvas c at the location + given by rect. + !*/ + + virtual void draw_middle ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const = 0; + /*! + requires + - the mutex drawable::m is locked + requires + - c == the canvas to draw on + - rect == the rectangle in which we are to draw the background + - enabled == true if the menu_item is to be drawn enabled + - is_selected == true if the menu_item is to be drawn selected + ensures + - draws the middle part of the menu_item on the canvas c at the location + given by rect. + !*/ + + virtual void draw_right ( + const canvas& c, + const rectangle& rect, + const bool enabled, + const bool is_selected + ) const {} + /*! + requires + - the mutex drawable::m is locked + requires + - c == the canvas to draw on + - rect == the rectangle in which we are to draw the background + - enabled == true if the menu_item is to be drawn enabled + - is_selected == true if the menu_item is to be drawn selected + ensures + - draws the right part of the menu_item on the canvas c at the location + given by rect. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class menu_item_text : public menu_item + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple text menu item + !*/ + + public: + + template < + typename T + > + menu_item_text ( + const std::string& str, + T& object, + void (T::*on_click_handler)(), + unichar hotkey = 0 + ); + /*! + ensures + - The text of this menu item will be str + - the on_click_handler function is called on object when this menu_item + clicked by the user. + - #get_hot_key() == hotkey + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class menu_item_submenu : public menu_item + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple text item intended to be used with + submenus inside a popup_menu. + !*/ + + public: + + menu_item_submenu ( + const std::string& str, + unichar hotkey = 0 + ); + /*! + ensures + - The text of this menu item will be str + clicked by the user. + - #get_hot_key() == hotkey + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class menu_item_separator : public menu_item + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a horizontal separator in a popup menu + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class popup_menu : public base_window + { + /*! + INITIAL VALUE + - size() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a popup menu window capable of containing + menu_item objects. + !*/ + + public: + + popup_menu ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + - dlib::thread_error + - dlib::gui_error + !*/ + + void clear ( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + template < + typename menu_item_type + > + unsigned long add_menu_item ( + const menu_item_type& new_item + ); + /*! + requires + - menu_item_type == a type that inherits from menu_item + ensures + - adds new_item onto the bottom of this popup_menu. + - returns size() + (This is also the index by which this item can be + referenced by the enable_menu_item() and disable_menu_item() + functions.) + !*/ + + template < + typename menu_item_type + > + unsigned long add_submenu ( + const menu_item_type& new_item, + popup_menu& submenu + ); + /*! + requires + - menu_item_type == a type that inherits from menu_item + ensures + - adds new_item onto the bottom of this popup_menu. + - when the user puts the mouse above this menu_item the given + submenu popup_menu will be displayed. + - returns size() + (This is also the index by which this item can be + referenced by the enable_menu_item() and disable_menu_item() + functions.) + !*/ + + void enable_menu_item ( + unsigned long idx + ); + /*! + requires + - idx < size() + ensures + - the menu_item in this with the index idx has been enabled + !*/ + + void disable_menu_item ( + unsigned long idx + ); + /*! + requires + - idx < size() + ensures + - the menu_item in this with the index idx has been disabled + !*/ + + unsigned long size ( + ) const; + /*! + ensures + - returns the number of menu_item objects in this popup_menu + !*/ + + template + void set_on_hide_handler ( + T& object, + void (T::*event_handler)() + ); + /*! + ensures + - the event_handler function is called on object when this popup_menu + hides itself due to an action by the user. + - Note that you can register multiple handlers for this event. + !*/ + + void select_first_item ( + ); + /*! + ensures + - causes this popup menu to highlight the first + menu item that it contains which has a click event + and is enabled. + !*/ + + bool forwarded_on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ); + /*! + requires + - key, is_printable, and state are the variables from the + base_window::on_keydown() event + ensures + - forwards this keyboard event to this popup window so that it + may deal with keyboard events from other windows. + - if (this popup_menu uses the keyboard event) then + - returns true + - else + - returns false + !*/ + + private: + + // restricted functions + popup_menu(popup_menu&); // copy constructor + popup_menu& operator=(popup_menu&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + + class zoomable_region : public drawable + { + /* + INITIAL VALUE + - min_zoom_scale() == 0.15 + - max_zoom_scale() == 1.0 + - zoom_increment() == 0.02 + - zoom_scale() == 1.0 + + WHAT THIS OBJECT REPRESENTS + This object represents a 2D Cartesian graph that you can zoom into and + out of. It is a graphical a widget that draws a rectangle with + a horizontal and vertical scroll bar that allow the user to scroll + around on a Cartesian graph that is much larger than the actual + area occupied by this object on the screen. It also allows + the user to zoom in and out. + + To use this object you inherit from it and make use of its public and + protected member functions. It provides functions for converting between + pixel locations and the points in our 2D Cartesian graph so that when the + user is scrolling/zooming the widget you can still determine where + things are to be placed on the screen and what screen pixels correspond + to in the Cartesian graph. + + Note that the Cartesian graph in this object is bounded by the point + (0,0), corresponding to the upper left corner when we are zoomed all + the way out, and max_graph_point() which corresponds to the lower right + corner when zoomed all the way out. The value of max_graph_point() is + determined automatically from the size of this object's on screen + rectangle and the value of min_zoom_scale() which determines how far + out you can zoom. + + Also note that while vector is used to represent graph points + the z field is always ignored by this object. + */ + + public: + + zoomable_region ( + drawable_window& w, + unsigned long events = 0 + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + - This object will not receive any events or draw() requests until + enable_events() is called + - the events flags are passed on to the drawable object's + constructor. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~zoomable_region ( + ) = 0; + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_zoom_increment ( + double zi + ); + /*! + ensures + - #zoom_increment() == zi + !*/ + + double zoom_increment ( + ) const; + /*! + ensures + - returns the amount by which zoom_scale() is changed when the user + zooms in or out by using the mouse wheel. + !*/ + + void set_max_zoom_scale ( + double ms + ); + /*! + ensures + - #max_zoom_scale() == ms + !*/ + + void set_min_zoom_scale ( + double ms + ); + /*! + ensures + - #min_zoom_scale() == ms + !*/ + + double min_zoom_scale ( + ) const; + /*! + ensures + - returns the minimum allowed value of zoom_scale() + !*/ + + double max_zoom_scale ( + ) const; + /*! + ensures + - returns the maximum allowed value of zoom_scale() + !*/ + + void set_size ( + long width, + long height + ); + /*! + ensures + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this button stays the + same but its width and height are modified + !*/ + + protected: + + rectangle display_rect ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns the rectangle on the screen that contains the Cartesian + graph in this widget. I.e. this is the area of this widget minus + the area taken up by the scroll bars and border decorations. + !*/ + + point graph_to_gui_space ( + const vector& graph_point + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns the location of the pixel on the screen that corresponds + to the given point in Cartesian graph space + !*/ + + vector gui_to_graph_space ( + const point& pixel_point + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns the point in Cartesian graph space that corresponds to the given + pixel location + !*/ + + vector max_graph_point ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns the pixel farthest from the graph point (0,0) that is still + in the graph. I.e. returns the point in graph space that corresponds + to the lower right corner of the display_rect() when we are zoomed + all the way out. + !*/ + + double zoom_scale ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns a double Z that represents the current zoom. + - Smaller values of Z represent the user zooming out. + - Bigger values of Z represent the user zooming in. + - The default unzoomed case is when Z == 1 + - objects should be drawn such that they are zoom_scale() + times their normal size + !*/ + + void set_zoom_scale ( + double new_scale + ); + /*! + requires + - mutex drawable::m is locked + ensures + - if (min_zoom_scale() <= new_scale && new_scale <= max_zoom_scale()) then + - #zoom_scale() == new_scale + - invalidates the display_rect() so that it will be redrawn + - else + - #zoom_scale() == zoom_scale() + I.e. this function has no effect + !*/ + + void center_display_at_graph_point ( + const vector& graph_point + ); + /*! + requires + - mutex drawable::m is locked + ensures + - causes the given graph point to be centered in the display + if possible + - invalidates the display_rect() so that it will be redrawn + !*/ + + // ---------------------------- event handlers ---------------------------- + // The following event handlers are used in this object. So if you + // use any of them in your derived object you should pass the events + // back to it so that they still operate unless you wish to hijack the + // event for your own reasons (e.g. to override the mouse drag this object + // performs) + + void on_wheel_down (); + void on_wheel_up (); + void on_mouse_move ( unsigned long state, long x, long y); + void on_mouse_up ( unsigned long btn, unsigned long state, long x, long y); + void on_mouse_down ( unsigned long btn, unsigned long state, long x, long y, bool is_double_click); + void draw ( const canvas& c) const; + + private: + + // restricted functions + zoomable_region(zoomable_region&); // copy constructor + zoomable_region& operator=(zoomable_region&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + + class scrollable_region : public drawable + { + /*! + INITIAL VALUE + - horizontal_scroll_pos() == 0 + - horizontal_scroll_increment() == 1 + - vertical_scroll_pos() == 0 + - vertical_scroll_increment() == 1 + - total_rect().empty() == true + + WHAT THIS OBJECT REPRESENTS + This object represents a 2D region of arbitrary size that is displayed + within a possibly smaller scrollable gui widget. That is, it is a + graphical a widget that draws a rectangle with a horizontal and vertical + scroll bar that allow the user to scroll around on a region that is much + larger than the actual area occupied by this object on the screen. + + To use this object you inherit from it and make use of its public and + protected member functions. It provides a function, total_rect(), that + tells you where the 2D region is on the screen. You draw your stuff + inside total_rect() as you would normally except that you only modify + pixels that are also inside display_rect(). + !*/ + + public: + scrollable_region ( + drawable_window& w, + unsigned long events = 0 + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + - This object will not receive any events or draw() requests until + enable_events() is called + - the events flags are passed on to the drawable object's + constructor. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~scrollable_region ( + ) = 0; + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + unsigned long width, + unsigned long height + ); + /*! + ensures + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this button stays the + same but its width and height are modified + !*/ + + long horizontal_scroll_pos ( + ) const; + /*! + ensures + - returns the current position of the horizontal scroll bar. + 0 means it is at the far left while bigger values represent + scroll positions closer to the right. + !*/ + + long vertical_scroll_pos ( + ) const; + /*! + ensures + - returns the current position of the vertical scroll bar. + 0 means it is at the top and bigger values represent scroll positions + closer to the bottom. + !*/ + + void set_horizontal_scroll_pos ( + long pos + ); + /*! + ensures + - if (pos is a valid horizontal scroll position) then + - #horizontal_scroll_pos() == pos + - else + - #horizontal_scroll_pos() == the valid scroll position closest to pos + !*/ + + void set_vertical_scroll_pos ( + long pos + ); + /*! + ensures + - if (pos is a valid vertical scroll position) then + - #vertical_scroll_pos() == pos + - else + - #vertical_scroll_pos() == the valid scroll position closest to pos + !*/ + + unsigned long horizontal_scroll_increment ( + ) const; + /*! + ensures + - returns the number of pixels that total_rect() is moved by when + the horizontal scroll bar moves by one position + !*/ + + unsigned long vertical_scroll_increment ( + ) const; + /*! + ensures + - returns the number of pixels that total_rect() is moved by when + the vertical scroll bar moves by one position + !*/ + + void set_horizontal_scroll_increment ( + unsigned long inc + ); + /*! + ensures + - #horizontal_scroll_increment() == inc + !*/ + + void set_vertical_scroll_increment ( + unsigned long inc + ); + /*! + ensures + - #vertical_scroll_increment() == inc + !*/ + + protected: + + rectangle display_rect ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns the rectangle on the screen that contains the scrollable + area in this widget. I.e. this is the area of this widget minus + the area taken up by the scroll bars and border decorations. + !*/ + + void set_total_rect_size ( + unsigned long width, + unsigned long height + ); + /*! + requires + - mutex drawable::m is locked + ensures + - #total_rect().width() == width + - #total_rect().height() == height + !*/ + + const rectangle& total_rect ( + ) const; + /*! + requires + - mutex drawable::m is locked + ensures + - returns a rectangle that represents the entire scrollable + region inside this widget, even the parts that are outside + this->rect. + !*/ + + void scroll_to_rect ( + const rectangle& r + ); + /*! + requires + - mutex drawable::m is locked + ensures + - adjusts the scroll bars of this object so that the rectangle + r is displayed in the display_rect() (or as close to being + displayed as possible if r is outside of total_rect()) + !*/ + + // ---------------------------- event handlers ---------------------------- + // The following event handlers are used in this object. So if you + // use any of them in your derived object you should pass the events + // back to it so that they still operate unless you wish to hijack the + // event for your own reasons (e.g. to override the mouse wheel action + // this object performs) + + void on_wheel_down (); + void on_wheel_up (); + void draw (const canvas& c) const; + + private: + + // restricted functions + scrollable_region(scrollable_region&); // copy constructor + scrollable_region& operator=(scrollable_region&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_BASE_WIDGETs_ABSTRACT_ + + diff --git a/dlib/gui_widgets/canvas_drawing.cpp b/dlib/gui_widgets/canvas_drawing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd0860d1a252b6debfe9d2b9136835180bfece89 --- /dev/null +++ b/dlib/gui_widgets/canvas_drawing.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CANVAS_DRAWINg_CPP_ +#define DLIB_CANVAS_DRAWINg_CPP_ + +#include "canvas_drawing.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + void draw_sunken_rectangle ( + const canvas& c, + const rectangle& border, + unsigned char alpha + ) + { + rectangle area = border.intersect(c); + if (area.is_empty() == false) + { + const rgb_alpha_pixel dark_gray(64,64,64,alpha); + const rgb_alpha_pixel gray(128,128,128,alpha); + const rgb_alpha_pixel white(255,255,255,alpha); + const rgb_alpha_pixel background(212,208,200,alpha); + + draw_line(c,point(border.left(),border.top()),point(border.right()-1,border.top()),gray); + + draw_line(c,point(border.left(),border.bottom()),point(border.right(),border.bottom()),white); + draw_line(c,point(border.left()+1,border.bottom()-1),point(border.right()-1,border.bottom()-1),background); + + draw_line(c,point(border.left(),border.top()+1),point(border.left(),border.bottom()-1),gray); + + draw_line(c,point(border.right(),border.top()),point(border.right(),border.bottom()-1),white); + draw_line(c,point(border.right()-1,border.top()+1),point(border.right()-1,border.bottom()-2),background); + + draw_line(c,point(border.left()+1,border.top()+1),point(border.left()+1,border.bottom()-2),dark_gray); + draw_line(c,point(border.left()+1,border.top()+1),point(border.right()-2,border.top()+1),dark_gray); + } + } + +// ---------------------------------------------------------------------------------------- + + void draw_button_down ( + const canvas& c, + const rectangle& btn, + unsigned char alpha + ) + { + rectangle area = btn.intersect(c); + if (area.is_empty() == false) + { + const rgb_alpha_pixel dark_gray(64,64,64,alpha); + const rgb_alpha_pixel gray(128,128,128,alpha); + const rgb_alpha_pixel black(0,0,0,alpha); + + draw_line(c,point(btn.left(),btn.top()),point(btn.right(),btn.top()),black); + + draw_line(c,point(btn.left()+1,btn.bottom()),point(btn.right(),btn.bottom()),dark_gray); + draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.right()-1,btn.top()+1),gray); + + draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()),black); + + draw_line(c,point(btn.right(),btn.top()+1),point(btn.right(),btn.bottom()-1),dark_gray); + draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.left()+1,btn.bottom()-1),gray); + } + } + +// ---------------------------------------------------------------------------------------- + + void draw_button_up ( + const canvas& c, + const rectangle& btn, + unsigned char alpha + ) + { + rectangle area = btn.intersect(c); + if (area.is_empty() == false) + { + const rgb_alpha_pixel dark_gray(64,64,64,alpha); + const rgb_alpha_pixel gray(128,128,128,alpha); + const rgb_alpha_pixel white(255,255,255,alpha); + + draw_line(c,point(btn.left(),btn.top()),point(btn.right()-1,btn.top()),white); + + draw_line(c,point(btn.left(),btn.bottom()),point(btn.right(),btn.bottom()),dark_gray); + draw_line(c,point(btn.left()+1,btn.bottom()-1),point(btn.right()-1,btn.bottom()-1),gray); + + draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()-1),white); + + draw_line(c,point(btn.right(),btn.top()),point(btn.right(),btn.bottom()-1),dark_gray); + draw_line(c,point(btn.right()-1,btn.top()+1),point(btn.right()-1,btn.bottom()-2),gray); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CANVAS_DRAWINg_CPP_ + diff --git a/dlib/gui_widgets/canvas_drawing.h b/dlib/gui_widgets/canvas_drawing.h new file mode 100644 index 0000000000000000000000000000000000000000..79db9191747a93ab02820e29c22808e0081f0089 --- /dev/null +++ b/dlib/gui_widgets/canvas_drawing.h @@ -0,0 +1,687 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_GUI_CANVAS_DRAWINg_ +#define DLIB_GUI_CANVAS_DRAWINg_ + +#include "canvas_drawing_abstract.h" +#include "../gui_core.h" +#include "../algs.h" +#include "../array2d.h" +#include "../pixel.h" +#include "../image_transforms.h" +#include "../geometry.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + void draw_line ( + const canvas& c, + const point& p1, + const point& p2, + const pixel_type& pixel, + const rectangle& area = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + rectangle valid_area(c.intersect(area)); + long x1 = p1.x(); + long y1 = p1.y(); + long x2 = p2.x(); + long y2 = p2.y(); + if (x1 == x2) + { + // if the x coordinate is inside the canvas's area + if (x1 <= valid_area.right() && x1 >= valid_area.left()) + { + // make sure y1 comes before y2 + if (y1 > y2) + swap(y1,y2); + + y1 = std::max(y1,valid_area.top()); + y2 = std::min(y2,valid_area.bottom()); + // this is a vertical line + for (long y = y1; y <= y2; ++y) + { + assign_pixel(c[y-c.top()][x1-c.left()], pixel); + } + } + } + else if (y1 == y2) + { + // if the y coordinate is inside the canvas's area + if (y1 <= valid_area.bottom() && y1 >= valid_area.top()) + { + // make sure x1 comes before x2 + if (x1 > x2) + swap(x1,x2); + + x1 = std::max(x1,valid_area.left()); + x2 = std::min(x2,valid_area.right()); + // this is a horizontal line + for (long x = x1; x <= x2; ++x) + { + assign_pixel(c[y1-c.top()][x-c.left()], pixel); + } + } + } + else + { + const long rise = (((long)y2) - ((long)y1)); + const long run = (((long)x2) - ((long)x1)); + if (std::abs(rise) < std::abs(run)) + { + const double slope = ((double)rise)/run; + + double first, last; + + if (x1 > x2) + { + first = std::max(x2,valid_area.left()); + last = std::min(x1,valid_area.right()); + } + else + { + first = std::max(x1,valid_area.left()); + last = std::min(x2,valid_area.right()); + } + + long y; + long x; + const double x1f = x1; + const double y1f = y1; + for (double i = first; i <= last; ++i) + { + y = static_cast(slope*(i-x1f) + y1f); + x = static_cast(i); + + if (y < valid_area.top() || y > valid_area.bottom() ) + continue; + + assign_pixel(c[y-c.top()][x-c.left()], pixel); + } + } + else + { + const double slope = ((double)run)/rise; + + double first, last; + + if (y1 > y2) + { + first = std::max(y2,valid_area.top()); + last = std::min(y1,valid_area.bottom()); + } + else + { + first = std::max(y1,valid_area.top()); + last = std::min(y2,valid_area.bottom()); + } + + long x; + long y; + const double x1f = x1; + const double y1f = y1; + for (double i = first; i <= last; ++i) + { + x = static_cast(slope*(i-y1f) + x1f); + y = static_cast(i); + + if (x < valid_area.left() || x > valid_area.right() ) + continue; + + assign_pixel(c[y-c.top()][x-c.left()], pixel); + } + } + } + + } + inline void draw_line ( + const canvas& c, + const point& p1, + const point& p2 + ){ draw_line(c,p1,p2,0); } + +// ---------------------------------------------------------------------------------------- + + void draw_sunken_rectangle ( + const canvas& c, + const rectangle& border, + unsigned char alpha = 255 + ); + +// ---------------------------------------------------------------------------------------- + + template + inline void draw_pixel ( + const canvas& c, + const point& p, + const pixel_type& pixel + ) + { + if (c.contains(p)) + { + assign_pixel(c[p.y()-c.top()][p.x()-c.left()],pixel); + } + } + +// ---------------------------------------------------------------------------------------- + + template + void draw_checkered ( + const canvas& c, + const rectangle& a, + const pixel_type& pixel1, + const pixel_type& pixel2 + ) + { + rectangle area = a.intersect(c); + if (area.is_empty()) + return; + + for (long i = area.left(); i <= area.right(); ++i) + { + for (long j = area.top(); j <= area.bottom(); ++j) + { + canvas::pixel& p = c[j - c.top()][i - c.left()]; + if (j&0x1 ^ i&0x1) + { + assign_pixel(p,pixel1); + } + else + { + assign_pixel(p,pixel2); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + void draw_button_down ( + const canvas& c, + const rectangle& btn, + unsigned char alpha = 255 + ); + +// ---------------------------------------------------------------------------------------- + + void draw_button_up ( + const canvas& c, + const rectangle& btn, + unsigned char alpha = 255 + ); + +// ---------------------------------------------------------------------------------------- + + template + void draw_circle ( + const canvas& c, + const point& center_point, + double radius, + const pixel_type& pixel, + const rectangle& area = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + using std::sqrt; + rectangle valid_area(c.intersect(area)); + const long x = center_point.x(); + const long y = center_point.y(); + if (radius > 1) + { + long first_x = static_cast(x - radius + 0.5); + long last_x = static_cast(x + radius + 0.5); + const double rs = radius*radius; + + // ensure that we only loop over the part of the x dimension that this + // canvas contains. + if (first_x < valid_area.left()) + first_x = valid_area.left(); + if (last_x > valid_area.right()) + last_x = valid_area.right(); + + long top, bottom; + + top = static_cast(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0))+0.5); + top += y; + long last = top; + + // draw the left half of the circle + long middle = std::min(x-1,last_x); + for (long i = first_x; i <= middle; ++i) + { + double a = i - x + 0.5; + // find the top of the arc + top = static_cast(sqrt(std::max(rs - a*a,0.0))+0.5); + top += y; + long temp = top; + + while(top >= last) + { + bottom = y - top + y; + if (top >= valid_area.top() && top <= valid_area.bottom() ) + { + assign_pixel(c[top-c.top()][i-c.left()],pixel); + } + + if (bottom >= valid_area.top() && bottom <= valid_area.bottom() ) + { + assign_pixel(c[bottom-c.top()][i-c.left()],pixel); + } + --top; + } + + last = temp; + } + + middle = std::max(x,first_x); + top = static_cast(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0))+0.5); + top += y; + last = top; + // draw the right half of the circle + for (long i = last_x; i >= middle; --i) + { + double a = i - x - 0.5; + // find the top of the arc + top = static_cast(sqrt(std::max(rs - a*a,0.0))+0.5); + top += y; + long temp = top; + + while(top >= last) + { + bottom = y - top + y; + if (top >= valid_area.top() && top <= valid_area.bottom() ) + { + assign_pixel(c[top-c.top()][i-c.left()],pixel); + } + + if (bottom >= valid_area.top() && bottom <= valid_area.bottom() ) + { + assign_pixel(c[bottom-c.top()][i-c.left()],pixel); + } + --top; + } + + last = temp; + } + } + else if (radius == 1 && + x >= valid_area.left() && x <= valid_area.right() && + y >= valid_area.top() && y <= valid_area.bottom() ) + { + assign_pixel(c[y-c.top()][x-c.left()], pixel); + } + } + inline void draw_circle ( + const canvas& c, + const point& center_point, + double radius + ){ draw_circle(c, center_point, radius, 0); } + +// ---------------------------------------------------------------------------------------- + + template + void draw_solid_circle ( + const canvas& c, + const point& center_point, + double radius, + const pixel_type& pixel, + const rectangle& area = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + using std::sqrt; + rectangle valid_area(c.intersect(area)); + const long x = center_point.x(); + const long y = center_point.y(); + if (radius > 1) + { + long first_x = static_cast(x - radius + 0.5); + long last_x = static_cast(x + radius + 0.5); + const double rs = radius*radius; + + // ensure that we only loop over the part of the x dimension that this + // canvas contains. + if (first_x < valid_area.left()) + first_x = valid_area.left(); + if (last_x > valid_area.right()) + last_x = valid_area.right(); + + long top, bottom; + + top = static_cast(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0))+0.5); + top += y; + long last = top; + + // draw the left half of the circle + long middle = std::min(x-1,last_x); + for (long i = first_x; i <= middle; ++i) + { + double a = i - x + 0.5; + // find the top of the arc + top = static_cast(sqrt(std::max(rs - a*a,0.0))+0.5); + top += y; + long temp = top; + + while(top >= last) + { + bottom = y - top + y; + draw_line(c, point(i,top),point(i,bottom),pixel,area); + --top; + } + + last = temp; + } + + middle = std::max(x,first_x); + top = static_cast(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0))+0.5); + top += y; + last = top; + // draw the right half of the circle + for (long i = last_x; i >= middle; --i) + { + double a = i - x - 0.5; + // find the top of the arc + top = static_cast(sqrt(std::max(rs - a*a,0.0))+0.5); + top += y; + long temp = top; + + while(top >= last) + { + bottom = y - top + y; + draw_line(c, point(i,top),point(i,bottom),pixel,area); + --top; + } + + last = temp; + } + } + else if (radius == 1 && + x >= valid_area.left() && x <= valid_area.right() && + y >= valid_area.top() && y <= valid_area.bottom() ) + { + assign_pixel(c[y-c.top()][x-c.left()], pixel); + } + } + inline void draw_solid_circle ( + const canvas& c, + const point& center_point, + double radius + ) { draw_solid_circle(c, center_point, radius, 0); } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void draw_image ( + const canvas& c, + const point& p, + const image_type& img, + const rectangle& area_ = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + const long x = p.x(); + const long y = p.y(); + rectangle rect(x,y,img.nc()+x-1,img.nr()+y-1); + rectangle area = c.intersect(rect).intersect(area_); + if (area.is_empty()) + return; + + for (long row = area.top(); row <= area.bottom(); ++row) + { + for (long col = area.left(); col <= area.right(); ++col) + { + assign_pixel(c[row-c.top()][col-c.left()], img[row-rect.top()][col-rect.left()]); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + void draw_rounded_rectangle ( + const canvas& c, + const rectangle& rect, + unsigned radius, + const pixel_type& color, + const rectangle& area_ = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + if ( rect.intersect ( c ).is_empty() ) + return; + + draw_line ( c, point(rect.left() + radius + 1, rect.bottom()), + point(rect.right() - radius - 1, rect.bottom()), color,area_ ); + + draw_line ( c, point(rect.left() + radius + 1, rect.top()), + point(rect.right() - radius - 1, rect.top()), color,area_ ); + + draw_line ( c, point(rect.left(), rect.top() + radius + 1), + point(rect.left(), rect.bottom() - radius - 1), color,area_ ); + + draw_line ( c, point(rect.right(), rect.top() + radius + 1), + point(rect.right(), rect.bottom() - radius - 1), color,area_ ); + + unsigned x = radius, y = 0, old_x = x; + + point p; + while ( x > y ) + { + p = point(rect.left() + radius - y, rect.top() + radius - x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.right() - radius + y, rect.top() + radius - x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.right() - radius + y, rect.bottom() - radius + x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.left() + radius - y, rect.bottom() - radius + x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.left() + radius - x, rect.top() + radius - y); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.right() - radius + x, rect.top() + radius - y); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.right() - radius + x, rect.bottom() - radius + y); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.left() + radius - x, rect.bottom() - radius + y); + if (area_.contains(p)) draw_pixel (c, p , color ); + y++; + old_x = x; + x = square_root ( ( radius * radius - y * y ) * 4 ) / 2; + } + + if ( x == y && old_x != x ) + { + p = point(rect.left() + radius - y, rect.top() + radius - x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.right() - radius + y, rect.top() + radius - x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.right() - radius + y, rect.bottom() - radius + x); + if (area_.contains(p)) draw_pixel (c, p , color ); + p = point(rect.left() + radius - y, rect.bottom() - radius + x); + if (area_.contains(p)) draw_pixel (c, p , color ); + } + } + +// ---------------------------------------------------------------------------------------- + + template + void fill_gradient_rounded ( + const canvas& c, + const rectangle& rect, + unsigned long radius, + const pixel_type& top_color, + const pixel_type& bottom_color, + const rectangle& area = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + + ) + { + rectangle valid_area(c.intersect(area.intersect(rect))); + if ( valid_area.is_empty() ) + return; + + + unsigned long m_prev = 0, m = radius, c_div = valid_area.height() - 1; + + long c_top = valid_area.top(); + + long c_bottom = valid_area.bottom(); + + for ( int y = c_top; y <= c_bottom;y++ ) + { + if ( y < valid_area.top() ) + continue; + + if ( y > valid_area.bottom() ) + break; + + unsigned long c_s = y - c_top; + + unsigned long c_t = c_bottom - y; + + + if ( c_div == 0 ) + { + // only a single round, just take the average color + c_div = 2; + c_s = c_t = 1; + } + + rgb_alpha_pixel color; + vector_to_pixel(color, + ((pixel_to_vector(top_color)*c_t + pixel_to_vector(bottom_color)*c_s)/c_div)); + + unsigned long s = y - rect.top(); + + unsigned long t = rect.bottom() - y; + + if ( s < radius ) + { + m = radius - square_root ( ( radius * radius - ( radius - s ) * ( radius - s ) ) * 4 ) / 2; + + if ( s == m && m + 1 < m_prev ) // these are hacks to remove distracting artefacts at small radii + m++; + } + else if ( t < radius ) + { + m = radius - square_root ( ( radius * radius - ( radius - t ) * ( radius - t ) ) * 4 ) / 2; + + if ( t == m && m == m_prev ) + m++; + } + else + { + m = 0; + } + + m_prev = m; + + draw_line ( c, point(valid_area.left() + m, y), + point(valid_area.right() - m, y), color ); + } + } + +// ---------------------------------------------------------------------------------------- + + template + void draw_rectangle ( + const canvas& c, + rectangle rect, + const pixel_type& pixel, + const rectangle& area = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + // top line + draw_line(c, point(rect.left(),rect.top()), + point(rect.right(),rect.top()), + pixel, area); + + // bottom line + draw_line(c, point(rect.left(),rect.bottom()), + point(rect.right(),rect.bottom()), + pixel, area); + + // left line + draw_line(c, point(rect.left(),rect.top()), + point(rect.left(),rect.bottom()), + pixel, area); + + // right line + draw_line(c, point(rect.right(),rect.top()), + point(rect.right(),rect.bottom()), + pixel, area); + } + inline void draw_rectangle ( + const canvas& c, + rectangle rect + ){ draw_rectangle(c, rect, 0); } + +// ---------------------------------------------------------------------------------------- + + template + void fill_rect ( + const canvas& c, + const rectangle& rect, + const pixel_type& pixel + ) + { + rectangle area = rect.intersect(c); + for (long y = area.top(); y <= area.bottom(); ++y) + { + for (long x = area.left(); x <= area.right(); ++x) + { + assign_pixel(c[y-c.top()][x-c.left()], pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template + void fill_rect_with_vertical_gradient ( + const canvas& c, + const rectangle& rect, + const pixel_type& pixel_top, + const pixel_type& pixel_bottom, + const rectangle& area_ = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) + { + rectangle area = rect.intersect(c).intersect(area_); + pixel_type pixel; + + const long s = rect.bottom()-rect.top(); + + for (long y = area.top(); y <= area.bottom(); ++y) + { + const long t = rect.bottom()-y; + const long b = y-rect.top(); + vector_to_pixel(pixel, + ((pixel_to_vector(pixel_top)*t + + pixel_to_vector(pixel_bottom)*b)/s)); + + for (long x = area.left(); x <= area.right(); ++x) + { + assign_pixel(c[y-c.top()][x-c.left()], pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "canvas_drawing.cpp" +#endif + +#endif // DLIB_GUI_CANVAS_DRAWINg_ + diff --git a/dlib/gui_widgets/canvas_drawing_abstract.h b/dlib/gui_widgets/canvas_drawing_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..9741a36e1c89f0ac2118d32411381a43c16d80af --- /dev/null +++ b/dlib/gui_widgets/canvas_drawing_abstract.h @@ -0,0 +1,312 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_ +#ifdef DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_ + +#include "../gui_core.h" +#include "../pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_line ( + const canvas& c, + const point& p1, + const point& p2, + const pixel_type& pixel = rgb_pixel(0,0,0), + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - draws the part of the line from p1 to p1 that overlaps with + the canvas and area onto the canvas. + - Uses the given pixel color. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_rectangle ( + const canvas& c, + rectangle rect, + const pixel_type& pixel = rgb_pixel(0,0,0), + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - Draws the part of the rectangle that overlaps with + the canvas and area onto the canvas. + - Uses the given pixel color. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_circle ( + const canvas& c, + const point& center_point, + double radius, + const pixel_type& pixel = rgb_pixel(0,0,0), + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - draws the part of the circle centered at center_point with the given radius + that overlaps with the canvas and area onto the canvas. + - Uses the given pixel color. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_pixel ( + const canvas& c, + const point& p, + const pixel_type& pixel + ); + /*! + requires + - pixel_traits is defined + ensures + - if (c.contains(p)) then + - sets the pixel in c that represents the point p to the + given pixel color. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_solid_circle ( + const canvas& c, + const point& center_point, + double radius, + const pixel_type& pixel = rgb_pixel(0,0,0), + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - draws the part of the solid circle centered at center_point with the given + radius that overlaps with the canvas and area onto the canvas. + ("solid" means that the interior is also filled in with the given + pixel color) + - Uses the given pixel color. + !*/ + +// ---------------------------------------------------------------------------------------- + + void draw_button_down ( + const canvas& c, + const rectangle& btn, + unsigned char alpha = 255 + ); + /*! + requires + - 0 <= alpha <= 255 + ensures + - draws the border of a button onto canvas c: + - the border will be that of a button that is depressed + - only the part of the border that overlaps with the canvas object + will be drawn. + - the border will be for the button whose area is defined by the + rectangle btn. + - performs alpha blending such that the button is drawn with full opacity + when alpha is 255 and fully transparent when alpha is 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + void draw_sunken_rectangle ( + const canvas& c, + const rectangle& border, + unsigned char alpha = 255 + ); + /*! + requires + - 0 <= alpha <= 255 + ensures + - draws a sunken rectangle around the given border. + (This is the type of border used for text_fields and + check_boxes and the like). + - performs alpha blending such that the rectangle is drawn with full opacity + when alpha is 255 and fully transparent when alpha is 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + void draw_button_up ( + const canvas& c, + const rectangle& btn, + unsigned char alpha = 255 + ); + /*! + requires + - 0 <= alpha <= 255 + ensures + - draws the border of a button onto canvas c: + - the border will be that of a button that is NOT depressed + - only the part of the border that overlaps with the canvas object + will be drawn. + - the border will be for the button whose area is defined by the + rectangle btn. + - performs alpha blending such that the button is drawn with full opacity + when alpha is 255 and fully transparent when alpha is 0. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_checkered ( + const canvas& c, + const rectangle& area, + const pixel_type& pixel1, + const pixel_type& pixel2 + ); + /*! + requires + - pixel_traits is defined + ensures + - fills the area on the given canvas defined by the rectangle area with a checkers + board pattern where every other pixel gets assigned either pixel1 or pixel2. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void draw_image ( + const canvas& c + const point& p, + const image_type& image, + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - image_type == an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - draws the given image object onto the canvas such that the upper left corner of the + image will appear at the point p in the canvas's window. (note that the + upper left corner of the image is assumed to be the pixel image[0][0] and the + lower right corner of the image is assumed to be image[image.nr()-1][image.nc()-1]) + - only draws the part of the image that overlaps with the area rectangle + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void fill_rect ( + const canvas& c, + const rectangle& rect, + const pixel_type& pixel + ); + /*! + requires + - pixel_traits is defined + ensures + - fills the area defined by rect in the given canvas with the given pixel color. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void fill_rect_with_vertical_gradient ( + const canvas& c, + const rectangle& rect, + const pixel_type& pixel_top, + const pixel_type& pixel_bottom, + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - fills the rectangle defined by rect in the given canvas with the given colors. + The top of the area will have the pixel_top color and will slowly fade + towards the pixel_bottom color towards the bottom of rect. + - only draws the part of the image that overlaps with the area rectangle + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void fill_gradient_rounded ( + const canvas& c, + const rectangle& rect, + unsigned long radius, + const pixel_type& top_color, + const pixel_type& bottom_color, + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - Fills the region defined by rect in the given canvas with the given colors. + The top of the region will have the top_color color and will slowly fade + towards the bottom_color color towards the bottom of rect. + - The drawn rectangle will have rounded corners and with the amount of + - rounding given by the radius argument. + - only the part of this object that overlaps with area and the canvas + will be drawn on the canvas + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename pixel_type + > + void draw_rounded_rectangle ( + const canvas& c, + const rectangle& rect, + unsigned radius, + const pixel_type& color, + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ); + /*! + requires + - pixel_traits is defined + ensures + - Draws the part of the rectangle that overlaps with + the canvas onto the canvas. + - The drawn rectangle will have rounded corners and with the amount of + rounding given by the radius argument. + - Uses the given pixel color. + - only draws the part of the image that overlaps with the area rectangle + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_ + diff --git a/dlib/gui_widgets/drawable.cpp b/dlib/gui_widgets/drawable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7618b7092a03c3dbc907b5df5d494c4349d29e79 --- /dev/null +++ b/dlib/gui_widgets/drawable.cpp @@ -0,0 +1,506 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DRAWABLe_CPP_ +#define DLIB_DRAWABLe_CPP_ + +#include "drawable.h" + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ----------- drawable_window object ------------------------------------------------------------ +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + rgb_pixel drawable_window:: + background_color ( + ) const + { + auto_mutex M(wm); + return bg_color; + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + set_background_color ( + unsigned long red_, + unsigned long green_, + unsigned long blue_ + ) + { + wm.lock(); + bg_color.red = red_; + bg_color.green = green_; + bg_color.blue = blue_; + wm.unlock(); + // now repaint the window + unsigned long width,height; + get_size(width,height); + rectangle rect(0,0,width-1,height-1); + invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + paint ( + const canvas& c + ) + { + ++event_id; + c.fill(bg_color.red,bg_color.green,bg_color.blue); + + widgets.reset(); + while (widgets.move_next()) + { + widgets.element().value().reset(); + while (widgets.element().value().move_next()) + { + // only dispatch a draw() call if this widget isn't hidden + if (widgets.element().value().element()->hidden == false && + widgets.element().value().element()->event_id != event_id) + { + widgets.element().value().element()->event_id = event_id; + widgets.element().value().element()->draw(c); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_user_event ( + void* p, + int i + ) + { + drawable* d = reinterpret_cast(p); + if (widget_set.is_member(d)) + { + d->on_user_event(i); + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_window_moved( + ) + { + ++event_id; + window_moved.reset(); + while (window_moved.move_next()) + { + if (window_moved.element()->event_id != event_id) + { + window_moved.element()->event_id = event_id; + window_moved.element()->on_window_moved(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_window_resized( + ) + { + ++event_id; + window_resized.reset(); + while (window_resized.move_next()) + { + if (window_resized.element()->event_id != event_id) + { + window_resized.element()->event_id = event_id; + window_resized.element()->on_window_resized(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + ++event_id; + keyboard.reset(); + while (keyboard.move_next()) + { + if (keyboard.element()->event_id != event_id) + { + keyboard.element()->event_id = event_id; + keyboard.element()->on_keydown(key,is_printable,state); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_focus_gained ( + ) + { + ++event_id; + focus.reset(); + while (focus.move_next()) + { + if (focus.element()->event_id != event_id) + { + focus.element()->event_id = event_id; + focus.element()->on_focus_gained(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_focus_lost ( + ) + { + ++event_id; + focus.reset(); + while (focus.move_next()) + { + if (focus.element()->event_id != event_id) + { + focus.element()->event_id = event_id; + focus.element()->on_focus_lost(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ) + { + lastx = x; + lasty = y; + + ++event_id; + mouse_click.reset(); + while (mouse_click.move_next()) + { + if (mouse_click.element()->event_id != event_id) + { + mouse_click.element()->event_id = event_id; + mouse_click.element()->on_mouse_down(btn,state,x,y,is_double_click); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ) + { + lastx = x; + lasty = y; + + ++event_id; + mouse_click.reset(); + while (mouse_click.move_next()) + { + if (mouse_click.element()->event_id != event_id) + { + mouse_click.element()->event_id = event_id; + mouse_click.element()->on_mouse_up(btn,state,x,y); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + lastx = x; + lasty = y; + + ++event_id; + mouse_move.reset(); + while (mouse_move.move_next()) + { + if (mouse_move.element()->event_id != event_id) + { + mouse_move.element()->event_id = event_id; + mouse_move.element()->on_mouse_move(state,x,y); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_mouse_leave ( + ) + { + lastx = -1; + lasty = -1; + + ++event_id; + mouse_move.reset(); + while (mouse_move.move_next()) + { + if (mouse_move.element()->event_id != event_id) + { + mouse_move.element()->event_id = event_id; + mouse_move.element()->on_mouse_leave(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_mouse_enter ( + ) + { + ++event_id; + mouse_move.reset(); + while (mouse_move.move_next()) + { + if (mouse_move.element()->event_id != event_id) + { + mouse_move.element()->event_id = event_id; + mouse_move.element()->on_mouse_enter(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_wheel_up ( + ) + { + ++event_id; + mouse_wheel.reset(); + while (mouse_wheel.move_next()) + { + if (mouse_wheel.element()->event_id != event_id) + { + mouse_wheel.element()->event_id = event_id; + mouse_wheel.element()->on_wheel_up(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable_window:: + on_wheel_down ( + ) + { + ++event_id; + mouse_wheel.reset(); + while (mouse_wheel.move_next()) + { + if (mouse_wheel.element()->event_id != event_id) + { + mouse_wheel.element()->event_id = event_id; + mouse_wheel.element()->on_wheel_down(); + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ----------- drawable object ---------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void drawable:: + enable_events ( + ) + { + auto_mutex M(m); + if (enabled_events == false) + { + enabled_events = true; + drawable* temp = this; + long zo = z_order_value; + + drawable_window::set_of_drawables* sod = parent.widgets[zo]; + if (sod == 0) + { + // this drawable is the first widget at this z order so we need + // to make its containing set + drawable_window::set_of_drawables s; + s.add(temp); + parent.widgets.add(zo,s); + } + else + { + sod->add(temp); + } + + temp = this; + parent.widget_set.add(temp); + + if (events & MOUSE_MOVE) + { + temp = this; + parent.mouse_move.add(temp); + } + if (events & MOUSE_CLICK) + { + temp = this; + parent.mouse_click.add(temp); + } + if (events & MOUSE_WHEEL) + { + temp = this; + parent.mouse_wheel.add(temp); + } + if (events & WINDOW_RESIZED) + { + temp = this; + parent.window_resized.add(temp); + } + if (events & KEYBOARD_EVENTS) + { + temp = this; + parent.keyboard.add(temp); + } + if (events & FOCUS_EVENTS) + { + temp = this; + parent.focus.add(temp); + } + if (events & WINDOW_MOVED) + { + temp = this; + parent.window_moved.add(temp); + } + parent.invalidate_rectangle(rect); + } + } + +// ---------------------------------------------------------------------------------------- + + void drawable:: + set_z_order ( + long order + ) + { + auto_mutex M(m); + if (order != z_order_value && enabled_events) + { + // first remove this drawable from widgets + drawable_window::set_of_drawables* sod = parent.widgets[z_order_value]; + drawable* junk; + sod->remove(this,junk); + + // if there are no more drawables at this z order then destroy the + // set for this order + if (sod->size() == 0) + parent.widgets.destroy(z_order_value); + + // now add this drawable to its new z order + sod = parent.widgets[order]; + if (sod == 0) + { + // this drawable is the first widget at this z order so we need + // to make its containing set + drawable_window::set_of_drawables s, x; + s.add(junk); + long temp_order = order; + parent.widgets.add(temp_order,s); + } + else + { + sod->add(junk); + } + parent.invalidate_rectangle(rect); + + } + z_order_value = order; + } + +// ---------------------------------------------------------------------------------------- + + void drawable:: + disable_events ( + ) + { + auto_mutex M(m); + if (enabled_events) + { + enabled_events = false; + // first remove this drawable from widgets + drawable_window::set_of_drawables* sod = parent.widgets[z_order_value]; + drawable* junk; + sod->remove(this,junk); + + // if there are no more drawables at this z order then destroy the + // set for this order + if (sod->size() == 0) + parent.widgets.destroy(z_order_value); + + parent.widget_set.remove(this,junk); + + // now unregister this drawable from all the events it has registered for. + if (events & MOUSE_MOVE) + parent.mouse_move.remove(this,junk); + if (events & MOUSE_CLICK) + parent.mouse_click.remove(this,junk); + if (events & MOUSE_WHEEL) + parent.mouse_wheel.remove(this,junk); + if (events & WINDOW_RESIZED) + parent.window_resized.remove(this,junk); + if (events & KEYBOARD_EVENTS) + parent.keyboard.remove(this,junk); + if (events & FOCUS_EVENTS) + parent.focus.remove(this,junk); + if (events & WINDOW_MOVED) + parent.window_moved.remove(this,junk); + } + } + +// ---------------------------------------------------------------------------------------- + + drawable:: + ~drawable ( + ) + { + DLIB_ASSERT(events_are_enabled() == false, + "\tdrawable::~drawable()" + << "\n\tYou must disable events for drawable objects in their destructor by calling disable_events()." + << "\n\tthis: " << this + ); + disable_events(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DRAWABLe_CPP_ + diff --git a/dlib/gui_widgets/drawable.h b/dlib/gui_widgets/drawable.h new file mode 100644 index 0000000000000000000000000000000000000000..ee3e722d44f64b1c6bfb8ff61adb18aaa064af33 --- /dev/null +++ b/dlib/gui_widgets/drawable.h @@ -0,0 +1,510 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_DRAWABLe_ +#define DLIB_DRAWABLe_ + +#include "drawable_abstract.h" +#include "../gui_core.h" +#include "../set.h" +#include "../binary_search_tree.h" +#include "../algs.h" +#include "../pixel.h" +#include "fonts.h" +#include "../matrix.h" +#include "canvas_drawing.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class drawable_window +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class drawable; + class drawable_window : public base_window + { + /*! + INITIAL VALUE + - lastx == -1 + - lasty == -1 + - event_id == 1 + + CONVENTION + - bg_color == backgroud_color() + + - widgets == this binary search tree contains every drawable that is in + this window. It is a mapping of each drawable's z-order to a pointer + to said drawable. + - widget_set == a set that contains all the widgets in this window and + want to receive events. + + - mouse_move == this is a set of drawables that are in this window and + want to receive the mouse movement events. + - mouse_wheel == this is a set of drawables that are in this window and + want to receive the mouse wheel events. + - mouse_click == this is a set of drawables that are in this window and + want to receive the mouse click events. + - window_resized == this is a set of drawables that are in this window and + want to receive the window_resized event. + - keyboard == this is a set of drawables that are in this window and + want to receive keyboard events. + - focus == this is a set of drawables that are in this window and + want to receive focus events. + - window_moved == this is a set of drawables that are in this window and + want to receive window move events. + + - lastx == the x coordinate that we last saw the mouse at or -1 if the + mouse is outside this window. + - lasty == the y coordinate that we last saw the mouse at or -1 if the + mouse is outside this window. + + - event_id == a number we use to tag events so we don't end up sending + an event to a drawable more than once. This could happen if one of the + event handlers does something to reset the enumerator while we are + dispatching events (e.g. creating a new widget). + !*/ + public: + + drawable_window( + bool resizable = true, + bool undecorated = false + ) : + base_window(resizable,undecorated), + bg_color(rgb_pixel(212,208,200)), + lastx(-1), + lasty(-1), + event_id(1) + {} + + void set_background_color ( + unsigned long red, + unsigned long green, + unsigned long blue + ); + + rgb_pixel background_color ( + ) const; + + virtual inline ~drawable_window()=0; + + private: + + void paint ( + const canvas& c + ); + + protected: + + void on_window_resized( + ); + + void on_window_moved( + ); + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ); + + void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ); + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + void on_mouse_leave ( + ); + + void on_mouse_enter ( + ); + + void on_wheel_up ( + ); + + void on_wheel_down ( + ); + + void on_focus_gained ( + ); + + void on_focus_lost ( + ); + + void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ); + + void on_user_event ( + void* p, + int i + ); + + private: + + friend class drawable; + + + rgb_pixel bg_color; + + typedef set::kernel_1a_c set_of_drawables; + + binary_search_tree::kernel_1a_c widgets; + + set_of_drawables widget_set; + set_of_drawables mouse_move; + set_of_drawables mouse_wheel; + set_of_drawables mouse_click; + set_of_drawables window_resized; + set_of_drawables keyboard; + set_of_drawables focus; + set_of_drawables window_moved; + + long lastx, lasty; + unsigned long event_id; + + + // restricted functions + drawable_window(drawable_window&); // copy constructor + drawable_window& operator=(drawable_window&); // assignment operator + + + }; + + drawable_window::~drawable_window(){ close_window();} + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class drawable +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + enum + { + MOUSE_MOVE = 1, + MOUSE_CLICK = 2, + MOUSE_WHEEL = 4, + WINDOW_RESIZED = 8, + KEYBOARD_EVENTS = 16, + FOCUS_EVENTS = 32, + WINDOW_MOVED = 64 + }; + + class drawable + { + + /*! + INITIAL VALUE + - enabled_events == false + - event_id == 0 + + CONVENTION + - events == a bitset specifying what events this drawable is to receive. + + - z_order_value == z_order() + + - if (this drawable has been added to the partent window's sets and + binary search tree) then + - enabled_events == true + - else + - enabled_events == false + + - event_id == the id of the last event we got from our parent window + !*/ + + public: + + friend class drawable_window; + + drawable ( + drawable_window& w, + unsigned long events_ = 0 + ) : + m(w.wm), + parent(w), + hidden(false), + enabled(true), + lastx(w.lastx), + lasty(w.lasty), + mfont(default_font::get_font()), + z_order_value(0), + events(events_), + enabled_events(false), + event_id(0) + {} + + virtual ~drawable ( + ); + + long z_order ( + ) const + { + m.lock(); + long temp = z_order_value; + m.unlock(); + return temp; + } + + virtual void set_z_order ( + long order + ); + + const rectangle get_rect ( + ) const + { + auto_mutex M(m); + return rect; + } + + long bottom ( + ) const + { + auto_mutex M(m); + return rect.bottom(); + } + + long top ( + ) const + { + auto_mutex M(m); + return rect.top(); + } + + long left ( + ) const + { + auto_mutex M(m); + return rect.left(); + } + + long right ( + ) const + { + auto_mutex M(m); + return rect.right(); + } + + long width ( + ) const + { + auto_mutex M(m); + return rect.width(); + } + + long height ( + ) const + { + auto_mutex M(m); + return rect.height(); + } + + bool is_enabled ( + ) const + { + auto_mutex M(m); + return enabled; + } + + virtual void enable ( + ) + { + auto_mutex M(m); + enabled = true; + parent.invalidate_rectangle(rect); + } + + virtual void disable ( + ) + { + auto_mutex M(m); + enabled = false; + parent.invalidate_rectangle(rect); + } + + virtual void set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + parent.invalidate_rectangle(rect); + } + + const font* main_font ( + ) const + { + return mfont; + } + + bool is_hidden ( + ) const + { + auto_mutex M(m); + return hidden; + } + + virtual void set_pos ( + long x, + long y + ) + { + m.lock(); + rectangle old(rect); + + const unsigned long width = rect.width(); + const unsigned long height = rect.height(); + rect.set_top(y); + rect.set_left(x); + rect.set_right(static_cast(x+width)-1); + rect.set_bottom(static_cast(y+height)-1); + + parent.invalidate_rectangle(rect+old); + m.unlock(); + } + + virtual void show ( + ) + { + m.lock(); + hidden = false; + parent.invalidate_rectangle(rect); + m.unlock(); + } + + virtual void hide ( + ) + { + m.lock(); + hidden = true; + parent.invalidate_rectangle(rect); + m.unlock(); + } + + base_window& parent_window ( + ) { return parent; } + + const base_window& parent_window ( + ) const { return parent; } + + virtual int next_free_user_event_number ( + )const { return 0; } + + protected: + rectangle rect; + const rmutex& m; + drawable_window& parent; + bool hidden; + bool enabled; + const long& lastx; + const long& lasty; + const font* mfont; + + + void enable_events ( + ); + + bool events_are_enabled ( + ) const { auto_mutex M(m); return enabled_events; } + + void disable_events ( + ); + + private: + + long z_order_value; + const unsigned long events; + bool enabled_events; + unsigned long event_id; + + + // restricted functions + drawable(drawable&); // copy constructor + drawable& operator=(drawable&); // assignment operator + + + protected: + + virtual void draw ( + const canvas& c + ) const=0; + + virtual void on_user_event ( + int i + ){} + + virtual void on_window_resized( + ){} + + virtual void on_window_moved( + ){} + + virtual void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ){} + + virtual void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ){} + + virtual void on_mouse_move ( + unsigned long state, + long x, + long y + ){} + + virtual void on_mouse_leave ( + ){} + + virtual void on_mouse_enter ( + ){} + + virtual void on_wheel_up ( + ){} + + virtual void on_wheel_down ( + ){} + + virtual void on_focus_gained ( + ){} + + virtual void on_focus_lost ( + ){} + + virtual void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ){} + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "drawable.cpp" +#endif + +#endif // DLIB_DRAWABLe_ + diff --git a/dlib/gui_widgets/drawable_abstract.h b/dlib/gui_widgets/drawable_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..3adba7964c06d7b82994d92573f1880fc0a137d2 --- /dev/null +++ b/dlib/gui_widgets/drawable_abstract.h @@ -0,0 +1,697 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#undef DLIB_DRAWABLe_ABSTRACT_ +#ifdef DLIB_DRAWABLe_ABSTRACT_ + +#include "../gui_core.h" +#include "fonts_abstract.h" +#include "canvas_drawing_abstract.h" + +namespace dlib +{ + + /*! + GENERAL REMARKS + This file defines the drawable interface class and the drawable_window which + is just a window that is capable of displaying drawable objects (i.e. objects + that implement the drawable interface). + + The drawable interface is a simple framework for creating more complex + graphical widgets. It provides a default set of functionality and a + set of events which a gui widget may use. + + THREAD SAFETY + All objects and functions defined in this file are thread safe. You may + call them from any thread without serializing access to them. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class drawable_window +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class drawable_window : public base_window + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a window on the desktop that is capable of + containing drawable objects. + + INITIAL STATE + The initial state of the drawable_window is to be hidden. This means + you need to call show() to make it appear. + + EVENTS + The drawable_window object uses all the events provided by base_window + except for the on_window_close() event. This means that if you + define handlers for these events yourself you will have to call + the drawable_window's version of them so that the drawable_window + can continue to process and forward these events to its drawable + objects. + !*/ + public: + + drawable_window ( + bool resizable = true, + bool undecorated = false + ); + /*! + requires + - if (undecorated == true) then + - resizable == false + ensures + - #*this has been properly initialized + - #background_color() == rgb_pixel(212,208,200) + - if (resizable == true) then + - this window will be resizable by the user + - else + - this window will not be resizable by the user + - if (undecorated == true) then + - this window will not have any graphical elements outside + of its drawable area or appear in the system task bar. + (e.g. a popup menu) + throws + - std::bad_alloc + - dlib::thread_error + - dlib::gui_error + This exception is thrown if there is an error while + creating this window. + !*/ + + virtual ~drawable_window( + )=0; + /*! + ensures + - if (this window has not already been closed) then + - closes the window + - does NOT trigger the on_window_close() event + - all resources associated with *this have been released + !*/ + + void set_background_color ( + unsigned long red, + unsigned long green, + unsigned long blue + ); + /*! + ensures + - #background_color().red == red + - #background_color().green == green + - #background_color().blue == blue + !*/ + + rgb_pixel background_color ( + ) const; + /*! + ensures + - returns the background color this window paints its canvas + with before it passes it onto its drawable widgets + !*/ + + private: + // restricted functions + drawable_window(drawable_window&); // copy constructor + drawable_window& operator=(drawable_window&); // assignment operator + + friend class drawable; + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class drawable +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + enum + { + MOUSE_MOVE = 1, + MOUSE_CLICK = 2, + MOUSE_WHEEL = 4, + WINDOW_RESIZED = 8, + KEYBOARD_EVENTS = 16, + FOCUS_EVENTS = 32, + WINDOW_MOVED = 64 + }; + + class drawable + { + /*! + INITIAL VALUE + top() == 1 + left() == 1 + right() == 0 + bottom() == 0 + get_rect().is_empty() == true + is_hidden() == false + is_enabled() == true + z_order() == 0 + main_font() == default_font::get_font() + + WHAT THIS OBJECT REPRESENTS + This is an interface that all drawable widgets implement. It + provides a standard method (draw()) to draw a widget onto a canvas + and many other convenient functions for drawable objects. + + EVENT FORWARDING + All the events that come to a drawable object are forwarded from its + parent window. Additionally, there is no filtering. This means that + if a drawable registers to receive a certain kind of event then whenever + its parent window receives that event the drawable object will get a + forwarded copy of it as well even if the event occurred outside the + drawable's rectangle. + + The only events that have anything in the way of filtering are the + draw() and on_user_event() events. draw() is only called on a drawable + object when that object is not hidden. on_user_event() is only called + for drawables that the on_user_event()'s first argument specifically + references. All other events are not filtered at all though. + + Z ORDER + Z order defines the order in which drawable objects are drawn. The + lower numbered drawables are drawn first and then the higher numbered + ones. So a drawable with a z order of 0 is drawn before one with a + z order of 1 and so on. + !*/ + + public: + + friend class drawable_window; + + drawable ( + drawable_window& w, + unsigned long events = 0 + ) : + m(w.wm), + parent(w), + hidden(false), + enabled(true) + {} + /*! + ensures + - #*this is properly initialized + - #parent_window() == w + - #*this will not receive any events or draw() requests until + enable_events() is called + - once events_are_enabled() == true this drawable will receive + the on_user_event() event. (i.e. you always get this event, you don't + have to enable it by setting something in the events bitset). + - if (events & MOUSE_MOVE) then + - once events_are_enabled() == true this drawable will receive + the following events related to mouse movement: on_mouse_move, + on_mouse_leave, and on_mouse_enter. + - if (events & MOUSE_CLICK) then + - once events_are_enabled() == true this drawable will receive + the following events related to mouse clicks: on_mouse_down and + on_mouse_up. + - if (events & MOUSE_WHEEL) then + - once events_are_enabled() == true this drawable will receive + the following events related to mouse wheel scrolling: + on_wheel_up and on_wheel_down. + - if (events & WINDOW_RESIZED) then + - once events_are_enabled() == true this drawable will receive + the following event related to its parent window resizing: + on_window_resized. + - if (events & KEYBOARD_EVENTS) then + - once events_are_enabled() == true this drawable will receive + the following keyboard event: on_keydown. + - if (events & FOCUS_EVENTS) then + - once events_are_enabled() == true this drawable will receive + the following focus events: on_focus_gained and on_focus_lost. + - if (events & WINDOW_MOVED) then + - once events_are_enabled() == true this drawable will receive + the following event related to its parent window moving: + on_window_moved. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~drawable ( + ); + /*! + requires + - events_are_enabled() == false + ensures + - any resources associated with *this have been released + - *this has been removed from its containing window parent_window() and + its parent window will no longer try to dispatch events to it. + Note that this does not trigger a redraw of the parent window. If you + want to do that you must do it yourself. + !*/ + + long z_order ( + ) const; + /*! + ensures + - returns the z order for this drawable. + !*/ + + virtual void set_z_order ( + long order + ); + /*! + ensures + - #z_order() == order + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + throws + - std::bad_alloc + !*/ + + const rectangle get_rect ( + ) const; + /*! + ensures + - returns the rectangle that defines the area and position of this + drawable inside its containing window parent_window(). + !*/ + + long bottom ( + ) const; + /*! + ensures + - returns get_rect().bottom() + !*/ + + long top ( + ) const; + /*! + ensures + - returns get_rect().top() + !*/ + + long left ( + ) const; + /*! + ensures + - returns get_rect().left() + !*/ + + long right ( + ) const; + /*! + ensures + - returns get_rect().right() + !*/ + + unsigned long width ( + ) const; + /*! + ensures + - returns get_rect().width() + !*/ + + unsigned long height ( + ) const; + /*! + ensures + - returns get_rect().height() + !*/ + + virtual void set_pos ( + long x, + long y + ); + /*! + ensures + - #top() == y + - #left() == x + - #width() == width() + - #height() == height() + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + - i.e. This just sets the upper left corner of this drawable to the + location (x,y) + !*/ + + bool is_enabled ( + ) const; + /*! + ensures + - returns true if this object is enabled and false otherwise. + (it is up to derived classes to define exactly what it means to be + "enabled") + !*/ + + virtual void enable ( + ); + /*! + ensures + - #is_enabled() == true + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + !*/ + + virtual void disable ( + ); + /*! + ensures + - #is_enabled() == false + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + !*/ + + virtual void set_main_font ( + const font* f + ); + /*! + ensures + - #main_font() == f + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + !*/ + + const font* main_font ( + ) const; + /*! + ensures + - returns the current main font being used by this widget + !*/ + + bool is_hidden ( + ) const; + /*! + ensures + - returns true if this object is NOT currently displayed on parent_window() + and false otherwise. + !*/ + + virtual void show ( + ); + /*! + ensures + - #is_hidden() == false + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + !*/ + + virtual void hide ( + ); + /*! + ensures + - #is_hidden() == true + - if (events_are_enabled() == true) then + - parent_window() is updated to reflect the new state of #*this + !*/ + + drawable_window& parent_window ( + ); + /*! + ensures + - returns a reference to the drawable_window that this drawable is + being drawn on and receiving events from. + !*/ + + const drawable_window& parent_window ( + ) const; + /*! + ensures + - returns a const reference to the drawable_window that this drawable + is being drawn on and receiving events from. + !*/ + + virtual int next_free_user_event_number ( + )const { return 0; } + /*! + ensures + - returns the smallest number, i, that is the next user event number you + can use in calls to parent.trigger_user_event((void*)this,i). + - This function exists because of the following scenario. Suppose + you make a class called derived1 that inherits from drawable and + in derived1 you use a user event to do something. Then suppose + you inherit from derived1 to make derived2. Now in derived2 you + may want to use a user event to do something as well. How are you + to know which user event numbers are in use already? This function + solves that problem. You would define derived1::next_free_user_event_number() + so that it returned a number bigger than any user event numbers used by + derived1 or its ancestors. Then derived2 could just call + derived1::next_free_user_event_number() to find out what numbers it could use. + !*/ + + protected: + /*!A drawable_protected_variables + + These protected members are provided because they are needed to + implement drawable widgets. + !*/ + + // This is the rectangle that is returned by get_rect() + rectangle rect; + + // This is the mutex used to serialize access to this class. + const rmutex& m; + + // This is the parent window of this drawable + drawable_window& parent; + + // This is the bool returned by is_hidden() + bool hidden; + + // This is the bool returned by is_enabled() + bool enabled; + + // This is the font pointer returned by main_font() + const font* mfont; + + // This is the x coordinate that we last saw the mouse at or -1 if the mouse + // is outside the parent window. + const long& lastx; + + // This is the y coordinate that we last saw the mouse at or -1 if the mouse + // is outside the parent window. + const long& lasty; + + + void enable_events ( + ); + /*! + ensures + - #events_are_enabled() == true + !*/ + + void disable_events ( + ); + /*! + ensures + - #events_are_enabled() == false + !*/ + + bool events_are_enabled ( + ) const; + /*! + ensures + - returns true if this object is receiving events and draw() + requests from its parent window. + - returns false otherwise + !*/ + + // ---------------- EVENT HANDLERS ------------------ + + virtual void on_user_event ( + int i + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - is called whenever the parent window receives an on_user_event(p,i) event + where p == this. (i.e. this is just a redirect of on_user_event for + cases where the first argument of on_user_event is equal to the + this pointer). + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_window_resized( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_window_resized() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_window_moved( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_window_moved() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_mouse_down() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_mouse_up() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_mouse_move ( + unsigned long state, + long x, + long y + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - x == lastx + - y == lasty + - this is just the base_window::on_mouse_move() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_mouse_leave ( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_mouse_leave() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_mouse_enter ( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_mouse_enter() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_wheel_up ( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_wheel_up() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_wheel_down ( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_wheel_down() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_focus_gained ( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_focus_gained() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_focus_lost ( + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_focus_lost() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ){} + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - this is just the base_window::on_keydown() event forwarded to + this object. See the gui_core specs for the details about this event. + ensures + - does not change the state of mutex m. + !*/ + + virtual void draw ( + const canvas& c + ) const=0; + /*! + requires + - events_are_enabled() == true + - mutex m is locked + - is_hidden() == false + - is called by parent_window() when it needs to repaint itself. + - c == the canvas object for the area of parent_window() that needs + to be repainted. + ensures + - does not change the state of mutex m. + - draws the area of *this that intersects with the canvas onto + the canvas object c. + !*/ + + private: + + // restricted functions + drawable(drawable&); // copy constructor + drawable& operator=(drawable&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DRAWABLe_ABSTRACT_ + diff --git a/dlib/gui_widgets/fonts.cpp b/dlib/gui_widgets/fonts.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5b818956b251fe721132f076409b139939d2ceee --- /dev/null +++ b/dlib/gui_widgets/fonts.cpp @@ -0,0 +1,665 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_FONTs_CPP_ +#define DLIB_FONTs_CPP_ + +#include "fonts.h" + +#include "../serialize.h" +#include +#include "../base64.h" +#include "../compress_stream.h" +#include +#include "../tokenizer.h" + +namespace dlib +{ + + scoped_ptr default_font::f; + mutex default_font::m; + +// ---------------------------------------------------------------------------------------- + + const std::string get_decoded_string_with_default_font_data() + { + dlib::base64::kernel_1a base64_coder; + dlib::compress_stream::kernel_1ea compressor; + std::ostringstream sout; + std::istringstream sin; + + /* + SOURCE BDF FILE (helvR12.bdf) COMMENTS + COMMENT $XConsortium: helvR12.bdf,v 1.15 95/01/26 18:02:58 gildea Exp $ + COMMENT $Id: helvR12.bdf,v 1.26 2004-11-28 20:08:46+00 mgk25 Rel $ + COMMENT + COMMENT + + COMMENT Copyright 1984-1989, 1994 Adobe Systems Incorporated. + COMMENT Copyright 1988, 1994 Digital Equipment Corporation. + COMMENT + COMMENT Adobe is a trademark of Adobe Systems Incorporated which may be + COMMENT registered in certain jurisdictions. + COMMENT Permission to use these trademarks is hereby granted only in + COMMENT association with the images described in this file. + COMMENT + COMMENT Permission to use, copy, modify, distribute and sell this software + COMMENT and its documentation for any purpose and without fee is hereby + COMMENT granted, provided that the above copyright notices appear in all + COMMENT copies and that both those copyright notices and this permission + COMMENT notice appear in supporting documentation, and that the names of + COMMENT Adobe Systems and Digital Equipment Corporation not be used in + COMMENT advertising or publicity pertaining to distribution of the software + COMMENT without specific, written prior permission. Adobe Systems and + COMMENT Digital Equipment Corporation make no representations about the + COMMENT suitability of this software for any purpose. It is provided "as + COMMENT is" without express or implied warranty. + COMMENT - + */ + + // The base64 encoded data we want to decode and return. + sout << "AXF+zOQzCgGitrKiOCGEL4hlIv1ZenWJyjMQ4rJ6f/oPMeHqsZn+8XnpehwFQTz3dtUGlZRAUoOa"; + sout << "uVo8UiplcFxuK69A+94rpMCMAyEeeOwZ/tRzkX4eKuU3L4xtsJDknMiYUNKaMrYimb1QJ0E+SRqQ"; + sout << "wATrMTecYNZvJJm02WibiwE4cJ5scvkHNl4KJT5QfdwRdGopTyUVdZvRvtbTLLjsJP0fQEQLqemf"; + sout << "qPE4kDD79ehrBIwLO1Y6TzxtrrIoQR57zlwTUyLenqRtSN3VLtjWYd82cehRIlTLtuxBg2s+zZVq"; + sout << "jNlNnYTSM+Swy06qnQgg+Dt0lhtlB9shR1OAlcfCtTW6HKoBk/FGeDmjTGW4bNCGv7RjgM6TlLDg"; + sout << "ZYSSA6ZCCAKBgE++U32gLHCCiVkPTkkp9P6ioR+e3SSKRNm9p5MHf+ZQ3LJkW8KFJ/K9gKT1yvyv"; + sout << "F99pAvOOq16tHRFvzBs+xZj/mUpH0lGIS7kLWr9oP2KuccVrz25aJn3kDruwTYoD+CYlOqtPO0Mv"; + sout << "dEI0LUR0Ykp1M2rWo76fJ/fpzHjV7737hjkNPJ13nO72RMDr4R5V3uG7Dw7Ng+vGX3WgJZ4wh1JX"; + sout << "pl2VMqC5JXccctzvnQvnuvBvRm7THgwQUgMKKT3WK6afUUVlJy8DHKuU4k1ibfVMxAmrwKdTUX2w"; + sout << "cje3A05Qji3aop65qEdwgI5O17HIVoRQOG/na+XRMowOfUvI4H8Z4+JGACfRrQctgYDAM9eJzm8i"; + sout << "PibyutmJfZBGg0a3oC75S5R9lTxEjPocnEyJRYNnmVnVAmKKbTbTsznuaD+D1XhPdr2t3A4bRTsp"; + sout << "toKKtlFnd9YGwLWwONDwLnoQ/IXwyF7txrRHNSVToh772U0Aih/yn5vnmcMF750eiMzRAgXu5sbR"; + sout << "VXEOVCiLgVevN5umkvjZt1eGTSSzDMrIvnv4nyOfaFsD+I76wQfgLqd71rheozGtjNc0AOTx4Ggc"; + sout << "eUSFHTDAVfTExBzckurtyuIAqF986a0JLHCtsDpBa2wWNuiQYOH3/LX1zkdU2hdamhBW774bpEwr"; + sout << "dguMxxOeDGOBgIlM5gxXGYXSf5IN3fUAEPfOPRxB7T+tpjFnWd7cg+JMabci3zhJ9ANaYT7HGeTX"; + sout << "bulKnGHjYrR1BxdK3YeliogQRU4ytmxlyL5zlNFU/759mA8XSfIPMEZn9Vxkb00q1htF7REiDcr3"; + sout << "kW1rtPAc7VQNEhT54vK/YF6rMvjO7kBZ/vLYo7E8e8hDKEnY8ucrC3KGmeo31Gei74BBcEbvJBd3"; + sout << "/YAaIKgXWwU2wSUw9wLq2RwGwyguvKBx0J/gn27tjcVAHorRBwxzPpk8r+YPyN+SifSzEL7LEy1G"; + sout << "lPHxmXTrcqnH9qraeAqXJUJvU8SJJpf/tmsAE+XSKD/kpVBnT5qXsJ1SRFS7MtfPjE1j/NYbaQBI"; + sout << "bOrh81zaYCEJR0IKHWCIsu/MC3zKXfkxFgQ9XpYAuWjSSK64YpgkxSMe8VG8yYvigOw2ODg/z4FU"; + sout << "+HpnEKF/M/mKfLKK1i/8BV7xcYVHrhEww1QznoFklJs/pEg3Kd5PE1lRii6hvTn6McVAkw+YbH9q"; + sout << "/sg4gFIAvai64hMcZ1oIZYppj3ZN6KMdyhK5s4++ZS/YOV2nNhW73ovivyi2Tjg7lxjJJtsYrLKb"; + sout << "zIN1slOICKYwBq42TFBcFXaZ6rf0Czd09tL+q6A1Ztgr3BNuhCenjhWN5ji0LccGYZo6bLTggRG/"; + sout << "Uz6K3CBBU/byLs79c5qCohrr7rlpDSdbuR+aJgNiWoU6T0i2Tvua6h51LcWEHy5P2n146/Ae2di4"; + sout << "eh20WQvclrsgm1oFTGD0Oe85GKOTA7vvwKmLBc1wwA0foTuxzVgj0TMTFBiYLTLG4ujUyBYy1N6e"; + sout << "H8EKi8H+ZAlqezrjABO3BQr33ewdZL5IeJ4w7gdGUDA6+P+7cODcBW50X9++6YTnKctuEw6aXBpy"; + sout << "GgcMfPE61G8YKBbFGFic3TVvGCLvre1iURv+F+hU4/ee6ILuPnpYnSXX2iCIK/kmkBse8805d4Qe"; + sout << "DG/8rBW9ojvAgc0jX7CatPEMHGkcz+KIZoKMI7XXK4PJpGQUdq6EdIhJC4koXEynjwwXMeC+jJqH"; + sout << "agwrlDNssq/8AA=="; + + + + // Put the data into the istream sin + sin.str(sout.str()); + sout.str(""); + + // Decode the base64 text into its compressed binary form + base64_coder.decode(sin,sout); + sin.clear(); + sin.str(sout.str()); + sout.str(""); + + // Decompress the data into its original form + compressor.decompress(sin,sout); + + // Return the decoded and decompressed data + return sout.str(); + } + + + default_font:: + default_font ( + ) + { + using namespace std; + l = new letter[256]; + + try + { + istringstream sin(get_decoded_string_with_default_font_data()); + + for (int i = 0; i < 256; ++i) + { + deserialize(l[i],sin); + } + + } + catch (...) + { + delete [] l; + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const letter& item, + std::ostream& out + ) + { + try + { + serialize(item.w,out); + serialize(item.count,out); + + for (unsigned long i = 0; i < item.count; ++i) + { + serialize(item.points[i].x,out); + serialize(item.points[i].y,out); + } + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type letter"); + } + } + + void deserialize ( + letter& item, + std::istream& in + ) + { + try + { + if (item.points) + delete [] item.points; + + deserialize(item.w,in); + deserialize(item.count,in); + + if (item.count > 0) + item.points = new letter::point[item.count]; + else + item.points = 0; + + for (unsigned long i = 0; i < item.count; ++i) + { + deserialize(item.points[i].x,in); + deserialize(item.points[i].y,in); + } + } + catch (serialization_error e) + { + item.w = 0; + item.count = 0; + item.points = 0; + throw serialization_error(e.info + "\n while deserializing object of type letter"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace bdf_font_helpers + { + class bdf_parser + { + public: + bdf_parser( std::istream& in ) : in_( in ) + { + std::string str_tmp; + int int_tmp; + + str_tmp = "STARTFONT"; int_tmp = STARTFONT; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "FONTBOUNDINGBOX";int_tmp = FONTBOUNDINGBOX; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "DWIDTH"; int_tmp = DWIDTH; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "CHARS"; int_tmp = CHARS; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "STARTCHAR"; int_tmp = STARTCHAR; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "ENCODING"; int_tmp = ENCODING; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "BBX"; int_tmp = BBX; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "BITMAP"; int_tmp = BITMAP; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "ENDCHAR"; int_tmp = ENDCHAR; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "ENDFONT"; int_tmp = ENDFONT; keyword_map.add( str_tmp, int_tmp ); + str_tmp = "DEFAULT_CHAR"; int_tmp = DEFAULT_CHAR; keyword_map.add( str_tmp, int_tmp ); + + tokzr.set_identifier_token( tokzr.uppercase_letters(), tokzr.uppercase_letters() + "_" ); + tokzr.set_stream( in ); + + } + + enum bdf_enums + { + NO_KEYWORD = 0, + STARTFONT = 1, + FONTBOUNDINGBOX = 2, + DWIDTH = 4, + DEFAULT_CHAR = 8, + CHARS = 16, + STARTCHAR = 32, + ENCODING = 64, + BBX = 128, + BITMAP = 256, + ENDCHAR = 512, + ENDFONT = 1024 + + }; + struct header_info + { + int FBBx, FBBy, Xoff, Yoff; + int dwx0, dwy0; + bool has_global_dw; + long default_char; + }; + struct char_info + { + int dwx0, dwy0; + int BBw, BBh, BBxoff0x, BByoff0y; + array2d::kernel_1a bitmap; + bool has_dw; + }; + bool parse_header( header_info& info ) + { + if ( required_keyword( STARTFONT ) == false ) + return false; // parse_error: required keyword missing + info.has_global_dw = false; + int find = FONTBOUNDINGBOX | DWIDTH | DEFAULT_CHAR; + int stop = CHARS | STARTCHAR | ENCODING | BBX | BITMAP | ENDCHAR | ENDFONT; + int res; + while ( 1 ) + { + res = find_keywords( find | stop ); + if ( res & FONTBOUNDINGBOX ) + { + in_ >> info.FBBx >> info.FBBy >> info.Xoff >> info.Yoff; + if ( in_.fail() ) + return false; // parse_error + find &= ~FONTBOUNDINGBOX; + continue; + } + if ( res & DWIDTH ) + { + in_ >> info.dwx0 >> info.dwy0; + if ( in_.fail() ) + return false; // parse_error + find &= ~DWIDTH; + info.has_global_dw = true; + continue; + } + if ( res & DEFAULT_CHAR ) + { + in_ >> info.default_char; + if ( in_.fail() ) + return false; // parse_error + find &= ~DEFAULT_CHAR; + continue; + } + if ( res & NO_KEYWORD ) + return false; // parse_error: unexpected EOF + break; + } + if ( res != CHARS || ( find & FONTBOUNDINGBOX ) ) + return false; // parse_error: required keyword missing or unexpeced keyword + return true; + } + int parse_glyph( char_info& info, unichar& enc ) + { + info.has_dw = false; + int e; + int res; + while ( 1 ) + { + res = find_keywords( ENCODING ); + if ( res != ENCODING ) + return 0; // no more glyphs + in_ >> e; + if ( in_.fail() ) + return -1; // parse_error + if ( e >= static_cast(enc) ) + break; + } + int find = BBX | DWIDTH; + int stop = STARTCHAR | ENCODING | BITMAP | ENDCHAR | ENDFONT; + while ( 1 ) + { + res = find_keywords( find | stop ); + if ( res & BBX ) + { + in_ >> info.BBw >> info.BBh >> info.BBxoff0x >> info.BByoff0y; + if ( in_.fail() ) + return -1; // parse_error + find &= ~BBX; + continue; + } + if ( res & DWIDTH ) + { + in_ >> info.dwx0 >> info.dwy0; + if ( in_.fail() ) + return -1; // parse_error + find &= ~DWIDTH; + info.has_dw = true; + continue; + } + if ( res & NO_KEYWORD ) + return -1; // parse_error: unexpected EOF + break; + } + if ( res != BITMAP || ( find != NO_KEYWORD ) ) + return -1; // parse_error: required keyword missing or unexpeced keyword + unsigned h = info.BBh; + unsigned w = ( info.BBw + 7 ) / 8 * 2; + info.bitmap.set_size( h, w ); + for ( unsigned r = 0;r < h;r++ ) + { + trim(); + std::string str = ""; + extract_hex(str); + if(str.size() < w) + return -1; // parse_error + for ( unsigned c = 0;c < w;c++ ) + info.bitmap[r][c] = str[c]; + } + if ( in_.fail() ) + return -1; // parse_error + if ( required_keyword( ENDCHAR ) == false ) + return -1; // parse_error: required keyword missing + enc = e; + return 1; + } + private: + map::kernel_1a_c keyword_map; + tokenizer::kernel_1a_c tokzr; + std::istream& in_; + void extract_hex(std::string& str) + { + int type; + std::string token; + while ( 1 ) + { + type = tokzr.peek_type(); + if ( type == tokenizer::kernel_1a_c::IDENTIFIER || type == tokenizer::kernel_1a_c::NUMBER ) + { + tokzr.get_token( type, token ); + str += token; + continue; + } + break; + } + } + void trim() + { + int type; + std::string token; + while ( 1 ) + { + type = tokzr.peek_type(); + if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE ) + { + tokzr.get_token( type, token ); + continue; + } + break; + } + } + bool required_keyword( int kw ) + { + int type; + std::string token; + while ( 1 ) + { + tokzr.get_token( type, token ); + if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE ) + continue; + if ( type != tokenizer::kernel_1a_c::IDENTIFIER || keyword_map.is_in_domain( token ) == false || ( keyword_map[token] & kw ) == 0 ) + return false; + break; + } + return true; + } + int find_keywords( int find ) + { + int type; + std::string token; + while ( 1 ) + { + tokzr.get_token( type, token ); + if ( type == tokenizer::kernel_1a_c::END_OF_FILE ) + return NO_KEYWORD; + if ( type == tokenizer::kernel_1a_c::IDENTIFIER && keyword_map.is_in_domain( token ) == true ) + { + int kw = keyword_map[token]; + if ( kw & find ) + return kw; + } + } + return true; + } + + }; + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// bdf_font functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + bdf_font::bdf_font( + long default_char_ + ) : + default_char(0), + is_initialized( false ), + right_overflow_( 0 ), + has_global_width( false ), + specified_default_char( default_char_ ) + { + // make sure gl contains at least one letter + gl.expand(1); + } + +// ---------------------------------------------------------------------------------------- + + void bdf_font::adjust_metrics( + ) + { + if ( is_initialized == false ) + return; + // set starting values for fbb + if ( gl[default_char].num_of_points() > 0 ) + { + letter& g = gl[default_char]; + fbb.set_top( g[0].y ); + fbb.set_bottom( g[0].y ); + fbb.set_left( g[0].x ); + fbb.set_right( g[0].x ); + } + else + { + // ok, the default char was a space + // let's just choose some safe arbitrary values then... + fbb.set_top( 10000 ); + fbb.set_bottom( -10000 ); + fbb.set_left( 10000 ); + fbb.set_right( -10000 ); + } + right_overflow_ = 0; + for ( unichar n = 0; n < gl.size(); n++ ) + { + letter& g = gl[n]; + unsigned short nr_pts = g.num_of_points(); + for ( unsigned short k = 0;k < nr_pts;k++ ) + { + fbb.set_top( std::min( fbb.top(), (long)g[k].y ) ); + fbb.set_left( std::min( fbb.left(), (long)g[k].x ) ); + fbb.set_bottom( std::max( fbb.bottom(), (long)g[k].y ) ); + fbb.set_right( std::max( fbb.right(), (long)g[k].x ) ); + right_overflow_ = std::max( right_overflow_, (unsigned long)(g[k].x - g.width()) ); // superfluous? + } + } + } + +// ---------------------------------------------------------------------------------------- + + long bdf_font:: + read_bdf_file( + std::istream& in, + unichar max_enc, + unichar min_enc + ) + { + using namespace bdf_font_helpers; + + bdf_parser parser( in ); + bdf_parser::header_info hinfo; + bdf_parser::char_info cinfo; + + gl.expand(max_enc+1); + hinfo.default_char = - 1; + if ( is_initialized == false || static_cast(in.tellg()) == std::ios::beg ) + { + if ( parser.parse_header( hinfo ) == false ) + return 0; // parse_error: invalid or missing header + } + else + { + // not start of file, so use values from previous read. + hinfo.has_global_dw = has_global_width; + hinfo.dwx0 = global_width; + } + int res; + unichar nr_letters_added = 0; + unsigned width; + for ( unichar n = min_enc; n <= max_enc; n++ ) + { + if ( in.eof() ) + break; + long pos = in.tellg(); + res = parser.parse_glyph( cinfo, n ); + if ( res < 0 ) + return 0; // parse_error + if ( res == 0 ) + continue; + if ( n > max_enc ) + { + in.seekg( pos ); + break; + } + + if ( cinfo.has_dw == false ) + { + if ( hinfo.has_global_dw == false ) + return 0; // neither width info for the glyph, nor for the font as a whole (monospace). + width = hinfo.dwx0; + } + else + width = cinfo.dwx0; + + + if ( bitmap_to_letter( cinfo.bitmap, n, width, cinfo.BBxoff0x, cinfo.BByoff0y ) == false ) + return 0; + nr_letters_added++; + + if ( is_initialized == false ) + { + // Bonding rectangle for the font. + fbb.set_top( -( hinfo.Yoff + hinfo.FBBy - 1 ) ); + fbb.set_bottom( -hinfo.Yoff ); + fbb.set_left( hinfo.Xoff ); + fbb.set_right( hinfo.Xoff + hinfo.FBBx - 1 ); + // We need to compute this after all the glyphs are loaded. + right_overflow_ = 0; + // set this to something valid now, just in case. + default_char = n; + // Save any global width in case we later read from the same file. + has_global_width = hinfo.has_global_dw; + if ( has_global_width ) + global_width = hinfo.dwx0; + // dont override value specified in the constructor with value specified in the file + if ( specified_default_char < 0 && hinfo.default_char >= 0 ) + specified_default_char = hinfo.default_char; + + is_initialized = true; + } + } + if ( is_initialized == false ) + return 0; // Not a single glyph was found within the specified range. + + if ( specified_default_char >= 0 ) + default_char = specified_default_char; + // no default char specified, try find something sane. + else + default_char = 0; + + return nr_letters_added; + } + +// ---------------------------------------------------------------------------------------- + + bool bdf_font:: + bitmap_to_letter( + array2d::kernel_1a& bitmap, + unichar enc, + unsigned long width, + int x_offset, + int y_offset + ) + { + unsigned nr_points = 0; + bitmap.reset(); + while ( bitmap.move_next() ) + { + unsigned char ch = bitmap.element(); + if ( ch > '9' ) + ch -= 'A' - '9' - 1; + ch -= '0'; + if ( ch > 0xF ) + return false; // parse error: invalid hex digit + bitmap.element() = ch; + if ( ch & 8 ) + nr_points++; + if ( ch & 4 ) + nr_points++; + if ( ch & 2 ) + nr_points++; + if ( ch & 1 ) + nr_points++; + } + + letter( width, nr_points ).swap(gl[enc]); + + unsigned index = 0; + for ( int r = 0;r < bitmap.nr();r++ ) + { + for ( int c = 0;c < bitmap.nc();c++ ) + { + int x = x_offset + c * 4; + int y = -( y_offset + bitmap.nr() - r - 1 ); + char ch = bitmap[r][c]; + letter& glyph = gl[enc]; + if ( ch & 8 ) + { + glyph[index] = letter::point( x, y ); + right_overflow_ = std::max( right_overflow_, x - width ); + index++; + } + if ( ch & 4 ) + { + glyph[index] = letter::point( x + 1, y ); + right_overflow_ = std::max( right_overflow_, x + 1 - width ); + index++; + } + if ( ch & 2 ) + { + glyph[index] = letter::point( x + 2, y ); + right_overflow_ = std::max( right_overflow_, x + 2 - width ); + index++; + } + if ( ch & 1 ) + { + glyph[index] = letter::point( x + 3, y ); + right_overflow_ = std::max( right_overflow_, x + 3 - width ); + index++; + } + } + } + return true; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_FONTs_CPP_ + diff --git a/dlib/gui_widgets/fonts.h b/dlib/gui_widgets/fonts.h new file mode 100644 index 0000000000000000000000000000000000000000..9c60bc37e6227a08f1843db5e078890e4e51d4fe --- /dev/null +++ b/dlib/gui_widgets/fonts.h @@ -0,0 +1,616 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_FONTs_ +#define DLIB_FONTs_ + +#include "fonts_abstract.h" +#include "../gui_core.h" +#include +#include "../algs.h" +#include "../serialize.h" +#include "../unicode.h" +#include "../array.h" +#include "../array2d.h" +#include "../threads.h" +#include "../smart_pointers.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class letter + { + /*! + INITIAL VALUE + - defined by constructor + + CONVENTION + - if (points != 0) then + - points == an array of count point structs + - w == width() + - count == num_of_points() + !*/ + public: + struct point + { + point (){} + + point ( + signed char x_, + signed char y_ + ) : + x(x_), + y(y_) + {} + + signed char x; + signed char y; + }; + + letter ( + ) : + points(0), + w(0), + count(0) + {} + + letter ( + unsigned short width_, + unsigned short point_count + ) : + points(new point[point_count]), + w(width_), + count(point_count) + {} + + ~letter( + ) + { + if (points) + delete [] points; + } + + const unsigned short width ( + ) const { return w; } + + const unsigned short num_of_points ( + ) const { return count;} + + point& operator[] ( + unsigned short i + ) + { + DLIB_ASSERT (i < num_of_points(), + "\tvoid letter::operator[]()" + << "\n\ti: " << i + << "\n\tnum_of_points(): " << num_of_points() ); + return points[i]; + } + + const point& operator[] ( + unsigned short i + ) const + { + DLIB_ASSERT (i < num_of_points(), + "\tvoid letter::operator[]()" + << "\n\ti: " << i + << "\n\tnum_of_points(): " << num_of_points() ); + return points[i]; + } + + friend void serialize ( + const letter& item, + std::ostream& out + ); + + friend void deserialize ( + letter& item, + std::istream& in + ); + + void swap ( + letter& item + ) + { + exchange(points, item.points); + exchange(w, item.w); + exchange(count, item.count); + } + + private: + point* points; + unsigned short w; + unsigned short count; + }; + + inline void swap ( + letter& a, + letter& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + class font + { + public: + virtual ~font() {} + + virtual bool has_character ( + unichar ch + )const=0; + bool has_character(char ch) const { return this->has_character(zero_extend_cast(ch)); } + bool has_character(wchar_t ch) const { return this->has_character(zero_extend_cast(ch)); } + + const letter& operator[] (char ch) const { return (*this)[zero_extend_cast(ch)]; }; + const letter& operator[] (wchar_t ch)const { return (*this)[zero_extend_cast(ch)]; }; + + virtual const letter& operator[] ( + unichar ch + )const=0; + + virtual const unsigned long height ( + ) const = 0; + + virtual const unsigned long ascender ( + ) const = 0; + + virtual const unsigned long left_overflow ( + ) const = 0; + + virtual const unsigned long right_overflow ( + ) const = 0; + + // ------------------------------------------------------------------------------------ + + template + void compute_size ( + const std::basic_string& str, + unsigned long& width, + unsigned long& height, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = (std::basic_string::npos) + ) const + { + typedef std::basic_string string; + DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size()) , + "\tvoid font::compute_size()" + << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false") + << "\n\tfirst: " << (unsigned long)first + << "\n\tlast: " << (unsigned long)last + << "\n\tstr.size(): " << (unsigned long)str.size() ); + + unsigned long line_width = 0; + unsigned long newlines = 0; + width = 0; + height = 0; + + if (str.size()) + { + if (last == string::npos) + last = str.size()-1; + const font& f = *this; + + for (typename string::size_type i = first; i <= last; ++i) + { + // ignore '\r' characters + if (str[i] == '\r') + continue; + + if (str[i] == '\n') + { + ++newlines; + width = std::max(width,line_width); + line_width = 0; + } + else + { + if (is_combining_char(str[i]) == false) + line_width += f[str[i]].width(); + } + } + width = std::max(width,line_width); + + height = (newlines+1)*f.height(); + width += f.left_overflow() + f.right_overflow(); + } + } + + // ------------------------------------------------------------------------------------ + + template + const void draw_string ( + const canvas& c, + const rectangle& rect, + const std::basic_string& str, + const pixel_type& color, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = (std::basic_string::npos), + const rectangle& area_ = rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max()) + ) const + { + typedef std::basic_string string; + DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size()) , + "\tvoid font::draw_string()" + << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false") + << "\n\tfirst: " << (unsigned long)first + << "\n\tlast: " << (unsigned long)last + << "\n\tstr.size(): " << (unsigned long)str.size() ); + + rectangle area = rect.intersect(c).intersect(area_); + if (area.is_empty() || str.size() == 0) + return; + + if (last == string::npos) + last = str.size()-1; + + const font& f = *this; + + long y_offset = rect.top() + f.ascender() - 1; + + long pos = rect.left()+f.left_overflow(); + for (typename string::size_type i = first; i <= last; ++i) + { + // ignore the '\r' character + if (str[i] == '\r') + continue; + + // A combining character should be applied to the previous character, and we + // therefore make one step back. If a combining comes right after a newline, + // then there must be some kind of error in the string, and we don't combine. + if(is_combining_char(str[i]) && + pos > rect.left() + static_cast(f.left_overflow())) + { + pos -= f[str[i]].width(); + } + + if (str[i] == '\n') + { + y_offset += f.height(); + pos = rect.left()+f.left_overflow(); + continue; + } + + // only look at letters in the intersection area + if (area.bottom() + static_cast(f.height()) < y_offset) + { + // the string is now below our rectangle so we are done + break; + } + else if (area.left() > pos - static_cast(f.left_overflow()) && + pos + static_cast(f[str[i]].width() + f.right_overflow()) < area.left() ) + { + pos += f[str[i]].width(); + continue; + } + else if (area.right() + static_cast(f.right_overflow()) < pos) + { + // keep looking because there might be a '\n' in the string that + // will wrap us around and put us back into our rectangle. + continue; + } + + // at this point in the loop we know that f[str[i]] overlaps + // horizontally with the intersection rectangle area. + + const letter& l = f[str[i]]; + for (unsigned short i = 0; i < l.num_of_points(); ++i) + { + const long x = l[i].x + pos; + const long y = l[i].y + y_offset; + // draw each pixel of the letter if it is inside the intersection + // rectangle + if (area.contains(x,y)) + { + assign_pixel(c[y-c.top()][x-c.left()], color); + } + } + + pos += l.width(); + } + } + template + const void draw_string ( + const canvas& c, + const rectangle& rect, + const std::basic_string& str + ) const + { + draw_string(c,rect, str, 0, 0, (std::basic_string::npos), + rectangle(std::numeric_limits::min(), std::numeric_limits::min(), + std::numeric_limits::max(), std::numeric_limits::max())); + } + + // ------------------------------------------------------------------------------------ + + template + const rectangle compute_cursor_rect ( + const rectangle& rect, + const std::basic_string& str, + unsigned long index, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = (std::basic_string::npos) + ) const + { + typedef std::basic_string string; + DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size()) , + "\trectangle font::compute_cursor_rect()" + << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false") + << "\n\tfirst: " << (unsigned long)first + << "\n\tlast: " << (unsigned long)last + << "\n\tindex: " << index + << "\n\tstr.size(): " << (unsigned long)str.size() ); + + const font& f = *this; + + if (last == string::npos) + last = str.size()-1; + + long x = f.left_overflow(); + long y = 0; + int count = 0; + + if (str.size() != 0) + { + for (typename string::size_type i = first; i <= last && i < index; ++i) + { + ++count; + if (str[i] == '\n') + { + x = f.left_overflow(); + y += f.height(); + count = 0; + } + else if (is_combining_char(str[i]) == false && + str[i] != '\r') + { + x += f[str[i]].width(); + } + } + } + + x += rect.left(); + y += rect.top(); + + // if the cursor is at the start of a line then back it up one pixel + if (count == 0) + --x; + + return rectangle(x,y,x,y+f.height()-1); + } + + // ------------------------------------------------------------------------------------ + + template + const unsigned long compute_cursor_pos ( + const rectangle& rect, + const std::basic_string& str, + long x, + long y, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = (std::basic_string::npos) + ) const + { + typedef std::basic_string string; + DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size()) , + "\tunsigned long font::compute_cursor_pos()" + << "\n\tlast == string::npos: " << ((last == string::npos)?"true":"false") + << "\n\tfirst: " << (unsigned long)first + << "\n\tlast: " << (unsigned long)last + << "\n\tx: " << x + << "\n\ty: " << y + << "\n\tstr.size(): " << (unsigned long)str.size() ); + const font& f = *this; + + + if (str.size() == 0) + return 0; + else if (first >= str.size()) + return static_cast(str.size()); + + y -= rect.top(); + x -= rect.left(); + if (y < 0) + y = 0; + if (x < 0) + x = 0; + + if (last == string::npos) + last = str.size()-1; + + + // first figure out what line we are on + typename string::size_type pos = first; + long line = 0; + while (static_cast(y) >= f.height()) + { + ++line; + y -= f.height(); + } + + // find the start of the given line + typename string::size_type last_pos = pos; + for (typename string::size_type i = first; i <= last && line != 0; ++i) + { + if (str[i] == '\n') + { + --line; + pos += (i - last_pos); + last_pos = pos; + } + } + + // now str[pos] == the first character of the start of the line + // that contains the cursor. + + + long cur_x = f.left_overflow(); + // set the current cursor position to where the mouse clicked + while (pos <= last) + { + if (x <= cur_x) + break; + + if (is_combining_char(str[pos]) == false && + str[pos] != '\r') + { + cur_x += f[str[pos]].width(); + } + ++pos; + } + + if (x <= cur_x) + { + if (pos != first) + { + const long width = f[str[pos-1]].width(); + if (x < cur_x - width/2) + --pos; + } + } + return static_cast(pos); + } + + }; + +// ---------------------------------------------------------------------------------------- + + class default_font : public font + { + letter* l; + + + default_font( + ); + default_font(default_font&); // copy constructor + default_font& operator=(default_font&); // assignment operator + + static scoped_ptr f; + static mutex m; + + public: + static const font* get_font ( + ) + { + auto_mutex M(m); + if (f.get() == 0) + f.reset(new default_font); + + return f.get(); + } + + ~default_font( + ) + { + delete [] l; + } + + const unsigned long height ( + ) const { return 16; } + + const unsigned long ascender ( + ) const { return 12; } + + const unsigned long left_overflow ( + ) const { return 1; } + + const unsigned long right_overflow ( + ) const { return 2; } + + bool has_character ( + unichar ch + )const + { + if (ch < 256 && (l[ch].width() != 0 || l[ch].num_of_points() != 0)) + return true; + else + return false; + } + + const letter& operator[] ( + unichar ch + ) const + { + if(ch < 256) + return l[ch]; + return l[0]; // just return one of the empty characters in this case + } + }; + + +// ---------------------------------------------------------------------------------------- + + class bdf_font : public font + { + + public: + bdf_font( long default_char_ = -1 ); + + long read_bdf_file( std::istream& in, unichar max_enc, unichar min_enc = 0 ); + const unsigned long height() const + { + return fbb.height(); + } + const unsigned long ascender() const + { + return std::max( 0L, 1 - fbb.top() ); + } + const unsigned long left_overflow() const + { + return std::max( 0L, -fbb.left() ); + } + const unsigned long right_overflow() const + { + return right_overflow_; + } + const letter& operator[] ( unichar uch ) const + { + if ( !has_character(uch) ) + { + return gl[default_char]; + } + return gl[uch]; + } + + bool has_character ( + unichar ch + )const + { + if (ch < gl.size() && (gl[ch].width() != 0 || gl[ch].num_of_points() != 0)) + return true; + else + return false; + } + + void adjust_metrics(); + private: + + bool bitmap_to_letter( array2d::kernel_1a& bitmap, unichar enc, unsigned long width, int x_offset, int y_offset ); + + array::expand_1b_c gl; + unichar default_char; // if (is_intialized == true), then this MUST be an actual glyph + bool is_initialized; + rectangle fbb; + unsigned long right_overflow_; + + unsigned global_width; + bool has_global_width; + long specified_default_char; + + bdf_font( bdf_font& ); // copy constructor + bdf_font& operator=( bdf_font& ); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "fonts.cpp" +#endif + +#endif // DLIB_FONTs_ + diff --git a/dlib/gui_widgets/fonts_abstract.h b/dlib/gui_widgets/fonts_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..58f3de938f668b3539550aadb890b84ade3da254 --- /dev/null +++ b/dlib/gui_widgets/fonts_abstract.h @@ -0,0 +1,486 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. + +#undef DLIB_FONTs_ABSTRACT_ +#ifdef DLIB_FONTs_ABSTRACT_ + +#include "../gui_core.h" +#include +#include "../serialize.h" +#include "../unicode.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class letter + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a letter in a font. It tells you the nominal + width of the letter and which pixels form the letter. + + THREAD SAFETY + const versions of this object are thread safe but if you are going to + be modifying it then you must serialize access to it. + !*/ + public: + struct point + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents one of the pixels of a letter. + + The origin (i.e. (0,0)) of the coordinate plane is at the left + side of the letter's baseline. Also note that y is negative when + above the baseline and positive below (it is zero on the baseline + itself). + + The x value is positive going to the right and negative to the left. + The meaning of a negative x value is that any points with a negative + x value will overlap with the preceding letter. + !*/ + + point ( + ); + /*! + ensures + - This constructor does nothing. The value of x and y + are undefined after its execution. + !*/ + + point ( + signed char x_, + signed char y_ + ); + /*! + ensures + - #x == x_ + - #y == y_ + !*/ + + + signed char x; + signed char y; + }; + + // --------------------------------- + + letter ( + ); + /*! + ensures + - #width() == 0 + - #num_of_points() == 0 + !*/ + + letter ( + unsigned short width_, + unsigned short point_count + ); + /*! + ensures + - #width() == width_ + - #num_of_points() == point_count + !*/ + + ~letter( + ); + /*! + ensures + - any resources used by *this have been freed + !*/ + + const unsigned short width ( + ) const; + /*! + ensures + - returns the width reserved for this letter in pixels. This is the + number of pixels that are reserved for this letter between adjoining + letters. It isn't necessarily the width of the actual letter itself. + (for example, you can make a letter with a width less than how wide it + actually is so that it overlaps with its neighbor letters.) + !*/ + + const unsigned short num_of_points ( + ) const; + /*! + ensures + - returns the number of pixels that make up this letter. + !*/ + + point& operator[] ( + unsigned short i + ); + /*! + requires + - i < num_of_points() + ensures + - returns a non-const reference to the ith point in this letter. + !*/ + + const point& operator[] ( + unsigned short i + ) const; + /*! + requires + - i < num_of_points() + ensures + - returns a const reference to the ith point in this letter. + !*/ + + void swap ( + letter& item + ); + /*! + ensures + - swaps *this with item + !*/ + + private: + + // restricted functions + letter(letter&); // copy constructor + letter& operator=(letter&); // assignment operator + }; + + inline void swap ( + letter& a, + letter& b + ) { a.swap(b); } + /*! + provides a global swap + !*/ + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const letter& item, + std::ostream& out + ); + /*! + provides serialization support for letter objects + !*/ + + void deserialize ( + letter& item, + std::istream& in + ); + /*! + provides deserialization support for letter objects + !*/ + +// ---------------------------------------------------------------------------------------- + + class font + { + /*! + WHAT THIS OBJECT REPRESENTS + This object defines an interface for a font type. It provides metrics + for the font and functions to help you draw strings on a canvas object. + + THREAD SAFETY + All the functions in this class are thread safe. + !*/ + + public: + + virtual bool has_character ( + unichar ch + )const=0; + /*! + ensures + - if (this font has a glyph for the given character) then + - returns true + - else + - returns false + !*/ + bool has_character(char ch) const { return this->has_character(zero_extend_cast(ch)); } + bool has_character(wchar_t ch) const { return this->has_character(zero_extend_cast(ch)); } + /* Cast char and wchar_t to unichar correctly when char or wchar_t is a signed type */ + + virtual const letter& operator[] ( + unichar ch + )const=0; + /*! + ensures + - if (has_character(ch) == true) then + - returns a letter object that tells you how to draw this character. + - else + - returns some default glyph for characters that aren't in this font. + !*/ + const letter& operator[] (char ch) const { return (*this)[zero_extend_cast(ch)]; }; + const letter& operator[] (wchar_t ch) const { return (*this)[zero_extend_cast(ch)]; }; + /* Cast char and wchar_t to unichar correctly when char or wchar_t is a signed type */ + + virtual const unsigned long height ( + ) const = 0; + /*! + ensures + - returns the height in pixels of the tallest letter in the font + !*/ + + virtual const unsigned long ascender ( + ) const = 0; + /*! + ensures + - returns the height() minus the number of pixels below the baseline used + by the letter that hangs the lowest below the baseline. + !*/ + + virtual const unsigned long left_overflow ( + ) const = 0; + /*! + ensures + - returns how far outside and to the left of its width a letter + from this font may set pixels. (i.e. how many extra pixels to its + left may a font use) + !*/ + + virtual const unsigned long right_overflow ( + ) const = 0; + /*! + ensures + - returns how far outside and to the right of its width a letter + from this font may set pixels. (i.e. how many extra pixels to its + right may a font use) + !*/ + + template + void compute_size ( + const std::basic_string& str, + unsigned long& width, + unsigned long& height, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = std::basic_string::npos + ) const; + /*! + requires + - if (last != std::basic_string::npos) then + - first <= last + - last < str.size() + ensures + - all characters in str with an index < first are ignored by this + function. + - if (last != std::basic_string::npos) then + - all characters in str with an index > last are ignored by + this function. + - if (str.size() == 0) then + - #width == 0 + - #height == 0 + - else + - #width == sum of the widths of the characters in the widest + line in str + left_overflow() + right_overflow(). + - #height == (count(str.begin(),str.end(),'\n')+1)*height() + !*/ + + template + const void draw_string ( + const canvas& c, + const rectangle& rect, + const std::basic_string& str, + const pixel_type& color = rgb_pixel(0,0,0), + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = std::basic_string::npos, + const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity) + ) const; + /*! + requires + - if (last != std::basic_string::npos) then + - first <= last + - last < str.size() + ensures + - all characters in str with an index < first are ignored by this + function. + - if (last != std::basic_string::npos) then + - all characters in str with an index > last are ignored by + this function. + - if (str.size() == 0) then + - does nothing + - else + - draws str on the given canvas at the position defined by rect. + Also uses the given pixel colors for the font color. + - If the string is too big to fit in rect then the right and + bottom sides of it will be clipped to make it fit. + - only the part of the string that is contained inside the area + rectangle will be drawn + !*/ + + template + const rectangle compute_cursor_rect ( + const rectangle& rect, + const std::basic_string& str, + unsigned long index, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = std::basic_string::npos + ) const; + /*! + requires + - if (last != std::basic_string::npos) then + - first <= last + - last < str.size() + ensures + - the returned rectangle has a width of 1 and a + height of this->height(). + - computes the location of the cursor that would sit just before + the character str[index] if str were drawn on the screen by + draw_string(rect,str,...,first,last). The cursor location is + returned in the form of a rectangle. + - if (index < first) then + - the returned cursor will be just before the character str[first]. + - if (last != std::basic_string::npos && index > last) then + - the returned cursor will be just after the character str[last] + - if (str.size() == 0) then + - the returned cursor will be just at the start of the rectangle where + str would be drawn if it wasn't empty. + - if (index > str.size()-1) then + - the returned cursor will be just after the character str[str.size()-1] + !*/ + + template + const unsigned long compute_cursor_pos ( + const rectangle& rect, + const std::basic_string& str, + long x, + long y, + typename std::basic_string::size_type first = 0, + typename std::basic_string::size_type last = std::basic_string::npos + ) const; + /*! + requires + - if (last != std::basic_string::npos) then + - first <= last + - last < str.size() + ensures + - returns a number idx that has the following properties: + - if (first < str.size()) then + - first <= idx + - else + - idx == str.size() + - if (last != std::basic_string::npos) then + - idx <= last + 1 + - compute_cursor_rect(rect,str,idx,first,last) == the cursor + position that is closest to the pixel (x,y) + !*/ + + + private: + + // restricted functions + font(font&); // copy constructor + font& operator=(font&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + class default_font : public font + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an implementation of the Times New Roman font. + + THREAD SAFETY + It is safe to call get_font() and access the returned font from any + thread and no synchronization is needed as long as it is called + after the main() function has been entered. + !*/ + + public: + static const font* get_font( + ); + /*! + ensures + - returns an instance of this font. + (Note that you do not need to and should NOT call delete on the + returned pointer) + throws + - std::bad_alloc + This exception is thrown if there is a problem gathering the needed + memory for the font object. + !*/ + + private: + + // restricted functions + default_font(); // normal constructor + default_font(default_font&); // copy constructor + default_font& operator=(default_font&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + class bdf_font : public font + { + + /*! + WHAT THIS OBJECT REPRESENTS + This is a font object that is capable of loading of loading BDF (Glyph + Bitmap Distribution Format) font files. + + THREAD SAFETY + If you only access this object via the functions in the parent class font + then this object is thread safe. But if you need to call any of the + functions introduced in this derived class then you need to serialize + access to this object while you call these functions. + !*/ + + public: + + bdf_font( + long default_char = -1 + ); + /*! + ensures + - for all x: + - #has_character(x) == false + (i.e. this font starts out empty. You have to call read_bdf_file() + to load it with data) + - if (default_char == -1) then + - the letter returned by (*this)[ch] for values of + ch where has_character(ch) == false will be the + default glyph defined in the bdf file. + - else + - the letter returned by (*this)[ch] for values of + ch where has_character(ch) == false will be the + letter (*this)[default_char]. + !*/ + + long read_bdf_file( + std::istream& in, + unichar max_enc, + unichar min_enc = 0 + ); + /*! + ensures + - attempts to read the font data from the given input stream into + *this. The input stream is expected to contain a valid BDF file. + - reads in characters with encodings in the range min_enc to max_enc + into this font. All characters in the font file outside this range + are ignored. + - returns the number of characters loaded into this font from the + given input stream. + !*/ + + void adjust_metrics(); + /*! + ensures + - Computes metrics based on actual glyphs loaded, instead of using + the values in the bdf file header. (May be useful if loading glyphs + from more than one file or a small part of a file.) + !*/ + + private: + + bdf_font( bdf_font& ); // copy constructor + bdf_font& operator=( bdf_font& ); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_FONTs_ABSTRACT_ + diff --git a/dlib/gui_widgets/style.cpp b/dlib/gui_widgets/style.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03bb5c8c0919c1b3e340970582e394bac4b23ab6 --- /dev/null +++ b/dlib/gui_widgets/style.cpp @@ -0,0 +1,589 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_WIDGETs_STYLE_CPP_ +#define DLIB_WIDGETs_STYLE_CPP_ + +#include "style.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // button style stuff +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void button_style_default::draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + fill_rect(c,rect,rgb_pixel(212,208,200)); + + unsigned char red, green, blue; + if (enabled) + { + red = 0; + green = 0; + blue = 0; + } + else + { + red = 128; + green = 128; + blue = 128; + } + + // compute the name length if it hasn't already been computed + if (name_width == 0) + { + unsigned long height; + mfont.compute_size(name,name_width,height); + } + + // figure out where the name string should appear + rectangle name_rect; + const unsigned long width = name_width; + const unsigned long height = mfont.height(); + name_rect.set_left((rect.right() + rect.left() - width)/2); + name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1); + name_rect.set_right(name_rect.left()+width-1); + name_rect.set_bottom(name_rect.top()+height); + + + if (is_depressed) + { + name_rect.set_left(name_rect.left()+1); + name_rect.set_right(name_rect.right()+1); + name_rect.set_top(name_rect.top()+1); + name_rect.set_bottom(name_rect.bottom()+1); + + mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); + + draw_button_down(c,rect); + } + else + { + mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); + + // now draw the edge of the button + draw_button_up(c,rect); + } + } + +// ---------------------------------------------------------------------------------------- + + rectangle button_style_default:: + get_min_size ( + const std::string& name, + const font& mfont + ) const + { + + unsigned long width; + unsigned long height; + mfont.compute_size(name,width,height); + name_width = width; + + return rectangle(width+2*padding, height+2*padding); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void button_style_toolbar1::draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + const long radius = 7; + + unsigned char red, green, blue; + if (enabled) + { + red = 0; + green = 0; + blue = 0; + + long d = 0; + if (rect.contains(lastx,lasty)) + d = -40; + + if (is_depressed) + d = 50; + + fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(180-d,180-d,200-d,150), + rgb_alpha_pixel(130-d,130-d,150-d,100)); + draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(80,80,100,190)); + } + else + { + red = 128; + green = 128; + blue = 128; + draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(red,green,blue,210)); + } + + + // compute the name length if it hasn't already been computed + if (name_width == 0) + { + unsigned long height; + mfont.compute_size(name,name_width,height); + } + + // figure out where the name string should appear + rectangle name_rect; + const unsigned long width = name_width; + const unsigned long height = mfont.height(); + name_rect.set_left((rect.right() + rect.left() - width)/2); + name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1); + name_rect.set_right(name_rect.left()+width-1); + name_rect.set_bottom(name_rect.top()+height); + + + if (is_depressed) + { + name_rect.set_left(name_rect.left()+1); + name_rect.set_right(name_rect.right()+1); + name_rect.set_top(name_rect.top()+1); + name_rect.set_bottom(name_rect.bottom()+1); + + mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); + + } + else + { + mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); + } + } + +// ---------------------------------------------------------------------------------------- + + rectangle button_style_toolbar1:: + get_min_size ( + const std::string& name, + const font& mfont + ) const + { + + unsigned long width; + unsigned long height; + mfont.compute_size(name,width,height); + name_width = width; + + return rectangle(width+2*padding, height+2*padding); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void button_style_toolbar_icon1::draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + const long radius = padding; + + if (enabled) + { + if (rect.contains(lastx,lasty)) + { + if (is_depressed) + { + fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(100,100,200,150), + rgb_alpha_pixel(50,50,100,100)); + draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200)); + } + else + { + fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(150,150,250,130), + rgb_alpha_pixel(100,100,150,90)); + draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200)); + } + } + + if (is_depressed) + { + rectangle img_rect(translate_rect(centered_rect(rect,img_mouseover.nc(),img_mouseover.nr()),1,1)); + point p(img_rect.left(),img_rect.top()); + draw_image(c,p,img_mouseover); + } + else + { + rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr())); + point p(img_rect.left(),img_rect.top()); + if (rect.contains(lastx,lasty)) + draw_image(c,p,img_mouseover); + else + draw_image(c,p,img_normal); + } + + } + else + { + rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr())); + point p(img_rect.left(),img_rect.top()); + draw_image(c,p,img_disabled); + } + } + +// ---------------------------------------------------------------------------------------- + + rectangle button_style_toolbar_icon1:: + get_min_size ( + const std::string& name, + const font& mfont + ) const + { + return rectangle(img_normal.nc()+2*padding, img_normal.nr()+2*padding); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // toggle button style stuff +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void toggle_button_style_default::draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + fill_rect(c,rect,rgb_pixel(212,208,200)); + + unsigned char red, green, blue; + if (enabled) + { + red = 0; + green = 0; + blue = 0; + } + else + { + red = 128; + green = 128; + blue = 128; + } + + // compute the name length if it hasn't already been computed + if (name_width == 0) + { + unsigned long height; + mfont.compute_size(name,name_width,height); + } + + // figure out where the name string should appear + rectangle name_rect; + const unsigned long width = name_width; + const unsigned long height = mfont.height(); + name_rect.set_left((rect.right() + rect.left() - width)/2); + name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1); + name_rect.set_right(name_rect.left()+width-1); + name_rect.set_bottom(name_rect.top()+height); + + long d = 0; + if (is_checked) + d = 1; + + if (is_depressed) + d = 2; + + name_rect.set_left(name_rect.left()+d); + name_rect.set_right(name_rect.right()+d); + name_rect.set_top(name_rect.top()+d); + name_rect.set_bottom(name_rect.bottom()+d); + + mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue)); + + // now draw the edge of the button + if (is_checked || is_depressed) + draw_button_down(c,rect); + else + draw_button_up(c,rect); + } + +// ---------------------------------------------------------------------------------------- + + rectangle toggle_button_style_default:: + get_min_size ( + const std::string& name, + const font& mfont + ) const + { + + unsigned long width; + unsigned long height; + mfont.compute_size(name,width,height); + name_width = width; + + return rectangle(width+2*padding, height+2*padding); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void toggle_button_style_check_box::draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + + rgb_pixel color; + if (enabled) + { + color.red = 0; + color.green = 0; + color.blue = 0; + } + else + { + color.red = 128; + color.green = 128; + color.blue = 128; + } + + + // figure out where the name string should appear + rectangle name_rect, box_rect; + unsigned long padding = 0; + if (mfont.height() < 13) + padding = (rect.height() - mfont.height())/2; + + name_rect = rect; + name_rect.set_left(rect.left() + 17-1); + name_rect.set_top(rect.top() + padding); + name_rect.set_bottom(rect.bottom() - padding); + + box_rect = rect; + box_rect.set_right(rect.left() + 12); + box_rect.set_bottom(rect.top() + 12); + + mfont.draw_string(c,name_rect,name,color); + + if (enabled && is_depressed == false) + fill_rect(c, box_rect,rgb_pixel(255,255,255)); + else + fill_rect(c, box_rect,rgb_pixel(212,208,200)); + + draw_sunken_rectangle(c, box_rect); + + + if (is_checked) + { + const long x = box_rect.left(); + const long y = box_rect.top(); + draw_line(c,point(3+x,5+y),point(6+x,8+y),color); + draw_line(c,point(3+x,6+y),point(5+x,8+y),color); + draw_line(c,point(3+x,7+y),point(5+x,9+y),color); + draw_line(c,point(6+x,6+y),point(9+x,3+y),color); + draw_line(c,point(6+x,7+y),point(9+x,4+y),color); + draw_line(c,point(6+x,8+y),point(9+x,5+y),color); + } + } + +// ---------------------------------------------------------------------------------------- + + rectangle toggle_button_style_check_box:: + get_min_size ( + const std::string& name, + const font& mfont + ) const + { + unsigned long width; + unsigned long height; + mfont.compute_size(name,width,height); + + if (height < 13) + height = 13; + + return rectangle(width + 17 -1, height -1); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void toggle_button_style_radio_button::draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + + rgb_pixel color; + + // figure out where the name string should appear + rectangle name_rect, box_rect; + unsigned long padding = 0; + if (mfont.height() < 13) + padding = (rect.height() - mfont.height())/2; + + name_rect = rect; + name_rect.set_left(rect.left() + 17-1); + name_rect.set_top(rect.top() + padding); + name_rect.set_bottom(rect.bottom() - padding); + + box_rect = rect; + box_rect.set_right(rect.left() + 12); + box_rect.set_bottom(rect.top() + 12); + + + const long x = box_rect.left(); + const long y = box_rect.top(); + + if (enabled && is_depressed == false) + draw_solid_circle(c,point(rect.left()+5,rect.top()+5),5,rgb_pixel(255,255,255)); + else + draw_solid_circle(c,point(rect.left()+5,rect.top()+5),5,rgb_pixel(212,208,200)); + + + color = rgb_pixel(128,128,128); + draw_line(c,point(0+x,4+y),point(0+x,7+y),color); + draw_line(c,point(1+x,2+y),point(1+x,9+y),color); + draw_line(c,point(2+x,1+y),point(9+x,1+y),color); + draw_line(c,point(4+x,0+y),point(7+x,0+y),color); + + color = rgb_pixel(255,255,255); + draw_line(c,point(4+x,11+y),point(7+x,11+y),color); + draw_line(c,point(2+x,10+y),point(9+x,10+y),color); + draw_line(c,point(10+x,2+y),point(10+x,9+y),color); + draw_line(c,point(11+x,4+y),point(11+x,7+y),color); + + color = rgb_pixel(64,64,64); + draw_line(c,point(1+x,4+y),point(1+x,7+y),color); + draw_line(c,point(4+x,1+y),point(7+x,1+y),color); + draw_pixel(c,point(2+x,3+y),color); + draw_pixel(c,point(3+x,2+y),color); + draw_pixel(c,point(2+x,2+y),color); + draw_pixel(c,point(2+x,8+y),color); + draw_pixel(c,point(8+x,2+y),color); + draw_pixel(c,point(9+x,2+y),color); + + color = rgb_pixel(212,208,200); + draw_line(c,point(4+x,10+y),point(7+x,10+y),color); + draw_line(c,point(10+x,4+y),point(10+x,7+y),color); + draw_pixel(c,point(3+x,9+y),color); + draw_pixel(c,point(9+x,3+y),color); + + if (enabled) + { + color.red = 0; + color.green = 0; + color.blue = 0; + } + else + { + color.red = 128; + color.green = 128; + color.blue = 128; + } + + mfont.draw_string(c,name_rect,name,color); + + if (is_checked) + { + draw_line(c,point(5+x,4+y),point(6+x,4+y),color); + draw_line(c,point(4+x,5+y),point(7+x,5+y),color); + draw_line(c,point(4+x,6+y),point(7+x,6+y),color); + draw_line(c,point(5+x,7+y),point(6+x,7+y),color); + } + + } + +// ---------------------------------------------------------------------------------------- + + rectangle toggle_button_style_radio_button:: + get_min_size ( + const std::string& name, + const font& mfont + ) const + { + unsigned long width; + unsigned long height; + mfont.compute_size(name,width,height); + + if (height < 13) + height = 13; + + return rectangle(width + 17 -1, height -1); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_WIDGETs_STYLE_CPP_ + diff --git a/dlib/gui_widgets/style.h b/dlib/gui_widgets/style.h new file mode 100644 index 0000000000000000000000000000000000000000..5861ea2f0c52017dd6149cd5f4d4c37e989a693d --- /dev/null +++ b/dlib/gui_widgets/style.h @@ -0,0 +1,351 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_WIDGETs_STYLE_ +#define DLIB_WIDGETs_STYLE_ + +#include "../algs.h" +#include "style_abstract.h" +#include "../gui_core.h" +#include "canvas_drawing.h" +#include +#include +#include "../unicode.h" +#include "../array2d.h" +#include "../pixel.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // button styles +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class button_style + { + public: + + button_style() + { + } + + virtual ~button_style() + {} + + virtual bool redraw_on_mouse_over ( + ) const { return false; } + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const = 0; + + virtual void draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const = 0; + }; + +// ---------------------------------------------------------------------------------------- + + class button_style_default : public button_style + { + public: + button_style_default () : padding(4), name_width(0) {} + + virtual void draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const; + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const; + + private: + + // this is the minimum amount of padding that can separate the name from the + // edge of the button + const unsigned long padding; + // this is the width of the name string + mutable unsigned long name_width; + + }; + +// ---------------------------------------------------------------------------------------- + + class button_style_toolbar1 : public button_style + { + public: + button_style_toolbar1 () : padding(4), name_width(0) {} + + virtual void draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const; + + virtual bool redraw_on_mouse_over ( + ) const { return true; } + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const; + + private: + + // this is the minimum amount of padding that can separate the name from the + // edge of the button + const unsigned long padding; + // this is the width of the name string + mutable unsigned long name_width; + + }; + +// ---------------------------------------------------------------------------------------- + + class button_style_toolbar_icon1 : public button_style + { + public: + template + button_style_toolbar_icon1 (const image_type& img_, unsigned long pad = 6) : padding(pad) + { + assign_image(img_mouseover,img_); + make_images(); + } + + button_style_toolbar_icon1( const button_style_toolbar_icon1& item): padding(item.padding) + { + assign_image(img_mouseover, item.img_mouseover); + assign_image(img_normal, item.img_normal); + assign_image(img_disabled, item.img_disabled); + } + + virtual void draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const; + + virtual bool redraw_on_mouse_over ( + ) const { return true; } + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const; + + private: + + void make_images ( + ) + { + // make the disabled image grayscale and make both non-mouseover images have weaker alpha channels + img_disabled.set_size(img_mouseover.nr(), img_mouseover.nc()); + img_normal.set_size(img_mouseover.nr(), img_mouseover.nc()); + + for (long r = 0; r < img_mouseover.nr(); ++r) + { + for (long c = 0; c < img_mouseover.nc(); ++c) + { + rgb_alpha_pixel p = img_mouseover[r][c]; + long avg = p.red; + avg += p.green; + avg += p.blue; + avg /= 3; + + if (p.alpha > 40) + p.alpha -= 40; + else + p.alpha = 0; + + img_normal[r][c] = p; + + if (p.alpha > 80) + p.alpha -= 80; + else + p.alpha = 0; + + p.red = avg; + p.green = avg; + p.blue = avg; + img_disabled[r][c] = p; + } + } + } + + array2d::kernel_1a img_mouseover; + array2d::kernel_1a img_normal; + array2d::kernel_1a img_disabled; + + // this is the minimum amount of padding that can separate the name from the + // edge of the button + const unsigned long padding; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // toggle button styles +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class toggle_button_style + { + public: + + toggle_button_style() + { + } + + virtual ~toggle_button_style() + {} + + virtual bool redraw_on_mouse_over ( + ) const { return false; } + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const = 0; + + virtual void draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const = 0; + }; + +// ---------------------------------------------------------------------------------------- + + class toggle_button_style_default : public toggle_button_style + { + public: + toggle_button_style_default () : padding(4), name_width(0) {} + + virtual void draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const; + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const; + + private: + + // this is the minimum amount of padding that can separate the name from the + // edge of the button + const unsigned long padding; + // this is the width of the name string + mutable unsigned long name_width; + + }; + +// ---------------------------------------------------------------------------------------- + + class toggle_button_style_check_box : public toggle_button_style + { + public: + virtual void draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const; + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const; + + }; + +// ---------------------------------------------------------------------------------------- + + class toggle_button_style_radio_button : public toggle_button_style + { + public: + virtual void draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const; + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const; + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "style.cpp" +#endif + +#endif // DLIB_WIDGETs_STYLE_ + + diff --git a/dlib/gui_widgets/style_abstract.h b/dlib/gui_widgets/style_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..8791de8707d4bd5c6e57ac7e8acbed2638fc498f --- /dev/null +++ b/dlib/gui_widgets/style_abstract.h @@ -0,0 +1,230 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_WIDGETs_STYLE_ABSTRACT_ +#ifdef DLIB_WIDGETs_STYLE_ABSTRACT_ + +#include "../algs.h" +#include "../gui_core.h" +#include "widgets_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // button styles +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class button_style + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an abstract class that defines the interface a + button style object must implement. + + Note that derived classes must be copyable via + their copy constructors. + !*/ + + public: + + virtual ~button_style() {} + + virtual bool redraw_on_mouse_over ( + ) const { return false; } + /*! + ensures + - if (this style draws buttons differently when a mouse is over them) then + - returns true + - else + - returns false + !*/ + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const = 0; + /*! + requires + - the mutex drawable::m is locked + ensures + - returns a rectangle that represents the minimum size of the button + given the name and font. + !*/ + + virtual void draw_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed + ) const = 0; + /*! + requires + - the mutex drawable::m is locked + - c == the canvas to draw on + - rect, hidden, enabled, mfont, lastx, and lasty are the variables + defined in the protected section of the drawable class. + - name == the name of the button to be drawn + - is_depressed == true if the button is to be drawn in a depressed state + ensures + - draws the button on the canvas c at the location given by rect. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class button_style_default : public button_style + { + /*! + This is the default style for button objects. It will cause + a button to appear as the simple MS Windows 2000 button style. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class button_style_toolbar1 : public button_style + { + /*! + This draws a simple toolbar style button that displays its name in the + middle of itself. When the mouse moves over it it will light up. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class button_style_toolbar_icon1 : public button_style + { + /*! + This draws a simple toolbar style button that displays an image in the + middle of itself. When the mouse moves over it it will light up. + !*/ + template + button_style_toolbar_icon1 ( + const image_type& img, + unsigned long border_size = 6 + ); + /*! + requires + - image_type == an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - displays image img in the middle of the button + - the distance between the edge of the button and the image + will be border_size pixels + !*/ + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // toggle button styles +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class toggle_button_style + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an abstract class that defines the interface a + toggle button style object must implement. + + Note that derived classes must be copyable via + their copy constructors. + !*/ + + public: + + virtual ~toggle_button_style() {} + + virtual bool redraw_on_mouse_over ( + ) const { return false; } + /*! + ensures + - if (this style draws buttons differently when a mouse is over them) then + - returns true + - else + - returns false + !*/ + + virtual rectangle get_min_size ( + const std::string& name, + const font& mfont + ) const = 0; + /*! + requires + - the mutex drawable::m is locked + ensures + - returns a rectangle that represents the minimum size of the button + given the name and font. + !*/ + + virtual void draw_toggle_button ( + const canvas& c, + const rectangle& rect, + const bool hidden, + const bool enabled, + const font& mfont, + const long lastx, + const long lasty, + const std::string& name, + const bool is_depressed, + const bool is_checked + ) const = 0; + /*! + requires + - the mutex drawable::m is locked + - c == the canvas to draw on + - rect, hidden, enabled, mfont, lastx, and lasty are the variables + defined in the protected section of the drawable class. + - name == the name of the button to be drawn + - is_depressed == true if the button is to be drawn in a depressed state + - is_checked == true if the toggle_button is in the checked state + ensures + - draws the button on the canvas c at the location given by rect. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class toggle_button_style_default : public toggle_button_style + { + /*! + This is the default style for toggle_button objects. It will cause + a button to appear as the simple MS Windows 2000 button style. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class toggle_button_style_check_box : public toggle_button_style + { + /*! + This draws a simple check box style toggle button that displays its + name to the right of a check box. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + class toggle_button_style_radio_button : public toggle_button_style + { + /*! + This draws a simple radio button style toggle button that displays its + name to the right of a circular radio button. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_WIDGETs_STYLE_ABSTRACT_ + + + diff --git a/dlib/gui_widgets/widgets.cpp b/dlib/gui_widgets/widgets.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9297c56a5c5ee4f9fffb865443945cb1351cec5c --- /dev/null +++ b/dlib/gui_widgets/widgets.cpp @@ -0,0 +1,2613 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_WIDGETs_CPP_ +#define DLIB_WIDGETs_CPP_ + +#include "widgets.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // button object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void button:: + set_size ( + unsigned long width, + unsigned long height + ) + { + auto_mutex M(m); + rectangle min_rect = style->get_min_size(name_,*mfont); + // only change the size if it isn't going to be too small to fit the name + if (height >= min_rect.height() && + width >= min_rect.width()) + { + rectangle old(rect); + rect = resize_rect(rect,width,height); + parent.invalidate_rectangle(rect+old); + btn_tooltip.set_size(width,height); + } + } + +// ---------------------------------------------------------------------------------------- + + void button:: + show ( + ) + { + button_action::show(); + btn_tooltip.show(); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + hide ( + ) + { + button_action::hide(); + btn_tooltip.hide(); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + enable ( + ) + { + button_action::enable(); + btn_tooltip.enable(); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + disable ( + ) + { + button_action::disable(); + btn_tooltip.disable(); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + set_tooltip_text ( + const std::string& text + ) + { + btn_tooltip.set_text(text); + } + +// ---------------------------------------------------------------------------------------- + + const std::string button:: + tooltip_text ( + ) const + { + return btn_tooltip.text(); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + set_name(name_); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + button_action::set_pos(x,y); + btn_tooltip.set_pos(x,y); + } + +// ---------------------------------------------------------------------------------------- + + void button:: + set_name ( + const std::string& name + ) + { + auto_mutex M(m); + name_ = name; + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + name_[0] = name_[0]; + + rectangle old(rect); + rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top()); + btn_tooltip.set_size(rect.width(),rect.height()); + + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + const std::string button:: + name ( + ) const + { + auto_mutex M(m); + std::string temp = name_; + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + temp[0] = name_[0]; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + void button:: + on_button_up ( + bool mouse_over + ) + { + if (mouse_over) + { + // this is a valid button click + if (event_handler.is_set()) + event_handler(); + else if (event_handler_self.is_set()) + event_handler_self(*this); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // toggle_button object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_size ( + unsigned long width, + unsigned long height + ) + { + auto_mutex M(m); + rectangle min_rect = style->get_min_size(name_,*mfont); + // only change the size if it isn't going to be too small to fit the name + if (height >= min_rect.height() && + width >= min_rect.width()) + { + rectangle old(rect); + rect = resize_rect(rect,width,height); + parent.invalidate_rectangle(rect+old); + btn_tooltip.set_size(width,height); + } + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_checked ( + ) + { + auto_mutex M(m); + checked = true; + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_unchecked ( + ) + { + auto_mutex M(m); + checked = false; + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + bool toggle_button:: + is_checked ( + ) const + { + auto_mutex M(m); + return checked; + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + show ( + ) + { + button_action::show(); + btn_tooltip.show(); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + hide ( + ) + { + button_action::hide(); + btn_tooltip.hide(); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + enable ( + ) + { + button_action::enable(); + btn_tooltip.enable(); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + disable ( + ) + { + button_action::disable(); + btn_tooltip.disable(); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_tooltip_text ( + const std::string& text + ) + { + btn_tooltip.set_text(text); + } + +// ---------------------------------------------------------------------------------------- + + const std::string toggle_button:: + tooltip_text ( + ) const + { + return btn_tooltip.text(); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + set_name(name_); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + button_action::set_pos(x,y); + btn_tooltip.set_pos(x,y); + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + set_name ( + const std::string& name + ) + { + auto_mutex M(m); + name_ = name; + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + name_[0] = name_[0]; + + rectangle old(rect); + rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top()); + btn_tooltip.set_size(rect.width(),rect.height()); + + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + const std::string toggle_button:: + name ( + ) const + { + auto_mutex M(m); + std::string temp = name_; + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + temp[0] = name_[0]; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + void toggle_button:: + on_button_up ( + bool mouse_over + ) + { + if (mouse_over) + { + checked = !checked; + // this is a valid toggle_button click + if (event_handler.is_set()) + event_handler(); + else if (event_handler_self.is_set()) + event_handler_self(*this); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // label object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void label:: + draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty() || text_.size() == 0) + return; + + using namespace std; + unsigned char r = text_color_.red; + unsigned char g = text_color_.green; + unsigned char b = text_color_.blue; + if (!enabled) + { + r = 128; + g = 128; + b = 128; + } + + rectangle text_rect(rect); + + string::size_type first, last; + first = 0; + last = text_.find_first_of('\n'); + mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last); + + while (last != string::npos) + { + first = last+1; + last = text_.find_first_of('\n',first); + text_rect.set_top(text_rect.top()+mfont->height()); + mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last); + } + } + +// ---------------------------------------------------------------------------------------- + + void label:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + set_text(text_); + } + +// ---------------------------------------------------------------------------------------- + + void label:: + set_text ( + const std::string& text + ) + { + using namespace std; + auto_mutex M(m); + text_ = text; + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + text_[0] = text[0]; + + rectangle old(rect); + + unsigned long width; + unsigned long height; + mfont->compute_size(text,width,height); + + rect.set_right(rect.left() + width - 1); + rect.set_bottom(rect.top() + height - 1); + + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + const std::string label:: + text ( + ) const + { + auto_mutex M(m); + std::string temp = text_; + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + temp[0] = text_[0]; + return temp; + } + +// ---------------------------------------------------------------------------------------- + + void label:: + set_text_color ( + const rgb_pixel color + ) + { + m.lock(); + text_color_ = color; + parent.invalidate_rectangle(rect); + m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + const rgb_pixel label:: + text_color ( + ) const + { + auto_mutex M(m); + return text_color_; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // text_field object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + rectangle text_field:: + get_text_rect ( + ) const + { + // figure out where the text string should appear + unsigned long vertical_pad = (rect.height() - mfont->height())/2+1; + + rectangle text_rect; + text_rect.set_left(rect.left()+(mfont->height()-mfont->ascender())); + text_rect.set_top(rect.top()+vertical_pad); + text_rect.set_right(rect.right()-(mfont->height()-mfont->ascender())); + text_rect.set_bottom(text_rect.top()+mfont->height()-1); + return text_rect; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + disable ( + ) + { + auto_mutex M(m); + drawable::disable(); + t.stop(); + has_focus = false; + cursor_visible = false; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + hide ( + ) + { + auto_mutex M(m); + drawable::hide(); + t.stop(); + has_focus = false; + cursor_visible = false; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + // adjust the height of this text field so that it is appropriate for the current + // font size + rect.set_bottom(rect.top() + mfont->height()+ (mfont->height()-mfont->ascender())*2); + set_text(text_); + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + if (enabled) + { + // first fill our area with the bg_color_ + fill_rect(c, area,bg_color_); + } + else + { + // first fill our area with gray + fill_rect(c, area,rgb_pixel(212,208,200)); + } + + const rectangle text_rect = get_text_rect(); + + if (enabled) + mfont->draw_string(c,text_rect,text_,text_color_,text_pos); + else + mfont->draw_string(c,text_rect,text_,rgb_pixel(128,128,128),text_pos); + + // now draw the edge of the text_field + draw_sunken_rectangle(c, rect); + + if (highlight_start <= highlight_end && enabled) + { + rectangle highlight_rect = text_rect; + unsigned long left_pad = 0, right_pad = mfont->left_overflow(); + + long i; + for (i = text_pos; i <= highlight_end; ++i) + { + if (i == highlight_start) + left_pad = right_pad; + + right_pad += (*mfont)[text_[i]].width(); + } + + highlight_rect.set_left(text_rect.left()+left_pad); + highlight_rect.set_right(text_rect.left()+right_pad); + + // highlight the highlight_rect area + highlight_rect = highlight_rect.intersect(c); + for (long row = highlight_rect.top(); row <= highlight_rect.bottom(); ++row) + { + for (long col = highlight_rect.left(); col <= highlight_rect.right(); ++col) + { + canvas::pixel& pixel = c[row-c.top()][col-c.left()]; + if (pixel.red == 255 && pixel.green == 255 && pixel.blue == 255) + { + // this is a background (and white) pixel so set it to a dark + // blueish color. + pixel.red = 10; + pixel.green = 36; + pixel.blue = 106; + } + else + { + // this should be a pixel that is part of a letter so set it to white + pixel.red = 255; + pixel.green = 255; + pixel.blue = 255; + } + } + } + } + + // now draw the cursor if we need to + if (cursor_visible && has_focus && enabled && !hidden) + { + const unsigned long top = rect.top()+3; + const unsigned long bottom = rect.bottom()-3; + draw_line(c, point(rect.left()+cursor_x,top),point(rect.left()+cursor_x,bottom)); + } + + + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + set_text ( + const std::string& text + ) + { + DLIB_ASSERT ( text.find_first_of('\n') == std::string::npos , + "\tvoid text_field::set_text()" + << "\n\ttext: " << text ); + auto_mutex M(m); + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + text_ = text.c_str(); + + move_cursor(0); + + highlight_start = 0; + highlight_end = -1; + + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + const std::string text_field:: + text ( + ) const + { + auto_mutex M(m); + // do this to get rid of any reference counting that may be present in + // the std::string implementation. + std::string temp = text_.c_str(); + return temp; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + set_width ( + unsigned long width + ) + { + if (width < 10) + return; + + m.lock(); + rectangle old(rect); + + rect.set_right(rect.left() + width - 1); + + parent.invalidate_rectangle(rect+old); + m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + set_background_color ( + const rgb_pixel color + ) + { + auto_mutex M(m); + bg_color_ = color; + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + const rgb_pixel text_field:: + background_color ( + ) const + { + auto_mutex M(m); + return bg_color_; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + set_text_color ( + const rgb_pixel color + ) + { + auto_mutex M(m); + text_color_ = color; + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + const rgb_pixel text_field:: + text_color ( + ) const + { + auto_mutex M(m); + return text_color_; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (!enabled || hidden || !has_focus) + { + return; + } + + if (state & base_window::LEFT) + { + if (highlight_start <= highlight_end) + { + if (highlight_start == cursor_pos) + shift_pos = highlight_end + 1; + else + shift_pos = highlight_start; + } + + unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos); + if (static_cast(new_pos) != cursor_pos) + { + move_cursor(new_pos); + parent.invalidate_rectangle(rect); + } + } + else if (shift_pos != -1) + { + shift_pos = -1; + } + + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + on_mouse_up ( + unsigned long btn, + unsigned long, + long , + long + ) + { + if (!enabled || hidden) + return; + + if (btn == base_window::LEFT) + shift_pos = -1; + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool double_clicked + ) + { + using namespace std; + if (!enabled || hidden || btn != (unsigned long)base_window::LEFT) + return; + + if (rect.contains(x,y)) + { + has_focus = true; + cursor_visible = true; + parent.invalidate_rectangle(rect); + t.start(); + + if (double_clicked) + { + // highlight the double clicked word + string::size_type first, last; + first = text_.substr(0,cursor_pos).find_last_of(" \t\n"); + last = text_.find_first_of(" \t\n",cursor_pos); + long f = static_cast(first); + long l = static_cast(last); + if (first == string::npos) + f = -1; + if (last == string::npos) + l = static_cast(text_.size()); + + ++f; + --l; + + move_cursor(l+1); + highlight_start = f; + highlight_end = l; + } + else + { + if (state & base_window::SHIFT) + { + if (highlight_start <= highlight_end) + { + if (highlight_start == cursor_pos) + shift_pos = highlight_end + 1; + else + shift_pos = highlight_start; + } + else + { + shift_pos = cursor_pos; + } + } + + bool at_end = false; + if (cursor_pos == 0 || cursor_pos == static_cast(text_.size())) + at_end = true; + const long old_pos = cursor_pos; + + unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos); + if (static_cast(new_pos) != cursor_pos) + { + move_cursor(new_pos); + parent.invalidate_rectangle(rect); + } + shift_pos = cursor_pos; + + if (at_end && cursor_pos == old_pos) + { + highlight_start = 0; + highlight_end = -1; + parent.invalidate_rectangle(rect); + } + } + + } + else if (has_focus) + { + t.stop(); + has_focus = false; + cursor_visible = false; + shift_pos = -1; + highlight_start = 0; + highlight_end = -1; + + parent.invalidate_rectangle(rect); + } + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0; + const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0; + if (has_focus && enabled && !hidden) + { + if (shift && is_printable == false) + { + if (shift_pos == -1) + { + if (highlight_start <= highlight_end) + { + if (highlight_start == cursor_pos) + shift_pos = highlight_end + 1; + else + shift_pos = highlight_start; + } + else + { + shift_pos = cursor_pos; + } + } + } + else + { + shift_pos = -1; + } + + if (key == base_window::KEY_LEFT || + key == base_window::KEY_UP) + { + if (cursor_pos != 0) + { + unsigned long new_pos; + if (ctrl) + { + // find the first non-whitespace to our left + std::string::size_type pos = text_.find_last_not_of(" \t\n",cursor_pos); + if (pos != std::string::npos) + { + pos = text_.find_last_of(" \n\t",pos); + if (pos != std::string::npos) + new_pos = static_cast(pos); + else + new_pos = 0; + } + else + { + new_pos = 0; + } + } + else + { + new_pos = cursor_pos-1; + } + + move_cursor(new_pos); + } + else if (shift_pos == -1) + { + highlight_start = 0; + highlight_end = -1; + parent.invalidate_rectangle(rect); + } + + } + else if (key == base_window::KEY_RIGHT || + key == base_window::KEY_DOWN) + { + if (cursor_pos != static_cast(text_.size())) + { + unsigned long new_pos; + if (ctrl) + { + // find the first non-whitespace to our left + std::string::size_type pos = text_.find_first_not_of(" \t\n",cursor_pos); + if (pos != std::string::npos) + { + pos = text_.find_first_of(" \n\t",pos); + if (pos != std::string::npos) + new_pos = static_cast(pos+1); + else + new_pos = static_cast(text_.size()); + } + else + { + new_pos = static_cast(text_.size()); + } + } + else + { + new_pos = cursor_pos+1; + } + + move_cursor(new_pos); + } + else if (shift_pos == -1) + { + highlight_start = 0; + highlight_end = -1; + parent.invalidate_rectangle(rect); + } + } + else if (is_printable) + { + if (ctrl) + { + if (key == 'a') + { + move_cursor(static_cast(text_.size())); + highlight_start = 0; + highlight_end = static_cast(text_.size()-1); + parent.invalidate_rectangle(rect); + } + } + else if (key != '\n') + { + if (highlight_start <= highlight_end) + { + text_ = text_.substr(0,highlight_start) + static_cast(key) + + text_.substr(highlight_end+1,text_.size()-highlight_end-1); + move_cursor(highlight_start+1); + highlight_start = 0; + highlight_end = -1; + parent.invalidate_rectangle(rect); + } + else + { + text_ = text_.substr(0,cursor_pos) + static_cast(key) + + text_.substr(cursor_pos,text_.size()-cursor_pos); + move_cursor(cursor_pos+1); + } + unsigned long height; + mfont->compute_size(text_,text_width,height,text_pos); + + // send out the text modified event + if (text_modified_handler.is_set()) + text_modified_handler(); + } + } + else if (key == base_window::KEY_BACKSPACE) + { + // if something is highlighted then delete that + if (highlight_start <= highlight_end) + { + text_ = text_.erase(highlight_start,highlight_end-highlight_start+1); + move_cursor(highlight_start); + highlight_start = 0; + highlight_end = -1; + + // send out the text modified event + if (text_modified_handler.is_set()) + text_modified_handler(); + } + else if (cursor_pos != 0) + { + text_ = text_.erase(cursor_pos-1,1); + move_cursor(cursor_pos-1); + + // send out the text modified event + if (text_modified_handler.is_set()) + text_modified_handler(); + } + else + { + // do this just so it repaints itself right + move_cursor(cursor_pos); + } + unsigned long height; + mfont->compute_size(text_,text_width,height,text_pos); + parent.invalidate_rectangle(rect); + } + else if (key == base_window::KEY_DELETE) + { + // if something is highlighted then delete that + if (highlight_start <= highlight_end) + { + text_ = text_.erase(highlight_start,highlight_end-highlight_start+1); + move_cursor(highlight_start); + highlight_start = 0; + highlight_end = -1; + + // send out the text modified event + if (text_modified_handler.is_set()) + text_modified_handler(); + } + else if (cursor_pos != static_cast(text_.size())) + { + text_ = text_.erase(cursor_pos,1); + + // send out the text modified event + if (text_modified_handler.is_set()) + text_modified_handler(); + } + else + { + // do this just so it repaints itself right + move_cursor(cursor_pos); + } + parent.invalidate_rectangle(rect); + + unsigned long height; + mfont->compute_size(text_,text_width,height,text_pos); + } + else if (key == base_window::KEY_HOME) + { + move_cursor(0); + if (shift_pos == -1) + { + highlight_start = 0; + highlight_end = -1; + parent.invalidate_rectangle(rect); + } + } + else if (key == base_window::KEY_END) + { + move_cursor(static_cast(text_.size())); + if (shift_pos == -1) + { + highlight_start = 0; + highlight_end = -1; + parent.invalidate_rectangle(rect); + } + } + cursor_visible = true; + recent_movement = true; + + } + } + +// ---------------------------------------------------------------------------------------- + + void text_field:: + move_cursor ( + unsigned long pos + ) + { + using namespace std; + const long old_cursor_pos = cursor_pos; + + if (text_pos >= pos) + { + // the cursor should go all the way to the left side of the text + if (pos >= 6) + text_pos = pos-6; + else + text_pos = 0; + + cursor_pos = pos; + unsigned long height; + mfont->compute_size(text_,text_width,height,text_pos); + + unsigned long width; + unsigned long new_x = (mfont->height()-mfont->ascender()); + if (static_cast(cursor_pos)-1 >= static_cast(text_pos)) + { + mfont->compute_size(text_,width,height,text_pos,cursor_pos-1); + if (cursor_pos != 0) + new_x += width - mfont->right_overflow(); + } + + cursor_x = new_x; + } + else + { + unsigned long height; + unsigned long width; + mfont->compute_size(text_,width,height,text_pos,pos-1); + + unsigned long new_x = (mfont->height()-mfont->ascender()) + + width - mfont->right_overflow(); + + // move the text to the left if necessary + if (new_x + 4 > rect.width()) + { + while (new_x > rect.width() - rect.width()/5) + { + new_x -= (*mfont)[text_[text_pos]].width(); + ++text_pos; + } + } + + cursor_x = new_x; + cursor_pos = pos; + mfont->compute_size(text_,text_width,height,text_pos); + } + + if (old_cursor_pos != cursor_pos) + { + if (shift_pos != -1) + { + highlight_start = std::min(shift_pos,cursor_pos); + highlight_end = std::max(shift_pos,cursor_pos)-1; + } + else + { + highlight_start = 0; + highlight_end = -1; + } + + recent_movement = true; + cursor_visible = true; + parent.invalidate_rectangle(rect); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// tabbed_display object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + tabbed_display:: + tabbed_display( + drawable_window& w + ) : + drawable(w,MOUSE_CLICK), + selected_tab_(0), + left_pad(6), + right_pad(4), + top_pad(3), + bottom_pad(3) + { + rect = rectangle(0,0,40,mfont->height()+top_pad+bottom_pad); + enable_events(); + tabs.set_max_size(1); + tabs.set_size(1); + } + +// ---------------------------------------------------------------------------------------- + + tabbed_display:: + ~tabbed_display( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + // we have to adjust the positions of all the tab rectangles + const long xdelta = rect.left() - x; + const long ydelta = rect.top() - y; + for (unsigned long i = 0; i < tabs.size(); ++i) + { + tabs[i].rect.set_left(tabs[i].rect.left()+xdelta); + tabs[i].rect.set_right(tabs[i].rect.right()+xdelta); + + tabs[i].rect.set_top(tabs[i].rect.top()+ydelta); + tabs[i].rect.set_bottom(tabs[i].rect.bottom()+ydelta); + + + // adjust the position of the group associated with this tab if it exists + if (tabs[i].group) + tabs[i].group->set_pos(x+3, y+mfont->height()+top_pad+bottom_pad+3); + } + drawable::set_pos(x,y); + recompute_tabs(); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + fit_to_contents ( + ) + { + auto_mutex M(m); + rectangle new_rect; + point p(rect.left(),rect.top()); + new_rect += p; + + for (unsigned long i = 0; i < tabs.size(); ++i) + { + if (tabs[i].group) + { + tabs[i].group->fit_to_contents(); + new_rect += tabs[i].group->get_rect(); + } + } + + // and give the new rect an additional 4 pixels on the bottom and right sides + // so that the contents to hit the edge of the tabbed display + new_rect = resize_rect(new_rect, new_rect.width()+4, new_rect.height()+4); + + parent.invalidate_rectangle(new_rect+rect); + rect = new_rect; + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + set_size ( + unsigned long width, + unsigned long height + ) + { + auto_mutex M(m); + rectangle old(rect); + const long x = rect.left(); + const long y = rect.top(); + rect.set_right(x+width-1); + rect.set_bottom(y+height-1); + + recompute_tabs(); + + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + set_number_of_tabs ( + unsigned long num + ) + { + auto_mutex M(m); + + DLIB_ASSERT ( num > 0 , + "\tvoid tabbed_display::set_number_of_tabs()" + << "\n\tnum: " << num ); + + tabs.set_max_size(num); + tabs.set_size(num); + + selected_tab_ = 0; + + recompute_tabs(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + unsigned long tabbed_display:: + number_of_tabs ( + ) const + { + auto_mutex M(m); + return tabs.size(); + } + +// ---------------------------------------------------------------------------------------- + + const std::string& tabbed_display:: + tab_name ( + unsigned long idx + ) const + { + auto_mutex M(m); + + DLIB_ASSERT ( idx < number_of_tabs() , + "\tvoid tabbed_display::tab_name()" + << "\n\tidx: " << idx + << "\n\tnumber_of_tabs(): " << number_of_tabs() ); + + return tabs[idx].name; + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + set_tab_name ( + unsigned long idx, + const std::string& new_name + ) + { + auto_mutex M(m); + + + DLIB_ASSERT ( idx < number_of_tabs() , + "\tvoid tabbed_display::set_tab_name()" + << "\n\tidx: " << idx + << "\n\tnumber_of_tabs(): " << number_of_tabs() ); + + + tabs[idx].name = new_name; + // do this so that there isn't any reference counting going on + tabs[idx].name[0] = tabs[idx].name[0]; + unsigned long height; + mfont->compute_size(new_name,tabs[idx].width,height); + + + recompute_tabs(); + + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + on_mouse_down ( + unsigned long btn, + unsigned long, + long x, + long y, + bool + ) + { + if (rect.contains(x,y) && btn == base_window::LEFT && enabled && !hidden) + { + rectangle temp = rect; + const long offset = mfont->height() + bottom_pad + top_pad; + temp.set_bottom(rect.top()+offset); + if (temp.contains(x,y)) + { + // now we have to figure out which tab was clicked + for (unsigned long i = 0; i < tabs.size(); ++i) + { + if (selected_tab_ != i && tabs[i].rect.contains(x,y) && + tabs[selected_tab_].rect.contains(x,y) == false) + { + unsigned long old_idx = selected_tab_; + selected_tab_ = i; + recompute_tabs(); + parent.invalidate_rectangle(temp); + + // adjust the widget_group objects for these tabs if they exist + if (tabs[i].group) + tabs[i].group->show(); + if (tabs[old_idx].group) + tabs[old_idx].group->hide(); + + if (event_handler.is_set()) + event_handler(i,old_idx); + break; + } + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + set_tab_group ( + unsigned long idx, + widget_group& group + ) + { + auto_mutex M(m); + + DLIB_ASSERT ( idx < number_of_tabs() , + "\tvoid tabbed_display::set_tab_group()" + << "\n\tidx: " << idx + << "\n\tnumber_of_tabs(): " << number_of_tabs() ); + + + tabs[idx].group = &group; + group.set_pos(rect.left()+3,rect.top()+mfont->height()+top_pad+bottom_pad+2); + if (idx == selected_tab_) + group.show(); + else + group.hide(); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + disable ( + ) + { + auto_mutex M(m); + if (tabs[selected_tab_].group) + tabs[selected_tab_].group->disable(); + drawable::disable(); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + enable ( + ) + { + auto_mutex M(m); + if (tabs[selected_tab_].group) + tabs[selected_tab_].group->enable(); + drawable::enable(); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + hide ( + ) + { + auto_mutex M(m); + if (tabs[selected_tab_].group) + tabs[selected_tab_].group->hide(); + drawable::hide(); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + show ( + ) + { + auto_mutex M(m); + if (tabs[selected_tab_].group) + tabs[selected_tab_].group->show(); + drawable::show(); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + // draw the main border first + rectangle main_box(rect.left(),rect.top()+mfont->height()+top_pad+bottom_pad,rect.right(),rect.bottom()); + draw_button_up(c,main_box); + draw_pixel(c,point(main_box.right()-1,main_box.top()),rgb_pixel(128,128,128)); + + rgb_pixel color; + if (enabled) + { + color.red = 0; + color.green = 0; + color.blue = 0; + } + else + { + color.red = 128; + color.green = 128; + color.blue = 128; + } + + // draw the tabs + for (unsigned long i = 0; i < tabs.size(); ++i) + { + if (selected_tab_ != i) + draw_tab(tabs[i].rect,c); + + // draw the name string + rectangle temp = tabs[i].rect; + temp.set_top(temp.top()+top_pad); + temp.set_bottom(temp.bottom()+bottom_pad); + temp.set_left(temp.left()+left_pad); + temp.set_right(temp.right()+right_pad); + mfont->draw_string(c,temp,tabs[i].name,color); + } + draw_tab(tabs[selected_tab_].rect,c); + draw_line(c, + point(tabs[selected_tab_].rect.left()+1, + tabs[selected_tab_].rect.bottom()), + point(tabs[selected_tab_].rect.right()-2, + tabs[selected_tab_].rect.bottom()), + rgb_pixel(212,208,200)); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + draw_tab ( + const rectangle& tab, + const canvas& c + ) const + { + const rgb_pixel white(255,255,255); + const rgb_pixel background(212,208,200); + const rgb_pixel dark_gray(64,64,64); + const rgb_pixel gray(128,128,128); + draw_line(c,point(tab.left(),tab.top()+2),point(tab.left(),tab.bottom()),white); + draw_line(c,point(tab.left()+1,tab.top()+2),point(tab.left()+1,tab.bottom()),background); + draw_line(c,point(tab.right(),tab.top()+2),point(tab.right(),tab.bottom()),dark_gray); + draw_line(c,point(tab.right()-1,tab.top()+2),point(tab.right()-1,tab.bottom()),gray); + draw_line(c,point(tab.left()+2,tab.top()),point(tab.right()-2,tab.top()),white); + draw_pixel(c,point(tab.left()+1,tab.top()+1),white); + draw_pixel(c,point(tab.right()-1,tab.top()+1),dark_gray); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + + for (unsigned long i = 0; i < tabs.size(); ++i) + { + unsigned long height; + mfont->compute_size(tabs[i].name,tabs[i].width,height); + } + + recompute_tabs(); + set_pos(rect.left(), rect.top()); + + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void tabbed_display:: + recompute_tabs ( + ) + { + const long offset = mfont->height() + bottom_pad + top_pad; + + + // figure out the size and position of all the tabs + rectangle sel_tab_rect, other_tab; + sel_tab_rect.set_top(rect.top()); + sel_tab_rect.set_bottom(rect.top()+offset); + + other_tab.set_top(rect.top()+2); + other_tab.set_bottom(rect.top()+offset-1); + + long cur_x = rect.left(); + for (unsigned long i = 0; i < tabs.size(); ++i) + { + const unsigned long str_width = tabs[i].width; + if (selected_tab_ != i) + { + other_tab.set_left(cur_x); + cur_x += left_pad + str_width + right_pad; + other_tab.set_right(cur_x); + tabs[i].rect = other_tab; + ++cur_x; + + } + else + { + if (i != 0) + sel_tab_rect.set_left(cur_x-2); + else + sel_tab_rect.set_left(cur_x); + + cur_x += left_pad + str_width + right_pad; + + if (i != tabs.size()-1) + sel_tab_rect.set_right(cur_x+2); + else + sel_tab_rect.set_right(cur_x); + ++cur_x; + + tabs[i].rect = sel_tab_rect; + } + } + + // make sure this object is wide enough + const rectangle& last = tabs[tabs.size()-1].rect; + const rectangle& first = tabs[0].rect; + rect = last + rect + first; + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// named_rectangle object methods +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + named_rectangle:: + named_rectangle( + drawable_window& w + ) : + drawable(w), + name_width(0), + name_height(0) + { + make_name_fit_in_rect(); + enable_events(); + } + +// ---------------------------------------------------------------------------------------- + + named_rectangle:: + ~named_rectangle( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void named_rectangle:: + set_size ( + unsigned long width, + unsigned long height + ) + { + auto_mutex M(m); + rectangle old(rect); + const long x = rect.left(); + const long y = rect.top(); + rect.set_right(x+width-1); + rect.set_bottom(y+height-1); + + make_name_fit_in_rect(); + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + void named_rectangle:: + wrap_around ( + const rectangle& r + ) + { + auto_mutex M(m); + rectangle old(rect); + const unsigned long pad = name_height/2; + + rect = rectangle(r.left()-pad, r.top()-name_height*4/3, r.right()+pad, r.bottom()+pad); + + make_name_fit_in_rect(); + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + void named_rectangle:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + mfont->compute_size(name_,name_width,name_height); + make_name_fit_in_rect(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void named_rectangle:: + make_name_fit_in_rect ( + ) + { + // make sure the named rectangle is big enough to contain the name + const unsigned long wtemp = mfont->height() + name_width; + const unsigned long htemp = mfont->height() + name_height; + if (rect.width() < wtemp) + rect.set_right(rect.left() + wtemp - 1 ); + if (rect.height() < htemp) + rect.set_bottom(rect.bottom() + htemp - 1 ); + } + +// ---------------------------------------------------------------------------------------- + + void named_rectangle:: + set_name ( + const std::string& name + ) + { + auto_mutex M(m); + name_ = name.c_str(); + mfont->compute_size(name_,name_width,name_height); + + make_name_fit_in_rect(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + const std::string named_rectangle:: + name ( + ) const + { + auto_mutex M(m); + return std::string(name_.c_str()); + } + +// ---------------------------------------------------------------------------------------- + + void named_rectangle:: + draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + const unsigned long gap = mfont->height()/2; + rectangle strrect = rect; + strrect.set_left(rect.left() + gap); + + const unsigned long rtop = rect.top() + name_height/2; + + const rgb_pixel white(255,255,255); + const rgb_pixel gray(128,128,128); + + mfont->draw_string(c,strrect,name_); + draw_line(c,point(rect.left(), rtop), + point(rect.left()+gap/2, rtop), gray); + draw_line(c,point(rect.left(), rtop), + point(rect.left(), rect.bottom()-1), gray); + draw_line(c,point(rect.left(), rect.bottom()-1), + point(rect.right()-1, rect.bottom()-1), gray); + draw_line(c,point(rect.right()-1, rtop), + point(rect.right()-1, rect.bottom()-2), gray); + draw_line(c,point(strrect.left() + name_width + 2, rtop), + point(rect.right()-1, rtop), gray); + + draw_line(c,point(strrect.left() + name_width + 2, rtop+1), + point( rect.right()-2, rtop+1), white); + draw_line(c,point(rect.right(), rtop), + point(rect.right(), rect.bottom()), white); + draw_line(c,point(rect.left(), rect.bottom()), + point(rect.right(), rect.bottom()), white); + draw_line(c,point(rect.left()+1, rtop+1), + point(rect.left()+1, rect.bottom()-2), white); + draw_line(c,point(rect.left()+1, rtop+1), + point(rect.left()+gap/2, rtop+1), white); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class mouse_tracker +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + mouse_tracker:: + mouse_tracker( + drawable_window& w + ) : + dragable(w), + offset(18), + nr(w), + x_label(w), + y_label(w), + click_x(-1), + click_y(-1) + { + set_dragable_area(rectangle(0,0,500,500)); + + + x_label.set_text("x: "); + y_label.set_text("y: "); + nr.set_name("mouse position"); + + + x_label.set_pos(offset,offset); + y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3); + + nr.wrap_around(x_label.get_rect() + y_label.get_rect()); + rect = nr.get_rect(); + + set_z_order(2000000000); + x_label.set_z_order(2000000001); + y_label.set_z_order(2000000001); + nr.set_z_order(2000000001); + + enable_events(); + } + +// ---------------------------------------------------------------------------------------- + + mouse_tracker:: + ~mouse_tracker( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + nr.set_main_font(f); + x_label.set_main_font(f); + y_label.set_main_font(f); + mfont = f; + nr.wrap_around(x_label.get_rect() + y_label.get_rect()); + rect = nr.get_rect(); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + set_pos ( + long x, + long y + ) + { + dragable::set_pos(x,y); + nr.set_pos(x,y); + x_label.set_pos(rect.left()+offset,rect.top()+offset); + y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + show ( + ) + { + dragable::show(); + nr.show(); + x_label.show(); + y_label.show(); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + hide ( + ) + { + dragable::hide(); + nr.hide(); + x_label.hide(); + y_label.hide(); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + enable ( + ) + { + dragable::enable(); + nr.enable(); + x_label.enable(); + y_label.enable(); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + disable ( + ) + { + dragable::disable(); + nr.disable(); + x_label.disable(); + y_label.disable(); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool double_clicked + ) + { + dragable::on_mouse_down(btn,state,x,y,double_clicked); + if ((state & base_window::SHIFT) && (btn == base_window::LEFT) && enabled && !hidden) + { + parent.invalidate_rectangle(rectangle(x,y,x,y)); + parent.invalidate_rectangle(rectangle(click_x,click_y,click_x,click_y)); + click_x = x; + click_y = y; + + y_label.set_text("y: 0"); + x_label.set_text("x: 0"); + } + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (!hidden && enabled) + { + parent.invalidate_rectangle(rect); + dragable::on_mouse_move(state,x,y); + + long dx = 0; + long dy = 0; + if (click_x != -1) + dx = click_x; + if (click_y != -1) + dy = click_y; + + sout.str(""); + sout << "y: " << y - dy; + y_label.set_text(sout.str()); + + sout.str(""); + sout << "x: " << x - dx; + x_label.set_text(sout.str()); + } + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + on_drag ( + ) + { + nr.set_pos(rect.left(),rect.top()); + x_label.set_pos(rect.left()+offset,rect.top()+offset); + y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3); + + long x = 0; + long y = 0; + if (click_x != -1) + x = click_x; + if (click_y != -1) + y = click_y; + + sout.str(""); + sout << "y: " << lasty - y; + y_label.set_text(sout.str()); + + sout.str(""); + sout << "x: " << lastx - x; + x_label.set_text(sout.str()); + } + +// ---------------------------------------------------------------------------------------- + + void mouse_tracker:: + draw ( + const canvas& c + ) const + { + fill_rect(c, rect,rgb_pixel(212,208,200)); + draw_pixel(c, point(click_x,click_y),rgb_pixel(255,0,0)); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class list_box +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + list_box:: + list_box( + drawable_window& w + ) : + drawable(w,MOUSE_WHEEL|MOUSE_CLICK), + ms_enabled(false), + pos(0), + text_start(0), + last_selected(0), + sbv(w,scroll_bar::VERTICAL), + sbh(w,scroll_bar::HORIZONTAL) + { + adjust_sliders(); + sbv.set_scroll_handler(*this,&list_box::sbv_handler); + sbh.set_scroll_handler(*this,&list_box::sbh_handler); + enable_events(); + } + +// ---------------------------------------------------------------------------------------- + + list_box:: + ~list_box( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + // recompute the sizes of all the items + for (unsigned long i = 0; i < items.size(); ++i) + { + mfont->compute_size(items[i].name,items[i].width, items[i].height); + } + adjust_sliders(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + set_size ( + unsigned long width_, + unsigned long height_ + ) + { + auto_mutex M(m); + rectangle old(rect); + const long x = rect.left(); + const long y = rect.top(); + rect.set_right(x+width_-1); + rect.set_bottom(y+height_-1); + + adjust_sliders(); + parent.invalidate_rectangle(rect+old); + } + +// ---------------------------------------------------------------------------------------- + + bool list_box:: + is_selected ( + unsigned long index + ) const + { + auto_mutex M(m); + DLIB_ASSERT ( index < size() , + "\tbool list_box::is_selected(index)" + << "\n\tindex: " << index + << "\n\tsize(): " << size() ); + + return items[index].is_selected; + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + select ( + unsigned long index + ) + { + auto_mutex M(m); + DLIB_ASSERT ( index < size() , + "\tvoid list_box::select(index)" + << "\n\tindex: " << index + << "\n\tsize(): " << size() ); + + items[index].is_selected = true; + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + unselect ( + unsigned long index + ) + { + auto_mutex M(m); + DLIB_ASSERT ( index < size() , + "\tvoid list_box::unselect(index)" + << "\n\tindex: " << index + << "\n\tsize(): " << size() ); + items[index].is_selected = false; + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + const std::string& list_box::operator [] ( + unsigned long index + ) const + { + auto_mutex M(m); + DLIB_ASSERT ( index < size() , + "\tconst std::string& list_box::operator[](index)" + << "\n\tindex: " << index + << "\n\tsize(): " << size() ); + return items[index].name; + } + +// ---------------------------------------------------------------------------------------- + + bool list_box:: + multiple_select_enabled ( + ) const + { + auto_mutex M(m); + return ms_enabled; + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + enable_multiple_select ( + ) + { + auto_mutex M(m); + ms_enabled = true; + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + disable_multiple_select ( + ) + { + auto_mutex M(m); + ms_enabled = false; + } + +// ---------------------------------------------------------------------------------------- + + bool list_box:: + at_start ( + ) const + { + auto_mutex M(m); + return items.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + reset ( + ) const + { + auto_mutex M(m); + items.reset(); + } + +// ---------------------------------------------------------------------------------------- + + bool list_box:: + current_element_valid ( + ) const + { + auto_mutex M(m); + return items.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + const std::string& list_box:: + element ( + ) const + { + auto_mutex M(m); + DLIB_ASSERT ( current_element_valid() , + "\tconst std::string& list_box::element()" + ); + return items.element().name; + } + +// ---------------------------------------------------------------------------------------- + + const std::string& list_box:: + element ( + ) + { + auto_mutex M(m); + DLIB_ASSERT ( current_element_valid() , + "\tconst std::string& list_box::element()" + ); + return items.element().name; + } + +// ---------------------------------------------------------------------------------------- + + bool list_box:: + move_next ( + ) const + { + auto_mutex M(m); + return items.move_next(); + } + +// ---------------------------------------------------------------------------------------- + + unsigned long list_box:: + size ( + ) const + { + auto_mutex M(m); + return items.size(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + draw ( + const canvas& c + ) const + { + rectangle area = rect.intersect(c); + if (area.is_empty()) + return; + + if (enabled) + { + // first fill our area with white + fill_rect(c, area,rgb_pixel(255,255,255)); + } + else + { + // first fill our area with gray + fill_rect(c, area,rgb_pixel(212,208,200)); + } + + draw_sunken_rectangle(c, rect); + + long y = text_area.top(); + long x = text_area.left(); + for (unsigned long i = pos; i < items.size(); ++i) + { + rectangle r(x-(long)text_start,y,text_area.right(),y+items[i].height); + rectangle draw_area(x,y,text_area.right(),y+items[i].height); + draw_area = draw_area.intersect(text_area); + if (draw_area.is_empty()) + break; + + if (items[i].is_selected) + { + if (enabled) + fill_rect_with_vertical_gradient(c,draw_area,rgb_pixel(110,160,255), rgb_pixel(100,130,250)); + else + fill_rect_with_vertical_gradient(c,draw_area,rgb_pixel(140,190,255), rgb_pixel(130,160,250)); + } + + if (enabled) + mfont->draw_string(c,r,items[i].name,rgb_pixel(0,0,0),0,std::string::npos,draw_area); + else + mfont->draw_string(c,r,items[i].name,rgb_pixel(128,128,128),0,std::string::npos,draw_area); + y += items[i].height; + if (y > area.bottom()) + break; + } + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + hide ( + ) + { + auto_mutex M(m); + sbv.hide(); + sbh.hide(); + drawable::hide(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + show ( + ) + { + auto_mutex M(m); + hidden = false; + adjust_sliders(); + drawable::show(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + disable ( + ) + { + sbv.disable(); + sbh.disable(); + drawable::disable(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + enable ( + ) + { + sbv.enable(); + sbh.enable(); + drawable::enable(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + set_pos ( + long x, + long y + ) + { + auto_mutex M(m); + drawable::set_pos(x,y); + adjust_sliders(); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + adjust_sliders ( + ) + { + text_area = rectangle(rect.left()+2,rect.top()+2,rect.right()-1,rect.bottom()-1); + + int extra_count = 0; + // find the max width and height of our text + unsigned long maxw = 0, maxh = 0; + for (unsigned long i = 0; i < items.size(); ++i) + { + maxh += items[i].height; + if (maxh > text_area.height()) + ++extra_count; + if (items[i].width > maxw ) + maxw = items[i].width; + } + + if (maxh > text_area.height() && text_area.is_empty() == false) + { + if (!hidden) + sbv.show(); + sbv.set_pos(rect.right()-sbv.width()-pad+1,rect.top()+pad); + sbv.set_length(rect.height()-pad*2); + + text_area.set_right(text_area.right()-sbv.width()-1); + + if (maxw > text_area.width()) + { + if (!hidden) + sbh.show(); + sbh.set_pos(rect.left()+pad,rect.bottom()-sbh.height()-pad+1); + sbh.set_length(rect.width()-pad*2 - sbv.width()); + text_area.set_bottom(text_area.bottom()-sbh.height()-1); + sbh.set_max_slider_pos(maxw - text_area.width()); + + ++extra_count; + } + else + { + sbh.hide(); + } + sbv.set_max_slider_pos(extra_count); + } + else + { + sbv.hide(); + pos = 0; + sbv.set_max_slider_pos(0); + if (maxw > text_area.width() && text_area.is_empty() == false) + { + if (!hidden) + sbh.show(); + sbh.set_pos(rect.left()+pad,rect.bottom()-sbh.height()-pad+1); + sbh.set_length(rect.width()-pad*2); + text_area.set_bottom(text_area.bottom()-sbh.height()-1); + sbh.set_max_slider_pos(maxw - text_area.width()); + } + else + { + sbh.hide(); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + sbh_handler ( + ) + { + text_start = sbh.slider_pos(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + sbv_handler ( + ) + { + pos = sbv.slider_pos(); + parent.invalidate_rectangle(rect); + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + on_wheel_up ( + ) + { + if (rect.contains(lastx,lasty) && enabled && !hidden) + { + long new_pos = sbv.slider_pos(); + if (new_pos > 0) + { + pos = new_pos-1; + sbv.set_slider_pos(pos); + parent.invalidate_rectangle(rect); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + on_wheel_down ( + ) + { + if (rect.contains(lastx,lasty) && enabled && !hidden) + { + long new_pos = sbv.slider_pos(); + if (new_pos < sbv.max_slider_pos()) + { + pos = new_pos+1; + sbv.set_slider_pos(pos); + parent.invalidate_rectangle(rect); + } + } + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ) + { + if (text_area.contains(x,y) && btn == base_window::LEFT && enabled && !hidden ) + { + if ( ms_enabled == false || + (!(state&base_window::CONTROL)) && !(state&base_window::SHIFT)) + { + items.reset(); + while (items.move_next()) + { + items.element().is_selected = false; + } + } + + y -= text_area.top(); + long h = 0; + for (unsigned long i = pos; i < items.size(); ++i) + { + h += items[i].height; + if (h >= y) + { + if (ms_enabled) + { + if (state&base_window::CONTROL) + { + items[i].is_selected = !items[i].is_selected; + if (items[i].is_selected) + last_selected = i; + } + else if (state&base_window::SHIFT) + { + // we want to select everything between (and including) the + // current thing clicked and last_selected. + const unsigned long first = std::min(i,last_selected); + const unsigned long last = std::max(i,last_selected); + for (unsigned long j = first; j <= last; ++j) + items[j].is_selected = true; + } + else + { + items[i].is_selected = true; + last_selected = i; + if (is_double_click && event_handler.is_set()) + event_handler(i); + else if (single_click_event_handler.is_set()) + single_click_event_handler(i); + } + } + else + { + items[i].is_selected = true; + last_selected = i; + if (is_double_click && event_handler.is_set()) + event_handler(i); + else if (single_click_event_handler.is_set()) + single_click_event_handler(i); + } + + break; + } + } + + parent.invalidate_rectangle(rect); + } + } + +// ---------------------------------------------------------------------------------------- + + void list_box:: + set_z_order ( + long order + ) + { + sbv.set_z_order(order); + sbh.set_z_order(order); + drawable::set_z_order(order); + } + +// ---------------------------------------------------------------------------------------- + + unsigned long list_box:: + get_selected ( + ) const + { + auto_mutex M(m); + DLIB_ASSERT ( multiple_select_enabled() == false, + "\tunsigned long list_box::get_selected()" + ); + for (unsigned long i = 0; i < items.size(); ++i) + { + if (items[i].is_selected) + return i; + } + return items.size(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_WIDGETs_CPP_ + diff --git a/dlib/gui_widgets/widgets.h b/dlib/gui_widgets/widgets.h new file mode 100644 index 0000000000000000000000000000000000000000..e70ed858bed183616e9353c52bed94ebd3d10005 --- /dev/null +++ b/dlib/gui_widgets/widgets.h @@ -0,0 +1,3816 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_WIDGETs_ +#define DLIB_WIDGETs_ + +#include "../algs.h" +#include "widgets_abstract.h" +#include "drawable.h" +#include "../gui_core.h" +#include "fonts.h" +#include +#include +#include "../timer.h" +#include "base_widgets.h" +#include "../member_function_pointer.h" +#include "../array.h" +#include "../sequence.h" +#include "../dir_nav.h" +#include "../queue.h" +#include "../smart_pointers.h" +#include "style.h" +#include "../string.h" +#include "../misc_api.h" +#include + +#ifdef _MSC_VER +// This #pragma directive is also located in the algs.h file but for whatever +// reason visual studio 9 just ignores it when it is only there. + +// this is to disable the "'this' : used in base member initializer list" +// warning you get from some of the GUI objects since all the objects +// require that their parent class be passed into their constructor. +// In this case though it is totally safe so it is ok to disable this warning. +#pragma warning(disable : 4355) +#endif + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class label +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class label : public drawable + { + public: + label( + drawable_window& w + ) : + drawable(w), + text_color_(0,0,0) + { + enable_events(); + } + + ~label() + { disable_events(); parent.invalidate_rectangle(rect); } + + void set_text ( + const std::string& text + ); + + const std::string text ( + ) const; + + void set_text_color ( + const rgb_pixel color + ); + + const rgb_pixel text_color ( + ) const; + + void set_main_font ( + const font* f + ); + + private: + std::string text_; + rgb_pixel text_color_; + + + // restricted functions + label(label&); // copy constructor + label& operator=(label&); // assignment operator + + protected: + + void draw ( + const canvas& c + ) const; + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class button : public button_action + { + public: + button( + drawable_window& w + ) : + button_action(w), + btn_tooltip(w) + { + style.reset(new button_style_default()); + enable_events(); + } + + ~button() { disable_events(); parent.invalidate_rectangle(rect); } + + void set_size ( + unsigned long width, + unsigned long height + ); + + void set_name ( + const std::string& name_ + ); + + const std::string name ( + ) const; + + void set_tooltip_text ( + const std::string& text + ); + + void set_pos( + long x, + long y + ); + + const std::string tooltip_text ( + ) const; + + void set_main_font ( + const font* f + ); + + void show ( + ); + + void hide ( + ); + + void enable ( + ); + + void disable ( + ); + + template < + typename style_type + > + void set_style ( + const style_type& style_ + ) + { + auto_mutex M(m); + style.reset(new style_type(style_)); + rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top()); + parent.invalidate_rectangle(rect); + } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler_)() + ) + { + auto_mutex M(m); + event_handler.set(object,event_handler_); + event_handler_self.clear(); + } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler_)(button&) + ) + { + auto_mutex M(m); + event_handler_self.set(object,event_handler_); + event_handler.clear(); + } + + private: + + // restricted functions + button(button&); // copy constructor + button& operator=(button&); // assignment operator + + std::string name_; + tooltip btn_tooltip; + + member_function_pointer<>::kernel_1a event_handler; + member_function_pointer::kernel_1a event_handler_self; + + scoped_ptr style; + + protected: + + void draw ( + const canvas& c + ) const { style->draw_button(c,rect,hidden,enabled,*mfont,lastx,lasty,name_,is_depressed()); } + + void on_button_up ( + bool mouse_over + ); + + void on_mouse_over ( + ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); } + + void on_mouse_not_over ( + ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); } + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class toggle_button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class toggle_button : public button_action + { + /*! + INITIAL VALUE + - checked == false + + CONVENTION + - is_checked() == checked + !*/ + + public: + + toggle_button( + drawable_window& w + ) : + button_action(w), + btn_tooltip(w), + checked(false) + { + style.reset(new toggle_button_style_default()); + enable_events(); + } + + ~toggle_button() { disable_events(); parent.invalidate_rectangle(rect); } + + void set_name ( + const std::string& name + ); + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + + void set_tooltip_text ( + const std::string& text + ); + + const std::string tooltip_text ( + ) const; + + bool is_checked ( + ) const; + + const std::string name ( + ) const; + + void set_checked ( + ); + + void set_unchecked ( + ); + + void show ( + ); + + void hide ( + ); + + void enable ( + ); + + void disable ( + ); + + void set_main_font ( + const font* f + ); + + void set_pos ( + long x, + long y + ); + + template < + typename style_type + > + void set_style ( + const style_type& style_ + ) + { + auto_mutex M(m); + style.reset(new style_type(style_)); + rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top()); + parent.invalidate_rectangle(rect); + } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler_)() + ) + { + auto_mutex M(m); + event_handler.set(object,event_handler_); + event_handler_self.clear(); + } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler_)(toggle_button&) + ) + { + auto_mutex M(m); + event_handler_self.set(object,event_handler_); + event_handler.clear(); + } + + private: + + // restricted functions + toggle_button(toggle_button&); // copy constructor + toggle_button& operator=(toggle_button&); // assignment operator + + std::string name_; + tooltip btn_tooltip; + bool checked; + + member_function_pointer<>::kernel_1a event_handler; + member_function_pointer::kernel_1a event_handler_self; + + scoped_ptr style; + + protected: + + void draw ( + const canvas& c + ) const { style->draw_toggle_button(c,rect,hidden,enabled,*mfont,lastx,lasty,name_,is_depressed(),checked); } + + void on_button_up ( + bool mouse_over + ); + + void on_mouse_over ( + ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); } + + void on_mouse_not_over ( + ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); } + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class text_field +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class text_field : public drawable + { + /*! + INITIAL VALUE + text_color_ == rgb_pixel(0,0,0) + bg_color_ == rgb_pixel(255,255,255) + cursor_pos == 0 + text_width == 0 + text_ == "" + has_focus == false + cursor_visible == false + recent_movement == false + highlight_start == 0 + highlight_end == -1 + shift_pos == -1 + text_pos == 0 + + CONVENTION + - cursor_pos == the position of the cursor in the string text_. The + cursor appears before the letter text_[cursor_pos] + - cursor_x == the x coordinate of the cursor relative to the left side + of rect. i.e. the number of pixels that separate the cursor from the + left side of the text_field. + - has_focus == true if this text field has keyboard input focus + - cursor_visible == true if the cursor should be painted + - text_ == text() + - text_pos == the index of the first letter in text_ that appears in + this text field. + - text_width == the width of text_[text_pos] though text_[text.size()-1] + + - if (has_focus && the user has recently moved the cursor) then + - recent_movement == true + - else + - recent_movement == false + + - if (highlight_start <= highlight_end) then + - text[highlight_start] though text[highlight_end] should be + highlighted + + - if (shift_pos != -1) then + - has_focus == true + - the shift key is being held down or the left mouse button is + being held down. + - shift_pos == the position of the cursor when the shift or mouse key + was first pressed. + + - text_color() == text_color_ + - background_color() == bg_color_ + !*/ + + public: + text_field( + drawable_window& w + ) : + drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE), + text_color_(0,0,0), + bg_color_(255,255,255), + text_width(0), + text_pos(0), + recent_movement(false), + has_focus(false), + cursor_visible(false), + cursor_pos(0), + highlight_start(0), + highlight_end(-1), + shift_pos(-1), + t(*this,&text_field::timer_action) + { + rect.set_bottom(mfont->height()+ (mfont->height()-mfont->ascender())*2); + rect.set_right(9); + cursor_x = (mfont->height()-mfont->ascender()); + enable_events(); + + t.set_delay_time(500); + } + + ~text_field ( + ) + { + disable_events(); + parent.invalidate_rectangle(rect); + t.stop_and_wait(); + } + + void set_text ( + const std::string& text_ + ); + + const std::string text ( + ) const; + + void set_text_color ( + const rgb_pixel color + ); + + const rgb_pixel text_color ( + ) const; + + void set_background_color ( + const rgb_pixel color + ); + + const rgb_pixel background_color ( + ) const; + + void set_width ( + unsigned long width + ); + + void set_main_font ( + const font* f + ); + + int next_free_user_event_number ( + ) const + { + return drawable::next_free_user_event_number()+1; + } + + void disable ( + ); + + void hide ( + ); + + template < + typename T + > + void set_text_modified_handler ( + T& object, + void (T::*event_handler)() + ) + { + auto_mutex M(m); + text_modified_handler.set(object,event_handler); + } + + private: + + void on_user_event ( + int num + ) + { + // ignore this user event if it isn't for us + if (num != drawable::next_free_user_event_number()) + return; + + if (recent_movement == false) + { + cursor_visible = !cursor_visible; + parent.invalidate_rectangle(rect); + } + else + { + if (cursor_visible == false) + { + cursor_visible = true; + parent.invalidate_rectangle(rect); + } + recent_movement = false; + } + } + + void timer_action ( + ) { parent.trigger_user_event(this,drawable::next_free_user_event_number()); } + /*! + ensures + - flips the state of cursor_visible + !*/ + + void move_cursor ( + unsigned long pos + ); + /*! + requires + - pos <= text_.size() + ensures + - moves the cursor to the position given by pos and moves the text + in the text box if necessary + - if the position changes then the parent window will be updated + !*/ + + rectangle get_text_rect ( + ) const; + /*! + ensures + - returns the rectangle that should contain the text in this widget + !*/ + + std::string text_; + rgb_pixel text_color_; + rgb_pixel bg_color_; + + unsigned long text_width; + unsigned long text_pos; + + + bool recent_movement; + bool has_focus; + bool cursor_visible; + long cursor_pos; + unsigned long cursor_x; + + // this tells you what part of the text is highlighted + long highlight_start; + long highlight_end; + long shift_pos; + member_function_pointer<>::kernel_1a_c text_modified_handler; + + + timer::kernel_2a t; + + // restricted functions + text_field(text_field&); // copy constructor + text_field& operator=(text_field&); // assignment operator + + + protected: + + void draw ( + const canvas& c + ) const; + + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ); + + void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ); + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ); + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class check_box +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class check_box : public toggle_button + { + public: + check_box( + drawable_window& w + ) : toggle_button(w) + { + set_style(toggle_button_style_check_box()); + } + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class radio_button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class radio_button : public toggle_button + { + public: + radio_button ( + drawable_window& w + ) : toggle_button(w) + { + set_style(toggle_button_style_radio_button()); + } + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class tabbed_display +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class tabbed_display : public drawable + { + /*! + INITIAL VALUE + - tabs.size() == 0 + - selected_tab_ == 0 + + CONVENTION + - number_of_tabs() == tabs.size() + - tab_name(idx) == tabs[idx] + - if (tabs.size() > 0) then + - selected_tab_ == the index of the tab that is currently selected + + - for all valid i: + - tabs[i].width == mfont->compute_size(tabs[i].name) + - tabs[i].rect == the rectangle that defines where this tab is + - if (tabs[i].group != 0) then + - tabs[i].group == a pointer to the widget_group for this tab. + + - left_pad == the amount of padding in a tab to the left of the name string. + - right_pad == the amount of padding in a tab to the right of the name string. + - top_pad == the amount of padding in a tab to the top of the name string. + - bottom_pad == the amount of padding in a tab to the bottom of the name string. + + - if (event_handler.is_set()) then + - event_handler() is what is called to process click events + on this object. + !*/ + + public: + + tabbed_display( + drawable_window& w + ); + + virtual ~tabbed_display( + ); + + void set_size ( + unsigned long width, + unsigned long height + ); + + void set_number_of_tabs ( + unsigned long num + ); + + unsigned long number_of_tabs ( + ) const; + + const std::string& tab_name ( + unsigned long idx + ) const; + + void set_tab_name ( + unsigned long idx, + const std::string& new_name + ); + + void set_pos ( + long x, + long y + ); + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*eh)(unsigned long new_idx,unsigned long old_idx) + ) + { + auto_mutex M(m); + event_handler.set(object,eh); + } + + void set_tab_group ( + unsigned long idx, + widget_group& group + ); + + void show ( + ); + + void hide ( + ); + + void enable ( + ); + + void disable ( + ); + + void set_main_font ( + const font* f + ); + + void fit_to_contents ( + ); + + protected: + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ); + + void draw ( + const canvas& c + ) const; + + private: + void recompute_tabs ( + ); + /*! + ensures + - recomputes the rectangles for all the tabs and makes this object + wider if needed + !*/ + + void draw_tab ( + const rectangle& tab, + const canvas& c + ) const; + /*! + ensures + - draws the outline of a tab as given by the rectangle onto c + !*/ + + struct tab_data + { + tab_data() : width(0), group(0) {} + + std::string name; + unsigned long width; + rectangle rect; + widget_group* group; + }; + + unsigned long selected_tab_; + + array::kernel_2a_c tabs; + + const long left_pad; + const long right_pad; + const long top_pad; + const long bottom_pad; + + member_function_pointer::kernel_1a event_handler; + + // restricted functions + tabbed_display(tabbed_display&); // copy constructor + tabbed_display& operator=(tabbed_display&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class named_rectangle +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class named_rectangle : public drawable + { + /*! + INITIAL VALUE + name == "" + + CONVENTION + name_ == name() + !*/ + + public: + + named_rectangle( + drawable_window& w + ); + + virtual ~named_rectangle( + ); + + void set_size ( + unsigned long width, + unsigned long height + ); + + void set_name ( + const std::string& name + ); + + const std::string name ( + ) const; + + void wrap_around ( + const rectangle& rect + ); + + void set_main_font ( + const font* f + ); + + protected: + + void draw ( + const canvas& c + ) const; + + private: + + void make_name_fit_in_rect ( + ); + + std::string name_; + unsigned long name_width; + unsigned long name_height; + + // restricted functions + named_rectangle(named_rectangle&); // copy constructor + named_rectangle& operator=(named_rectangle&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class mouse_tracker +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class mouse_tracker : public dragable + { + + public: + + mouse_tracker( + drawable_window& w + ); + + ~mouse_tracker( + ); + + void show ( + ); + + void hide ( + ); + + void enable ( + ); + + void disable ( + ); + + void set_pos ( + long x, + long y + ); + + void set_main_font ( + const font* f + ); + + protected: + + void on_mouse_move ( + unsigned long state, + long x, + long y + ); + + void on_drag ( + ); + + void draw ( + const canvas& c + ) const; + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ); + + + private: + + const long offset; + named_rectangle nr; + label x_label; + label y_label; + std::ostringstream sout; + + long click_x, click_y; + + // restricted functions + mouse_tracker(mouse_tracker&); // copy constructor + mouse_tracker& operator=(mouse_tracker&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // function message_box() +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace message_box_helper + { + class box_win : public drawable_window + { + public: + box_win ( + const std::string& title_, + const std::string& message_ + ) : + drawable_window(false), + title(title_), + message(message_), + msg(*this), + btn_ok(*this) + { + msg.set_pos(20,20); + msg.set_text(message); + rectangle msg_rect = msg.get_rect(); + btn_ok.set_name("OK"); + btn_ok.set_size(60,btn_ok.height()); + if (msg_rect.width() >= 60) + btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15); + else + btn_ok.set_pos(20,msg_rect.bottom()+15); + btn_ok.set_click_handler(*this,&box_win::on_click); + + rectangle size = btn_ok.get_rect() + msg_rect; + set_size(size.right()+20,size.bottom()+20); + + + show(); + set_title(title_); + } + + ~box_win ( + ) + { + close_window(); + } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler_)() + ) + { + auto_mutex M(wm); + event_handler.set(object,event_handler_); + } + + private: + + static void deleter_thread ( + void* param + ) + { + // The point of this extra member function pointer stuff is to allow the user + // to end the program from within the callback. So we want to destroy the + // window *before* we call their callback. + box_win& w = *reinterpret_cast(param); + w.close_window(); + member_function_pointer<>::kernel_1a event_handler(w.event_handler); + delete &w; + if (event_handler.is_set()) + event_handler(); + } + + void on_click ( + ) + { + hide(); + create_new_thread(&deleter_thread,this); + } + + on_close_return_code on_window_close ( + ) + { + // The point of this extra member function pointer stuff is to allow the user + // to end the program within the callback. So we want to destroy the + // window *before* we call their callback. + member_function_pointer<>::kernel_1a event_handler_copy(event_handler); + delete this; + if (event_handler_copy.is_set()) + event_handler_copy(); + return CLOSE_WINDOW; + } + + const std::string title; + const std::string message; + label msg; + button btn_ok; + + member_function_pointer<>::kernel_1a event_handler; + }; + + class blocking_box_win : public drawable_window + { + public: + blocking_box_win ( + const std::string& title_, + const std::string& message_ + ) : + drawable_window(false), + title(title_), + message(message_), + msg(*this), + btn_ok(*this) + { + msg.set_pos(20,20); + msg.set_text(message); + rectangle msg_rect = msg.get_rect(); + btn_ok.set_name("OK"); + btn_ok.set_size(60,btn_ok.height()); + if (msg_rect.width() >= 60) + btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15); + else + btn_ok.set_pos(20,msg_rect.bottom()+15); + btn_ok.set_click_handler(*this,&blocking_box_win::on_click); + + rectangle size = btn_ok.get_rect() + msg_rect; + set_size(size.right()+20,size.bottom()+20); + + + set_title(title_); + show(); + } + + ~blocking_box_win ( + ) + { + close_window(); + } + + private: + + void on_click ( + ) + { + close_window(); + } + + const std::string title; + const std::string message; + label msg; + button btn_ok; + }; + } + + template < + typename T + > + void message_box ( + const std::string& title, + const std::string& message, + T& object, + void (T::*event_handler)() + ) + { + using namespace message_box_helper; + box_win* win = new box_win(title,message); + win->set_click_handler(object,event_handler); + } + + inline void message_box ( + const std::string& title, + const std::string& message + ) + { + using namespace message_box_helper; + new box_win(title,message); + } + + inline void message_box_blocking ( + const std::string& title, + const std::string& message + ) + { + using namespace message_box_helper; + blocking_box_win w(title,message); + w.wait_until_closed(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class list_box +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class list_box : public drawable, + public enumerable + { + /*! + INITIAL VALUE + - ms_enabled == false + - items.size() == 0 + - pos == 0 + - text_start = 0 + - last_selected = 0 + + CONVENTION + - size() == items.size() + - (*this)[i] == items[i].name + - is_selected(i) == items[i].is_selected + + - items[i].width == the width of items[i].name as given by font::compute_size() + - items[i].height == the height of items[i].name as given by font::compute_size() + + - items[pos] == the item currently being displayed at the top of the list box + - sbv == our vertical scroll bar + - sbh == our horizontal scroll bar + - text_area == the area that is free to be used for text display (e.g. not occluded + by scroll bars or anything) + - text_start == the amount of pixels the text should be shifted to the left (but the + part outside this widget should be clipped). This is used by the horizontal + scroll bar. + - pos == the first line that is shown in the list box + - last_selected == the last item the user selected + !*/ + + public: + + list_box( + drawable_window& w + ); + + ~list_box( + ); + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + + void set_pos ( + long x, + long y + ); + + bool is_selected ( + unsigned long index + ) const; + + void select ( + unsigned long index + ); + + void unselect ( + unsigned long index + ); + + template + void get_selected ( + T& list + ) const + { + auto_mutex M(m); + list.clear(); + for (unsigned long i = 0; i < items.size(); ++i) + { + if (items[i].is_selected) + { + unsigned long idx = i; + list.enqueue(idx); + } + } + } + + template + void load ( + const T& list + ) + { + auto_mutex M(m); + items.clear(); + unsigned long i = 0; + items.set_max_size(list.size()); + items.set_size(list.size()); + list.reset(); + while (list.move_next()) + { + items[i].is_selected = false; + items[i].name = list.element(); + mfont->compute_size(items[i].name,items[i].width, items[i].height); + ++i; + } + pos = 0; + adjust_sliders(); + parent.invalidate_rectangle(rect); + last_selected = 0; + } + + const std::string& operator[] ( + unsigned long index + ) const; + + bool multiple_select_enabled ( + ) const; + + void enable_multiple_select ( + ); + + void disable_multiple_select ( + ); + + template < + typename T + > + void set_double_click_handler ( + T& object, + void (T::*eh)(unsigned long index) + ) { auto_mutex M(m); event_handler.set(object,eh); } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*eh)(unsigned long index) + ) { auto_mutex M(m); single_click_event_handler.set(object,eh); } + + bool at_start ( + ) const; + + void reset ( + ) const; + + bool current_element_valid ( + ) const; + + const std::string& element ( + ) const; + + const std::string& element ( + ); + + bool move_next ( + ) const; + + unsigned long size ( + ) const; + + void show( + ); + + void hide ( + ); + + void enable ( + ); + + void disable ( + ); + + void set_z_order ( + long order + ); + + unsigned long get_selected ( + ) const; + + void set_main_font ( + const font* f + ); + + private: + + void sbv_handler ( + ); + + void sbh_handler ( + ); + + void adjust_sliders ( + ); + /*! + requires + - m is locked + ensures + - adjusts the scroll bars so that they are properly displayed + !*/ + + void on_wheel_up ( + ); + + void on_wheel_down ( + ); + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ); + + void draw ( + const canvas& c + ) const; + + struct data + { + std::string name; + bool is_selected; + unsigned long width; + unsigned long height; + }; + + const static long pad = 2; + + bool ms_enabled; + array::kernel_2a_c items; + member_function_pointer::kernel_1a event_handler; + member_function_pointer::kernel_1a single_click_event_handler; + unsigned long pos; + unsigned long text_start; + unsigned long last_selected; + scroll_bar sbv; + scroll_bar sbh; + rectangle text_area; + + + // restricted functions + list_box(list_box&); // copy constructor + list_box& operator=(list_box&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // function open_file_box() +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace open_file_box_helper + { + class box_win : public drawable_window + { + public: + box_win ( + const std::string& title, + bool has_text_field = false + ) : + lbl_dirs(*this), + lbl_files(*this), + lbl_file_name(*this), + lb_dirs(*this), + lb_files(*this), + btn_ok(*this), + btn_cancel(*this), + btn_root(*this), + tf_file_name(*this) + { + if (has_text_field == false) + { + tf_file_name.hide(); + lbl_file_name.hide(); + } + else + { + lbl_file_name.set_text("File: "); + } + + cur_dir = -1; + set_size(500,300); + + lbl_dirs.set_text("Directories:"); + lbl_files.set_text("Files:"); + btn_ok.set_name("Ok"); + btn_cancel.set_name("Cancel"); + btn_root.set_name("/"); + + btn_root.set_click_handler(*this,&box_win::on_root_click); + btn_cancel.set_click_handler(*this,&box_win::on_cancel_click); + btn_ok.set_click_handler(*this,&box_win::on_open_click); + lb_dirs.set_double_click_handler(*this,&box_win::on_dirs_click); + lb_files.set_click_handler(*this,&box_win::on_files_click); + lb_files.set_double_click_handler(*this,&box_win::on_files_double_click); + + + btn_root.set_pos(5,5); + + set_sizes(); + set_title(title); + + on_root_click(); + + // make it so that the file box starts out in our current working + // directory + std::string full_name(get_current_dir()); + + while (full_name.size() > 0) + { + std::string::size_type pos = full_name.find_first_of("\\/"); + std::string left(full_name.substr(0,pos)); + if (pos != std::string::npos) + full_name = full_name.substr(pos+1); + else + full_name.clear(); + + if (left.size() > 0) + enter_folder(left); + } + + + show(); + } + + ~box_win ( + ) + { + close_window(); + } + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler_)(const std::string&) + ) + { + auto_mutex M(wm); + event_handler.set(object,event_handler_); + } + + private: + + void set_sizes( + ) + { + unsigned long width, height; + get_size(width,height); + + + if (lbl_file_name.is_hidden()) + { + lbl_dirs.set_pos(0,btn_root.bottom()+5); + lb_dirs.set_pos(0,lbl_dirs.bottom()); + lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10); + + lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5); + lb_files.set_pos(lb_dirs.right(),lbl_files.bottom()); + lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10); + + btn_ok.set_pos(width - btn_ok.width()-25,lb_files.bottom()+5); + btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,lb_files.bottom()+5); + } + else + { + + lbl_dirs.set_pos(0,btn_root.bottom()+5); + lb_dirs.set_pos(0,lbl_dirs.bottom()); + lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10-tf_file_name.height()); + + lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5); + lb_files.set_pos(lb_dirs.right(),lbl_files.bottom()); + lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10-tf_file_name.height()); + + lbl_file_name.set_pos(lb_files.left(), lb_files.bottom()+8); + tf_file_name.set_pos(lbl_file_name.right(), lb_files.bottom()+5); + tf_file_name.set_width(width-tf_file_name.left()-5); + + btn_ok.set_pos(width - btn_ok.width()-25,tf_file_name.bottom()+5); + btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,tf_file_name.bottom()+5); + } + + } + + void on_window_resized ( + ) + { + set_sizes(); + } + + void deleter_thread ( + ) + { + close_window(); + delete this; + } + + void enter_folder ( + const std::string& folder_name + ) + { + if (btn_root.is_checked()) + btn_root.set_unchecked(); + if (cur_dir != -1) + sob[cur_dir]->set_unchecked(); + + + const std::string old_path = path; + const long old_cur_dir = cur_dir; + + scoped_ptr new_btn(new toggle_button(*this)); + new_btn->set_name(folder_name); + new_btn->set_click_handler(*this,&box_win::on_path_button_click); + + // remove any path buttons that won't be part of the path anymore + if (sob.size()) + { + while (sob.size() > (unsigned long)(cur_dir+1)) + { + scoped_ptr junk; + sob.remove(cur_dir+1,junk); + } + } + + if (sob.size()) + new_btn->set_pos(sob[sob.size()-1]->right()+5,sob[sob.size()-1]->top()); + else + new_btn->set_pos(btn_root.right()+5,btn_root.top()); + + cur_dir = sob.size(); + sob.add(sob.size(),new_btn); + + path += folder_name + directory::get_separator(); + if (set_dir(prefix + path) == false) + { + sob.remove(sob.size()-1,new_btn); + path = old_path; + cur_dir = old_cur_dir; + } + + sob[cur_dir]->set_checked(); + } + + void on_dirs_click ( + unsigned long idx + ) + { + enter_folder(lb_dirs[idx]); + } + + void on_files_click ( + unsigned long idx + ) + { + if (tf_file_name.is_hidden() == false) + { + tf_file_name.set_text(lb_files[idx]); + } + } + + void on_files_double_click ( + unsigned long + ) + { + on_open_click(); + } + + void on_cancel_click ( + ) + { + hide(); + create_new_thread(*this); + } + + void on_open_click ( + ) + { + if (lb_files.get_selected() != lb_files.size() || tf_file_name.text().size() > 0) + { + if (event_handler.is_set()) + { + if (tf_file_name.is_hidden()) + event_handler(prefix + path + lb_files[lb_files.get_selected()]); + else if (tf_file_name.text().size() > 0) + event_handler(prefix + path + tf_file_name.text()); + } + hide(); + create_new_thread(*this); + } + } + + void on_path_button_click ( + toggle_button& btn + ) + { + if (btn_root.is_checked()) + btn_root.set_unchecked(); + if (cur_dir != -1) + sob[cur_dir]->set_unchecked(); + std::string new_path; + + for (unsigned long i = 0; i < sob.size(); ++i) + { + new_path += sob[i]->name() + directory::get_separator(); + if (sob[i].get() == &btn) + { + cur_dir = i; + sob[i]->set_checked(); + break; + } + } + if (path != new_path) + { + path = new_path; + set_dir(prefix+path); + } + } + + struct case_insensitive_compare + { + bool operator() ( + const std::string& a, + const std::string& b + ) const + { + std::string::size_type i, size; + size = std::min(a.size(),b.size()); + for (i = 0; i < size; ++i) + { + if (std::tolower(a[i]) < std::tolower(b[i])) + return true; + else if (std::tolower(a[i]) > std::tolower(b[i])) + return false; + } + if (a.size() < b.size()) + return true; + else + return false; + } + }; + + bool set_dir ( + const std::string& dir + ) + { + try + { + directory d(dir); + queue::kernel_1a_c qod; + queue::kernel_1a_c qof; + queue::sort_1a_c qos; + d.get_dirs(qod); + d.get_files(qof); + + qod.reset(); + while (qod.move_next()) + { + std::string temp = qod.element().name(); + qos.enqueue(temp); + } + qos.sort(case_insensitive_compare()); + lb_dirs.load(qos); + qos.clear(); + + qof.reset(); + while (qof.move_next()) + { + std::string temp = qof.element().name(); + qos.enqueue(temp); + } + qos.sort(case_insensitive_compare()); + lb_files.load(qos); + return true; + } + catch (directory::listing_error& ) + { + return false; + } + catch (directory::dir_not_found&) + { + return false; + } + } + + void on_root_click ( + ) + { + btn_root.set_checked(); + if (cur_dir != -1) + sob[cur_dir]->set_unchecked(); + + queue::kernel_1a_c qod, qod2; + queue::kernel_1a_c qof; + queue::sort_1a_c qos; + get_filesystem_roots(qod); + path.clear(); + cur_dir = -1; + if (qod.size() == 1) + { + qod.current().get_files(qof); + qod.current().get_dirs(qod2); + prefix = qod.current().full_name(); + + qod2.reset(); + while (qod2.move_next()) + { + std::string temp = qod2.element().name(); + qos.enqueue(temp); + } + qos.sort(case_insensitive_compare()); + lb_dirs.load(qos); + qos.clear(); + + qof.reset(); + while (qof.move_next()) + { + std::string temp = qof.element().name(); + qos.enqueue(temp); + } + qos.sort(case_insensitive_compare()); + lb_files.load(qos); + } + else + { + prefix.clear(); + qod.reset(); + while (qod.move_next()) + { + std::string temp = qod.element().full_name(); + temp = temp.substr(0,temp.size()-1); + qos.enqueue(temp); + } + qos.sort(case_insensitive_compare()); + lb_dirs.load(qos); + qos.clear(); + lb_files.load(qos); + } + } + + on_close_return_code on_window_close ( + ) + { + delete this; + return CLOSE_WINDOW; + } + + label lbl_dirs; + label lbl_files; + label lbl_file_name; + list_box lb_dirs; + list_box lb_files; + button btn_ok; + button btn_cancel; + toggle_button btn_root; + text_field tf_file_name; + std::string path; + std::string prefix; + int cur_dir; + + member_function_pointer::kernel_1a event_handler; + sequence >::kernel_2a_c sob; + }; + } + + template < + typename T + > + void open_file_box ( + T& object, + void (T::*event_handler)(const std::string&) + ) + { + using namespace open_file_box_helper; + box_win* win = new box_win("Open File",true); + win->set_click_handler(object,event_handler); + } + + template < + typename T + > + void open_existing_file_box ( + T& object, + void (T::*event_handler)(const std::string&) + ) + { + using namespace open_file_box_helper; + box_win* win = new box_win("Open File"); + win->set_click_handler(object,event_handler); + } + + template < + typename T + > + void save_file_box ( + T& object, + void (T::*event_handler)(const std::string&) + ) + { + using namespace open_file_box_helper; + box_win* win = new box_win("Save File",true); + win->set_click_handler(object,event_handler); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class menu_bar +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class menu_bar : public drawable + { + /*! + INITIAL VALUE + - menus.size() == 0 + - open_menu == 0 + + CONVENTION + - size() == menus.size() + - all menu data is stored in menus + - menus[x].name == the name of the xth menu + - if (menus[x].underline_pos != std::string::npos) then + - menus[x].underline_pos == the position of the character in the + menu name that should be underlined + - menus[x].underline_p1 != menus[x].underline_p2 + and these two points define the underline bar + - else + - menus[x].underline_p1 == menus[x].underline_p2 + - menus[x].menu == menu(x) + - menus[x].rect == the rectangle in which menus[x].name is drawn + - menus[x].bgrect == the rectangle for the xth menu button + + - if (there is an open menu on the screen) then + - open_menu == the index of the open menu from menus + - else + - open_menu == menus.size() + !*/ + + public: + menu_bar( + drawable_window& w + ) : + drawable(w, 0xFFFF), // listen for all events + open_menu(0) + { + adjust_position(); + enable_events(); + } + + ~menu_bar() + { disable_events(); parent.invalidate_rectangle(rect); } + + // this function does nothing + void set_pos(long,long){} + + void set_main_font ( + const font* f + ) + { + auto_mutex M(m); + mfont = f; + adjust_position(); + compute_menu_geometry(); + parent.invalidate_rectangle(rect); + } + + void set_number_of_menus ( + unsigned long num + ) + { + auto_mutex M(m); + menus.set_max_size(num); + menus.set_size(num); + open_menu = menus.size(); + compute_menu_geometry(); + + for (unsigned long i = 0; i < menus.size(); ++i) + { + menus[i].menu.set_on_hide_handler(*this,&menu_bar::on_popup_hide); + } + + parent.invalidate_rectangle(rect); + } + + unsigned long number_of_menus ( + ) const + { + auto_mutex M(m); + return menus.size(); + } + + void set_menu_name ( + unsigned long idx, + const std::string name, + char underline_ch = '\0' + ) + { + DLIB_ASSERT ( idx < number_of_menus() , + "\tvoid menu_bar::set_menu_name()" + << "\n\tidx: " << idx + << "\n\tnumber_of_menus(): " << number_of_menus() + ); + auto_mutex M(m); + menus[idx].name = name.c_str(); + menus[idx].underline_pos = name.find_first_of(underline_ch); + compute_menu_geometry(); + parent.invalidate_rectangle(rect); + } + + const std::string menu_name ( + unsigned long idx + ) const + { + DLIB_ASSERT ( idx < number_of_menus() , + "\tstd::string menu_bar::menu_name()" + << "\n\tidx: " << idx + << "\n\tnumber_of_menus(): " << number_of_menus() + ); + auto_mutex M(m); + return menus[idx].name.c_str(); + } + + popup_menu& menu ( + unsigned long idx + ) + { + DLIB_ASSERT ( idx < number_of_menus() , + "\tpopup_menu& menu_bar::menu()" + << "\n\tidx: " << idx + << "\n\tnumber_of_menus(): " << number_of_menus() + ); + auto_mutex M(m); + return menus[idx].menu; + } + + const popup_menu& menu ( + unsigned long idx + ) const + { + DLIB_ASSERT ( idx < number_of_menus() , + "\tconst popup_menu& menu_bar::menu()" + << "\n\tidx: " << idx + << "\n\tnumber_of_menus(): " << number_of_menus() + ); + auto_mutex M(m); + return menus[idx].menu; + } + + protected: + + void on_window_resized ( + ) + { + adjust_position(); + hide_menu(); + } + + void draw ( + const canvas& c + ) const + { + rectangle area(rect.intersect(c)); + if (area.is_empty()) + return; + + const unsigned char opacity = 40; + fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(255,255,255,opacity), + rgb_alpha_pixel(0,0,0,opacity)); + + // first draw the border between the menu and the rest of the window + draw_line(c, point(rect.left(),rect.bottom()-1), + point(rect.right(),rect.bottom()-1), 100); + draw_line(c, point(rect.left(),rect.bottom()), + point(rect.right(),rect.bottom()), 255); + + // now draw all the menu buttons + for (unsigned long i = 0; i < menus.size(); ++i) + { + mfont->draw_string(c,menus[i].rect, menus[i].name ); + if (menus[i].underline_p1 != menus[i].underline_p2) + draw_line(c, menus[i].underline_p1, menus[i].underline_p2); + + if (open_menu == i) + { + fill_rect_with_vertical_gradient(c, menus[i].bgrect,rgb_alpha_pixel(255,255,0,40), rgb_alpha_pixel(0,0,0,40)); + } + } + } + + void on_window_moved ( + ) + { + hide_menu(); + } + + void on_focus_lost ( + ) + { + hide_menu(); + } + + void on_mouse_down ( + unsigned long btn, + unsigned long , + long x, + long y, + bool + ) + { + + if (rect.contains(x,y) == false || btn != (unsigned long)base_window::LEFT) + { + hide_menu(); + return; + } + + unsigned long old_menu = menus.size(); + + // if a menu is currently open then save its index + if (open_menu != menus.size()) + { + old_menu = open_menu; + hide_menu(); + } + + // figure out which menu should be open if any + for (unsigned long i = 0; i < menus.size(); ++i) + { + if (menus[i].bgrect.contains(x,y)) + { + if (old_menu != i) + show_menu(i); + + break; + } + } + + } + + void on_mouse_move ( + unsigned long , + long x, + long y + ) + { + // if the mouse is over the menu_bar and some menu is currently open + if (rect.contains(x,y) && open_menu != menus.size()) + { + // if the mouse is still in the same rectangle then don't do anything + if (menus[open_menu].bgrect.contains(x,y) == false) + { + // figure out which menu should be instead + for (unsigned long i = 0; i < menus.size(); ++i) + { + if (menus[i].bgrect.contains(x,y)) + { + show_menu(i); + break; + } + } + + } + } + } + + void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + if (state&base_window::KBD_MOD_ALT) + { + // check if the key matches any of our underlined keys + for (unsigned long i = 0; i < menus.size(); ++i) + { + // if we have found a matching key + if (is_printable && + menus[i].underline_pos != std::string::npos && + std::tolower(menus[i].name[menus[i].underline_pos]) == std::tolower(key)) + { + show_menu(i); + menus[open_menu].menu.select_first_item(); + return; + } + } + } + + if (open_menu != menus.size()) + { + unsigned long i = open_menu; + // if the submenu doesn't use this key for something then we will + if (menus[open_menu].menu.forwarded_on_keydown(key,is_printable,state) == false) + { + if (key == base_window::KEY_LEFT) + { + i = (i+menus.size()-1)%menus.size(); + show_menu(i); + menus[open_menu].menu.select_first_item(); + } + else if (key == base_window::KEY_RIGHT) + { + i = (i+1)%menus.size(); + show_menu(i); + menus[open_menu].menu.select_first_item(); + } + else if (key == base_window::KEY_ESC) + { + hide_menu(); + } + } + } + } + + private: + + void show_menu ( + unsigned long i + ) + { + rectangle temp; + + // menu already open so do nothing + if (i == open_menu) + return; + + // if a menu is currently open + if (open_menu != menus.size()) + { + menus[open_menu].menu.hide(); + temp = menus[open_menu].bgrect; + } + + // display the new menu + open_menu = i; + long wx, wy; + parent.get_pos(wx,wy); + wx += menus[i].bgrect.left(); + wy += menus[i].bgrect.bottom()+1; + menus[i].menu.set_pos(wx,wy); + menus[i].menu.show(); + parent.invalidate_rectangle(menus[i].bgrect+temp); + } + + void hide_menu ( + ) + { + // if a menu is currently open + if (open_menu != menus.size()) + { + menus[open_menu].menu.hide(); + parent.invalidate_rectangle(menus[open_menu].bgrect); + open_menu = menus.size(); + } + } + + void on_popup_hide ( + ) + { + // if a menu is currently open + if (open_menu != menus.size()) + { + parent.invalidate_rectangle(menus[open_menu].bgrect); + open_menu = menus.size(); + } + } + + struct menu_data + { + std::string name; + std::string::size_type underline_pos; + popup_menu menu; + rectangle rect; + rectangle bgrect; + point underline_p1; + point underline_p2; + }; + + array::kernel_2a_c menus; + unsigned long open_menu; + + // restricted functions + menu_bar(menu_bar&); // copy constructor + menu_bar& operator=(menu_bar&); // assignment operator + + void compute_menu_geometry ( + ) + { + long x = 7; + long bg_x = 0; + for (unsigned long i = 0; i < menus.size(); ++i) + { + // compute the locations of the text rectangles + menus[i].rect.set_top(5); + menus[i].rect.set_left(x); + menus[i].rect.set_bottom(rect.bottom()-2); + + unsigned long width, height; + mfont->compute_size(menus[i].name,width,height); + menus[i].rect = resize_rect_width(menus[i].rect, width); + x = menus[i].rect.right()+10; + + menus[i].bgrect.set_top(0); + menus[i].bgrect.set_left(bg_x); + menus[i].bgrect.set_bottom(rect.bottom()-2); + menus[i].bgrect.set_right(x-5); + bg_x = menus[i].bgrect.right()+1; + + if (menus[i].underline_pos != std::string::npos) + { + // now compute the location of the underline bar + rectangle r1 = mfont->compute_cursor_rect( + menus[i].rect, + menus[i].name, + menus[i].underline_pos); + + rectangle r2 = mfont->compute_cursor_rect( + menus[i].rect, + menus[i].name, + menus[i].underline_pos+1); + + menus[i].underline_p1.x() = r1.left()+1; + menus[i].underline_p2.x() = r2.left()-1; + menus[i].underline_p1.y() = r1.bottom()-mfont->height()+mfont->ascender()+2; + menus[i].underline_p2.y() = r2.bottom()-mfont->height()+mfont->ascender()+2; + } + else + { + // there is no underline in this case + menus[i].underline_p1 = menus[i].underline_p2; + } + + } + } + + void adjust_position ( + ) + { + unsigned long width, height; + rectangle old(rect); + parent.get_size(width,height); + rect.set_left(0); + rect.set_top(0); + rect = resize_rect(rect,width,mfont->height()+10); + parent.invalidate_rectangle(old+rect); + } + + }; + +// ---------------------------------------------------------------------------------------- + + template + class directed_graph_drawer : public zoomable_region + { + /*! + INITIAL VALUE + - edge_selected == false + - mouse_drag == false + - selected_node == 0 + - graph_.number_of_nodes() == 0 + - external_graph.number_of_nodes() == 0 + - radius == 25 + - last_mouse_click_in_display == false + + CONVENTION + - radius == the radius of the nodes when they aren't zoomed + - external_graph and graph_ have the same graph structure + - external_graph == graph() + - external_graph.node(i) == graph_node(i) + + - if (one of the nodes is selected) then + - selected_node < graph_.number_of_nodes() + - graph_.node(selected_node) == the selected node + - else + - selected_node == graph_.number_of_nodes() + + - if (the user is dragging a node with the mouse) then + - mouse_drag == true + - drag_offset == the vector from the mouse position to the + center of the node + - else + - mouse_drag == false + + - if (the user has selected an edge) then + - edge_selected == true + - the parent node is graph_.node(selected_edge_parent) + - the child node is graph_.node(selected_edge_parent) + - else + - edge_selected == false + + - for all valid i: + - graph_.node(i).data.p == the center of the node in graph space + - graph_.node(i).data.name == node_label(i) + - graph_.node(i).data.color == node_color(i) + - graph_.node(i).data.str_rect == a rectangle sized to contain graph_.node(i).data.name + + - if (the last mouse click in our parent window as in our display_rect_ ) then + - last_mouse_click_in_display == true + - else + - last_mouse_click_in_display == false + !*/ + + public: + directed_graph_drawer ( + drawable_window& w + ) : + zoomable_region(w,MOUSE_CLICK | MOUSE_WHEEL | KEYBOARD_EVENTS), + radius(25), + edge_selected(false), + last_mouse_click_in_display(false) + { + mouse_drag = false; + selected_node = 0; + + // Whenever you make your own drawable (or inherit from dragable or button_action) + // you have to remember to call this function to enable the events. The idea + // here is that you can perform whatever setup you need to do to get your + // object into a valid state without needing to worry about event handlers + // triggering before you are ready. + enable_events(); + } + + ~directed_graph_drawer ( + ) + { + // Disable all further events for this drawable object. We have to do this + // because we don't want draw() events coming to this object while or after + // it has been destructed. + disable_events(); + + // Tell the parent window to redraw its area that previously contained this + // drawable object. + parent.invalidate_rectangle(rect); + } + + void clear_graph ( + ) + { + auto_mutex M(m); + graph_.clear(); + external_graph.clear(); + parent.invalidate_rectangle(display_rect()); + } + + const typename graph_type::node_type& graph_node ( + unsigned long i + ) const + { + DLIB_ASSERT ( i < number_of_nodes() , + "\tgraph_type::node_type& directed_graph_drawer::graph_node(i)" + << "\n\ti: " << i + << "\n\tnumber_of_nodes(): " << number_of_nodes() + ); + return external_graph.node(i); + } + + typename graph_type::node_type& graph_node ( + unsigned long i + ) + { + DLIB_ASSERT ( i < number_of_nodes() , + "\tgraph_type::node_type& directed_graph_drawer::graph_node(i)" + << "\n\ti: " << i + << "\n\tnumber_of_nodes(): " << number_of_nodes() + ); + return external_graph.node(i); + } + + const graph_type& graph ( + ) const + { + return external_graph; + } + + void save_graph ( + std::ostream& out + ) + { + auto_mutex M(m); + serialize(external_graph, out); + serialize(graph_, out); + parent.invalidate_rectangle(display_rect()); + } + + void load_graph ( + std::istream& in + ) + { + auto_mutex M(m); + deserialize(external_graph, in); + deserialize(graph_, in); + parent.invalidate_rectangle(display_rect()); + } + + unsigned long number_of_nodes ( + ) const + { + auto_mutex M(m); + return graph_.number_of_nodes(); + } + + void set_node_label ( + unsigned long i, + const std::string& label + ) + { + auto_mutex M(m); + DLIB_ASSERT ( i < number_of_nodes() , + "\tvoid directed_graph_drawer::set_node_label(i,label)" + << "\n\ti: " << i + << "\n\tlabel: " << label + << "\n\tnumber_of_nodes(): " << number_of_nodes() + ); + graph_.node(i).data.name = label.c_str(); + unsigned long width, height; + mfont->compute_size(label,width,height); + graph_.node(i).data.str_rect = rectangle(width,height); + parent.invalidate_rectangle(display_rect()); + } + + void set_node_color ( + unsigned long i, + rgb_pixel color + ) + { + auto_mutex M(m); + DLIB_ASSERT ( i < number_of_nodes() , + "\tvoid directed_graph_drawer::set_node_color(i,label)" + << "\n\ti: " << i + << "\n\tnumber_of_nodes(): " << number_of_nodes() + ); + graph_.node(i).data.color = color; + parent.invalidate_rectangle(display_rect()); + } + + rgb_pixel node_color ( + unsigned long i + ) const + { + auto_mutex M(m); + DLIB_ASSERT ( i < number_of_nodes() , + "\trgb_pixel directed_graph_drawer::node_color(i)" + << "\n\ti: " << i + << "\n\tnumber_of_nodes(): " << number_of_nodes() + ); + return graph_.node(i).data.color; + } + + const std::string node_label ( + unsigned long i + ) const + { + auto_mutex M(m); + DLIB_ASSERT ( i < number_of_nodes() , + "\tconst std::string directed_graph_drawer::node_label(i)" + << "\n\ti: " << i + << "\n\tnumber_of_nodes(): " << number_of_nodes() + ); + return graph_.node(i).data.name.c_str(); + } + + template < + typename T + > + void set_node_selected_handler ( + T& object, + void (T::*event_handler_)(unsigned long) + ) + { + auto_mutex M(m); + node_selected_handler.set(object,event_handler_); + } + + template < + typename T + > + void set_node_deselected_handler ( + T& object, + void (T::*event_handler_)(unsigned long) + ) + { + auto_mutex M(m); + node_deselected_handler.set(object,event_handler_); + } + + template < + typename T + > + void set_node_deleted_handler ( + T& object, + void (T::*event_handler_)() + ) + { + auto_mutex M(m); + node_deleted_handler.set(object,event_handler_); + } + + template < + typename T + > + void set_graph_modified_handler ( + T& object, + void (T::*event_handler_)() + ) + { + auto_mutex M(m); + graph_modified_handler.set(object,event_handler_); + } + + protected: + + void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + // ignore all keyboard input if the last thing the user clicked on + // wasn't the display area + if (last_mouse_click_in_display == false) + return; + + // if a node is selected + if (selected_node != graph_.number_of_nodes()) + { + // deselect the node if the user hits escape + if (key == base_window::KEY_ESC) + { + parent.invalidate_rectangle(display_rect()); + if (node_deselected_handler.is_set()) + node_deselected_handler(selected_node); + selected_node = graph_.number_of_nodes(); + } + + // delete the node if the user hits delete + if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE) + { + parent.invalidate_rectangle(display_rect()); + graph_.remove_node(selected_node); + external_graph.remove_node(selected_node); + selected_node = graph_.number_of_nodes(); + if (graph_modified_handler.is_set()) + graph_modified_handler(); + if (node_deleted_handler.is_set()) + node_deleted_handler(); + } + } + + // if an edge is selected + if (edge_selected) + { + // deselect the node if the user hits escape + if (key == base_window::KEY_ESC) + { + parent.invalidate_rectangle(display_rect()); + edge_selected = false; + } + + // delete the node if the user hits delete + if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE) + { + parent.invalidate_rectangle(display_rect()); + graph_.remove_edge(selected_edge_parent, selected_edge_child); + external_graph.remove_edge(selected_edge_parent, selected_edge_child); + edge_selected = false; + + if (graph_modified_handler.is_set()) + graph_modified_handler(); + } + } + } + + + void on_mouse_move ( + unsigned long state, + long x, + long y + ) + { + if (mouse_drag) + { + const point p(nearest_point(display_rect(),point(x,y))); + + point center = drag_offset + p; + graph_.node(selected_node).data.p = gui_to_graph_space(center); + parent.invalidate_rectangle(display_rect()); + } + else + { + zoomable_region::on_mouse_move(state,x,y); + } + + // check if the mouse isn't being dragged anymore + if ((state & base_window::LEFT) == 0) + { + mouse_drag = false; + } + } + + void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ) + { + mouse_drag = false; + zoomable_region::on_mouse_up(btn,state,x,y); + } + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ) + { + bool redraw = false; + + if (display_rect().contains(x,y) && + (btn == base_window::RIGHT || btn == base_window::LEFT) && + (state & base_window::SHIFT) == 0 ) + { + // start out saying no edge is selected + if (edge_selected) + { + edge_selected = false; + redraw = true; + } + + bool click_hit_node = false; + dlib::vector p(gui_to_graph_space(point(x,y))); + // check if this click is on an existing node + for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i) + { + dlib::vector n(graph_.node(i).data.p); + if ((p-n).length() < radius) + { + click_hit_node = true; + point center = graph_to_gui_space(graph_.node(i).data.p); + mouse_drag = true; + drag_offset = center - point(x,y); + + // only do something if the click isn't on the currently + // selected node + if (selected_node != i) + { + // send out the deselected event if appropriate + if (selected_node != graph_.number_of_nodes() && node_deselected_handler.is_set()) + node_deselected_handler(selected_node); + + selected_node = i; + redraw = true; + if (node_selected_handler.is_set()) + node_selected_handler(selected_node); + } + break; + } + } + + // if the click didn't hit any node then make sure nothing is selected + if (click_hit_node == false && selected_node != graph_.number_of_nodes()) + { + if (node_deselected_handler.is_set()) + node_deselected_handler(selected_node); + selected_node = graph_.number_of_nodes(); + redraw = true; + } + + + // check if this click is on an edge if we didn't click on a node + if (click_hit_node == false) + { + for (unsigned long n = 0; n < graph_.number_of_nodes() && edge_selected == false; ++n) + { + const dlib::vector parent_center(graph_to_gui_space(graph_.node(n).data.p)); + for (unsigned long e = 0; e < graph_.node(n).number_of_children() && edge_selected == false; ++e) + { + const dlib::vector child_center(graph_to_gui_space(graph_.node(n).child(e).data.p)); + + rectangle area; + area += parent_center; + area += child_center; + // if the point(x,y) is between the two nodes then lets consider it further + if (area.contains(point(x,y))) + { + p = point(x,y); + const dlib::vector z(0,0,1); + // find the distance from the line between the two nodes + const dlib::vector perpendicular(z.cross(parent_center-child_center).normalize()); + double distance = std::abs((child_center-p).dot(perpendicular)); + if (distance < 8) + { + edge_selected = true; + selected_edge_parent = n; + selected_edge_child = graph_.node(n).child(e).index(); + redraw = true; + } + } + } + } + } + + + // if the click didn't land on any node then add a new one if this was + // a right mouse button click + if (click_hit_node == false && btn == base_window::RIGHT) + { + const unsigned long n = graph_.add_node(); + external_graph.add_node(); + + graph_.node(n).data.p = gui_to_graph_space(point(x,y)); + + redraw = true; + selected_node = n; + mouse_drag = false; + if (graph_modified_handler.is_set()) + graph_modified_handler(); + + if (node_selected_handler.is_set()) + node_selected_handler(selected_node); + + } + else if (selected_node == graph_.number_of_nodes()) + { + // in this case the click landed in the white area between nodes + zoomable_region::on_mouse_down( btn, state, x, y, is_double_click); + } + } + + // If the user is shift clicking with the mouse then see if we + // should add a new edge. + if (display_rect().contains(x,y) && + btn == base_window::LEFT && + (state & base_window::SHIFT) && + selected_node != graph_.number_of_nodes() ) + { + dlib::vector p(gui_to_graph_space(point(x,y))); + // check if this click is on an existing node + for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i) + { + dlib::vector n(graph_.node(i).data.p); + if ((p-n).length() < radius) + { + // add the edge if it doesn't already exist and isn't an edge back to + // the same node + if (graph_.has_edge(selected_node,i) == false && selected_node != i && + graph_.has_edge(i, selected_node) == false) + { + graph_.add_edge(selected_node,i); + external_graph.add_edge(selected_node,i); + redraw = true; + + if (graph_modified_handler.is_set()) + graph_modified_handler(); + } + break; + } + } + } + + + if (redraw) + parent.invalidate_rectangle(display_rect()); + + + if (display_rect().contains(x,y) == false) + last_mouse_click_in_display = false; + else + last_mouse_click_in_display = true; + } + + void draw ( + const canvas& c + ) const + { + zoomable_region::draw(c); + + rectangle area = c.intersect(display_rect()); + if (area.is_empty() == true) + return; + + + if (enabled) + fill_rect(c,display_rect(),255); + else + fill_rect(c,display_rect(),128); + + + const unsigned long rad = static_cast(radius*zoom_scale()); + point center; + + + // first draw all the edges + for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i) + { + center = graph_to_gui_space(graph_.node(i).data.p); + const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8))); + + // draw lines to all this node's parents + const dlib::vector z(0,0,1); + for (unsigned long j = 0; j < graph_.node(i).number_of_parents(); ++j) + { + point p(graph_to_gui_space(graph_.node(i).parent(j).data.p)); + + rgb_pixel color(0,0,0); + // if this is the selected edge then draw it with red instead of black + if (edge_selected && selected_edge_child == i && selected_edge_parent == graph_.node(i).parent(j).index()) + { + color.red = 255; + // we need to be careful when drawing this line to not draw it over the node dots since it + // has a different color from them and would look weird + dlib::vector v(p-center); + v = v.normalize()*rad; + draw_line(c,center+v,p-v ,color, area); + } + else + { + draw_line(c,center,p ,color, area); + } + + + // draw the triangle pointing to this node + if (area.intersect(circle_area).is_empty() == false) + { + dlib::vector v(p-center); + v = v.normalize(); + + dlib::vector cross = z.cross(v).normalize(); + dlib::vector r(center + v*rad); + for (double i = 0; i < 8*zoom_scale(); i += 0.1) + draw_line(c,(r+v*i)+cross*i, (r+v*i)-cross*i,color,area); + } + } + } + + + // now draw all the node dots + for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i) + { + center = graph_to_gui_space(graph_.node(i).data.p); + const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8))); + + // draw the actual dot for this node + if (area.intersect(circle_area).is_empty()==false) + { + rgb_alpha_pixel color; + assign_pixel(color, graph_.node(i).data.color); + // this node is in area so lets draw it and all of it's edges as well + draw_solid_circle(c,center,rad-3,color,area); + color.alpha = 240; + draw_circle(c,center,rad-3,color,area); + color.alpha = 200; + draw_circle(c,center,rad-2.5,color,area); + color.alpha = 160; + draw_circle(c,center,rad-2.0,color,area); + color.alpha = 120; + draw_circle(c,center,rad-1.5,color,area); + color.alpha = 80; + draw_circle(c,center,rad-1.0,color,area); + color.alpha = 40; + draw_circle(c,center,rad-0.5,color,area); + + } + + + if (i == selected_node) + draw_circle(c,center,rad+5,rgb_pixel(0,0,255),area); + } + + + // now draw all the strings last + for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i) + { + center = graph_to_gui_space(graph_.node(i).data.p); + rectangle circle_area(centered_rect(center,2*rad+3,2*rad+3)); + if (area.intersect(circle_area).is_empty()==false) + { + rgb_pixel color = graph_.node(i).data.color; + // invert this color + color.red = 255-color.red; + color.green = 255-color.green; + color.blue = 255-color.blue; + sout << i; + unsigned long width, height; + mfont->compute_size(sout.str(),width,height); + rectangle str_rect(centered_rect(center, width,height)); + if (circle_area.contains(str_rect)) + { + mfont->draw_string(c,str_rect,sout.str(),color,0,std::string::npos,area); + + // draw the label for this node if it isn't empty + if(graph_.node(i).data.name.size() > 0) + { + rectangle str_rect(graph_.node(i).data.str_rect); + str_rect = centered_rect(center.x(), center.y()-rad-mfont->height(), str_rect.width(), str_rect.height()); + mfont->draw_string(c,str_rect,graph_.node(i).data.name,0,0,std::string::npos,area); + } + } + sout.str(""); + } + } + } + + private: + + struct data + { + data() : color(0,0,0) {} + vector p; + std::string name; + rectangle str_rect; + rgb_pixel color; + }; + + friend void serialize(const data& item, std::ostream& out) + { + serialize(item.p, out); + serialize(item.name, out); + serialize(item.str_rect, out); + } + + friend void deserialize(data& item, std::istream& in) + { + deserialize(item.p, in); + deserialize(item.name, in); + deserialize(item.str_rect, in); + } + + mutable std::ostringstream sout; + + const double radius; + unsigned long selected_node; + bool mouse_drag; // true if the user is dragging a node + point drag_offset; + + bool edge_selected; + unsigned long selected_edge_parent; + unsigned long selected_edge_child; + + member_function_pointer::kernel_1a node_selected_handler; + member_function_pointer::kernel_1a node_deselected_handler; + member_function_pointer<>::kernel_1a node_deleted_handler; + member_function_pointer<>::kernel_1a graph_modified_handler; + + graph_type external_graph; + // rebind the graph_ type to make us a graph_ of data structs + typename graph_type::template rebind::other graph_; + + bool last_mouse_click_in_display; + }; + +// ---------------------------------------------------------------------------------------- + + class text_grid : public scrollable_region + { + /*! + INITIAL VALUE + - has_focus == false + - vertical_scroll_increment() == 10 + - horizontal_scroll_increment() == 10 + - border_color_ == rgb_pixel(128,128,128) + + CONVENTION + - grid.nr() == row_height.size() + - grid.nc() == col_width.size() + - border_color() == border_color_ + - text(r,c) == grid[r][c].text + - text_color(r,c) == grid[r][c].text_color + - background_color(r,c) == grid[r][c].bg_color + + - if (the user has clicked on this widget and caused one of the + boxes to have input focus) then + - has_focus == true + - grid[active_row][active_col] == the active text box + - cursor_pos == the position of the cursor in the above box + - if (the cursor should be displayed) then + - show_cursor == true + - else + - show_cursor == false + - else + - has_focus == false + !*/ + + public: + text_grid ( + drawable_window& w + ) : + scrollable_region(w, KEYBOARD_EVENTS | MOUSE_CLICK | FOCUS_EVENTS ), + has_focus(false), + cursor_timer(*this,&text_grid::timer_action), + border_color_(128,128,128) + { + + cursor_timer.set_delay_time(500); + set_vertical_scroll_increment(10); + set_horizontal_scroll_increment(10); + enable_events(); + } + + ~text_grid ( + ) + { + // Disable all further events for this drawable object. We have to do this + // because we don't want draw() events coming to this object while or after + // it has been destructed. + disable_events(); + + // wait for the timer to stop doing its thing + cursor_timer.stop_and_wait(); + // Tell the parent window to redraw its area that previously contained this + // drawable object. + parent.invalidate_rectangle(rect); + } + + void set_grid_size ( + unsigned long rows, + unsigned long cols + ) + { + auto_mutex M(m); + row_height.set_max_size(rows); + row_height.set_size(rows); + + col_width.set_max_size(cols); + col_width.set_size(cols); + + grid.set_size(rows,cols); + + for (unsigned long i = 0; i < row_height.size(); ++i) + row_height[i] = (mfont->height()*3)/2; + for (unsigned long i = 0; i < col_width.size(); ++i) + col_width[i] = mfont->height()*5; + + compute_total_rect(); + compute_bg_rects(); + } + + unsigned long number_of_columns ( + ) const + { + auto_mutex M(m); + return grid.nc(); + } + + unsigned long number_of_rows ( + ) const + { + auto_mutex M(m); + return grid.nr(); + } + + int next_free_user_event_number ( + ) const + { + return scrollable_region::next_free_user_event_number()+1; + } + + rgb_pixel border_color ( + ) const + { + auto_mutex M(m); + return border_color_; + } + + void set_border_color ( + rgb_pixel color + ) + { + auto_mutex M(m); + border_color_ = color; + parent.invalidate_rectangle(rect); + } + + const std::string text ( + unsigned long row, + unsigned long col + ) const + { + auto_mutex M(m); + return grid[row][col].text.c_str(); + } + + void set_text ( + unsigned long row, + unsigned long col, + const std::string& str + ) + { + auto_mutex M(m); + grid[row][col].text = str.c_str(); + parent.invalidate_rectangle(get_text_rect(row,col)); + } + + const rgb_pixel text_color ( + unsigned long row, + unsigned long col + ) const + { + auto_mutex M(m); + return grid[row][col].text_color; + } + + void set_text_color ( + unsigned long row, + unsigned long col, + const rgb_pixel color + ) + { + auto_mutex M(m); + grid[row][col].text_color = color; + parent.invalidate_rectangle(get_text_rect(row,col)); + } + + const rgb_pixel background_color ( + unsigned long row, + unsigned long col + ) const + { + auto_mutex M(m); + return grid[row][col].bg_color; + } + + void set_background_color ( + unsigned long row, + unsigned long col, + const rgb_pixel color + ) + { + auto_mutex M(m); + grid[row][col].bg_color = color; + parent.invalidate_rectangle(get_bg_rect(row,col)); + } + + bool is_editable ( + unsigned long row, + unsigned long col + ) const + { + auto_mutex M(m); + return grid[row][col].is_editable; + } + + void set_editable ( + unsigned long row, + unsigned long col, + bool editable + ) + { + auto_mutex M(m); + grid[row][col].is_editable = editable; + if (has_focus && active_row == static_cast(row) && active_col == static_cast(col)) + { + drop_input_focus(); + } + } + + void set_column_width ( + unsigned long col, + unsigned long width + ) + { + auto_mutex M(m); + col_width[col] = width; + compute_total_rect(); + compute_bg_rects(); + } + + void set_row_height ( + unsigned long row, + unsigned long height + ) + { + auto_mutex M(m); + row_height[row] = height; + compute_total_rect(); + compute_bg_rects(); + } + + void disable ( + ) + { + auto_mutex M(m); + scrollable_region::disable(); + drop_input_focus(); + } + + void hide ( + ) + { + auto_mutex M(m); + scrollable_region::hide(); + drop_input_focus(); + } + + template < + typename T + > + void set_text_modified_handler ( + T& object, + void (T::*eh)(unsigned long, unsigned long) + ) { text_modified_handler.set(object,eh); } + + private: + + void on_user_event ( + int num + ) + { + // ignore this user event if it isn't for us + if (num != scrollable_region::next_free_user_event_number()) + return; + + if (has_focus && !recent_cursor_move && enabled && !hidden) + { + show_cursor = !show_cursor; + parent.invalidate_rectangle(get_text_rect(active_row,active_col)); + } + recent_cursor_move = false; + } + + void timer_action ( + ) { parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); } + /*! + ensures + - flips the state of show_cursor + !*/ + + void compute_bg_rects ( + ) + { + // loop over each element in the grid and figure out what its rectangle should be + // with respect to the total_rect() + point p1, p2; + p1.y() = total_rect().top(); + for (long row = 0; row < grid.nr(); ++row) + { + p1.x() = total_rect().left(); + p2.y() = p1.y() + row_height[row]-1; + for (long col = 0; col < grid.nc(); ++col) + { + // if this is the last box in this row make it super wide so that it always + // goes to the end of the widget + if (col+1 == grid.nc()) + p2.x() = 1000000; + else + p2.x() = p1.x() + col_width[col]-1; + + // at this point p1 is the upper left corner of this box and p2 is the + // lower right corner of the box; + rectangle bg_rect(p1); + bg_rect += p2; + + grid[row][col].bg_rect = translate_rect(bg_rect, -total_rect().left(), -total_rect().top()); + + + p1.x() += 1 + col_width[col]; + } + p1.y() += 1 + row_height[row]; + } + } + + void compute_total_rect ( + ) + { + if (grid.size() == 0) + { + set_total_rect_size(0,0); + } + else + { + unsigned long width = col_width.size()-1; + unsigned long height = row_height.size()-1; + + for (unsigned long i = 0; i < col_width.size(); ++i) + width += col_width[i]; + for (unsigned long i = 0; i < row_height.size(); ++i) + height += row_height[i]; + + set_total_rect_size(width,height); + } + } + + void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + // ignore this event if we are disabled or hidden + if (!enabled || hidden) + return; + + if (has_focus) + { + if (is_printable) + { + // if the user hit the tab key then jump to the next box + if (key == '\t') + { + if (active_col+1 == grid.nc()) + { + if (active_row+1 == grid.nr()) + move_cursor(0,0,0); + else + move_cursor(active_row+1,0,0); + } + else + { + move_cursor(active_row,active_col+1,0); + } + } + if (key == '\n') + { + // ignore the enter key + } + else if (grid[active_row][active_col].is_editable) + { + // insert the key the user pressed into the string + grid[active_row][active_col].text.insert(cursor_pos,1,static_cast(key)); + move_cursor(active_row,active_col,cursor_pos+1); + + if (text_modified_handler.is_set()) + text_modified_handler(active_row,active_col); + } + } + else if ((state & base_window::KBD_MOD_CONTROL)) + { + if (key == base_window::KEY_LEFT) + move_cursor(active_row,active_col-1,0); + else if (key == base_window::KEY_RIGHT) + move_cursor(active_row,active_col+1,0); + else if (key == base_window::KEY_UP) + move_cursor(active_row-1,active_col,0); + else if (key == base_window::KEY_DOWN) + move_cursor(active_row+1,active_col,0); + else if (key == base_window::KEY_END) + move_cursor(active_row,active_col,grid[active_row][active_col].text.size()); + else if (key == base_window::KEY_HOME) + move_cursor(active_row,active_col,0); + } + else + { + if (key == base_window::KEY_LEFT) + move_cursor(active_row,active_col,cursor_pos-1); + else if (key == base_window::KEY_RIGHT) + move_cursor(active_row,active_col,cursor_pos+1); + else if (key == base_window::KEY_UP) + move_cursor(active_row-1,active_col,0); + else if (key == base_window::KEY_DOWN) + move_cursor(active_row+1,active_col,0); + else if (key == base_window::KEY_END) + move_cursor(active_row,active_col,grid[active_row][active_col].text.size()); + else if (key == base_window::KEY_HOME) + move_cursor(active_row,active_col,0); + else if (key == base_window::KEY_BACKSPACE) + { + if (cursor_pos > 0 && grid[active_row][active_col].is_editable) + { + grid[active_row][active_col].text.erase( + grid[active_row][active_col].text.begin()+cursor_pos-1, + grid[active_row][active_col].text.begin()+cursor_pos); + move_cursor(active_row,active_col,cursor_pos-1); + + if (text_modified_handler.is_set()) + text_modified_handler(active_row,active_col); + } + } + else if (key == base_window::KEY_DELETE) + { + if (cursor_pos < static_cast(grid[active_row][active_col].text.size()) && + grid[active_row][active_col].is_editable) + { + grid[active_row][active_col].text.erase( + grid[active_row][active_col].text.begin()+cursor_pos); + move_cursor(active_row,active_col,cursor_pos); + + if (text_modified_handler.is_set()) + text_modified_handler(active_row,active_col); + } + } + } + } // if (has_focus) + } + + void on_mouse_down ( + unsigned long btn, + unsigned long state, + long x, + long y, + bool is_double_click + ) + { + if (display_rect().contains(x,y) && enabled && !hidden) + { + // figure out which box this click landed in + rectangle hit; + + // find which column we hit + unsigned long col = 0; + long box_x = total_rect().left(); + for (unsigned long i = 0; i < col_width.size(); ++i) + { + if (box_x <= x && (x < box_x+static_cast(col_width[i]) || (i+1 == col_width.size()))) + { + col = i; + hit.set_left(box_x); + hit.set_right(box_x+col_width[i]-1); + break; + } + else + { + box_x += col_width[i]+1; + } + } + + // find which row we hit + unsigned long row = 0; + long box_y = total_rect().top(); + for (unsigned long i = 0; i < row_height.size(); ++i) + { + if (box_y <= y && y < box_y+static_cast(row_height[i])) + { + row = i; + hit.set_top(box_y); + hit.set_bottom(box_y+row_height[i]-1); + break; + } + else + { + box_y += row_height[i]+1; + } + } + + // if we hit a box + if (hit.is_empty() == false) + { + move_cursor(row, + col, + mfont->compute_cursor_pos(get_text_rect(row,col), grid[row][col].text, x, y, grid[row][col].first) + ); + } + else + { + drop_input_focus(); + } + } + else + { + drop_input_focus(); + } + } + + void on_mouse_up ( + unsigned long btn, + unsigned long state, + long x, + long y + ) + { + } + + void on_focus_lost ( + ) + { + drop_input_focus(); + } + + void draw ( + const canvas& c + ) const + { + scrollable_region::draw(c); + rectangle area = c.intersect(display_rect()); + if (area.is_empty() == true) + return; + + if (enabled) + fill_rect(c, area, 255); + + // don't do anything if the grid is empty + if (grid.size() == 0) + return; + + // draw all the vertical lines + point p1, p2; + p1.x() = p2.x() = total_rect().left(); + p1.y() = total_rect().top(); + p2.y() = total_rect().bottom(); + for (unsigned long i = 0; i < col_width.size()-1; ++i) + { + p1.x() += col_width[i]; + p2.x() += col_width[i]; + if (enabled) + draw_line(c,p1,p2,border_color_,area); + else + draw_line(c,p1,p2,128,area); + p1.x() += 1; + p2.x() += 1; + } + + // draw all the horizontal lines + p1.y() = p2.y() = total_rect().top(); + p1.x() = display_rect().left(); + p2.x() = display_rect().right(); + for (unsigned long i = 0; i < row_height.size(); ++i) + { + p1.y() += row_height[i]; + p2.y() += row_height[i]; + if (enabled) + draw_line(c,p1,p2,border_color_,area); + else + draw_line(c,p1,p2,128,area); + p1.y() += 1; + p2.y() += 1; + } + + // draw the backgrounds and text for each box + for (long row = 0; row < grid.nr(); ++row) + { + for (long col = 0; col < grid.nc(); ++col) + { + rectangle bg_rect(get_bg_rect(row,col)); + + rectangle text_rect(get_text_rect(row,col)); + + if (enabled) + { + fill_rect(c,bg_rect.intersect(area),grid[row][col].bg_color); + + mfont->draw_string(c, + text_rect, + grid[row][col].text, + grid[row][col].text_color, + grid[row][col].first, + std::string::npos, + area); + } + else + { + mfont->draw_string(c, + text_rect, + grid[row][col].text, + 128, + grid[row][col].first, + std::string::npos, + area); + } + + // if this box has input focus then draw it with a cursor + if (has_focus && active_col == col && active_row == row && show_cursor) + { + rectangle cursor_rect = mfont->compute_cursor_rect(text_rect, + grid[row][col].text, + cursor_pos, + grid[row][col].first); + draw_rectangle(c,cursor_rect,0,area); + } + + } + } + + + } + + rectangle get_text_rect ( + unsigned long row, + unsigned long col + ) const + { + rectangle bg_rect(get_bg_rect(row,col)); + long padding = (bg_rect.height() - mfont->height())/2 + (bg_rect.height() - mfont->height())%2; + if (padding < 0) + padding = 0; + bg_rect.set_left(bg_rect.left()+padding); + bg_rect.set_top(bg_rect.top()+padding); + bg_rect.set_right(bg_rect.right()-padding); + bg_rect.set_bottom(bg_rect.bottom()-padding); + return bg_rect; + } + + rectangle get_bg_rect ( + unsigned long row, + unsigned long col + ) const + { + return translate_rect(grid[row][col].bg_rect, total_rect().left(), total_rect().top()); + } + + struct data_type + { + data_type(): text_color(0,0,0), bg_color(255,255,255), + first(0), is_editable(true) + {} + + std::string text; + rgb_pixel text_color; + rgb_pixel bg_color; + rectangle bg_rect; + std::string::size_type first; + bool is_editable; + }; + + void drop_input_focus ( + ) + { + if (has_focus) + { + parent.invalidate_rectangle(get_text_rect(active_row,active_col)); + has_focus = false; + show_cursor = false; + cursor_timer.stop(); + } + } + + void move_cursor ( + long row, + long col, + long new_cursor_pos + ) + { + // don't do anything if the grid is empty + if (grid.size() == 0) + { + return; + } + + if (row < 0) + row = 0; + if (row >= grid.nr()) + row = grid.nr()-1; + if (col < 0) + col = 0; + if (col >= grid.nc()) + col = grid.nc()-1; + + if (new_cursor_pos < 0) + { + if (col == 0) + { + new_cursor_pos = 0; + } + else + { + --col; + new_cursor_pos = grid[row][col].text.size(); + } + } + + if (new_cursor_pos > static_cast(grid[row][col].text.size())) + { + if (col+1 == grid.nc()) + { + new_cursor_pos = grid[row][col].text.size(); + } + else + { + ++col; + new_cursor_pos = 0; + } + } + + // if some other box had the input focus then redraw it + if (has_focus && (active_row != row || active_col != col )) + { + parent.invalidate_rectangle(get_text_rect(active_row,active_col)); + } + + if (has_focus == false) + { + cursor_timer.start(); + } + + has_focus = true; + recent_cursor_move = true; + show_cursor = true; + active_row = row; + active_col = col; + cursor_pos = new_cursor_pos; + + // adjust the first character to draw so that the string is displayed well + rectangle text_rect(get_text_rect(active_row,active_col)); + rectangle cursor_rect = mfont->compute_cursor_rect(text_rect, + grid[row][col].text, + cursor_pos, + grid[row][col].first); + + // if the cursor rect is too far to the left of the string + if (cursor_pos < static_cast(grid[row][col].first)) + { + if (cursor_pos > 5) + { + grid[row][col].first = cursor_pos - 5; + } + else + { + grid[row][col].first = 0; + } + } + // if the cursor rect is too far to the right of the string + else if (cursor_rect.left() > text_rect.right()) + { + long distance = (cursor_rect.left() - text_rect.right()) + text_rect.width()/3; + // find the letter that is distance pixels from the start of the string + long sum = 0; + for (unsigned long i = grid[row][col].first; i < grid[row][col].text.size(); ++i) + { + sum += (*mfont)[grid[row][col].text[i]].width(); + if (sum >= distance) + { + grid[row][col].first = i; + break; + } + } + } + + scroll_to_rect(get_bg_rect(row,col)); + + // redraw our box + parent.invalidate_rectangle(text_rect); + + } + + array2d::kernel_1a_c grid; + array::kernel_2a_c col_width; + array::kernel_2a_c row_height; + bool has_focus; + long active_col; + long active_row; + long cursor_pos; + bool show_cursor; + bool recent_cursor_move; + timer::kernel_2a cursor_timer; + rgb_pixel border_color_; + member_function_pointer::kernel_1a_c text_modified_handler; + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "widgets.cpp" +#endif + +#endif // DLIB_WIDGETs_ + diff --git a/dlib/gui_widgets/widgets_abstract.h b/dlib/gui_widgets/widgets_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..32fcba97bbd9d4f29d7641da5078bd564e45965e --- /dev/null +++ b/dlib/gui_widgets/widgets_abstract.h @@ -0,0 +1,1860 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#undef DLIB_WIDGETs_ABSTRACT_ +#ifdef DLIB_WIDGETs_ABSTRACT_ + +#include "fonts_abstract.h" +#include "drawable_abstract.h" +#include "base_widgets_abstract.h" + +#include "../gui_core.h" +#include +#include "../interfaces/enumerable.h" +#include "style_abstract.h" + +namespace dlib +{ + + /*! + GENERAL REMARKS + This component is a collection of various windowing widgets such as buttons, + labels, text boxes, and so on. This component also includes the drawable + interface, drawable_window, and font handling objects. The file you are + currently viewing defines all the high level graphical widgets which are + provided by this component that can appear in a drawable_window. To view + the specifications for the other members of this component look at + fonts_abstract.h, base_widgets_abstract.h, and drawable_abstract.h + + THREAD SAFETY + All objects and functions defined in this file are thread safe. You may + call them from any thread without serializing access to them. + + EVENT HANDLERS + Note that all event handlers, including the user registered callback + functions, are executed in the event handling thread. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // function open_file_box(), open_existing_file_box(), and save_file_box() +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void open_file_box ( + T& object, + void (T::*event_handler)(const std::string&) + ); + /*! + requires + - event_handler == a valid pointer to a member function of object T. + ensures + - Displays a window titled "Open File" that will allow the user to select a + file. + - The displayed window will start out showing the directory get_current_dir() + (i.e. it starts in the current working directory) + - The event_handler function is called on object if the user selects + a file. If the user closes the window without selecting a file + then nothing occurs. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void open_existing_file_box ( + T& object, + void (T::*event_handler)(const std::string&) + ); + /*! + requires + - event_handler == a valid pointer to a member function of object T. + ensures + - Displays a window titled "Open File" that will allow the user to select + a file. But only a file that already exists. + - The displayed window will start out showing the directory get_current_dir() + (i.e. it starts in the current working directory) + - The event_handler function is called on object if the user selects + a file. If the user closes the window without selecting a file + then nothing occurs. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void save_file_box ( + T& object, + void (T::*event_handler)(const std::string&) + ); + /*! + requires + - event_handler == a valid pointer to a member function of object T. + ensures + - Displays a window titled "Save File" that will allow the user to select + a file. + - The displayed window will start out showing the directory get_current_dir() + (i.e. it starts in the current working directory) + - The event_handler function is called on object if the user selects + a file. If the user closes the window without selecting a file + then nothing occurs. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // function message_box() +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void message_box ( + const std::string& title, + const std::string& message + ); + /*! + ensures + - displays a message box with the given title and message. It will have a + single button and when the user clicks it the message box will go away. + - this function does not block but instead returns immediately. + !*/ + + void message_box_blocking ( + const std::string& title, + const std::string& message + ); + /*! + ensures + - displays a message box with the given title and message. It will have a + single button and when the user clicks it the message box will go away. + - this function blocks until the user clicks on the message box and + causes it to go away. + !*/ + + template < + typename T + > + void message_box ( + const std::string& title, + const std::string& message, + T& object, + void (T::*event_handler)() + ); + /*! + requires + - event_handler == a valid pointer to a member function of object T. + ensures + - Displays a message box with the given title and message. It will have a + single button and when the user clicks it the message box will go away. + - The event_handler function is called on object when the user clicks + ok or otherwise closes the message box window. + - this function does not block but instead returns immediately. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class label +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class label : public drawable + { + /*! + INITIAL VALUE + text() == "" + the text color will be black + + WHAT THIS OBJECT REPRESENTS + This object represents a simple text label. The size of the label + is automatically set to be just big enough to contain its text. + !*/ + + public: + + label( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~label( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_text ( + const std::string& text + ); + /*! + ensures + - #text() == text + throws + - std::bad_alloc + !*/ + + const std::string text ( + ) const; + /*! + ensures + - returns the text of this label + throws + - std::bad_alloc + !*/ + + void set_text_color ( + const rgb_pixel color + ); + /*! + ensures + - #text_color() == color + !*/ + + const rgb_pixel text_color ( + ) const; + /*! + ensures + - returns the color used to draw the text in this widget + !*/ + + private: + + // restricted functions + label(label&); // copy constructor + label& operator=(label&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class button : public button_action + { + /*! + INITIAL VALUE + name() == "" + tooltip_text() == "" (i.e. there is no tooltip by default) + + WHAT THIS OBJECT REPRESENTS + This object represents a simple button. + + When this object is disabled it means it will not respond to user clicks. + !*/ + + public: + + button( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~button( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - if (width and height are big enough to contain the name of this button) then + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this button stays the + same but its width and height are modified + !*/ + + void set_name ( + const std::string& name + ); + /*! + ensures + - #name() == name + - this button has been resized such that it is big enough to contain + the new name. + throws + - std::bad_alloc + !*/ + + const std::string name ( + ) const; + /*! + ensures + - returns the name of this button + throws + - std::bad_alloc + !*/ + + void set_tooltip_text ( + const std::string& text + ); + /*! + ensures + - #tooltip_text() == text + - enables the tooltip for this button + !*/ + + const std::string tooltip_text ( + ) const; + /*! + ensures + - returns the text that is displayed in the tooltip for this button + !*/ + + template < + typename style_type + > + void set_style ( + const style_type& style + ); + /*! + requires + - style_type == a type that inherits from button_style + ensures + - this button object will draw itself using the given + button style + !*/ + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the button is + clicked by the user. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler)(button& self) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - &self == this + - the event_handler function is called on object when the button is + clicked by the user. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + button(button&); // copy constructor + button& operator=(button&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class toggle_button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class toggle_button : public button_action + { + /*! + INITIAL VALUE + name() == "" + is_checked() == false + + WHAT THIS OBJECT REPRESENTS + This object represents a simple two state toggle button. Is is either + in the checked or unchecked state and when a user clicks on it it toggles its + state. + + When this object is disabled it means it will not respond to user clicks. + !*/ + + public: + + toggle_button( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~toggle_button( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_name ( + const std::string& name + ); + /*! + ensures + - #name() == name + - this toggle_button has been resized such that it is big enough to contain + the new name. + throws + - std::bad_alloc + !*/ + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - if (width and height are big enough to contain the name of this button) then + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this button stays the + same but its width and height are modified + !*/ + + void set_tooltip_text ( + const std::string& text + ); + /*! + ensures + - #tooltip_text() == text + - enables the tooltip for this toggle_button + !*/ + + const std::string tooltip_text ( + ) const; + /*! + ensures + - returns the text that is displayed in the tooltip for this toggle_button + !*/ + + template < + typename style_type + > + void set_style ( + const style_type& style + ); + /*! + requires + - style_type == a type that inherits from toggle_button_style + ensures + - this toggle_button object will draw itself using the given + button style + !*/ + + bool is_checked ( + ) const; + /*! + ensures + - if (this box is currently checked) then + - returns true + - else + - returns false + !*/ + + const std::string name ( + ) const; + /*! + ensures + - returns the name of this toggle_button. The name is a string + that appears to the right of the actual check box. + throws + - std::bad_alloc + !*/ + + void set_checked ( + ); + /*! + ensures + - #is_checked() == true + !*/ + + void set_unchecked ( + ); + /*! + ensures + - #is_checked() == false + !*/ + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the toggle_button is + toggled by the user. + - this event is NOT triggered by calling set_checked() or set_unchecked(). + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler)(toggle_button& self) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T. + ensures + - the event_handler function is called on object when the toggle_button is + toggled by the user. self will be a reference to the toggle_button object + that the user clicked. + - this event is NOT triggered by calling set_checked() or set_unchecked(). + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + toggle_button(toggle_button&); // copy constructor + toggle_button& operator=(toggle_button&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class text_field +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class text_field : public drawable + { + /*! + INITIAL VALUE + text() == "" + width() == 10 + height() == a height appropriate for the font used. + The text color will be black. + + WHAT THIS OBJECT REPRESENTS + This object represents a simple one line text input field. + !*/ + + public: + + text_field( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~text_field( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_text ( + const std::string& text + ); + /*! + requires + - text.find_first_of('\n') == std::string::npos + (i.e. there aren't any new lines in text) + ensures + - #text() == text + throws + - std::bad_alloc + !*/ + + const std::string text ( + ) const; + /*! + ensures + - returns the text of this text_field + throws + - std::bad_alloc + !*/ + + void set_width ( + unsigned long width_ + ); + /*! + ensures + - if (width >= 10) then + - #width() == width_ + - #height() == height() + - #top() == top() + - #left() == left() + - i.e. The width of this drawable is set to the given width but + nothing else changes. + !*/ + + void set_text_color ( + const rgb_pixel color + ); + /*! + ensures + - #text_color() == color + !*/ + + const rgb_pixel text_color ( + ) const; + /*! + ensures + - returns the color used to draw the text in this widget + !*/ + + void set_background_color ( + const rgb_pixel color + ); + /*! + ensures + - #background_color() == color + !*/ + + const rgb_pixel background_color ( + ) const; + /*! + ensures + - returns the color used to fill in the background of this widget + !*/ + + template < + typename T + > + void set_text_modified_handler ( + T& object, + void (T::*event_handler)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the text + in this text_field is modified by the user. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + + private: + + // restricted functions + text_field(text_field&); // copy constructor + text_field& operator=(text_field&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class check_box +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class check_box : public toggle_button + { + /*! + This is just a toggle button with the style set to + toggle_button_style_check_box. + !*/ + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class radio_button +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class radio_button : public toggle_button + { + /*! + This is just a toggle button with the style set to + toggle_button_style_radio_button. + !*/ + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class tabbed_display +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class tabbed_display : public drawable + { + /*! + INITIAL VALUE + number_of_tabs() == 1 + selected_tab() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a row of tabs that are user selectable. + + When this object is disabled it means it will not respond to user clicks. + !*/ + + public: + + tabbed_display( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~tabbed_display( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - if (width and height are big enough to contain the tabs) then + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this widget stays the + same but its width and height are modified + !*/ + + void set_number_of_tabs ( + unsigned long num + ); + /*! + requires + - num > 0 + ensures + - #number_of_tabs() == num + - no tabs have any widget_groups associated with them. + - for all valid idx: + - #tab_name(idx) == "" + throws + - std::bad_alloc + !*/ + + unsigned long selected_tab ( + ) const; + /*! + ensures + - returns the index of the currently selected tab + !*/ + + unsigned long number_of_tabs ( + ) const; + /*! + ensures + - returns the number of tabs in this tabbed_display + !*/ + + const std::string& tab_name ( + unsigned long idx + ) const; + /*! + requires + - idx < number_of_tabs() + ensures + - returns a const reference to the name of the tab given by idx + !*/ + + void set_tab_name ( + unsigned long idx, + const std::string& new_name + ); + /*! + requires + - idx < number_of_tabs() + ensures + - #tab_name(idx) == new_name + throws + - std::bad_alloc + !*/ + + void set_tab_group ( + unsigned long idx, + widget_group& group + ); + /*! + requires + - idx < number_of_tabs() + ensures + - if (is_hidden()) then + - group.is_hidden() == true + - else + - whenever the tab with index idx is selected group.is_hidden() == false + - whenever the tab with index idx is deselected group.is_hidden() == true + - whenever the position of *this changes the position of group will be + updated so that it is still inside the tabbed_display. The position of group + will also be updated after this call to set_tab_group(). + - any previous calls to set_tab_group() with this index are overridden by this + new call. (i.e. you can only have one widget_group associated with a single + tab at a time) + !*/ + + void fit_to_contents ( + ); + /*! + ensures + - Adjusts the size this tabbed_display so that it nicely contains + all of its widget_group objects. + - does not change the position of this object. + (i.e. the upper left corner of get_rect() remains at the same position) + !*/ + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler)(unsigned long new_idx, unsigned long old_idx) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - The event_handler function is called on object when the user clicks + on a tab that isn't already selected. new_idx will give the index of + the newly selected tab and old_idx will give the index of the tab + that was previously selected. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + tabbed_display(tabbed_display&); // copy constructor + tabbed_display& operator=(tabbed_display&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class named_rectangle +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class named_rectangle : public drawable + { + /*! + INITIAL VALUE + name() == "" + + WHAT THIS OBJECT REPRESENTS + This object represents a simple named rectangle. + !*/ + + public: + + named_rectangle( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~named_rectangle( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this widget stays the + same but its width and height are modified + !*/ + + void wrap_around ( + const rectangle& rect + ); + /*! + ensures + - This object will be repositioned and sized so that it fits + around the given rectangle. + !*/ + + void set_name ( + const std::string& name + ); + /*! + ensures + - #name() == name + throws + - std::bad_alloc + !*/ + + const std::string name ( + ) const; + /*! + ensures + - returns the name of this named_rectangle + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + named_rectangle(named_rectangle&); // copy constructor + named_rectangle& operator=(named_rectangle&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class mouse_tracker +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class mouse_tracker : public dragable + { + /*! + INITIAL VALUE + dragable_area() == rectangle(0,0,500,500) + + WHAT THIS OBJECT REPRESENTS + This object represents a simple dragable box that displays the + current location of the mouse. + + Also, if you hold shift and left click on the parent window then the + mouse_tracker will place a single red pixel where you clicked and will + display the mouse position relative to that point. + !*/ + + public: + + mouse_tracker( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~mouse_tracker( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + private: + + // restricted functions + mouse_tracker(mouse_tracker&); // copy constructor + mouse_tracker& operator=(mouse_tracker&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class list_box +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class list_box : public drawable, + public enumerable + { + /*! + INITIAL VALUE + multiple_select_enabled() == false + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements in the list_box from + the 0th element to the (size()-1)th element. i.e. (*this)[0] to + (*this)[size()-1]. + + WHAT THIS OBJECT REPRESENTS + This object represents a simple textual list box. It contains a + vertical list of strings which the user may select from. + !*/ + + public: + + list_box( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~list_box( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_size ( + unsigned long width_, + unsigned long height_ + ); + /*! + ensures + - #width() == width_ + - #height() == height_ + - #top() == top() + - #left() == left() + - i.e. The location of the upper left corner of this widget stays the + same but its width and height are modified + !*/ + + bool is_selected ( + unsigned long index + ) const; + /*! + requires + - index < size() + ensures + - if (the item given by index is currently selected) then + - returns true + - else + - returns false + !*/ + + void select ( + unsigned long index + ); + /*! + requires + - index < size() + ensures + - #is_selected(index) == true + !*/ + + void unselect ( + unsigned long index + ); + /*! + requires + - index < size() + ensures + - #is_selected(index) == false + !*/ + + template + void get_selected ( + T& list + ) const; + /*! + requires + - T == an implementation of dlib/queue/queue_kernel_abstract.h + - T::type == unsigned long + ensures + - #list == a list of all the currently selected indices for this list_box. + !*/ + + unsigned long get_selected ( + ) const; + /*! + requires + - multiple_select_enabled() == false + ensures + - if (there is currently something selected) then + - returns the index of the selected item + - else + - returns size() + !*/ + + template + void load ( + const T& list + ); + /*! + requires + - T == compatible with dlib::enumerable + ensures + - #size() == list.size() + - Copies all the strings from list into *this in the order in which they are enumerated. + (i.e. The first one goes into (*this)[0], the second into (*this)[1], and so on...) + !*/ + + const std::string& operator[] ( + unsigned long index + ) const; + /*! + requires + - index < size() + ensures + - returns the name of the indexth item/row in this list box. + !*/ + + bool multiple_select_enabled ( + ) const; + /*! + ensures + - if (this object will allow the user to select more than one item at a time) then + - returns true + - else + - returns false + !*/ + + void enable_multiple_select ( + ); + /*! + ensures + - #multiple_select_enabled() == true + !*/ + + void disable_multiple_select ( + ); + /*! + ensures + - #multiple_select_enabled() == false + !*/ + + template < + typename T + > + void set_double_click_handler ( + T& object, + void (T::*event_handler)(unsigned long index) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T. + ensures + - The event_handler function is called on object when the user double + clicks on one of the rows in this list box. index gives the row + number for the item the user clicked. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_click_handler ( + T& object, + void (T::*event_handler)(unsigned long index) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T. + ensures + - The event_handler function is called on object when the user + clicks on one of the rows in this list box. index gives the row + number for the item the user clicked. (Note that the second click + in a double click triggers the double click handler above instead + of this event) + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + list_box(list_box&); // copy constructor + list_box& operator=(list_box&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // class menu_bar +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class menu_bar : public drawable + { + /*! + INITIAL VALUE + - number_of_menus() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a menu bar that appears at the top of a + window. + !*/ + + public: + + menu_bar( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~menu_bar( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_number_of_menus ( + unsigned long num + ); + /*! + ensures + - #number_of_menus() == num + !*/ + + unsigned long number_of_menus ( + ) const; + /*! + ensures + - returns the number of menus in this menu_bar + !*/ + + void set_menu_name ( + unsigned long idx, + const std::string name, + char underline_ch = '\0' + ); + /*! + requires + - idx < number_of_menus() + ensures + - #menu_name(idx) == name + - if (underline_ch is present in name) then + - The menu with index idx will have the first underline_ch character + in its name underlined and users will be able to activate the menu + by hitting alt+underline_char + !*/ + + const std::string menu_name ( + unsigned long idx + ) const; + /*! + requires + - idx < number_of_menus() + ensures + - returns the name of the menu with index idx + !*/ + + popup_menu& menu ( + unsigned long idx + ); + /*! + requires + - idx < number_of_menus() + ensures + - returns a non-const reference to the popup_menu for the menu with + index idx. + !*/ + + const popup_menu& menu ( + unsigned long idx + ) const; + /*! + requires + - idx < number_of_menus() + ensures + - returns a const reference to the popup_menu for the menu with + index idx. + !*/ + + private: + + // restricted functions + menu_bar(menu_bar&); // copy constructor + menu_bar& operator=(menu_bar&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename graph_type + > + class directed_graph_drawer : public zoomable_region + { + /*! + REQUIREMENTS ON graph_type + - must be an implementation of directed_graph/directed_graph_kernel_abstract.h + + INITIAL VALUE + - get_graph().size() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a graphical widget that allows the user to draw + a directed graph. + + The user can create nodes by right clicking on the draw area and add + edges by selecting a node (via left clicking on it) and then holding + shift and clicking on the node that is to be the child node of the + selected node. + !*/ + + public: + + directed_graph_drawer ( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~directed_graph_drawer ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + const graph_type& graph ( + ) const; + /*! + requires + - drawable::m is locked + ensures + - returns a const reference to the graph that this widget has been drawing + !*/ + + unsigned long number_of_nodes ( + ) const; + /*! + ensures + - returns graph().number_of_nodes() + !*/ + + void clear_graph ( + ); + /*! + ensures + - #number_of_nodes() == 0 + !*/ + + const typename graph_type::node_type& graph_node ( + unsigned long i + ) const; + /*! + requires + - drawable::m is locked + - i < number_of_nodes() + ensures + - returns a const reference to get_graph().node(i) + !*/ + + typename graph_type::node_type& graph_node ( + unsigned long i + ); + /*! + requires + - drawable::m is locked + - i < number_of_nodes() + ensures + - returns a non-const reference to get_graph().node(i) + !*/ + + void save_graph ( + std::ostream& out + ); + /*! + ensures + - saves the state of the graph to the output stream. Does so in a + way that not only preserves the state of the graph this->graph() + but also preserves the graphical layout of the graph in this + GUI widget. + - Also, the first part of the saved state is a serialized + version of this->graph(). Thus, you can deserialize just the + this->graph() object from the serialized data if you like. + !*/ + + void load_graph ( + std::istream& in + ); + /*! + ensures + - loads a saved graph from the given input stream. + !*/ + + void set_node_label ( + unsigned long i, + const std::string& label + ); + /*! + requires + - i < number_of_nodes() + ensures + - #node_label(i) == label + !*/ + + void set_node_color ( + unsigned long i, + rgb_pixel color + ); + /*! + requires + - i < number_of_nodes() + ensures + - #node_color(i) == color + !*/ + + rgb_pixel node_color ( + unsigned long i + ) const; + /*! + requires + - i < number_of_nodes() + ensures + - returns the color used to draw node graph_node(i) + !*/ + + const std::string node_label ( + unsigned long i + ) const; + /*! + requires + - i < number_of_nodes() + ensures + - returns the text label for node graph_node(i) + !*/ + + template < + typename T + > + void set_node_selected_handler ( + T& object, + void (T::*event_handler_)(unsigned long node_index) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the user selects + a node. + - node_index == the index of the node that was selected + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_node_deselected_handler ( + T& object, + void (T::*event_handler_)(unsigned long node_index) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the user + deselects a node. + - node_index == the index of the node that was deselected + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_node_deleted_handler ( + T& object, + void (T::*event_handler_)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the user + deletes a node. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + template < + typename T + > + void set_graph_modified_handler ( + T& object, + void (T::*event_handler_)() + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the user + modifies the graph (i.e. adds or removes a node or edge) + - the event_handler function is not called when the user just + moves nodes around on the screen. + - This event is always dispatched before any more specific event + that results from the user modifying the graph. + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + directed_graph_drawer(directed_graph_drawer&); // copy constructor + directed_graph_drawer& operator=(directed_graph_drawer&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + class text_grid : public scrollable_region + { + /*! + INITIAL VALUE + - vertical_scroll_increment() == 10 + - horizontal_scroll_increment() == 10 + - border_color() == rgb_pixel(128,128,128) + - number_of_columns() == 0 + - number_of_rows() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a simple grid of square text fields that + looks more or less like a spreadsheet grid. + !*/ + + public: + + text_grid ( + drawable_window& w + ); + /*! + ensures + - #*this is properly initialized + - #*this has been added to window w + - #parent_window() == w + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~text_grid ( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void set_grid_size ( + unsigned long rows, + unsigned long cols + ); + /*! + ensures + - #number_of_rows() == rows + - #number_of_columns() == cols + - for all valid r and c: + - #text(r,c) == "" + - #text_color(r,c) == rgb_pixel(0,0,0) + - #background_color(r,c) == rgb_pixel(255,255,255) + - #is_editable(r,c) == true + !*/ + + unsigned long number_of_columns ( + ) const; + /*! + ensures + - returns the number of columns contained in this grid + !*/ + + unsigned long number_of_rows ( + ) const; + /*! + ensures + - returns the number of rows contained in this grid + !*/ + + rgb_pixel border_color ( + ) const; + /*! + ensures + - returns the color of the lines drawn between the grid elements + !*/ + + void set_border_color ( + rgb_pixel color + ); + /*! + ensures + - #border_color() == color + !*/ + + const std::string text ( + unsigned long row, + unsigned long col + ) const; + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - returns the text in the given grid location + !*/ + + void set_text ( + unsigned long row, + unsigned long col, + const std::string& str + ); + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - #text(row,col) == str + !*/ + + const rgb_pixel text_color ( + unsigned long row, + unsigned long col + ) const; + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - returns the color of the text in the given grid location + !*/ + + void set_text_color ( + unsigned long row, + unsigned long col, + const rgb_pixel color + ); + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - #text_color(row,col) == color + !*/ + + const rgb_pixel background_color ( + unsigned long row, + unsigned long col + ) const; + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - returns the background color of the given grid location + !*/ + + void set_background_color ( + unsigned long row, + unsigned long col, + const rgb_pixel color + ); + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - #background_color(row,col) == color + !*/ + + bool is_editable ( + unsigned long row, + unsigned long col + ) const; + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - if (the given grid location is editable by the user) then + - returns true + - else + - returns false + !*/ + + void set_editable ( + unsigned long row, + unsigned long col, + bool editable + ); + /*! + requires + - row < number_of_rows() + - col < number_of_columns() + ensures + - #is_editable(row,col) == editable + !*/ + + void set_column_width ( + unsigned long col, + unsigned long width + ); + /*! + requires + - col < number_of_columns() + ensures + - the given column will be displayed such that it is width pixels wide + !*/ + + void set_row_height ( + unsigned long row, + unsigned long height + ); + /*! + requires + - row < number_of_rows() + ensures + - the given row will be displayed such that it is height pixels wide + !*/ + + template < + typename T + > + void set_text_modified_handler ( + T& object, + void (T::*event_handler)(unsigned long row, unsigned long col) + ); + /*! + requires + - event_handler is a valid pointer to a member function in T + ensures + - the event_handler function is called on object when the user selects + a node. + - row == row will give the row of the grid item that was modified + - col == col will give the column of the grid item that was modified + - any previous calls to this function are overridden by this new call. + (i.e. you can only have one event handler associated with this + event at a time) + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + text_grid(text_grid&); // copy constructor + text_grid& operator=(text_grid&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_WIDGETs_ABSTRACT_ + diff --git a/dlib/hash_map.h b/dlib/hash_map.h new file mode 100644 index 0000000000000000000000000000000000000000..a61bc5299c7589efa318fc081f0bd426693c9320 --- /dev/null +++ b/dlib/hash_map.h @@ -0,0 +1,63 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_MAp_ +#define DLIB_HASH_MAp_ + +#include "hash_map/hash_map_kernel_1.h" +#include "hash_map/hash_map_kernel_c.h" + +#include "hash_table.h" +#include "algs.h" + +#include "memory_manager.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + unsigned long expnum, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_map + { + hash_map() {} + + typedef typename hash_table::kernel_1a + hash_table_1; + typedef typename hash_table::kernel_2a + hash_table_2; + typedef typename hash_table::kernel_2b + hash_table_3; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef hash_map_kernel_1 + kernel_1a; + typedef hash_map_kernel_c + kernel_1a_c; + + // kernel_1b + typedef hash_map_kernel_1 + kernel_1b; + typedef hash_map_kernel_c + kernel_1b_c; + + // kernel_1c + typedef hash_map_kernel_1 + kernel_1c; + typedef hash_map_kernel_c + kernel_1c_c; + + + }; +} + +#endif // DLIB_HASH_MAp_ + diff --git a/dlib/hash_map/hash_map_kernel_1.h b/dlib/hash_map/hash_map_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..c14f20a3286f799ac8705ac2fc4c0eeda0819771 --- /dev/null +++ b/dlib/hash_map/hash_map_kernel_1.h @@ -0,0 +1,461 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_MAP_KERNEl_1_ +#define DLIB_HASH_MAP_KERNEl_1_ + +#include "hash_map_kernel_abstract.h" +#include "../algs.h" +#include "../general_hash/general_hash.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/remover.h" +#include "../assert.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager = memory_manager::kernel_1a + > + class hash_map_kernel_1 : public enumerable >, + public pair_remover + { + + /*! + REQUIREMENTS ON hash_table + hash_table is instantiated with domain and range and + T_is_POD must be set to false and + implements hash_table/hash_table_kernel_abstract.h + + INITIAL VALUE + table.size() == 0 + + CONVENTION + table.size() = size() == the number of elements in the map + the elements in this hash_map are stored in table + !*/ + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef typename hash_table::compare_type compare_type; + typedef mem_manager mem_manager_type; + + hash_map_kernel_1( + ) : + table(expnum) + { + COMPILE_TIME_ASSERT(expnum < 32); + } + + virtual ~hash_map_kernel_1( + ) + {} + + inline void clear( + ); + + void add ( + domain& d, + range& r + ); + + inline bool is_in_domain ( + const domain& d + ) const; + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& d + ); + + range& operator[] ( + const domain& d + ); + + const range& operator[] ( + const domain& d + ) const; + + inline void swap ( + hash_map_kernel_1& item + ); + + // functions from the remover interface + inline void remove_any ( + domain& d, + range& r + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + inline bool current_element_valid ( + ) const; + + inline const map_pair& element ( + ) const; + + inline map_pair& element ( + ); + + inline bool move_next ( + ) const; + + private: + + hash_table table; + + // restricted functions + hash_map_kernel_1(hash_map_kernel_1&); + hash_map_kernel_1& operator= ( hash_map_kernel_1&); + + }; + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + inline void swap ( + hash_map_kernel_1& a, + hash_map_kernel_1& b + ) { a.swap(b); } + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void deserialize ( + hash_map_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item.add(d,r); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type hash_map_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + clear ( + ) + { + table.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + add ( + domain& d, + range& r + ) + { + table.add(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_map_kernel_1:: + is_in_domain( + const domain& d + ) const + { + return (table[d] != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + remove_any ( + domain& d, + range& r + ) + { + table.remove_any(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + remove( + const domain& d, + domain& d_copy, + range& r + ) + { + table.remove(d,d_copy,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + destroy( + const domain& d + ) + { + table.destroy(d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + range& hash_map_kernel_1:: + operator[]( + const domain& d + ) + { + return *table[d]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + const range& hash_map_kernel_1:: + operator[]( + const domain& d + ) const + { + return *table[d]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + unsigned long hash_map_kernel_1:: + size ( + ) const + { + return table.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + swap ( + hash_map_kernel_1& item + ) + { + table.swap(item.table); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_map_kernel_1:: + at_start ( + ) const + { + return table.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_map_kernel_1:: + reset ( + ) const + { + table.reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_map_kernel_1:: + current_element_valid ( + ) const + { + return table.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + const map_pair& hash_map_kernel_1:: + element ( + ) const + { + return table.element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + map_pair& hash_map_kernel_1:: + element ( + ) + { + return table.element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_map_kernel_1:: + move_next ( + ) const + { + return table.move_next(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_HASH_MAP_KERNEl_1_ + diff --git a/dlib/hash_map/hash_map_kernel_abstract.h b/dlib/hash_map/hash_map_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..4ddeabfc260283597e5a661c394880add2d4384a --- /dev/null +++ b/dlib/hash_map/hash_map_kernel_abstract.h @@ -0,0 +1,244 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_HASH_MAP_KERNEl_ABSTRACT_ +#ifdef DLIB_HASH_MAP_KERNEl_ABSTRACT_ + +#include "../general_hash/general_hash.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../interfaces/map_pair.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + unsigned long expnum, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_map : public enumerable >, + public pair_remover + { + + /*! + REQUIREMENTS ON domain + domain must be comparable by compare where compare is a functor compatible with std::less and + domain must be hashable by general_hash + (general_hash is defined in dlib/general_hash) and + domain must be swappable by a global swap() and + domain must have a default constructor + + REQUIREMENTS ON range + range must be swappable by a global swap() and + range must have a default constructor + + REQUIREMENTS ON expnum + expnum < 32 + 2^expnum is the number of buckets to hash items of type T into. + Note that this is really just a suggestion to the hash table. + Implementations are free to manage the table size however is most + appropriate. + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap(), is_in_domain(), and operator[] functions do + not invalidate pointers or references to internal data. + All other functions have no such guarantees. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + No order is specified. Only that each element will be visited once + and only once. + + WHAT THIS OBJECT REPRESENTS + hash_map contains items of type domain and range + + This object is similar an array. It maps items of type domain on to + items of type range. + + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + hash_map( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + !*/ + + virtual ~hash_map( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void add ( + domain& d, + range& r + ); + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + - is_in_domain(d) == false + ensures + - #is_in_domain(d) == true + - #operator[](d) == r + - #d and #r have initial values for their types + - #size() == size() + 1 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if add() throws then it has no effect + !*/ + + bool is_in_domain ( + const domain& d + ) const; + /*! + ensures + - returns whether or not an element equivalent to d is in the + domain of *this + !*/ + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + - &d != &d_copy (i.e. d and d_copy cannot be the same variable) + - &r != &d_copy (i.e. r and d_copy cannot be the same variable) + - is_in_domain(d) == true + ensures + - #is_in_domain(d) == false + - #d_copy is equivalent to d + - the element in the range of *this associated with #d_copy has + been swapped into #r + - #size() == size() - 1 + - #at_start() == true + !*/ + + void destroy ( + const domain& d + ); + /*! + requires + - is_in_domain(d) == true + ensures + - #is_in_domain(d) == false + - #size() == size() - 1 + - #at_start() == true + !*/ + + range& operator[] ( + const domain& d + ); + /*! + requires + - is_in_domain(d) == true + ensures + - returns a non-const reference to the element in the range of *this + associated with the element equivalent to d + !*/ + + const range& operator[] ( + const domain& d + ) const; + /*! + requires + - is_in_domain(d) == true + ensures + - returns a const reference to the element in the range of *this + associated with the element equivalent to d + !*/ + + void swap ( + hash_map& item + ); + /*! + ensures + - swaps *this and item + !*/ + + + private: + + // restricted functions + hash_map(hash_map&); + hash_map& operator=(hash_map&); + }; + + template < + typename domain, + typename range, + unsigned long expnum, + typename mem_manager, + typename compare + > + inline void swap ( + hash_map& a, + hash_map& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename domain, + typename range, + unsigned long expnum, + typename mem_manager, + typename compare + > + void deserialize ( + hash_map& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_HASH_MAP_KERNEl_ABSTRACT_ + diff --git a/dlib/hash_map/hash_map_kernel_c.h b/dlib/hash_map/hash_map_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..677160e4473f2dddd9364500e41cf343d32f4258 --- /dev/null +++ b/dlib/hash_map/hash_map_kernel_c.h @@ -0,0 +1,276 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_MAP_KERNEl_C_ +#define DLIB_HASH_MAP_KERNEl_C_ + +#include "hash_map_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename hash_map_base + > + class hash_map_kernel_c : public hash_map_base + { + + typedef typename hash_map_base::domain_type domain; + typedef typename hash_map_base::range_type range; + + + public: + void add ( + domain& d, + range& r + ); + + void remove_any ( + domain& d, + range& r + ); + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& d + ); + + range& operator[] ( + const domain& d + ); + + const range& operator[] ( + const domain& d + ) const; + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + }; + + template < + typename hash_map_base + > + inline void swap ( + hash_map_kernel_c& a, + hash_map_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + void hash_map_kernel_c:: + add ( + domain& d, + range& r + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT( (!is_in_domain(d)) && + (reinterpret_cast(&d) != reinterpret_cast(&r)), + "\tvoid hash_map::add" + << "\n\tdomain element being added must not already be in the hash_map" + << "\n\tand d and r must not be the same variable" + << "\n\tis_in_domain(d): " << (is_in_domain(d) ? "true" : "false") + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + << "\n\t&r: " << reinterpret_cast(&r) + ); + + + // call the real function + hash_map_base::add(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + void hash_map_kernel_c:: + remove_any ( + domain& d, + range& r + ) + { + + + // make sure requires clause is not broken + DLIB_CASSERT( (this->size() > 0) && + (reinterpret_cast(&d) != reinterpret_cast(&r)), + "\tvoid hash_map::remove_any" + << "\n\tsize() must be greater than zero if something is going to be removed" + << "\n\tand d and r must not be the same variable." + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + << "\n\t&r: " << reinterpret_cast(&r) + ); + + + // call the real function + hash_map_base::remove_any(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + void hash_map_kernel_c:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + + + // make sure requires clause is not broken + DLIB_CASSERT( (is_in_domain(d)) && + (reinterpret_cast(&d) != reinterpret_cast(&r)) && + (reinterpret_cast(&r) != reinterpret_cast(&d_copy)) && + (reinterpret_cast(&d) != reinterpret_cast(&d_copy)), + "\tvoid hash_map::remove" + << "\n\tcan't remove something that isn't in the hash_map or if the paremeters" + << "\n\tare actually the same variable. Either way can't remove." + << "\n\tis_in_domain(d): " << (is_in_domain(d) ? "true" : "false") + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + << "\n\t&r: " << reinterpret_cast(&r) + << "\n\t&d_copy: " << reinterpret_cast(&d_copy) + ); + + + // call the real function + hash_map_base::remove(d,d_copy,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + void hash_map_kernel_c:: + destroy ( + const domain& d + ) + { + + + // make sure requires clause is not broken + DLIB_CASSERT( is_in_domain(d), + "\tvoid hash_map::destroy" + << "\n\tcan't remove something that isn't in the hash_map" + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + ); + + + // call the real function + hash_map_base::destroy(d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + typename hash_map_base::range_type& hash_map_kernel_c:: + operator[] ( + const domain& d + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_in_domain(d), + "\trange& hash_map::operator[]" + << "\n\td must be in the domain of the hash_map" + << "\n\tthis: " << this + ); + + // call the real function + return hash_map_base::operator[](d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + const typename hash_map_base::range_type& hash_map_kernel_c:: + operator[] ( + const domain& d + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( is_in_domain(d), + "\tconst range& hash_map::operator[]" + << "\n\td must be in the domain of the hash_map" + << "\n\tthis: " << this + ); + + // call the real function + return hash_map_base::operator[](d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + const map_pair& hash_map_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst map_pair& hash_map::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return hash_map_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_map_base + > + map_pair& hash_map_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tmap_pair& hash_map::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return hash_map_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_HASH_MAP_KERNEl_C_ + diff --git a/dlib/hash_set.h b/dlib/hash_set.h new file mode 100644 index 0000000000000000000000000000000000000000..a08b3d540da4cd3ab938dba97bd18ab8a2dccb4d --- /dev/null +++ b/dlib/hash_set.h @@ -0,0 +1,63 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_SEt_ +#define DLIB_HASH_SEt_ + +#include "hash_set/hash_set_kernel_1.h" +#include "hash_set/hash_set_kernel_c.h" + +#include "hash_table.h" +#include "algs.h" + + +#include "memory_manager.h" +#include + + +namespace dlib +{ + + template < + typename T, + unsigned long expnum, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_set + { + hash_set() {} + + typedef typename hash_table::kernel_1a ht1a; + typedef typename hash_table::kernel_1a ht2a; + typedef typename hash_table::kernel_1a ht2b; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef hash_set_kernel_1 + kernel_1a; + typedef hash_set_kernel_c + kernel_1a_c; + + // kernel_1b + typedef hash_set_kernel_1 + kernel_1b; + typedef hash_set_kernel_c + kernel_1b_c; + + // kernel_1c + typedef hash_set_kernel_1 + kernel_1c; + typedef hash_set_kernel_c + kernel_1c_c; + + + + + }; +} + +#endif // DLIB_HASH_SEt_ + diff --git a/dlib/hash_set/hash_set_kernel_1.h b/dlib/hash_set/hash_set_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..0dcb8c7fa77a74d1ab7ace41f36018b7f3049293 --- /dev/null +++ b/dlib/hash_set/hash_set_kernel_1.h @@ -0,0 +1,392 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_SET_KERNEl_1_ +#define DLIB_HASH_SET_KERNEl_1_ + +#include "hash_set_kernel_abstract.h" +#include "../algs.h" +#include "../general_hash/general_hash.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../assert.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager = memory_manager::kernel_1a + > + class hash_set_kernel_1 : public enumerable, + public remover + { + + /*! + REQUIREMENTS ON hash_table + hash_table is instantiated with and + T_is_POD must be set to false and + is an implementation of hash_table/hash_table_kernel_abstract.h + + INITIAL VALUE + table.size() == 0 + + CONVENTION + table.size() = size() == the number of elements in the set and + the elements in this hash_set are stored in table + !*/ + + public: + + typedef T type; + typedef typename hash_table::compare_type compare_type; + typedef mem_manager mem_manager_type; + + hash_set_kernel_1( + ) : + table(expnum) + { + COMPILE_TIME_ASSERT(expnum < 32); + } + + virtual ~hash_set_kernel_1( + ) + {} + + inline void clear( + ); + + inline void add ( + T& item + ); + + inline bool is_member ( + const T& item + ) const; + + inline void remove ( + const T& item, + T& item_copy + ); + + inline void destroy ( + const T& item + ); + + inline void swap ( + hash_set_kernel_1& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + inline bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline const T& element ( + ); + + inline bool move_next ( + ) const; + + private: + + hash_table table; + char junk; + + // restricted functions + hash_set_kernel_1(hash_set_kernel_1&); + hash_set_kernel_1& operator= ( hash_set_kernel_1&); + + }; + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + inline void swap ( + hash_set_kernel_1& a, + hash_set_kernel_1& b + ) { a.swap(b); } + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void deserialize ( + hash_set_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + item.add(temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type hash_set_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + clear ( + ) + { + table.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + add ( + T& item + ) + { + table.add(item,junk); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_set_kernel_1:: + is_member( + const T& item + ) const + { + return (table[item] != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + remove_any ( + T& item + ) + { + table.remove_any(item,junk); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + remove( + const T& item, + T& item_copy + ) + { + table.remove(item,item_copy,junk); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + destroy( + const T& item + ) + { + table.destroy(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + unsigned long hash_set_kernel_1:: + size ( + ) const + { + return table.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + swap ( + hash_set_kernel_1& item + ) + { + table.swap(item.table); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_set_kernel_1:: + at_start ( + ) const + { + return table.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + void hash_set_kernel_1:: + reset ( + ) const + { + table.reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_set_kernel_1:: + current_element_valid ( + ) const + { + return table.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + const T& hash_set_kernel_1:: + element ( + ) const + { + return table.element().key(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + const T& hash_set_kernel_1:: + element ( + ) + { + return table.element().key(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long expnum, + typename hash_table, + typename mem_manager + > + bool hash_set_kernel_1:: + move_next ( + ) const + { + return table.move_next(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_HASH_SET_KERNEl_1_ + diff --git a/dlib/hash_set/hash_set_kernel_abstract.h b/dlib/hash_set/hash_set_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..be322f20bc2079633dcfd888643568cb098dca64 --- /dev/null +++ b/dlib/hash_set/hash_set_kernel_abstract.h @@ -0,0 +1,204 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_HASH_SET_KERNEl_ABSTRACT_ +#ifdef DLIB_HASH_SET_KERNEl_ABSTRACT_ + +#include "../general_hash/general_hash.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename T, + unsigned long expnum, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_set : public enumerable, + public remover + { + + /*! + REQUIREMENTS ON T + domain must be comparable by compare where compare is a functor compatible with std::less and + T must be hashable by general_hash + (general_hash is defined in dlib/general_hash) and + T must be swappable by a global swap() and + T must have a default constructor + + REQUIREMENTS ON expnum + expnum < 32 + 2^expnum is the number of buckets to hash items of type T into. + Note that this is really just a suggestion to the hash table. + Implementations are free to manage the table size however is most + appropriate. + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap() and is_member() functions do not invalidate + pointers or references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + No order is specified. Only that each element will be visited once + and only once. + + WHAT THIS OBJECT REPRESENTS + hash_set contains items of type T + + This object represents an unaddressed collection + of items. Every element in a hash_set is unique. + + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + public: + + typedef T type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + hash_set( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + virtual ~hash_set( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void add ( + T& item + ); + /*! + requires + - is_member(item) == false + ensures + - #is_member(item) == true + - #item has an initial value for its type + - #size() == size() + 1 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + if add() throws then it has no effect + !*/ + + bool is_member ( + const T& item + ) const; + /*! + ensures + - returns whether or not there is an element in *this equivalent + to item + !*/ + + void remove ( + const T& item, + T& item_copy + ); + /*! + requires + - is_member(item) == true + - &item != &item_copy (i.e. item and item_copy cannot be the + same variable) + ensures + - #is_member(item) == false + - the element in *this equivalent to item has been removed and + swapped into #item_copy + - #size() == size() - 1 + - #at_start() == true + !*/ + + void destroy ( + const T& item + ); + /*! + requires + - is_member(item) == true + ensures + - #is_member(item) == false + - #size() == size() - 1 + - #at_start() == true + !*/ + + void swap ( + hash_set& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + hash_set(hash_set&); // copy constructor + hash_set& operator=(hash_set&); // assignment operator + + }; + + template < + typename T, + unsigned long expnum, + typename mem_manager, + typename compare + > + inline void swap ( + hash_set& a, + hash_set& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + unsigned long expnum, + typename mem_manager, + typename compare + > + void deserialize ( + hash_set& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_HASH_SET_KERNEl_ABSTRACT_ + diff --git a/dlib/hash_set/hash_set_kernel_c.h b/dlib/hash_set/hash_set_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..cf8138a5272b84da955484674343d5fdef9f3e04 --- /dev/null +++ b/dlib/hash_set/hash_set_kernel_c.h @@ -0,0 +1,190 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_SET_KERNEl_C_ +#define DLIB_HASH_SET_KERNEl_C_ + +#include "hash_set_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename hash_set_base + > + class hash_set_kernel_c : public hash_set_base + { + typedef typename hash_set_base::type T; + public: + + void add ( + T& item + ); + + void remove_any ( + T& item + ); + + void remove ( + const T& item, + T& item_copy + ); + + void destroy ( + const T& item + ); + + const T& element ( + ) const; + + const T& element ( + ); + + + }; + + + template < + typename hash_set_base + > + inline void swap ( + hash_set_kernel_c& a, + hash_set_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename hash_set_base + > + void hash_set_kernel_c:: + add( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !is_member(item), + "\tvoid hash_set::add" + << "\n\titem being added must not already be in the hash_set" + << "\n\tthis: " << this + ); + + // call the real function + hash_set_base::add(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_set_base + > + void hash_set_kernel_c:: + remove ( + const T& item, + T& item_copy + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_member(item) && + (reinterpret_cast(&item) != reinterpret_cast(&item_copy)), + "\tvoid hash_set::remove" + << "\n\titem should be in the hash_set if it's going to be removed" + << "\n\tthis: " << this + << "\n\t&item: " << &item + << "\n\t&item_copy: " << &item_copy + ); + + // call the real function + hash_set_base::remove(item,item_copy); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_set_base + > + void hash_set_kernel_c:: + destroy ( + const T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_member(item), + "\tvoid hash_set::destroy" + << "\n\titem should be in the hash_set if it's going to be removed" + << "\n\tthis: " << this + << "\n\t&item: " << &item + ); + + // call the real function + hash_set_base::destroy(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_set_base + > + void hash_set_kernel_c:: + remove_any ( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->size() != 0, + "\tvoid hash_set::remove_any" + << "\n\tsize must be greater than zero if an item is to be removed" + << "\n\tthis: " << this + ); + + // call the real function + hash_set_base::remove_any(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_set_base + > + const typename hash_set_base::type& hash_set_kernel_c:: + element ( + ) const + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& hash_set::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return hash_set_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename hash_set_base + > + const typename hash_set_base::type& hash_set_kernel_c:: + element ( + ) + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tT& hash_set::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return hash_set_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_HASH_SET_KERNEl_C_ + diff --git a/dlib/hash_table.h b/dlib/hash_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6d3831ab37d8cb06d9309e1d3b18819a61f8844c --- /dev/null +++ b/dlib/hash_table.h @@ -0,0 +1,60 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_TABLe_ +#define DLIB_HASH_TABLe_ + + +#include "hash_table/hash_table_kernel_1.h" +#include "hash_table/hash_table_kernel_2.h" +#include "hash_table/hash_table_kernel_c.h" +#include "memory_manager.h" + +#include "binary_search_tree.h" +#include + + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_table + { + hash_table() {} + + typedef typename binary_search_tree::kernel_1a + bst_1; + typedef typename binary_search_tree::kernel_2a + bst_2; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef hash_table_kernel_1 + kernel_1a; + typedef hash_table_kernel_c + kernel_1a_c; + + + // kernel_2a + typedef hash_table_kernel_2 + kernel_2a; + typedef hash_table_kernel_c + kernel_2a_c; + + // kernel_2b + typedef hash_table_kernel_2 + kernel_2b; + typedef hash_table_kernel_c + kernel_2b_c; + }; +} + +#endif // DLIB_HASH_TABLe_ + diff --git a/dlib/hash_table/hash_table_kernel_1.h b/dlib/hash_table/hash_table_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..835d85a29ef3d6ad39f4be06d57feefe59f16693 --- /dev/null +++ b/dlib/hash_table/hash_table_kernel_1.h @@ -0,0 +1,820 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_TABLE_KERNEl_1_ +#define DLIB_HASH_TABLE_KERNEl_1_ + +#include "hash_table_kernel_abstract.h" +#include "../general_hash/general_hash.h" +#include "../algs.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../assert.h" +#include "../serialize.h" +#include "../memory_manager.h" +#include + + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_table_kernel_1 : public enumerable >, + public pair_remover + { + + /*! + INITIAL VALUE + hash_size == 0 + table == pointer to an array of num_of_buckets node pointers + num_of_buckets == the number of buckets in the hash table + current_element == 0 + at_start_ == true + mask == num_of_buckets-1 + + CONVENTION + current_element_valid() == (current_element != 0) + element() == current_element->d and current_element->r + at_start_ == at_start() + if (current_element != 0) then + table[current_bucket] == a pointer to the linked list that contains + the node pointed to by current_element + + mask == num_of_buckets-1 + + + + hash_size = size() == the number of elements in the hash_table and + table == pointer to an array of num_of_buckets node pointers and + num_of_buckets == the number of buckets in the hash table and + for all i: + table[i] == pointer to the first node in a linked list or + table[i] == 0 if this bucket is currently not in use + + + for all nodes: + d == the domain element stored in this node + r == the range element stored in this node which is associated with + d. + next == pointer to the next node in the linked list or + next == 0 if this is the last node in the linked list + + !*/ + + struct node + { + node* next; + domain d; + range r; + }; + + + class mpair : public map_pair + { + public: + const domain* d; + range* r; + + const domain& key( + ) const { return *d; } + + const range& value( + ) const { return *r; } + + range& value( + ) { return *r; } + }; + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + explicit hash_table_kernel_1( + unsigned long expnum + ); + + virtual ~hash_table_kernel_1( + ); + + void clear( + ); + + unsigned long count ( + const domain& item + ) const; + + void add ( + domain& d, + range& r + ); + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& d + ); + + const range* operator[] ( + const domain& d + ) const; + + range* operator[] ( + const domain& d + ); + + void swap ( + hash_table_kernel_1& item + ); + + // functions from the remover interface + void remove_any ( + domain& d, + range& r + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + bool move_next ( + ) const; + + private: + + // data members + typename mem_manager::template rebind::other pool; + typename mem_manager::template rebind::other ppool; + unsigned long hash_size; + node** table; + general_hash hash; + unsigned long num_of_buckets; + unsigned long mask; + + mutable mpair p; + + mutable unsigned long current_bucket; + mutable node* current_element; + mutable bool at_start_; + compare comp; + + // restricted functions + hash_table_kernel_1(hash_table_kernel_1&); + hash_table_kernel_1& operator=(hash_table_kernel_1&); + + }; + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + inline void swap ( + hash_table_kernel_1& a, + hash_table_kernel_1& b + ) { a.swap(b); } + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void deserialize ( + hash_table_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item.add(d,r); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type hash_table_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + hash_table_kernel_1:: + hash_table_kernel_1( + unsigned long expnum + ) : + hash_size(0), + current_element(0), + at_start_(true) + { + + num_of_buckets = 1; + while (expnum != 0) + { + --expnum; + num_of_buckets <<= 1; + } + mask = num_of_buckets-1; + + table = ppool.allocate_array(num_of_buckets); + for (unsigned long i = 0; i < num_of_buckets; ++i) + { + table[i] = 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + hash_table_kernel_1:: + ~hash_table_kernel_1( + ) + { + for (unsigned long i = 0; i < num_of_buckets; ++i) + { + // delete this linked list + node* temp = table[i]; + while (temp) + { + node* t = temp; + temp = temp->next; + pool.deallocate(t); + } + table[i] = 0; + } + ppool.deallocate_array(table); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + clear( + ) + { + if (hash_size > 0) + { + for (unsigned long i = 0; i < num_of_buckets; ++i) + { + // delete this linked list + node* temp = table[i]; + while (temp) + { + node* t = temp; + temp = temp->next; + pool.deallocate(t); + } + table[i] = 0; + } + hash_size = 0; + } + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long hash_table_kernel_1:: + size( + ) const + { + return hash_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + unsigned long hash_table_kernel_1:: + count( + const domain& d + ) const + { + unsigned long items_found = 0; + node* temp = table[hash(d)&mask]; + + while (temp != 0) + { + // look for an element equivalent to d + if ( !(comp(temp->d , d) || comp(d , temp->d)) ) + { + ++items_found; + } + temp = temp->next; + } + + return items_found; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + add( + domain& d, + range& r + ) + { + unsigned long hash_value = hash(d)&mask; + + // make a new node for this item + node& temp = *(pool.allocate()); + exchange(d,temp.d); + exchange(r,temp.r); + + // add this new node to the head of the linked list in bucket number hash_value + temp.next = table[hash_value]; + table[hash_value] = &temp; + + ++hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + destroy( + const domain& d + ) + { + node* last; + const unsigned long hash_value = hash(d)&mask; + node* temp = table[hash_value]; + + // if there is more than one thing in this bucket + if (temp->next != 0) + { + // start looking with the second item in the list + last = temp; + temp = temp->next; + while (true) + { + // if we hit the end of the list without finding item then it must + // be the first element in the list so splice it out + if (temp == 0) + { + temp = table[hash_value]; + table[hash_value] = temp->next; + + break; + } + + // look for an element equivalent to item + if ( !(comp(temp->d , d) || comp(d , temp->d)) ) + { + // splice out the node we want to remove + last->next = temp->next; + break; + } + + last = temp; + temp = temp->next; + } + + } + // else there is only one node in this linked list + else + { + table[hash_value] = 0; + } + + pool.deallocate(temp); + + --hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + remove( + const domain& d, + domain& d_copy, + range& r + ) + { + node* last; + const unsigned long hash_value = hash(d)&mask; + node* temp = table[hash_value]; + + // if there is more than one thing in this bucket + if (temp->next != 0) + { + // start looking with the second item in the list + last = temp; + temp = temp->next; + while (true) + { + // if we hit the end of the list without finding item then it must + // be the first element in the list so splice it out + if (temp == 0) + { + temp = table[hash_value]; + table[hash_value] = temp->next; + + break; + } + + // look for an element equivalent to item + if ( !(comp(temp->d , d) || comp(d , temp->d)) ) + { + // splice out the node we want to remove + last->next = temp->next; + break; + } + + last = temp; + temp = temp->next; + } + + } + // else there is only one node in this linked list + else + { + table[hash_value] = 0; + } + + + exchange(d_copy,temp->d); + exchange(r,temp->r); + pool.deallocate(temp); + + --hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + remove_any( + domain& d, + range& r + ) + { + unsigned long i = 0; + + // while the ith bucket is empty keep looking + while (table[i] == 0) + { + ++i; + } + + // remove the first node in the linked list in the ith bucket + node& temp = *(table[i]); + + exchange(temp.d,d); + exchange(temp.r,r); + table[i] = temp.next; + + pool.deallocate(&temp); + + --hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const range* hash_table_kernel_1:: + operator[]( + const domain& d + ) const + { + node* temp = table[hash(d)&mask]; + + while (temp != 0) + { + // look for an element equivalent to item + if ( !(comp(temp->d , d) || comp(d , temp->d)) ) + return &(temp->r); + + temp = temp->next; + } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + range* hash_table_kernel_1:: + operator[]( + const domain& d + ) + { + node* temp = table[hash(d)&mask]; + + while (temp != 0) + { + // look for an element equivalent to item + if ( !(comp(temp->d , d) || comp(d , temp->d)) ) + return &(temp->r); + + temp = temp->next; + } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + swap( + hash_table_kernel_1& item + ) + { + exchange(mask,item.mask); + exchange(table,item.table); + exchange(hash_size,item.hash_size); + exchange(num_of_buckets,item.num_of_buckets); + exchange(current_bucket,item.current_bucket); + exchange(current_element,item.current_element); + exchange(at_start_,item.at_start_); + pool.swap(item.pool); + ppool.swap(item.ppool); + exchange(p,item.p); + exchange(comp,item.comp); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool hash_table_kernel_1:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void hash_table_kernel_1:: + reset ( + ) const + { + at_start_ = true; + current_element = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool hash_table_kernel_1:: + current_element_valid ( + ) const + { + return (current_element != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + const map_pair& hash_table_kernel_1:: + element ( + ) const + { + p.d = &(current_element->d); + p.r = &(current_element->r); + return p; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + map_pair& hash_table_kernel_1:: + element ( + ) + { + p.d = &(current_element->d); + p.r = &(current_element->r); + return p; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + bool hash_table_kernel_1:: + move_next ( + ) const + { + if (at_start_) + { + at_start_ = false; + // if the queue is empty then there is nothing to do + if (hash_size == 0) + { + return false; + } + else + { + // find the first element in the hash table + for (current_bucket = 0; true ; ++current_bucket) + { + if (table[current_bucket] != 0) + { + current_element = table[current_bucket]; + break; + } + } + return true; + } + } + else + { + // if we have already enumerated every element + if (current_element == 0) + { + return false; + } + else + { + // find the next element if it exists + if (current_element->next != 0) + { + current_element = current_element->next; + return true; + } + else + { + // find next bucket with something in it + for (current_bucket+=1; current_bucket + +namespace dlib +{ + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_table_kernel_2 : public enumerable >, + public pair_remover + { + + /*! + REQUIREMENTS ON bst_base + bst_base is instantiated with domain and range and + implements binray_search_tree/binary_search_tree_kernel_abstract.h + + INITIAL VALUE + hash_size == 0 + table == pointer to an array of num_of_buckets bst_base objects + num_of_buckets == the number of buckets in the hash table + current_bucket == 0 + at_start_ == true + + CONVENTION + current_element_valid() == (current_bucket != 0) + element() == current_bucket->element() + at_start_ == at_start() + + mask == num_of_buckets-1 + + for all integers i where &table[i] != current_bucket + table[i].at_start() == true + + + hash_size = size() == the number of elements in the hash_table and + table == pointer to an array of num_of_buckets bst_base objects + num_of_buckets == the number of buckets in the hash table and + the elements in this hash table are stored in the bst_base objects in the + array table + + !*/ + + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + explicit hash_table_kernel_2( + unsigned long expnum + ); + + virtual ~hash_table_kernel_2( + ) + { pool.deallocate_array(table); } + + void clear( + ); + + unsigned long count ( + const domain& item + ) const; + + inline void add ( + domain& d, + range& r + ); + + void destroy ( + const domain& d + ); + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + const range* operator[] ( + const domain& item + ) const; + + range* operator[] ( + const domain& item + ); + + inline void swap ( + hash_table_kernel_2& item + ); + + // functions from the remover interface + void remove_any ( + domain& d, + range& r + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + inline const map_pair& element ( + ) const; + + inline map_pair& element ( + ); + + bool move_next ( + ) const; + + private: + + // data members + typename mem_manager::template rebind::other pool; + unsigned long mask; + unsigned long hash_size; + unsigned long num_of_buckets; + bst_base* table; + general_hash hash; + mutable bst_base* current_bucket; + mutable bool at_start_; + compare comp; + + // restricted functions + hash_table_kernel_2(hash_table_kernel_2&); + hash_table_kernel_2& operator=(hash_table_kernel_2&); + + }; + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + inline void swap ( + hash_table_kernel_2& a, + hash_table_kernel_2& b + ) { a.swap(b); } + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void deserialize ( + hash_table_kernel_2& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item.add(d,r); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type hash_table_kernel_2"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + hash_table_kernel_2:: + hash_table_kernel_2( + unsigned long expnum + ) : + hash_size(0), + current_bucket(0), + at_start_(true) + { + + num_of_buckets = 1; + while (expnum != 0) + { + --expnum; + num_of_buckets <<= 1; + } + mask = num_of_buckets-1; + + table = pool.allocate_array(num_of_buckets); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + clear( + ) + { + if (hash_size != 0) + { + hash_size = 0; + for (unsigned long i = 0; i < num_of_buckets; ++i) + table[i].clear(); + } + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + unsigned long hash_table_kernel_2:: + size( + ) const + { + return hash_size; + } +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + unsigned long hash_table_kernel_2:: + count( + const domain& item + ) const + { + return table[hash(item)&mask].count(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + destroy( + const domain& item + ) + { + table[hash(item)&mask].destroy(item); + --hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + add( + domain& d, + range& r + ) + { + table[hash(d)&mask].add(d,r); + ++hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + remove( + const domain& d, + domain& d_copy, + range& r + ) + { + table[hash(d)&mask].remove(d,d_copy,r); + --hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + remove_any( + domain& d, + range& r + ) + { + unsigned long i = 0; + while (table[i].size() == 0) + { + ++i; + } + table[i].remove_any(d,r); + --hash_size; + + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + const range* hash_table_kernel_2:: + operator[]( + const domain& d + ) const + { + return table[hash(d)&mask][d]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + range* hash_table_kernel_2:: + operator[]( + const domain& d + ) + { + return table[hash(d)&mask][d]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + swap( + hash_table_kernel_2& item + ) + { + pool.swap(item.pool); + exchange(mask,item.mask); + exchange(hash_size,item.hash_size); + exchange(num_of_buckets,item.num_of_buckets); + exchange(table,item.table); + exchange(current_bucket,item.current_bucket); + exchange(at_start_,item.at_start_); + exchange(comp,item.comp); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + bool hash_table_kernel_2:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + void hash_table_kernel_2:: + reset ( + ) const + { + at_start_ = true; + if (current_bucket != 0) + { + current_bucket->reset(); + current_bucket = 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + bool hash_table_kernel_2:: + current_element_valid ( + ) const + { + return (current_bucket != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + const map_pair& hash_table_kernel_2:: + element ( + ) const + { + return current_bucket->element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + map_pair& hash_table_kernel_2:: + element ( + ) + { + return current_bucket->element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager, + typename compare + > + bool hash_table_kernel_2:: + move_next ( + ) const + { + if (at_start_) + { + at_start_ = false; + // if the queue is empty then there is nothing to do + if (hash_size == 0) + { + return false; + } + else + { + // find the first element in the hash table + current_bucket = table; + while (current_bucket->size() == 0) + { + ++current_bucket; + } + + current_bucket->move_next(); + + return true; + } + } + else + { + // if we have already enumerated every element + if (current_bucket == 0) + { + return false; + } + else + { + if (current_bucket->move_next()) + { + // if there is another element in this current bucket then use that + return true; + } + else + { + // find the next bucket + bst_base* end = table + num_of_buckets; + current_bucket->reset(); + + while (true) + { + ++current_bucket; + // if we ran out of buckets and didn't find anything + if (current_bucket == end) + { + current_bucket = 0; + return false; + } + if (current_bucket->size() > 0) + { + current_bucket->move_next(); + return true; + } + } + } + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_HASH_TABLE_KERNEl_2_ + diff --git a/dlib/hash_table/hash_table_kernel_abstract.h b/dlib/hash_table/hash_table_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..5c7c07c3e49253bd6543cce828f0508832257699 --- /dev/null +++ b/dlib/hash_table/hash_table_kernel_abstract.h @@ -0,0 +1,250 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_HASH_TABLE_KERNEl_ABSTRACT_ +#ifdef DLIB_HASH_TABLE_KERNEl_ABSTRACT_ + +#include "../interfaces/map_pair.h" +#include "../general_hash/general_hash.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class hash_table : public enumerable >, + public pair_remover + { + + /*! + REQUIREMENTS ON domain + domain must be comparable by compare where compare is a functor compatible with std::less and + domain must be hashable by general_hash + (general_hash is defined in dlib/general_hash) and + domain must be swappable by a global swap() and + domain must have a default constructor + + REQUIREMENTS ON range + range must be swappable by a global swap() and + range must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap(), count(), and operator[] functions do + not invalidate pointers or references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + No order is specified. Only that each element will be visited once + and only once. + + WHAT THIS OBJECT REPRESENTS + hash_table contains items of type T + + This object represents a data dictionary that is built on top of some + kind of hash table. The number of buckets in the hash table is + defined by the constructor argument and is some power of 2. + + NOTE: + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + explicit hash_table( + unsigned long expnum + ); + /*! + requires + - expnum < 32 + ensures + - #*this is properly initialized + - #*this will use 2^expnum as a suggestion for the initial number + of buckets. + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + !*/ + + virtual ~hash_table( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + unsigned long count ( + const domain& d + ) const; + /*! + ensures + - returns the number of elements in the domain of *this that are + equivalent to d + !*/ + + void add ( + domain& d, + range& r + ); + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + ensures + - adds a mapping between d and r to *this + - if (count(d) == 0) then + - #*(*this)[d] == r + - else + - #(*this)[d] != 0 + - #d and #r have initial values for their types + - #count(d) == count(d) + 1 + - #at_start() == true + - #size() == size() + 1 + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if add() throws then it has no effect + !*/ + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + /*! + requires + - (*this)[d] != 0 + - &d != &r (i.e. d and r cannot be the same variable) + - &d != &d_copy (i.e. d and d_copy cannot be the same variable) + - &r != &d_copy (i.e. r and d_copy cannot be the same variable) + ensures + - some element in the domain of *this that is equivalent to d has + been removed and swapped into #d_copy. Additionally, its + associated range element has been removed and swapped into #r. + - #count(d) = count(d) - 1 + - #size() == size() - 1 + - #at_start() == true + !*/ + + void destroy ( + const domain& d + ); + /*! + requires + - (*this)[d] != 0 + ensures + - an element in the domain of *this equivalent to d has been removed. + The element in the range of *this associated with d has also been + removed. + - #count(d) == count(d) - 1 + - #size() == size() - 1 + - #at_start() == true + !*/ + + const range* operator[] ( + const domain& d + ) const; + /*! + ensures + - if (there is an element in the domain equivalent to d) then + - returns a pointer to an element in the range of *this that + is associated with an element in the domain of *this + equivalent to d. + - else + - returns 0 + !*/ + + range* operator[] ( + const domain& d + ); + /*! + ensures + - if (there is an element in the domain equivalent to d) then + - returns a pointer to an element in the range of *this that + is associated with an element in the domain of *this + equivalent to d. + - else + - returns 0 + !*/ + + void swap ( + hash_table& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + hash_table(hash_table&); + hash_table& operator=(hash_table&); + + }; + + template < + typename domain, + typename range, + typename mem_manager + > + inline void swap ( + hash_table& a, + hash_table& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename domain, + typename range, + typename mem_manager + > + void deserialize ( + hash_table& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_HASH_TABLE_KERNEl_ABSTRACT_ + diff --git a/dlib/hash_table/hash_table_kernel_c.h b/dlib/hash_table/hash_table_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..c16c98f68d24ec6b75784e69ee4e1df39235eaf5 --- /dev/null +++ b/dlib/hash_table/hash_table_kernel_c.h @@ -0,0 +1,212 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_HASH_TABLE_KERNEl_C_ +#define DLIB_HASH_TABLE_KERNEl_C_ + +#include "hash_table_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/map_pair.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename ht_base + > + class hash_table_kernel_c : public ht_base + { + typedef typename ht_base::domain_type domain; + typedef typename ht_base::range_type range; + public: + + explicit hash_table_kernel_c ( + unsigned long expnum + ) : + ht_base(expnum) + { + DLIB_CASSERT(expnum < 32, + "\thash_table::hash_table(unsigned long)" + << "\n\tyou can't set expnum >= 32" + << "\n\tthis: " << this + << "\n\texpnum: " << expnum + ); + } + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void remove_any ( + domain& d, + range& r + ); + + void add ( + domain& d, + range& r + ); + + void destroy ( + const domain& d + ); + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + + }; + + + template < + typename ht_base + > + inline void swap ( + hash_table_kernel_c& a, + hash_table_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename ht_base + > + void hash_table_kernel_c:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + DLIB_CASSERT(operator[](d) != 0 && + (reinterpret_cast(&d) != reinterpret_cast(&d_copy)) && + (reinterpret_cast(&d) != reinterpret_cast(&r)) && + (reinterpret_cast(&r) != reinterpret_cast(&d_copy)), + "\tvoid binary_search_tree::remove" + << "\n\tthe element must be in the table for it to be removed" + << "\n\tthis: " << this + << "\n\t&d: " << &d + << "\n\t&d_copy: " << &d_copy + << "\n\t&r: " << &r + ); + + ht_base::remove(d,d_copy,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename ht_base + > + void hash_table_kernel_c:: + add( + domain& d, + range& r + ) + { + DLIB_CASSERT( reinterpret_cast(&d) != reinterpret_cast(&r), + "\tvoid binary_search_tree::add" + << "\n\tyou can't call add() and give the same object to both arguments." + << "\n\tthis: " << this + << "\n\t&d: " << &d + << "\n\t&r: " << &r + << "\n\tsize(): " << this->size() + ); + + ht_base::add(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename ht_base + > + void hash_table_kernel_c:: + destroy( + const domain& d + ) + { + DLIB_CASSERT((*this)[d] != 0, + "\tvoid hash_table::destroy" + << "\n\tthe element must be in the table for it to be destroyed" + << "\n\tthis: " << this + << "\n\t&d: " << &d + ); + + ht_base::destroy(d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename ht_base + > + void hash_table_kernel_c:: + remove_any( + domain& d, + range& r + ) + { + DLIB_CASSERT(this->size() != 0 && + (reinterpret_cast(&d) != reinterpret_cast(&r)), + "\tvoid hash_table::remove_any" + << "\n\ttable must not be empty if something is going to be removed" + << "\n\tthis: " << this + << "\n\t&d: " << &d + << "\n\t&r: " << &r + ); + + ht_base::remove_any(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename ht_base + > + const map_pair& hash_table_kernel_c:: + element ( + ) const + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst map_pair& hash_table::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return ht_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename ht_base + > + map_pair& hash_table_kernel_c:: + element ( + ) + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tmap_pair& hash_table::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return ht_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_HASH_TABLE_KERNEl_C_ + diff --git a/dlib/image_io.h b/dlib/image_io.h new file mode 100644 index 0000000000000000000000000000000000000000..f3502b63e8cd81e9c2af4464a7f6b4b627ad3203 --- /dev/null +++ b/dlib/image_io.h @@ -0,0 +1,11 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_IMAGe_IO_ +#define DLIB_IMAGe_IO_ + +#include "image_loader/image_loader.h" +#include "image_loader/png_loader.h" +#include "image_saver/image_saver.h" + +#endif // DLIB_IMAGe_IO_ + diff --git a/dlib/image_loader/image_loader.h b/dlib/image_loader/image_loader.h new file mode 100644 index 0000000000000000000000000000000000000000..4a7d6e6e4cf43756d6598e74e1b04bb9fc2612c4 --- /dev/null +++ b/dlib/image_loader/image_loader.h @@ -0,0 +1,688 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_IMAGE_LOADEr_ +#define DLIB_IMAGE_LOADEr_ + +#include "image_loader_abstract.h" +#include +#include +#include "../algs.h" +#include "../pixel.h" +#include "../image_saver/dng_shared.h" +#include "../entropy_decoder_model.h" +#include "../entropy_decoder.h" +#include "../uintn.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class image_load_error : public dlib::error { + public: image_load_error(const std::string& str) : error(EIMAGE_LOAD,str){} + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void load_bmp ( + image_type& image, + std::istream& in_ + ) + { + try + { + unsigned long bytes_read_so_far = 0; + unsigned long bfSize; + unsigned long bfOffBits; + unsigned long bfReserved; + unsigned long biSize; + unsigned long biWidth; + unsigned long biHeight; + unsigned short biBitCount; + /* + unsigned long biCompression; + unsigned long biSizeImage; + unsigned long biClrUsed; + unsigned long biClrImportant; + */ + unsigned long a, b, c, d, i; + + using namespace std; + + streambuf& in = *in_.rdbuf(); + // streamsize num; + unsigned char buf[100]; + + + // first make sure the BMP starts with BM + if (in.sgetn(reinterpret_cast(buf),2) != 2) + throw image_load_error("bmp load error 1: header error"); + bytes_read_so_far += 2; + + if (buf[0] != 'B' || buf[1] != 'M') + throw image_load_error("bmp load error 2: header error"); + + // now read the BITMAPFILEHEADER + if (in.sgetn(reinterpret_cast(buf),12) != 12) + throw image_load_error("bmp load error 3: header error"); + + bytes_read_so_far += 12; + + i = 0; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + bfSize = a | (b<<8) | (c<<16) | (d<<24); + + i = 4; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + bfReserved = a | (b<<8) | (c<<16) | (d<<24); + + i = 8; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + bfOffBits = a | (b<<8) | (c<<16) | (d<<24); + + // if this value isn't zero then there is something wrong + // with this bitmap. + if (bfReserved != 0) + throw image_load_error("bmp load error 4: reserved area not zero"); + + + // load the BITMAPINFOHEADER + if (in.sgetn(reinterpret_cast(buf),40) != 40) + throw image_load_error("bmp load error 5: file too short"); + bytes_read_so_far += 40; + + + i = 0; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biSize = a | (b<<8) | (c<<16) | (d<<24); + + i += 4; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biWidth = a | (b<<8) | (c<<16) | (d<<24); + + i += 4; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biHeight = a | (b<<8) | (c<<16) | (d<<24); + + i += 4+2; + a = buf[i]; b = buf[i+1]; + biBitCount = static_cast(a | (b<<8)); + + /* + i += 2; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biCompression = a | (b<<8) | (c<<16) | (d<<24); + + i += 4; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biSizeImage = a | (b<<8) | (c<<16) | (d<<24); + + i += 4+4+4; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biClrUsed = a | (b<<8) | (c<<16) | (d<<24); + + i += 4; + a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3]; + biClrImportant = a | (b<<8) | (c<<16) | (d<<24); + */ + + + if (biSize != 40) + throw image_load_error("bmp load error 6: header too small"); + + // read and discard any extra bytes that are part of the header + if (biSize > 40) + { + if (in.sgetn(reinterpret_cast(buf),biSize-40) != static_cast(biSize - 40)) + { + throw image_load_error("bmp load error 7: header too small"); + } + bytes_read_so_far += biSize-40; + } + + image.set_size(biHeight, biWidth); + + switch (biBitCount) + { + case 1: + { + // figure out how the pixels are packed + long padding; + if (bfSize - bfOffBits == biWidth*biHeight/8) + padding = 0; + else + padding = 4 - ((biWidth+7)/8)%4; + + const unsigned int palette_size = 2; + unsigned char red[palette_size]; + unsigned char green[palette_size]; + unsigned char blue[palette_size]; + + for (unsigned int i = 0; i < palette_size; ++i) + { + if (in.sgetn(reinterpret_cast(buf),4) != 4) + { + throw image_load_error("bmp load error 20: color palette missing"); + } + bytes_read_so_far += 4; + blue[i] = buf[0]; + green[i] = buf[1]; + red[i] = buf[2]; + } + + + // seek to the start of the pixel data + while (bytes_read_so_far != bfOffBits) + { + const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf)); + if (in.sgetn(reinterpret_cast(buf), to_read) != to_read) + { + throw image_load_error("bmp load error: missing data"); + } + bytes_read_so_far += to_read; + } + + // load the image data + for (long row = biHeight-1; row >= 0; --row) + { + for (unsigned long col = 0; col < biWidth; col+=8) + { + if (in.sgetn(reinterpret_cast(buf),1) != 1) + { + throw image_load_error("bmp load error 21: file too short"); + } + + unsigned char pixels[8]; + + pixels[0] = (buf[0]>>7); + pixels[1] = ((buf[0]>>6)&0x01); + pixels[2] = ((buf[0]>>5)&0x01); + pixels[3] = ((buf[0]>>4)&0x01); + pixels[4] = ((buf[0]>>3)&0x01); + pixels[5] = ((buf[0]>>2)&0x01); + pixels[6] = ((buf[0]>>1)&0x01); + pixels[7] = ((buf[0])&0x01); + + for (int i = 0; i < 8 && col+i < biWidth; ++i) + { + rgb_pixel p; + p.red = red[pixels[i]]; + p.green = green[pixels[i]]; + p.blue = blue[pixels[i]]; + assign_pixel(image[row][col+i],p); + } + } + if (in.sgetn(reinterpret_cast(buf),padding) != padding) + throw image_load_error("bmp load error 9: file too short"); + } + + + + } break; + case 4: + { + // figure out how the pixels are packed + long padding; + if (bfSize - bfOffBits == biWidth*biHeight/2) + padding = 0; + else + padding = 4 - ((biWidth+1)/2)%4; + + const unsigned int palette_size = 16; + unsigned char red[palette_size]; + unsigned char green[palette_size]; + unsigned char blue[palette_size]; + + for (unsigned int i = 0; i < palette_size; ++i) + { + if (in.sgetn(reinterpret_cast(buf),4) != 4) + { + throw image_load_error("bmp load error 20: color palette missing"); + } + bytes_read_so_far += 4; + blue[i] = buf[0]; + green[i] = buf[1]; + red[i] = buf[2]; + } + + + // seek to the start of the pixel data + while (bytes_read_so_far != bfOffBits) + { + const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf)); + if (in.sgetn(reinterpret_cast(buf), to_read) != to_read) + { + throw image_load_error("bmp load error: missing data"); + } + bytes_read_so_far += to_read; + } + + // load the image data + for (long row = biHeight-1; row >= 0; --row) + { + for (unsigned long col = 0; col < biWidth; col+=2) + { + if (in.sgetn(reinterpret_cast(buf),1) != 1) + { + throw image_load_error("bmp load error 21: file too short"); + } + + const unsigned char pixel1 = (buf[0]>>4); + const unsigned char pixel2 = (buf[0]&0x0F); + + rgb_pixel p; + p.red = red[pixel1]; + p.green = green[pixel1]; + p.blue = blue[pixel1]; + assign_pixel(image[row][col], p); + + if (col+1 < biWidth) + { + p.red = red[pixel2]; + p.green = green[pixel2]; + p.blue = blue[pixel2]; + assign_pixel(image[row][col+1], p); + } + } + if (in.sgetn(reinterpret_cast(buf),padding) != padding) + throw image_load_error("bmp load error 9: file too short"); + } + + + + } break; + case 8: + { + // figure out how the pixels are packed + long padding; + if (bfSize - bfOffBits == biWidth*biHeight) + padding = 0; + else + padding = 4 - biWidth%4; + + // check for this case. It shouldn't happen but some BMP writers screw up the files + // so we have to do this. + if (biHeight*(biWidth+padding) > bfSize - bfOffBits) + padding = 0; + + const unsigned int palette_size = 256; + unsigned char red[palette_size]; + unsigned char green[palette_size]; + unsigned char blue[palette_size]; + + for (unsigned int i = 0; i < palette_size; ++i) + { + if (in.sgetn(reinterpret_cast(buf),4) != 4) + { + throw image_load_error("bmp load error 20: color palette missing"); + } + bytes_read_so_far += 4; + blue[i] = buf[0]; + green[i] = buf[1]; + red[i] = buf[2]; + } + + + // seek to the start of the pixel data + while (bytes_read_so_far != bfOffBits) + { + const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf)); + if (in.sgetn(reinterpret_cast(buf), to_read) != to_read) + { + throw image_load_error("bmp load error: missing data"); + } + bytes_read_so_far += to_read; + } + + // load the image data + for (long row = biHeight-1; row >= 0; --row) + { + for (unsigned long col = 0; col < biWidth; ++col) + { + if (in.sgetn(reinterpret_cast(buf),1) != 1) + { + throw image_load_error("bmp load error 21: file too short"); + } + + rgb_pixel p; + p.red = red[buf[0]]; + p.green = green[buf[0]]; + p.blue = blue[buf[0]]; + assign_pixel(image[row][col],p); + } + if (in.sgetn(reinterpret_cast(buf),padding) != padding) + throw image_load_error("bmp load error 9: file too short"); + } + + + + } + break; + case 16: + throw image_load_error ("16 bit BMP images not supported"); + case 24: + { + // figure out how the pixels are packed + long padding; + if (bfSize - bfOffBits == biWidth*biHeight*3) + padding = 0; + else + padding = 4 - (biWidth*3)%4; + + // check for this case. It shouldn't happen but some BMP writers screw up the files + // so we have to do this. + if (biHeight*(biWidth*3+padding) > bfSize - bfOffBits) + padding = 0; + + // seek to the start of the pixel data + while (bytes_read_so_far != bfOffBits) + { + const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf)); + if (in.sgetn(reinterpret_cast(buf), to_read) != to_read) + { + throw image_load_error("bmp load error: missing data"); + } + bytes_read_so_far += to_read; + } + + // load the image data + for (long row = biHeight-1; row >= 0; --row) + { + for (unsigned long col = 0; col < biWidth; ++col) + { + if (in.sgetn(reinterpret_cast(buf),3) != 3) + { + throw image_load_error("bmp load error 8: file too short"); + } + + rgb_pixel p; + p.red = buf[2]; + p.green = buf[1]; + p.blue = buf[0]; + assign_pixel(image[row][col], p); + + } + if (in.sgetn(reinterpret_cast(buf),padding) != padding) + throw image_load_error("bmp load error 9: file too short"); + } + + break; + } + case 32: + throw image_load_error ("32 bit BMP images not supported"); + default: + throw image_load_error("bmp load error 10: unknown color depth"); + + } + } + catch (...) + { + image.clear(); + throw; + } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void load_dng ( + image_type& image, + std::istream& in + ) + { + using namespace dng_helpers_namespace; + try + { + if (in.get() != 'D' || in.get() != 'N' || in.get() != 'G') + throw image_load_error("the stream does not contain a dng image file"); + + unsigned long version; + deserialize(version,in); + if (version != 1) + throw image_load_error("You need the new version of the dlib library to read this dng file"); + + unsigned long type; + deserialize(type,in); + + long width, height; + deserialize(width,in); + deserialize(height,in); + + if (width > 0 && height > 0) + image.set_size(height,width); + else + image.clear(); + + typedef entropy_decoder::kernel_2a decoder_type; + decoder_type decoder; + decoder.set_stream(in); + + entropy_decoder_model<256,decoder_type>::kernel_5a edm(decoder); + unsigned long symbol; + rgb_pixel p_rgb; + rgb_alpha_pixel p_rgba; + hsi_pixel p_hsi; + switch (type) + { + case rgb_alpha_paeth: + if (get_pixel_type() != rgb_alpha) + { + image.clear(); + throw image_load_error("You have tried to load a dng file that contains rgb_alpha_pixel data into an incompatible pixel type"); + } + + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + p_rgba = predictor_rgb_alpha_paeth(image,r,c); + edm.decode(symbol); + p_rgba.red += static_cast(symbol); + + edm.decode(symbol); + p_rgba.green += static_cast(symbol); + + edm.decode(symbol); + p_rgba.blue += static_cast(symbol); + + edm.decode(symbol); + p_rgba.alpha += static_cast(symbol); + + assign_pixel(image[r][c],p_rgba); + } + } + break; + + case rgb_alpha: + if (get_pixel_type() != rgb_alpha) + { + image.clear(); + throw image_load_error("You have tried to load a dng file that contains rgb_alpha_pixel data into an incompatible pixel type"); + } + + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + p_rgba = predictor_rgb_alpha(image,r,c); + edm.decode(symbol); + p_rgba.red += static_cast(symbol); + + edm.decode(symbol); + p_rgba.green += static_cast(symbol); + + edm.decode(symbol); + p_rgba.blue += static_cast(symbol); + + edm.decode(symbol); + p_rgba.alpha += static_cast(symbol); + + assign_pixel(image[r][c],p_rgba); + } + } + break; + + case rgb_paeth: + if (get_pixel_type() != rgb) + { + image.clear(); + throw image_load_error("You have tried to load a dng file that contains rgb_pixel data into an incompatible pixel type"); + } + + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + p_rgb = predictor_rgb_paeth(image,r,c); + edm.decode(symbol); + p_rgb.red += static_cast(symbol); + + edm.decode(symbol); + p_rgb.green += static_cast(symbol); + + edm.decode(symbol); + p_rgb.blue += static_cast(symbol); + + assign_pixel(image[r][c],p_rgb); + } + } + break; + + case rgb: + if (get_pixel_type() != rgb) + { + image.clear(); + throw image_load_error("You have tried to load a dng file that contains rgb_pixel data into an incompatible pixel type"); + } + + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + p_rgb = predictor_rgb(image,r,c); + edm.decode(symbol); + p_rgb.red += static_cast(symbol); + + edm.decode(symbol); + p_rgb.green += static_cast(symbol); + + edm.decode(symbol); + p_rgb.blue += static_cast(symbol); + + assign_pixel(image[r][c],p_rgb); + } + } + break; + + case hsi: + if (get_pixel_type() != hsi) + { + image.clear(); + throw image_load_error("You have tried to load a dng file that contains hsi_pixel data into an incompatible pixel type"); + } + + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + p_hsi = predictor_hsi(image,r,c); + edm.decode(symbol); + p_hsi.h += static_cast(symbol); + + edm.decode(symbol); + p_hsi.s += static_cast(symbol); + + edm.decode(symbol); + p_hsi.i += static_cast(symbol); + + assign_pixel(image[r][c],p_hsi); + } + } + break; + + case grayscale: + { + // An 8bit grayscale image should load successfully into any type of pixel since + // the assign_pixel() function converts perfectly between this pixel type and all + // others. + + unsigned char p; + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + edm.decode(symbol); + p = static_cast(symbol); + p += predictor_grayscale(image,r,c); + assign_pixel(image[r][c],p); + } + } + } + break; + + case grayscale_16bit: + { + if (get_pixel_type() != grayscale_16bit) + { + image.clear(); + throw image_load_error("You have tried to load a dng file that contains 16bit grayscale data into an incompatible pixel type"); + } + + uint16 p; + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + edm.decode(symbol); + p = static_cast(symbol); + p <<= 8; + edm.decode(symbol); + p |= static_cast(symbol); + + p += predictor_grayscale_16(image,r,c); + assign_pixel(image[r][c],p); + } + } + } + break; + + default: + throw image_load_error("corruption detected in the dng file"); + } // switch (type) + + edm.decode(symbol); + if (symbol != dng_magic_byte) + throw image_load_error("corruption detected in the dng file"); + edm.decode(symbol); + if (symbol != dng_magic_byte) + throw image_load_error("corruption detected in the dng file"); + edm.decode(symbol); + if (symbol != dng_magic_byte) + throw image_load_error("corruption detected in the dng file"); + edm.decode(symbol); + if (symbol != dng_magic_byte) + throw image_load_error("corruption detected in the dng file"); + } + catch (...) + { + image.clear(); + throw; + } + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_IMAGE_LOADEr_ + + + diff --git a/dlib/image_loader/image_loader_abstract.h b/dlib/image_loader/image_loader_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..744dd09ef1a8cb97c3f322639cf1ee1a2730be70 --- /dev/null +++ b/dlib/image_loader/image_loader_abstract.h @@ -0,0 +1,91 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_IMAGE_LOADEr_ABSTRACT_ +#ifdef DLIB_IMAGE_LOADEr_ABSTRACT_ + +#include +#include "../algs.h" +#include "../pixel.h" + +namespace dlib +{ + class image_load_error : public dlib::error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an exception used to indicate a failure to load an image. + Its type member variable will be set to EIMAGE_LOAD. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void load_bmp ( + image_type& image, + std::istream& in + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - #image == the image of the MS Windows BMP file that was available + in the input stream in. + - #image[0][0] will be the upper left corner of the image + - #image[image.nr()-1][image.nc()-1] will be the lower right + corner of the image + throws + - image_load_error + This exception is thrown if there is an error that prevents us + from loading the image. If this exception is thrown then + #image will have an initial value for its type. + - std::bad_alloc + If this exception is thrown then #image will have an initial + value for its type. + !*/ + +// ---------------------------------------------------------------------------------------- + + /*! + dlib dng file format: + This is a file format I created for this library. It is a lossless + compressed image format that is similar to the PNG format but uses + the dlib PPM compression algorithms instead of the DEFLATE algorithm. + !*/ + + template < + typename image_type + > + void load_dng ( + image_type& image, + std::istream& in + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - #image == the image of the dlib dng file that was available + in the input stream in. + - #image[0][0] will be the upper left corner of the image + - #image[image.nr()-1][image.nc()-1] will be the lower right + corner of the image + throws + - image_load_error + This exception is thrown if there is an error that prevents us + from loading the image. If this exception is thrown then + #image will have an initial value for its type. + - std::bad_alloc + If this exception is thrown then #image will have an initial + value for its type. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_IMAGE_LOADEr_ABSTRACT_ + diff --git a/dlib/image_loader/png_loader.cpp b/dlib/image_loader/png_loader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3594b4b8b4be82c1cb01f203a55fcb1392adc09a --- /dev/null +++ b/dlib/image_loader/png_loader.cpp @@ -0,0 +1,164 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net), Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PNG_LOADER_CPp_ +#define DLIB_PNG_LOADER_CPp_ + +// only do anything with this file if DLIB_PNG_SUPPORT is defined +#ifdef DLIB_PNG_SUPPORT + +#include "../array2d.h" +#include "../pixel.h" +#include "../dir_nav.h" +#include "png_loader.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct LibpngData + { + png_bytep* row_pointers_; + png_structp png_ptr_; + png_infop info_ptr_; + png_infop end_info_; + }; + +// ---------------------------------------------------------------------------------------- + + png_loader:: + png_loader( const char* filename ) : height_( 0 ), width_( 0 ) + { + read_image( filename ); + } + +// ---------------------------------------------------------------------------------------- + + png_loader:: + png_loader( const std::string& filename ) : height_( 0 ), width_( 0 ) + { + read_image( filename.c_str() ); + } + +// ---------------------------------------------------------------------------------------- + + png_loader:: + png_loader( const dlib::file& f ) : height_( 0 ), width_( 0 ) + { + read_image( f.full_name().c_str() ); + } + +// ---------------------------------------------------------------------------------------- + + const unsigned char* png_loader::get_row( unsigned i ) const + { + return ld_->row_pointers_[i]; + } + +// ---------------------------------------------------------------------------------------- + + png_loader::~png_loader() + { + if ( ld_ && ld_->row_pointers_ != NULL ) + png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); + } + +// ---------------------------------------------------------------------------------------- + + bool png_loader::is_gray() const + { + return ( color_type_ == PNG_COLOR_TYPE_GRAY ); + } + +// ---------------------------------------------------------------------------------------- + + bool png_loader::is_rgb() const + { + return ( color_type_ == PNG_COLOR_TYPE_RGB ); + } + +// ---------------------------------------------------------------------------------------- + + bool png_loader::is_rgba() const + { + return ( color_type_ == PNG_COLOR_TYPE_RGB_ALPHA ); + } + +// ---------------------------------------------------------------------------------------- + + void png_loader::read_image( const char* filename ) + { + ld_.reset(new LibpngData); + if ( filename == NULL ) + { + throw image_load_error("png_loader: invalid filename, it is NULL"); + } + FILE *fp = fopen( filename, "rb" ); + if ( !fp ) + { + throw image_load_error(std::string("png_loader: unable to open file ") + filename); + } + png_byte sig[8]; + fread( sig, 1, 8, fp ); + if ( png_sig_cmp( sig, 0, 8 ) != 0 ) + { + fclose( fp ); + throw image_load_error(std::string("png_loader: format error in file ") + filename); + } + ld_->png_ptr_ = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); + if ( ld_->png_ptr_ == NULL ) + { + fclose( fp ); + throw image_load_error(std::string("png_loader: parse error in file ") + filename); + } + ld_->info_ptr_ = png_create_info_struct( ld_->png_ptr_ ); + if ( ld_->info_ptr_ == NULL ) + { + fclose( fp ); + png_destroy_read_struct( &( ld_->png_ptr_ ), ( png_infopp )NULL, ( png_infopp )NULL ); + throw image_load_error(std::string("png_loader: parse error in file ") + filename); + } + ld_->end_info_ = png_create_info_struct( ld_->png_ptr_ ); + if ( ld_->end_info_ == NULL ) + { + fclose( fp ); + png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), ( png_infopp )NULL ); + throw image_load_error(std::string("png_loader: parse error in file ") + filename); + } + png_init_io( ld_->png_ptr_, fp ); + png_set_sig_bytes( ld_->png_ptr_, 8 ); + // flags force one byte per channel output + png_read_png( ld_->png_ptr_, ld_->info_ptr_, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL ); + height_ = png_get_image_height( ld_->png_ptr_, ld_->info_ptr_ ); + width_ = png_get_image_width( ld_->png_ptr_, ld_->info_ptr_ ); + bit_depth_ = png_get_bit_depth( ld_->png_ptr_, ld_->info_ptr_ ); + color_type_ = png_get_color_type( ld_->png_ptr_, ld_-> info_ptr_ ); + + if (color_type_ != PNG_COLOR_TYPE_GRAY && + color_type_ != PNG_COLOR_TYPE_RGB && + color_type_ != PNG_COLOR_TYPE_RGB_ALPHA ) + { + fclose( fp ); + png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) ); + throw image_load_error(std::string("png_loader: unsupported color type in file ") + filename); + } + + ld_->row_pointers_ = png_get_rows( ld_->png_ptr_, ld_->info_ptr_ ); + // FIXME: the following call makes libpng crash. Why? + //png_read_end( ld_->png_ptr_, ld_->end_info_ ); + fclose( fp ); + if ( ld_->row_pointers_ == NULL ) + { + throw image_load_error(std::string("png_loader: parse error in file ") + filename); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_PNG_SUPPORT + +#endif // DLIB_PNG_LOADER_CPp_ + diff --git a/dlib/image_loader/png_loader.h b/dlib/image_loader/png_loader.h new file mode 100644 index 0000000000000000000000000000000000000000..b7a9d9f3fc9190a65bf4f05f901ed3f93ddf1b70 --- /dev/null +++ b/dlib/image_loader/png_loader.h @@ -0,0 +1,89 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net), Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PNG_IMPORT +#define DLIB_PNG_IMPORT + +#include "png_loader_abstract.h" +#include "../smart_pointers.h" +#include "image_loader.h" +#include "../pixel.h" +#include "../dir_nav.h" + +namespace dlib +{ + + struct LibpngData; + class png_loader : noncopyable + { + public: + + png_loader( const char* filename ); + png_loader( const std::string& filename ); + png_loader( const dlib::file& f ); + ~png_loader(); + + bool is_gray() const; + bool is_rgb() const; + bool is_rgba() const; + + template + void get_image( T& t) const + { +#ifndef DLIB_PNG_SUPPORT + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + You are getting this error because you are trying to use the png_loader + object but you haven't defined DLIB_PNG_SUPPORT. You must do so to use + this object. You must also make sure you set your build environment + to link against the libpng library. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + COMPILE_TIME_ASSERT(sizeof(T) == 0); +#endif + + t.set_size( height_, width_ ); + for ( unsigned n = 0; n < height_;n++ ) + { + const unsigned char* v = get_row( n ); + for ( unsigned m = 0; m < width_;m++ ) + { + if ( is_gray() ) + { + unsigned char p = v[m]; + assign_pixel( t[n][m], p ); + } + else if ( is_rgb() ) + { + rgb_pixel p; + p.red = v[m*3]; + p.green = v[m*3+1]; + p.blue = v[m*3+2]; + assign_pixel( t[n][m], p ); + } + else if ( is_rgba() ) + { + rgb_alpha_pixel p; + p.red = v[m*4]; + p.green = v[m*4+1]; + p.blue = v[m*4+2]; + p.alpha = v[m*4+3]; + assign_pixel( t[n][m], p ); + } + } + } + } + + private: + const unsigned char* get_row( unsigned i ) const; + void read_image( const char* filename ); + unsigned height_, width_; + unsigned bit_depth_; + int color_type_; + scoped_ptr ld_; + }; +} + +#ifdef NO_MAKEFILE +#include "png_loader.cpp" +#endif + +#endif // DLIB_PNG_IMPORT + diff --git a/dlib/image_loader/png_loader_abstract.h b/dlib/image_loader/png_loader_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..14894e5e635fba70ef70dfa1c157b2f5626b1ee7 --- /dev/null +++ b/dlib/image_loader/png_loader_abstract.h @@ -0,0 +1,123 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net), Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_PNG_IMPORT_ABSTRACT +#ifdef DLIB_PNG_IMPORT_ABSTRACT + +#include "image_loader_abstract.h" +#include "../algs.h" +#include "../pixel.h" +#include "../dir_nav.h" + +namespace dlib +{ + + class png_loader : noncopyable + { + /*! + INITIAL VALUE + Defined by the constructors + + WHAT THIS OBJECT REPRESENTS + This object represents a class capable of loading PNG image files. + Once an instance of it is created to contain a PNG file from + disk you can obtain the image stored in it via get_image(). + !*/ + + public: + + png_loader( + const char* filename + ); + /*! + ensures + - loads the PNG file with the given file name into this object + throws + - std::bad_alloc + - image_load_error + This exception is thrown if there is some error that prevents + us from loading the given PNG file. + !*/ + + png_loader( + const std::string& filename + ); + /*! + ensures + - loads the PNG file with the given file name into this object + throws + - std::bad_alloc + - image_load_error + This exception is thrown if there is some error that prevents + us from loading the given PNG file. + !*/ + + png_loader( + const dlib::file& f + ); + /*! + ensures + - loads the PNG file with the given file name into this object + throws + - std::bad_alloc + - image_load_error + This exception is thrown if there is some error that prevents + us from loading the given PNG file. + !*/ + + ~png_loader( + ); + /*! + ensures + - all resources associated with *this has been released + !*/ + + bool is_gray( + ) const; + /*! + ensures + - if (this object contains a grayscale image) then + - returns true + - else + - returns false + !*/ + + bool is_rgb( + ) const; + /*! + ensures + - if (this object contains a 3 channel RGB image) then + - returns true + - else + - returns false + !*/ + + bool is_rgba( + ) const; + /*! + ensures + - if (this object contains a 4 channel RGB alpha image) then + - returns true + - else + - returns false + !*/ + + template< + typename image_type + > + void get_image( + image_type& img + ) const; + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - loads the PNG image stored in this object into img + !*/ + + }; +} + +#endif // DLIB_PNG_IMPORT_ABSTRACT + + diff --git a/dlib/image_saver/dng_shared.h b/dlib/image_saver/dng_shared.h new file mode 100644 index 0000000000000000000000000000000000000000..55c85d2ef72b6facdd9e33eb26f79e0ab9c7ebcb --- /dev/null +++ b/dlib/image_saver/dng_shared.h @@ -0,0 +1,302 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DNG_SHAREd_ +#define DLIB_DNG_SHAREd_ + +#include "../pixel.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + namespace dng_helpers_namespace + { + enum + { + grayscale = 1, + rgb, + hsi, + rgb_paeth, + rgb_alpha, + rgb_alpha_paeth, + grayscale_16bit, + }; + + template + int get_pixel_type() + { + if (pixel_traits::grayscale == true && sizeof(typename image_type::type) == 2) + return grayscale_16bit; + else if (pixel_traits::grayscale == true && sizeof(typename image_type::type) == 1) + return grayscale_16bit; + else if (pixel_traits::rgb == true) + return rgb; + else if (pixel_traits::hsi == true) + return hsi; + else if (pixel_traits::rgb_alpha == true) + return rgb_alpha; + } + + const unsigned long dng_magic_byte = 100; + + template + rgb_pixel predictor_rgb_paeth (const T& img, long row, long col) + /* + This is similar to the Paeth filter from the PNG image format. + */ + { + // a = left, b = above, c = upper left + rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0); + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + else + assign_pixel(a,(unsigned char)0); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + else + assign_pixel(c,(unsigned char)0); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + else + assign_pixel(b,(unsigned char)0); + + + rgb_pixel p; + p.red = a.red + b.red - c.red; + p.green = a.green + b.green - c.green; + p.blue = a.blue + b.blue - c.blue; + + short pa = std::abs((short)p.red - (short)a.red) + + std::abs((short)p.green - (short)a.green) + + std::abs((short)p.blue - (short)a.blue); + short pb = std::abs((short)p.red - (short)b.red) + + std::abs((short)p.green - (short)b.green) + + std::abs((short)p.blue - (short)b.blue); + short pc = std::abs((short)p.red - (short)c.red) + + std::abs((short)p.green - (short)c.green) + + std::abs((short)p.blue - (short)c.blue); + + if (pa <= pb && pa <= pc) + return a; + else if (pb <= pc) + return b; + else + return c; + } + + + template + rgb_pixel predictor_rgb (const T& img, long row, long col) + { + // a = left, b = above, c = upper left + rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0); + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + else + assign_pixel(a,(unsigned char)0); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + else + assign_pixel(c,(unsigned char)0); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + else + assign_pixel(b,(unsigned char)0); + + + rgb_pixel p; + p.red = a.red + b.red - c.red; + p.green = a.green + b.green - c.green; + p.blue = a.blue + b.blue - c.blue; + return p; + } + + template + rgb_alpha_pixel predictor_rgb_alpha_paeth (const T& img, long row, long col) + /* + This is similar to the Paeth filter from the PNG image format. + */ + { + // a = left, b = above, c = upper left + rgb_alpha_pixel a, b, c; + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + else + assign_pixel(a,(unsigned char)0); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + else + assign_pixel(c,(unsigned char)0); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + else + assign_pixel(b,(unsigned char)0); + + + rgb_alpha_pixel p; + p.red = a.red + b.red - c.red; + p.green = a.green + b.green - c.green; + p.blue = a.blue + b.blue - c.blue; + + short pa = std::abs((short)p.red - (short)a.red) + + std::abs((short)p.green - (short)a.green) + + std::abs((short)p.blue - (short)a.blue); + short pb = std::abs((short)p.red - (short)b.red) + + std::abs((short)p.green - (short)b.green) + + std::abs((short)p.blue - (short)b.blue); + short pc = std::abs((short)p.red - (short)c.red) + + std::abs((short)p.green - (short)c.green) + + std::abs((short)p.blue - (short)c.blue); + + if (pa <= pb && pa <= pc) + return a; + else if (pb <= pc) + return b; + else + return c; + } + + + template + rgb_alpha_pixel predictor_rgb_alpha (const T& img, long row, long col) + { + // a = left, b = above, c = upper left + rgb_alpha_pixel a, b, c; + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + else + assign_pixel(a,(unsigned char)0); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + else + assign_pixel(c,(unsigned char)0); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + else + assign_pixel(b,(unsigned char)0); + + + rgb_alpha_pixel p; + p.red = a.red + b.red - c.red; + p.green = a.green + b.green - c.green; + p.blue = a.blue + b.blue - c.blue; + p.alpha = a.alpha + b.alpha - c.alpha; + return p; + } + + + template + hsi_pixel predictor_hsi (const T& img, long row, long col) + { + // a = left, b = above, c = upper left + hsi_pixel a(0,0,0), b(0,0,0), c(0,0,0); + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + else + assign_pixel(a,(unsigned char)0); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + else + assign_pixel(c,(unsigned char)0); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + else + assign_pixel(b,(unsigned char)0); + + + hsi_pixel p; + p.h = a.h + b.h - c.h; + p.s = a.s + b.s - c.s; + p.i = a.i + b.i - c.i; + return p; + } + + template + unsigned char predictor_grayscale (const T& img, long row, long col) + { + // a = left, b = above, c = upper left + unsigned char a = 0, b = 0, c = 0; + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + + + unsigned char p = a + b - c; + return p; + } + + template + uint16 predictor_grayscale_16 (const T& img, long row, long col) + { + // a = left, b = above, c = upper left + uint16 a = 0, b = 0, c = 0; + + + const long c1 = col-1; + const long r1 = row-1; + + if (c1 >= 0) + assign_pixel(a, img[row][c1]); + + if (c1 >= 0 && r1 >= 0) + assign_pixel(c, img[r1][c1]); + + if (r1 >= 0) + assign_pixel(b, img[r1][col]); + + + uint16 p = a + b - c; + return p; + } + + } +} + +#endif // DLIB_DNG_SHAREd_ + diff --git a/dlib/image_saver/image_saver.h b/dlib/image_saver/image_saver.h new file mode 100644 index 0000000000000000000000000000000000000000..ae497ee3ce71480a9ea86e419c35ede80fc20779 --- /dev/null +++ b/dlib/image_saver/image_saver.h @@ -0,0 +1,534 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_IMAGE_SAVEr_ +#define DLIB_IMAGE_SAVEr_ + +#include "image_saver_abstract.h" +#include +#include +#include "../algs.h" +#include "../pixel.h" +#include "../byte_orderer.h" +#include "../entropy_encoder.h" +#include "../entropy_encoder_model.h" +#include "dng_shared.h" +#include "../uintn.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class image_save_error : public dlib::error { + public: image_save_error(const std::string& str) : error(EIMAGE_SAVE,str){} + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type, + bool grayscale = pixel_traits::grayscale + > + struct save_bmp_helper; + + + template + struct save_bmp_helper + { + static void save_bmp ( + const image_type& image, + std::ostream& out + ) + { + // we are going to write out a 24bit color image. + byte_orderer::kernel_1a bo; + + out.write("BM",2); + + if (!out) + throw image_save_error("error writing image to output stream"); + + + unsigned long pad = 4 - (image.nc()*3)%4; + if (pad == 4) + pad = 0; + + unsigned long bfSize = 14 + 40 + (image.nc()*3 + pad)*image.nr(); + unsigned long bfReserved = 0; + unsigned long bfOffBits = 14 + 40; + unsigned long biSize = 40; + unsigned long biWidth = image.nc(); + unsigned long biHeight = image.nr(); + unsigned short biPlanes = 1; + unsigned short biBitCount = 24; + unsigned long biCompression = 0; + unsigned long biSizeImage = 0; + unsigned long biXPelsPerMeter = 0; + unsigned long biYPelsPerMeter = 0; + unsigned long biClrUsed = 0; + unsigned long biClrImportant = 0; + + bo.host_to_little(bfSize); + bo.host_to_little(bfOffBits); + bo.host_to_little(biSize); + bo.host_to_little(biWidth); + bo.host_to_little(biHeight); + bo.host_to_little(biPlanes); + bo.host_to_little(biBitCount); + + out.write((char*)&bfSize,4); + out.write((char*)&bfReserved,4); + out.write((char*)&bfOffBits,4); + out.write((char*)&biSize,4); + out.write((char*)&biWidth,4); + out.write((char*)&biHeight,4); + out.write((char*)&biPlanes,2); + out.write((char*)&biBitCount,2); + out.write((char*)&biCompression,4); + out.write((char*)&biSizeImage,4); + out.write((char*)&biXPelsPerMeter,4); + out.write((char*)&biYPelsPerMeter,4); + out.write((char*)&biClrUsed,4); + out.write((char*)&biClrImportant,4); + + + if (!out) + throw image_save_error("error writing image to output stream"); + + // now we write out the pixel data + for (long row = image.nr()-1; row >= 0; --row) + { + for (long col = 0; col < image.nc(); ++col) + { + rgb_pixel p; + p.red = 0; + p.green = 0; + p.blue = 0; + assign_pixel(p,image[row][col]); + out.write((char*)&p.blue,1); + out.write((char*)&p.green,1); + out.write((char*)&p.red,1); + } + + // write out some zeros so that this line is a multiple of 4 bytes + for (unsigned long i = 0; i < pad; ++i) + { + unsigned char p = 0; + out.write((char*)&p,1); + } + } + + if (!out) + throw image_save_error("error writing image to output stream"); + } + }; + + template + struct save_bmp_helper + { + static void save_bmp ( + const image_type& image, + std::ostream& out + ) + { + // we are going to write out an 8bit color image. + byte_orderer::kernel_1a bo; + + out.write("BM",2); + + if (!out) + throw image_save_error("error writing image to output stream"); + + unsigned long pad = 4 - image.nc()%4; + if (pad == 4) + pad = 0; + + unsigned long bfSize = 14 + 40 + (image.nc() + pad)*image.nr() + 256*4; + unsigned long bfReserved = 0; + unsigned long bfOffBits = 14 + 40 + 256*4; + unsigned long biSize = 40; + unsigned long biWidth = image.nc(); + unsigned long biHeight = image.nr(); + unsigned short biPlanes = 1; + unsigned short biBitCount = 8; + unsigned long biCompression = 0; + unsigned long biSizeImage = 0; + unsigned long biXPelsPerMeter = 0; + unsigned long biYPelsPerMeter = 0; + unsigned long biClrUsed = 0; + unsigned long biClrImportant = 0; + + bo.host_to_little(bfSize); + bo.host_to_little(bfOffBits); + bo.host_to_little(biSize); + bo.host_to_little(biWidth); + bo.host_to_little(biHeight); + bo.host_to_little(biPlanes); + bo.host_to_little(biBitCount); + + out.write((char*)&bfSize,4); + out.write((char*)&bfReserved,4); + out.write((char*)&bfOffBits,4); + out.write((char*)&biSize,4); + out.write((char*)&biWidth,4); + out.write((char*)&biHeight,4); + out.write((char*)&biPlanes,2); + out.write((char*)&biBitCount,2); + out.write((char*)&biCompression,4); + out.write((char*)&biSizeImage,4); + out.write((char*)&biXPelsPerMeter,4); + out.write((char*)&biYPelsPerMeter,4); + out.write((char*)&biClrUsed,4); + out.write((char*)&biClrImportant,4); + + + // write out the color palette + for (unsigned int i = 0; i <= 255; ++i) + { + unsigned char ch = static_cast(i); + out.write((char*)&ch,1); + out.write((char*)&ch,1); + out.write((char*)&ch,1); + ch = 0; + out.write((char*)&ch,1); + } + + if (!out) + throw image_save_error("error writing image to output stream"); + + // now we write out the pixel data + for (long row = image.nr()-1; row >= 0; --row) + { + for (long col = 0; col < image.nc(); ++col) + { + unsigned char p = 0; + assign_pixel(p,image[row][col]); + out.write((char*)&p,1); + } + + // write out some zeros so that this line is a multiple of 4 bytes + for (unsigned long i = 0; i < pad; ++i) + { + unsigned char p = 0; + out.write((char*)&p,1); + } + } + + if (!out) + throw image_save_error("error writing image to output stream"); + + } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + inline void save_bmp ( + const image_type& image, + std::ostream& out + ) + { + save_bmp_helper::save_bmp(image,out); + } + +// ---------------------------------------------------------------------------------------- + + namespace dng_helpers_namespace + { + + template < + typename image_type, + int pixel_type = static_switch < + pixel_traits::grayscale && sizeof(typename image_type::type) != 2, + pixel_traits::rgb, + pixel_traits::hsi, + false, + pixel_traits::rgb_alpha, + false, + pixel_traits::grayscale && sizeof(typename image_type::type) == 2 + >::value + > + struct save_dng_helper; + + typedef entropy_encoder::kernel_2a encoder_type; + typedef entropy_encoder_model<256,encoder_type>::kernel_5a eem_type; + + template + struct save_dng_helper + { + static void save_dng ( + const image_type& image, + std::ostream& out + ) + { + out.write("DNG",3); + unsigned long version = 1; + serialize(version,out); + unsigned long type = grayscale_16bit; + serialize(type,out); + serialize(image.nc(),out); + serialize(image.nr(),out); + + encoder_type encoder; + encoder.set_stream(out); + + eem_type eem(encoder); + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + uint16 cur; + assign_pixel(cur, image[r][c]); + cur -= predictor_grayscale_16(image,r,c); + unsigned char byte1 = cur&0xFF; + unsigned char byte2 = cur>>8; + eem.encode(byte2); + eem.encode(byte1); + } + } + // write out the magic byte to mark the end of the data + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + } + }; + + + template + struct save_dng_helper + { + static void save_dng ( + const image_type& image, + std::ostream& out + ) + { + out.write("DNG",3); + unsigned long version = 1; + serialize(version,out); + unsigned long type = grayscale; + serialize(type,out); + serialize(image.nc(),out); + serialize(image.nr(),out); + + encoder_type encoder; + encoder.set_stream(out); + + eem_type eem(encoder); + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + unsigned char cur; + assign_pixel(cur, image[r][c]); + eem.encode(cur - predictor_grayscale(image,r,c)); + } + } + // write out the magic byte to mark the end of the data + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + } + }; + + template + struct save_dng_helper + { + static void save_dng ( + const image_type& image, + std::ostream& out + ) + { + out.write("DNG",3); + unsigned long version = 1; + serialize(version,out); + + unsigned long type = rgb; + // if this is a small image then we will use a different predictor + if (image.size() < 4000) + type = rgb_paeth; + + serialize(type,out); + serialize(image.nc(),out); + serialize(image.nr(),out); + + encoder_type encoder; + encoder.set_stream(out); + + rgb_pixel pre, cur; + eem_type eem(encoder); + + if (type == rgb) + { + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + pre = predictor_rgb(image,r,c); + assign_pixel(cur, image[r][c]); + + eem.encode((unsigned char)(cur.red - pre.red)); + eem.encode((unsigned char)(cur.green - pre.green)); + eem.encode((unsigned char)(cur.blue - pre.blue)); + } + } + } + else + { + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + pre = predictor_rgb_paeth(image,r,c); + assign_pixel(cur, image[r][c]); + + eem.encode((unsigned char)(cur.red - pre.red)); + eem.encode((unsigned char)(cur.green - pre.green)); + eem.encode((unsigned char)(cur.blue - pre.blue)); + } + } + } + // write out the magic byte to mark the end of the data + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + } + }; + + template + struct save_dng_helper + { + static void save_dng ( + const image_type& image, + std::ostream& out + ) + { + out.write("DNG",3); + unsigned long version = 1; + serialize(version,out); + + unsigned long type = rgb_alpha; + // if this is a small image then we will use a different predictor + if (image.size() < 4000) + type = rgb_alpha_paeth; + + serialize(type,out); + serialize(image.nc(),out); + serialize(image.nr(),out); + + encoder_type encoder; + encoder.set_stream(out); + + rgb_alpha_pixel pre, cur; + eem_type eem(encoder); + + if (type == rgb_alpha) + { + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + pre = predictor_rgb_alpha(image,r,c); + assign_pixel(cur, image[r][c]); + + eem.encode((unsigned char)(cur.red - pre.red)); + eem.encode((unsigned char)(cur.green - pre.green)); + eem.encode((unsigned char)(cur.blue - pre.blue)); + eem.encode((unsigned char)(cur.alpha - pre.alpha)); + } + } + } + else + { + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + pre = predictor_rgb_alpha_paeth(image,r,c); + assign_pixel(cur, image[r][c]); + + eem.encode((unsigned char)(cur.red - pre.red)); + eem.encode((unsigned char)(cur.green - pre.green)); + eem.encode((unsigned char)(cur.blue - pre.blue)); + eem.encode((unsigned char)(cur.alpha - pre.alpha)); + } + } + } + // write out the magic byte to mark the end of the data + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + } + }; + + template + struct save_dng_helper + { + static void save_dng ( + const image_type& image, + std::ostream& out + ) + { + out.write("DNG",3); + unsigned long version = 1; + serialize(version,out); + unsigned long type = hsi; + serialize(type,out); + serialize(image.nc(),out); + serialize(image.nr(),out); + + encoder_type encoder; + encoder.set_stream(out); + + hsi_pixel pre, cur; + eem_type eem(encoder); + for (long r = 0; r < image.nr(); ++r) + { + for (long c = 0; c < image.nc(); ++c) + { + pre = predictor_hsi(image,r,c); + assign_pixel(cur, image[r][c]); + + eem.encode((unsigned char)(cur.h - pre.h)); + eem.encode((unsigned char)(cur.s - pre.s)); + eem.encode((unsigned char)(cur.i - pre.i)); + } + } + // write out the magic byte to mark the end of the data + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + eem.encode(dng_magic_byte); + } + }; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + inline void save_dng ( + const image_type& image, + std::ostream& out + ) + { + using namespace dng_helpers_namespace; + save_dng_helper::save_dng(image,out); + } + +// ---------------------------------------------------------------------------------------- + + +} + +#endif // DLIB_IMAGE_SAVEr_ + + + + diff --git a/dlib/image_saver/image_saver_abstract.h b/dlib/image_saver/image_saver_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..4f3c5f08ac210ff508505ce9a72b07529ff930b9 --- /dev/null +++ b/dlib/image_saver/image_saver_abstract.h @@ -0,0 +1,84 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_IMAGE_SAVEr_ABSTRACT_ +#ifdef DLIB_IMAGE_SAVEr_ABSTRACT_ + +#include +#include "../algs.h" +#include "../pixel.h" + +namespace dlib +{ + class image_save_error : public dlib::error + { + /*! + WHAT THIS OBJECT REPRESENTS + This is an exception used to indicate a failure to save an image. + Its type member variable will be set to EIMAGE_SAVE. + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void save_bmp ( + const image_type& image, + std::ostream& out + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - writes the image to the out stream in the Microsoft Windows BMP format. + - image[0][0] will be in the upper left corner of the image. + - image[image.nr()-1][image.nc()-1] will be in the lower right + corner of the image. + throws + - image_save_error + This exception is thrown if there is an error that prevents us + from saving the image. + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + + /*! + dlib dng file format: + This is a file format I created for this library. It is a lossless + compressed image format that is similar to the PNG format but uses + the dlib PPM compression algorithms instead of the DEFLATE algorithm. + !*/ + + template < + typename image_type + > + void save_dng ( + const image_type& image, + std::ostream& out + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + ensures + - writes the image to the out stream in the dlib dng format. + - image[0][0] will be in the upper left corner of the image. + - image[image.nr()-1][image.nc()-1] will be in the lower right + corner of the image. + throws + - image_save_error + This exception is thrown if there is an error that prevents us + from saving the image. + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_IMAGE_SAVEr_ABSTRACT_ + + diff --git a/dlib/image_transforms.h b/dlib/image_transforms.h new file mode 100644 index 0000000000000000000000000000000000000000..353bd541fafc45939fe02deb9bfb6395ee2d9352 --- /dev/null +++ b/dlib/image_transforms.h @@ -0,0 +1,15 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_IMAGE_TRANSFORMs_ +#define DLIB_IMAGE_TRANSFORMs_ + +#include "image_transforms/assign_image.h" +#include "image_transforms/equalize_histogram.h" +#include "image_transforms/morphological_operations.h" +#include "image_transforms/spatial_filtering.h" +#include "image_transforms/thresholding.h" +#include "image_transforms/edge_detector.h" +#include "image_transforms/draw.h" + +#endif // DLIB_IMAGE_TRANSFORMs_ + diff --git a/dlib/image_transforms/assign_image.h b/dlib/image_transforms/assign_image.h new file mode 100644 index 0000000000000000000000000000000000000000..22f493be9614be263592a2d8072cbdd6dfb9781d --- /dev/null +++ b/dlib/image_transforms/assign_image.h @@ -0,0 +1,138 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ASSIGN_IMAGe_ +#define DLIB_ASSIGN_IMAGe_ + +#include "../pixel.h" +#include "assign_image_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename dest_image_type, + typename src_image_type + > + void assign_image ( + dest_image_type& dest, + const src_image_type& src + ) + { + // check for the case where dest is the same object as src + if ((void*)&dest == (void*)&src) + return; + + dest.set_size(src.nr(),src.nc()); + + for (long r = 0; r < src.nr(); ++r) + { + for (long c = 0; c < src.nc(); ++c) + { + assign_pixel(dest[r][c], src[r][c]); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename dest_image_type, + typename src_pixel_type + > + void assign_all_pixels ( + dest_image_type& dest_img, + const src_pixel_type& src_pixel + ) + { + for (long r = 0; r < dest_img.nr(); ++r) + { + for (long c = 0; c < dest_img.nc(); ++c) + { + assign_pixel(dest_img[r][c], src_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void assign_border_pixels ( + image_type& img, + long x_border_size, + long y_border_size, + const typename image_type::type& p + ) + { + DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0, + "\tvoid assign_border_pixels(img, p, border_size)" + << "\n\tYou have given an invalid border_size" + << "\n\tx_border_size: " << x_border_size + << "\n\ty_border_size: " << y_border_size + ); + + // assign the top border + for (long r = 0; r < y_border_size; ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + img[r][c] = p; + } + } + + // assign the bottom border + for (long r = img.nr()-y_border_size; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + img[r][c] = p; + } + } + + // now assign the two sides + for (long r = y_border_size; r < img.nr()-y_border_size; ++r) + { + // left border + for (long c = 0; c < x_border_size; ++c) + img[r][c] = p; + + // right border + for (long c = img.nc()-x_border_size; c < img.nc(); ++c) + img[r][c] = p; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void zero_border_pixels ( + image_type& img, + long x_border_size, + long y_border_size + ) + { + DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0, + "\tvoid zero_border_pixels(img, p, border_size)" + << "\n\tYou have given an invalid border_size" + << "\n\tx_border_size: " << x_border_size + << "\n\ty_border_size: " << y_border_size + ); + + typename image_type::type zero_pixel; + assign_pixel_intensity(zero_pixel, 0); + assign_border_pixels(img, x_border_size, y_border_size, zero_pixel); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ASSIGN_IMAGe_ + + + diff --git a/dlib/image_transforms/assign_image_abstract.h b/dlib/image_transforms/assign_image_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..96641245642fcc9af0f8a7f5060ab13fe191649a --- /dev/null +++ b/dlib/image_transforms/assign_image_abstract.h @@ -0,0 +1,115 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_ASSIGN_IMAGe_ABSTRACT +#ifdef DLIB_ASSIGN_IMAGe_ABSTRACT + +#include "../pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename dest_image_type, + typename src_image_type + > + void assign_image ( + dest_image_type& dest_img, + const src_image_type& src_img + ); + /*! + requires + - src_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - dest_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + - pixel_traits is defined + ensures + - #dest_img.nc() == src_img.nc() + - #dest_img.nr() == src_img.nr() + - for all valid r and c: + - performs assign_pixel(#dest_img[r][c],src_img[r][c]) + (i.e. copies the src image to dest image) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename dest_image_type, + typename src_pixel_type + > + void assign_all_pixels ( + dest_image_type& dest_img, + const src_pixel_type& src_pixel + ); + /*! + requires + - dest_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits is defined + - pixel_traits is defined + ensures + - #dest_img.nc() == dest_img.nc() + - #dest_img.nr() == dest_img.nr() + (i.e. the size of dest_img isn't changed by this function) + - for all valid r and c: + - performs assign_pixel(#dest_img[r][c],src_pixel) + (i.e. assigns the src pixel to every pixel in the dest image) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void assign_border_pixels ( + image_type& img, + long x_border_size, + long y_border_size, + const typename image_type::type& p + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - x_border_size >= 0 + - y_border_size >= 0 + ensures + - #img.nc() == img.nc() + - #img.nr() == img.nr() + (i.e. the size of img isn't changed by this function) + - for all valid r such that r+y_border_size or r-y_border_size gives an invalid row + - for all valid c such that c+x_border_size or c-x_border_size gives an invalid column + - performs assign_pixel(#img[r][c],p) + (i.e. assigns the given pixel to every pixel in the border of img) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void assign_border_pixels ( + image_type& img, + long x_border_size, + long y_border_size + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + - x_border_size >= 0 + - y_border_size >= 0 + ensures + - #img.nc() == img.nc() + - #img.nr() == img.nr() + (i.e. the size of img isn't changed by this function) + - let p be a pixel such that get_pixel_intensity(p) == 0 + - performs assign_border_pixels(img, x_border_size, y_border_size, p) + (i.e. zeros the border of the given image) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ASSIGN_IMAGe_ABSTRACT + + diff --git a/dlib/image_transforms/draw.h b/dlib/image_transforms/draw.h new file mode 100644 index 0000000000000000000000000000000000000000..98f911ad237ccb98bf8f9d1eb09e6d4ce506825f --- /dev/null +++ b/dlib/image_transforms/draw.h @@ -0,0 +1,154 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_DRAW_IMAGe_ +#define DLIB_DRAW_IMAGe_ + +#include "draw_abstract.h" +#include "../algs.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void draw_line ( + long x1, + long y1, + long x2, + long y2, + image_type& c, + typename image_type::type val + ) + { + if (x1 == x2) + { + // make sure y1 comes before y2 + if (y1 > y2) + swap(y1,y2); + + + // this is a vertical line + for (long y = y1; y <= y2; ++y) + { + if (y < 0 || y >= c.nr()) + continue; + + c[y][x1] = val; + } + } + else if (y1 == y2) + { + + // make sure x1 comes before x2 + if (x1 > x2) + swap(x1,x2); + + + // this is a horizontal line + for (long x = x1; x <= x2; ++x) + { + if (x < 0 || x >= c.nc()) + continue; + + c[y1][x] = val; + } + } + else + { + const long rise = (((long)y2) - ((long)y1)); + const long run = (((long)x2) - ((long)x1)); + if (std::abs(rise) < std::abs(run)) + { + const double slope = ((double)rise)/run; + + + double first, last; + + + if (x1 > x2) + { + first = x2; + last = x1; + } + else + { + first = x1; + last = x2; + } + + long y; + long x; + const double x1f = x1; + const double y1f = y1; + for (double i = first; i <= last; ++i) + { + y = static_cast(slope*(i-x1f) + y1f); + x = static_cast(i); + + + if (y < 0 || y >= c.nr()) + continue; + + if (x < 0 || x >= c.nc()) + continue; + + + c[y][x] = val; + } + } + else + { + const double slope = ((double)run)/rise; + + + double first, last; + + + if (y1 > y2) + { + first = y2; + last = y1; + } + else + { + first = y1; + last = y2; + } + + + long x; + long y; + const double x1f = x1; + const double y1f = y1; + for (double i = first; i <= last; ++i) + { + x = static_cast(slope*(i-y1f) + x1f); + y = static_cast(i); + + + if (x < 0 || x >= c.nc()) + continue; + + if (y < 0 || y >= c.nr()) + continue; + + c[y][x] = val; + } + } + } + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DRAW_IMAGe_ + + + + diff --git a/dlib/image_transforms/draw_abstract.h b/dlib/image_transforms/draw_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..2b1961c9c48f20caaf685e23161f98b0ec9e8949 --- /dev/null +++ b/dlib/image_transforms/draw_abstract.h @@ -0,0 +1,42 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_DRAW_IMAGe_ABSTRACT +#ifdef DLIB_DRAW_IMAGe_ABSTRACT + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void draw_line ( + long x1, + long y1, + long x2, + long y2, + image_type& img, + typename image_type::type val + ); + /*! + requires + - image_type == is an implementation of array2d/array2d_kernel_abstract.h + ensures + - #img.nr() == img.nr() && #img.nc() == img.nc() + (i.e. the dimensions of the input image are not chanaged) + - for all valid r and c that are on the line between point (x1,y1) + and point (x2,y2): + - performs img[r][c] = val + (i.e. it draws the line from (x1,y1) to (x2,y2) onto the image) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_DRAW_IMAGe_ABSTRACT + + + diff --git a/dlib/image_transforms/edge_detector.h b/dlib/image_transforms/edge_detector.h new file mode 100644 index 0000000000000000000000000000000000000000..7c7f95d1b48bb32d9ae6107872cba1569c2882cb --- /dev/null +++ b/dlib/image_transforms/edge_detector.h @@ -0,0 +1,270 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_EDGE_DETECTOr_ +#define DLIB_EDGE_DETECTOr_ + +#include "edge_detector_abstract.h" +#include "../pixel.h" +#include "../array2d.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + inline char edge_orientation ( + long x, + long y + ) + { + // if this is a perfectly horizontal gradient then return right away + if (x == 0) + { + return '|'; + } + else if (y == 0) // if this is a perfectly vertical gradient then return right away + { + return '-'; + } + + if (x < 0) + { + x = -x; + if (y < 0) + { + y = -y; + x <<= 7; + const long temp = x/y; + if (temp > 309) + return '-'; + else if (temp > 53) + return '/'; + else + return '|'; + } + else + { + x <<= 7; + const long temp = x/y; + if (temp > 309) + return '-'; + else if (temp > 53) + return '\\'; + else + return '|'; + } + } + else + { + if (y < 0) + { + y = -y; + x <<= 7; + + const long temp = x/y; + if (temp > 309) + return '-'; + else if (temp > 53) + return '\\'; + else + return '|'; + } + else + { + x <<= 7; + + const long temp = x/y; + if (temp > 309) + return '-'; + else if (temp > 53) + return '/'; + else + return '|'; + } + } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void sobel_edge_detector ( + const in_image_type& in_img, + out_image_type& horz, + out_image_type& vert + ) + { + COMPILE_TIME_ASSERT(is_signed_type::value); + DLIB_ASSERT( (((void*)&in_img != (void*)&horz) && ((void*)&in_img != (void*)&vert) && ((void*)&vert != (void*)&horz)), + "\tvoid sobel_edge_detector(in_img, horz, vert)" + << "\n\tYou can't give the same image as more than one argument" + << "\n\t&in_img: " << &in_img + << "\n\t&horz: " << &horz + << "\n\t&vert: " << &vert + ); + + + const long vert_filter[3][3] = {{-1,-2,-1}, + {0,0,0}, + {1,2,1}}; + const long horz_filter[3][3] = { {-1,0,1}, + {-2,0,2}, + {-1,0,1}}; + + const long M = 3; + const long N = 3; + + horz.set_size(in_img.nr(),in_img.nc()); + vert.set_size(in_img.nr(),in_img.nc()); + + assign_border_pixels(horz,1,1,0); + assign_border_pixels(vert,1,1,0); + + // figure out the range that we should apply the filter to + const long first_row = M/2; + const long first_col = N/2; + const long last_row = in_img.nr() - M/2; + const long last_col = in_img.nc() - N/2; + + + // apply the filter to the image + for (long r = first_row; r < last_row; ++r) + { + for (long c = first_col; c < last_col; ++c) + { + unsigned long p; + long horz_temp = 0; + long vert_temp = 0; + for (long m = 0; m < M; ++m) + { + for (long n = 0; n < N; ++n) + { + // pull out the current pixel and put it into p + p = get_pixel_intensity(in_img[r-M/2+m][c-N/2+n]); + + horz_temp += static_cast(p)*horz_filter[m][n]; + vert_temp += static_cast(p)*vert_filter[m][n]; + } + } + + horz[r][c] = horz_temp; + vert[r][c] = vert_temp; + + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void suppress_non_maximum_edges ( + const in_image_type& horz, + const in_image_type& vert, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT(is_signed_type::value); + DLIB_ASSERT( horz.nr() == vert.nr() && horz.nc() == vert.nc(), + "\tvoid suppress_non_maximum_edges(horz, vert, out_img)" + << "\n\tYou have to give horz and vert gradient images that are the same size" + << "\n\thorz.nr(): " << horz.nr() + << "\n\thorz.nc(): " << horz.nc() + << "\n\tvert.nr(): " << vert.nr() + << "\n\tvert.nc(): " << vert.nc() + ); + DLIB_ASSERT( ((void*)&out_img != (void*)&horz) && ((void*)&out_img != (void*)&vert), + "\tvoid suppress_non_maximum_edges(horz, vert, out_img)" + << "\n\tYou can't give the same image as more than one argument" + << "\n\t&horz: " << &horz + << "\n\t&vert: " << &vert + << "\n\t&out_img: " << &out_img + ); + + using std::min; + using std::abs; + + typedef typename out_image_type::type pixel_type; + + // if there isn't any input image then don't do anything + if (horz.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(horz.nr(),horz.nc()); + + zero_border_pixels(out_img,1,1); + + // now do non maximum suppression while we copy the + const long M = 3; + const long N = 3; + + // figure out the range that we should apply the filter to + const long first_row = M/2; + const long first_col = N/2; + const long last_row = horz.nr() - M/2; + const long last_col = horz.nc() - N/2; + + + // apply the filter to the image + for (long r = first_row; r < last_row; ++r) + { + for (long c = first_col; c < last_col; ++c) + { + const long y = horz[r][c]; + const long x = vert[r][c]; + + const long val = abs(horz[r][c]) + abs(vert[r][c]); + + const char ori = edge_orientation(x,y); + const unsigned char zero = 0; + switch (ori) + { + case '-': + if (abs(horz[r-1][c])+abs(vert[r-1][c]) > val || abs(horz[r+1][c]) + abs(vert[r+1][c]) > val) + assign_pixel(out_img[r][c] , zero); + else + assign_pixel(out_img[r][c] , static_cast(val)); + break; + + case '|': + if (abs(horz[r][c-1]) + abs(vert[r][c-1]) > val || abs(horz[r][c+1]) + abs(vert[r][c+1]) > val) + assign_pixel(out_img[r][c] , zero); + else + assign_pixel(out_img[r][c] , static_cast(val)); + break; + + case '/': + if (abs(horz[r-1][c-1]) + abs(vert[r-1][c-1]) > val || abs(horz[r+1][c+1]) + abs(vert[r+1][c+1]) > val) + assign_pixel(out_img[r][c] , zero); + else + assign_pixel(out_img[r][c] , static_cast(val)); + break; + + case '\\': + if (abs(horz[r+1][c-1]) + abs(vert[r+1][c-1]) > val || abs(horz[r-1][c+1]) + abs(vert[r-1][c+1]) > val) + assign_pixel(out_img[r][c] , zero); + else + assign_pixel(out_img[r][c] , static_cast(val)); + break; + + } + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_EDGE_DETECTOr_ + + + diff --git a/dlib/image_transforms/edge_detector_abstract.h b/dlib/image_transforms/edge_detector_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..edba2b34b1e85eb4551770a8685242b8f6b896c5 --- /dev/null +++ b/dlib/image_transforms/edge_detector_abstract.h @@ -0,0 +1,103 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_EDGE_DETECTOr_ABSTRACT_ +#ifdef DLIB_EDGE_DETECTOr_ABSTRACT_ + +#include "../pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + inline char edge_orientation ( + long x, + long y + ); + /*! + ensures + - returns the orientation of the line drawn from the origin to the point (x,y). + The orientation is represented pictorially using the four ascii + characters /,|,\, and -. + - if (the line is horizontal) then + returns '-' + - if (the line is vertical) then + returns '|' + - if (the line is diagonal with a positive slope) then + returns '/' + - if (the line is diagonal with a negative slope) then + returns '\\' + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void sobel_edge_detector ( + const in_image_type& in_img, + out_image_type& horz, + out_image_type& vert + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits must be defined + out_image_type::type == a signed integral type + - (&in_img != &horz) && (&in_img != &vert) && (&vert != &horz) + (i.e. all three images are different image objects) + ensures + - Applies the sobel edge detector to the given input image and stores the resulting + edge detections in the horz and vert images + - #horz.nr() == in_img.nr() + - #horz.nc() == in_img.nc() + - #vert.nr() == in_img.nr() + - #vert.nc() == in_img.nc() + - for all valid r and c: + - #horz[r][c] == the magnitude of the horizontal gradient at the point in_img[r][c] + - #vert[r][c] == the magnitude of the vertical gradient at the point in_img[r][c] + - edge_orientation(#vert[r][c], #horz[r][c]) == the edge direction at this point in + the image + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void suppress_non_maximum_edges ( + const in_image_type& horz, + const in_image_type& vert, + out_image_type& out_img + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits must be defined + - horz.nr() == vert.nr() + - horz.nc() == vert.nc() + - (&out_img != &horz) && (&out_img != &vert) + - in_image_type::type == a signed integral type + ensures + - #out_img.nr() = horz.nr() + - #out_img.nc() = horz.nc() + - let edge_strength(r,c) == abs(horz[r][c]) + abs(vert[r][c]) + - for all valid r and c: + - if (edge_strength(r,c) is at a maximum with respect to its 2 neighboring + pixels along the line given by edge_orientation(vert[r][c],horz[r][c])) then + - performs assign_pixel(#out_img[r][c], edge_strength(r,c)) + - else + - performs assign_pixel(#out_img[r][c], 0) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_EDGE_DETECTOr_ABSTRACT_ + + diff --git a/dlib/image_transforms/equalize_histogram.h b/dlib/image_transforms/equalize_histogram.h new file mode 100644 index 0000000000000000000000000000000000000000..ecb58ee0f4dac8f9f8074c6f6034841387efb78e --- /dev/null +++ b/dlib/image_transforms/equalize_histogram.h @@ -0,0 +1,115 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_EQUALIZE_HISTOGRAm_ +#define DLIB_EQUALIZE_HISTOGRAm_ + +#include "../pixel.h" +#include "equalize_histogram_abstract.h" +#include +#include "../enable_if.h" +#include "../matrix.h" + +namespace dlib +{ + +// --------------------------------------------------------------------------------------- + + template < + typename in_image_type, + long R, + long C, + typename MM + > + void get_histogram ( + const in_image_type& in_img, + matrix& hist + ) + { + // make sure hist is the right size + if (R == 1) + hist.set_size(1,pixel_traits::max()+1); + else + hist.set_size(pixel_traits::max()+1,1); + + + set_all_elements(hist,0); + + // compute the histogram + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + unsigned long p = get_pixel_intensity(in_img[r][c]); + ++hist(p); + } + } + } + +// --------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void equalize_histogram ( + const in_image_type& in_img, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + typedef typename in_image_type::type in_pixel_type; + typedef typename out_image_type::type out_pixel_type; + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + unsigned long p; + + matrix histogram; + get_histogram(in_img, histogram); + + double scale = pixel_traits::max(); + if (in_img.size() > histogram(0)) + scale /= in_img.size()-histogram(0); + else + scale = 0; + + // make the black pixels remain black in the output image + histogram(0) = 0; + + // compute the transform function + for (long i = 1; i < histogram.size(); ++i) + histogram(i) += histogram(i-1); + // scale so that it is in the range [0,pixel_traits::max()] + for (long i = 0; i < histogram.size(); ++i) + histogram(i) = static_cast(histogram(i)*scale); + + // now do the transform + for (long row = 0; row < in_img.nr(); ++row) + { + for (long col = 0; col < in_img.nc(); ++col) + { + p = histogram(get_pixel_intensity(in_img[row][col])); + assign_pixel(out_img[row][col], in_img[row][col]); + assign_pixel_intensity(out_img[row][col],p); + } + } + + } + +// --------------------------------------------------------------------------------------- + +} + +#endif // DLIB_EQUALIZE_HISTOGRAm_ + + + diff --git a/dlib/image_transforms/equalize_histogram_abstract.h b/dlib/image_transforms/equalize_histogram_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..fb72f6cd25e69fcbd41ad146d6ea8a9dd1a5e98b --- /dev/null +++ b/dlib/image_transforms/equalize_histogram_abstract.h @@ -0,0 +1,65 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_ +#ifdef DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_ + +#include "../pixel.h" +#include "../matrix.h" + +namespace dlib +{ + +// --------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void equalize_histogram ( + const in_image_type& in_img, + out_image_type& out_img + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + ensures + - #out_img == the histogram equalized version of in_img + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// --------------------------------------------------------------------------------------- + + template < + typename in_image_type, + long R, + long C + > + void get_histogram ( + const in_image_type& in_img, + matrix& hist + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - hist must be capable of representing a vector of length + pixel_traits::max(). I.e. if R and C are nonzero + then they must be values that don't conflict with the previous sentence. + ensures + - #hist.size() == pixel_traits::max() + - #hist == the histogram for in_img. I.e. it is the case that for all + valid i: + - hist[i] == the number of times a pixel with intensity i appears + in in_img + !*/ + +// --------------------------------------------------------------------------------------- + +} + +#endif // DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_ + + diff --git a/dlib/image_transforms/morphological_operations.h b/dlib/image_transforms/morphological_operations.h new file mode 100644 index 0000000000000000000000000000000000000000..a6bf83ba896f62d206da32dfeca43fb80885d2d7 --- /dev/null +++ b/dlib/image_transforms/morphological_operations.h @@ -0,0 +1,615 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MORPHOLOGICAL_OPERATIONs_ +#define DLIB_MORPHOLOGICAL_OPERATIONs_ + +#include "../pixel.h" +#include "thresholding.h" +#include "morphological_operations_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace morphological_operations_helpers + { + template + bool is_binary_image ( + const image_type& img + ) + /*! + ensures + - returns true if img contains only on_pixel and off_pixel values. + - returns false otherwise + !*/ + { + for (long r = 0; r < img.nr(); ++r) + { + for (long c = 0; c < img.nc(); ++c) + { + if (img[r][c] != on_pixel && img[r][c] != off_pixel) + { + return false; + } + } + } + return true; + } + + template < + long M, + long N + > + bool is_binary_image ( + const unsigned char (&structuring_element)[M][N] + ) + /*! + ensures + - returns true if structuring_element contains only on_pixel and off_pixel values. + - returns false otherwise + !*/ + { + for (long m = 0; m < M; ++m) + { + for (long n = 0; n < N; ++n) + { + if (structuring_element[m][n] != on_pixel && + structuring_element[m][n] != off_pixel) + { + return false; + } + } + } + return true; + } + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_dilation ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N] + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(M%2 == 1); + COMPILE_TIME_ASSERT(N%2 == 1); + DLIB_ASSERT((void*)&in_img != (void*)&out_img , + "\tvoid binary_dilation()" + << "\n\tYou must give two different image objects" + ); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img) , + "\tvoid binary_dilation()" + << "\n\tin_img must be a binary image" + ); + DLIB_ASSERT(is_binary_image(structuring_element) , + "\tvoid binary_dilation()" + << "\n\tthe structuring_element must be a binary image" + ); + + + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + // apply the filter to the image + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + unsigned char out_pixel = off_pixel; + for (long m = 0; m < M && out_pixel == off_pixel; ++m) + { + for (long n = 0; n < N && out_pixel == off_pixel; ++n) + { + if (structuring_element[m][n] == on_pixel) + { + // if this pixel is inside the image then get it from the image + // but if it isn't just pretend it was an off_pixel value + if (r+m >= M/2 && c+n >= N/2 && + r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc()) + { + out_pixel = in_img[r+m-M/2][c+n-N/2]; + } + } + } + } + assign_pixel(out_img[r][c], out_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_erosion ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N] + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(M%2 == 1); + COMPILE_TIME_ASSERT(N%2 == 1); + DLIB_ASSERT((void*)&in_img != (void*)&out_img , + "\tvoid binary_erosion()" + << "\n\tYou must give two different image objects" + ); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img) , + "\tvoid binary_erosion()" + << "\n\tin_img must be a binary image" + ); + DLIB_ASSERT(is_binary_image(structuring_element) , + "\tvoid binary_erosion()" + << "\n\tthe structuring_element must be a binary image" + ); + + + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + // apply the filter to the image + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + unsigned char out_pixel = on_pixel; + for (long m = 0; m < M && out_pixel == on_pixel; ++m) + { + for (long n = 0; n < N && out_pixel == on_pixel; ++n) + { + if (structuring_element[m][n] == on_pixel) + { + // if this pixel is inside the image then get it from the image + // but if it isn't just pretend it was an off_pixel value + if (r+m >= M/2 && c+n >= N/2 && + r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc()) + { + out_pixel = in_img[r+m-M/2][c+n-N/2]; + } + else + { + out_pixel = off_pixel; + } + } + } + } + assign_pixel(out_img[r][c], out_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_open ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N], + const unsigned long iter = 1 + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(M%2 == 1); + COMPILE_TIME_ASSERT(N%2 == 1); + DLIB_ASSERT((void*)&in_img != (void*)&out_img , + "\tvoid binary_open()" + << "\n\tYou must give two different image objects" + ); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img) , + "\tvoid binary_open()" + << "\n\tin_img must be a binary image" + ); + DLIB_ASSERT(is_binary_image(structuring_element) , + "\tvoid binary_open()" + << "\n\tthe structuring_element must be a binary image" + ); + + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + if (iter == 0) + { + // just copy the image over + assign_image(out_img, in_img); + } + else if (iter == 1) + { + in_image_type temp; + binary_erosion(in_img,temp,structuring_element); + binary_dilation(temp,out_img,structuring_element); + } + else + { + in_image_type temp1, temp2; + binary_erosion(in_img,temp1,structuring_element); + + // do the extra erosions + for (unsigned long i = 1; i < iter; ++i) + { + temp1.swap(temp2); + binary_erosion(temp2,temp1,structuring_element); + } + + // do the extra dilations + for (unsigned long i = 1; i < iter; ++i) + { + temp1.swap(temp2); + binary_dilation(temp2,temp1,structuring_element); + } + + binary_dilation(temp1,out_img,structuring_element); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_close ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N], + const unsigned long iter = 1 + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(M%2 == 1); + COMPILE_TIME_ASSERT(N%2 == 1); + DLIB_ASSERT((void*)&in_img != (void*)&out_img , + "\tvoid binary_close()" + << "\n\tYou must give two different image objects" + ); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img) , + "\tvoid binary_close()" + << "\n\tin_img must be a binary image" + ); + DLIB_ASSERT(is_binary_image(structuring_element) , + "\tvoid binary_close()" + << "\n\tthe structuring_element must be a binary image" + ); + + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + if (iter == 0) + { + // just copy the image over + assign_image(out_img, in_img); + } + else if (iter == 1) + { + in_image_type temp; + binary_dilation(in_img,temp,structuring_element); + binary_erosion(temp,out_img,structuring_element); + } + else + { + in_image_type temp1, temp2; + binary_dilation(in_img,temp1,structuring_element); + + // do the extra dilations + for (unsigned long i = 1; i < iter; ++i) + { + temp1.swap(temp2); + binary_dilation(temp2,temp1,structuring_element); + } + + // do the extra erosions + for (unsigned long i = 1; i < iter; ++i) + { + temp1.swap(temp2); + binary_erosion(temp2,temp1,structuring_element); + } + + binary_erosion(temp1,out_img,structuring_element); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type1, + typename in_image_type2, + typename out_image_type + > + void binary_intersection ( + const in_image_type1& in_img1, + const in_image_type2& in_img2, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img1) , + "\tvoid binary_intersection()" + << "\n\tin_img1 must be a binary image" + ); + DLIB_ASSERT(is_binary_image(in_img2) , + "\tvoid binary_intersection()" + << "\n\tin_img2 must be a binary image" + ); + DLIB_ASSERT(in_img1.nc() == in_img2.nc(), + "\tvoid binary_intersection()" + << "\n\tin_img1 and in_img2 must have the same ncs." + << "\n\tin_img1.nc(): " << in_img1.nc() + << "\n\tin_img2.nc(): " << in_img2.nc() + ); + DLIB_ASSERT(in_img1.nr() == in_img2.nr(), + "\tvoid binary_intersection()" + << "\n\tin_img1 and in_img2 must have the same nrs." + << "\n\tin_img1.nr(): " << in_img1.nr() + << "\n\tin_img2.nr(): " << in_img2.nr() + ); + + + + // if there isn't any input image then don't do anything + if (in_img1.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img1.nr(),in_img1.nc()); + + for (long r = 0; r < in_img1.nr(); ++r) + { + for (long c = 0; c < in_img1.nc(); ++c) + { + if (in_img1[r][c] == on_pixel && in_img2[r][c] == on_pixel) + assign_pixel(out_img[r][c], on_pixel); + else + assign_pixel(out_img[r][c], off_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type1, + typename in_image_type2, + typename out_image_type + > + void binary_union ( + const in_image_type1& in_img1, + const in_image_type2& in_img2, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img1) , + "\tvoid binary_intersection()" + << "\n\tin_img1 must be a binary image" + ); + DLIB_ASSERT(is_binary_image(in_img2) , + "\tvoid binary_intersection()" + << "\n\tin_img2 must be a binary image" + ); + DLIB_ASSERT(in_img1.nc() == in_img2.nc(), + "\tvoid binary_intersection()" + << "\n\tin_img1 and in_img2 must have the same ncs." + << "\n\tin_img1.nc(): " << in_img1.nc() + << "\n\tin_img2.nc(): " << in_img2.nc() + ); + DLIB_ASSERT(in_img1.nr() == in_img2.nr(), + "\tvoid binary_intersection()" + << "\n\tin_img1 and in_img2 must have the same nrs." + << "\n\tin_img1.nr(): " << in_img1.nr() + << "\n\tin_img2.nr(): " << in_img2.nr() + ); + + + + // if there isn't any input image then don't do anything + if (in_img1.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img1.nr(),in_img1.nc()); + + for (long r = 0; r < in_img1.nr(); ++r) + { + for (long c = 0; c < in_img1.nc(); ++c) + { + if (in_img1[r][c] == on_pixel || in_img2[r][c] == on_pixel) + assign_pixel(out_img[r][c], on_pixel); + else + assign_pixel(out_img[r][c], off_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type1, + typename in_image_type2, + typename out_image_type + > + void binary_difference ( + const in_image_type1& in_img1, + const in_image_type2& in_img2, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img1) , + "\tvoid binary_difference()" + << "\n\tin_img1 must be a binary image" + ); + DLIB_ASSERT(is_binary_image(in_img2) , + "\tvoid binary_difference()" + << "\n\tin_img2 must be a binary image" + ); + DLIB_ASSERT(in_img1.nc() == in_img2.nc(), + "\tvoid binary_difference()" + << "\n\tin_img1 and in_img2 must have the same ncs." + << "\n\tin_img1.nc(): " << in_img1.nc() + << "\n\tin_img2.nc(): " << in_img2.nc() + ); + DLIB_ASSERT(in_img1.nr() == in_img2.nr(), + "\tvoid binary_difference()" + << "\n\tin_img1 and in_img2 must have the same nrs." + << "\n\tin_img1.nr(): " << in_img1.nr() + << "\n\tin_img2.nr(): " << in_img2.nr() + ); + + + + // if there isn't any input image then don't do anything + if (in_img1.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img1.nr(),in_img1.nc()); + + for (long r = 0; r < in_img1.nr(); ++r) + { + for (long c = 0; c < in_img1.nc(); ++c) + { + if (in_img1[r][c] == on_pixel && in_img2[r][c] == off_pixel) + assign_pixel(out_img[r][c], on_pixel); + else + assign_pixel(out_img[r][c], off_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void binary_complement ( + const in_image_type& in_img, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + using namespace morphological_operations_helpers; + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + DLIB_ASSERT(is_binary_image(in_img) , + "\tvoid binary_complement()" + << "\n\tin_img must be a binary image" + ); + + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + if (in_img[r][c] == on_pixel) + assign_pixel(out_img[r][c], off_pixel); + else + assign_pixel(out_img[r][c], on_pixel); + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MORPHOLOGICAL_OPERATIONs_ + diff --git a/dlib/image_transforms/morphological_operations_abstract.h b/dlib/image_transforms/morphological_operations_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..368e1663cbbe58aa1a1af8a0ca75311db9199ba4 --- /dev/null +++ b/dlib/image_transforms/morphological_operations_abstract.h @@ -0,0 +1,287 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_ +#ifdef DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_ + +#include "../pixel.h" +#include "thresholding_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_dilation ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N] + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - &in_img != &out_img + - M % 2 == 1 (i.e. M must be odd) + - N % 2 == 1 (i.e. N must be odd) + - all pixels in in_img are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + - all pixels in structuring_element are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + ensures + - Does a binary dilation of in_img using the given structuring element and + stores the result in out_img. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_erosion ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N] + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - &in_img != &out_img + - M % 2 == 1 (i.e. M must be odd) + - N % 2 == 1 (i.e. N must be odd) + - all pixels in in_img are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + - all pixels in structuring_element are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + ensures + - Does a binary erosion of in_img using the given structuring element and + stores the result in out_img. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_open ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N], + const unsigned long iter = 1 + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - &in_img != &out_img + - M % 2 == 1 (i.e. M must be odd) + - N % 2 == 1 (i.e. N must be odd) + - all pixels in in_img are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + - all pixels in structuring_element are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + ensures + - Does a binary open of in_img using the given structuring element and + stores the result in out_img. Specifically, iter iterations of binary + erosion are applied and then iter iterations of binary dilation. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + long M, + long N + > + void binary_close ( + const in_image_type& in_img, + out_image_type& out_img, + const unsigned char (&structuring_element)[M][N], + const unsigned long iter = 1 + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - &in_img != &out_img + - M % 2 == 1 (i.e. M must be odd) + - N % 2 == 1 (i.e. N must be odd) + - all pixels in in_img are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + - all pixels in structuring_element are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + ensures + - Does a binary close of in_img using the given structuring element and + stores the result in out_img. Specifically, iter iterations of binary + dilation are applied and then iter iterations of binary erosion. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type1, + typename in_image_type2, + typename out_image_type + > + void binary_intersection ( + const in_image_type1& in_img1, + const in_image_type2& in_img2, + out_image_type& out_img + ); + /*! + requires + - in_image_type1 == is an implementation of array2d/array2d_kernel_abstract.h + - in_image_type2 == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel + (i.e. they must be binary images) + - in_img1.nc() == in_img2.nc() + - in_img1.nr() == in_img2.nr() + ensures + - #out_img == the binary intersection of in_img1 and in_img2. (i.e. All + the pixels that are set to on_pixel in both in_img1 and in_img2 will be set + to on_pixel in #out_img. All other pixels will be set to off_pixel) + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type1, + typename in_image_type2, + typename out_image_type + > + void binary_union ( + const in_image_type1& in_img1, + const in_image_type2& in_img2, + out_image_type& out_img + ); + /*! + requires + - in_image_type1 == is an implementation of array2d/array2d_kernel_abstract.h + - in_image_type2 == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel + (i.e. they must be binary images) + - in_img1.nc() == in_img2.nc() + - in_img1.nr() == in_img2.nr() + ensures + - #out_img == the binary union of in_img1 and in_img2. (i.e. All + the pixels that are set to on_pixel in in_img1 and/or in_img2 will be set + to on_pixel in #out_img. All other pixels will be set to off_pixel) + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type1, + typename in_image_type2, + typename out_image_type + > + void binary_difference ( + const in_image_type1& in_img1, + const in_image_type2& in_img2, + out_image_type& out_img + ); + /*! + requires + - in_image_type1 == is an implementation of array2d/array2d_kernel_abstract.h + - in_image_type2 == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel + (i.e. they must be binary images) + - in_img1.nc() == in_img2.nc() + - in_img1.nr() == in_img2.nr() + ensures + - #out_img == the binary difference of in_img1 and in_img2. (i.e. #out_img + will be a copy of in_img1 except that any pixels in in_img2 that are set to + on_pixel will be set to off_pixel) + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void binary_complement ( + const in_image_type& in_img, + out_image_type& out_img + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - all pixels in in_img are set to either on_pixel or off_pixel + (i.e. it must be a binary image) + ensures + - #out_img == the binary complement of in_img. (i.e. For each pixel in + in_img, if it is on_pixel then it will be set to off_pixel in #out_img and + if it was off_pixel in in_img then it will be on_pixel in #out_img) + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_ + + diff --git a/dlib/image_transforms/spatial_filtering.h b/dlib/image_transforms/spatial_filtering.h new file mode 100644 index 0000000000000000000000000000000000000000..1cc3312e7c004b2c29800f53506a64cb8caf846a --- /dev/null +++ b/dlib/image_transforms/spatial_filtering.h @@ -0,0 +1,115 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SPATIAL_FILTERINg_H_ +#define DLIB_SPATIAL_FILTERINg_H_ + +#include "../pixel.h" +#include "spatial_filtering_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type, + typename filter_type, + long M, + long N + > + void spatially_filter_image ( + const in_image_type& in_img, + out_image_type& out_img, + const filter_type (&filter)[M][N], + unsigned long scale = 1, + bool use_abs = false + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + COMPILE_TIME_ASSERT(M%2 == 1); + COMPILE_TIME_ASSERT(N%2 == 1); + DLIB_ASSERT(scale > 0, + "\tvoid spatially_filter_image()" + << "\n\tYou can't give a scale of zero" + ); + DLIB_ASSERT((void*)&in_img != (void*)&out_img , + "\tvoid spatially_filter_image()" + << "\n\tYou must give two different image objects" + ); + + + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + zero_border_pixels(out_img, M/2, N/2); + + // figure out the range that we should apply the filter to + const long first_row = M/2; + const long first_col = N/2; + const long last_row = in_img.nr() - M/2; + const long last_col = in_img.nc() - N/2; + + // apply the filter to the image + for (long r = first_row; r < last_row; ++r) + { + for (long c = first_col; c < last_col; ++c) + { + unsigned long p; + long temp = 0; + for (long m = 0; m < M; ++m) + { + for (long n = 0; n < N; ++n) + { + // pull out the current pixel and put it into p + p = get_pixel_intensity(in_img[r-M/2+m][c-N/2+n]); + temp += static_cast(p)*filter[m][n]; + } + } + + temp /= scale; + + // Catch any underflow or apply abs as appropriate + if (temp < 0) + { + if (use_abs) + { + temp = -temp; + } + else + { + temp = 0; + } + } + + // apply our new value for the intensity + p = static_cast(temp); + + // save this pixel to the output image + assign_pixel(out_img[r][c], in_img[r][c]); + assign_pixel_intensity(out_img[r][c],p); + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SPATIAL_FILTERINg_H_ + + + + diff --git a/dlib/image_transforms/spatial_filtering_abstract.h b/dlib/image_transforms/spatial_filtering_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..abb66cedd9e2b7059c9edb697379b8fa9528d2e5 --- /dev/null +++ b/dlib/image_transforms/spatial_filtering_abstract.h @@ -0,0 +1,58 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SPATIAL_FILTERINg_ABSTRACT_ +#ifdef DLIB_SPATIAL_FILTERINg_ABSTRACT_ + +#include "../pixel.h" + +namespace dlib +{ + + template < + typename in_image_type, + typename out_image_type, + typename filter_type, + long M, + long N + > + void spatially_filter_image ( + const in_image_type& in_img, + out_image_type& out_img, + const filter_type (&filter)[M][N], + unsigned long scale = 1, + bool use_abs = false + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - &in_img != &out_img + - scale > 0 + - M % 2 == 1 (i.e. M must be odd) + - N % 2 == 1 (i.e. N must be odd) + ensures + - Applies the given spatial filter to in_img and stores the result in out_img. Also + divides each resulting pixel by scale. + - pixel values after filtering that are > pixel_traits::max() are + set to pixel_traits::max() + - if (pixel_traits::grayscale == false) then + - the pixel values are converted to the HSI color space and the filtering + is done on the intensity channel only. + - if (use_abs == true) then + - pixel values after filtering that are < 0 are converted to their absolute values + - else + - pixel values after filtering that are < 0 are assigned the value of 0 + - Pixels close enough to the edge of in_img to not have the filter still fit + inside the image are not modified. i.e. Whatever value the border of out_img + had to begin with is what it will have after this function returns. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + + +} + +#endif // DLIB_SPATIAL_FILTERINg_ABSTRACT_ + diff --git a/dlib/image_transforms/thresholding.h b/dlib/image_transforms/thresholding.h new file mode 100644 index 0000000000000000000000000000000000000000..1379063ea32a0efdde4490694e5d6e82f9eb50d0 --- /dev/null +++ b/dlib/image_transforms/thresholding.h @@ -0,0 +1,307 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THRESHOLDINg_ +#define DLIB_THRESHOLDINg_ + +#include "../pixel.h" +#include "thresholding_abstract.h" +#include "equalize_histogram.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + const unsigned char on_pixel = 255; + const unsigned char off_pixel = 0; + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void threshold_image ( + const in_image_type& in_img, + out_image_type& out_img, + unsigned long thresh + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + typename out_image_type::type p; + assign_pixel(p,in_img[r][c]); + if (p >= thresh) + p = on_pixel; + else + p = off_pixel; + out_img[r][c] = p; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void auto_threshold_image ( + const in_image_type& in_img, + out_image_type& out_img + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + unsigned long thresh; + // find the threshold we should use + matrix hist; + get_histogram(in_img,hist); + + // Start our two means (a and b) out at the ends of the histogram + long a = 0; + long b = hist.size()-1; + bool moved_a = true; + bool moved_b = true; + while (moved_a || moved_b) + { + moved_a = false; + moved_b = false; + + // catch the degenerate case where the histogram is empty + if (a >= b) + break; + + if (hist(a) == 0) + { + ++a; + moved_a = true; + } + + if (hist(b) == 0) + { + --b; + moved_b = true; + } + } + + // now do k-means clustering with k = 2 on the histogram. + moved_a = true; + moved_b = true; + while (moved_a || moved_b) + { + moved_a = false; + moved_b = false; + + long a_hits = 0; + long b_hits = 0; + long a_mass = 0; + long b_mass = 0; + + for (long i = 0; i < hist.size(); ++i) + { + // if i is closer to a + if (std::abs(i-a) < std::abs(i-b)) + { + a_mass += hist(i)*i; + a_hits += hist(i); + } + else // if i is closer to b + { + b_mass += hist(i)*i; + b_hits += hist(i); + } + } + + long new_a = (a_mass + a_hits/2)/a_hits; + long new_b = (b_mass + b_hits/2)/b_hits; + + if (new_a != a) + { + moved_a = true; + a = new_a; + } + + if (new_b != b) + { + moved_b = true; + b = new_b; + } + } + + // put the threshold between the two means we found + thresh = (a + b)/2; + + // now actually apply the threshold + threshold_image(in_img,out_img,thresh); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void hysteresis_threshold ( + const in_image_type& in_img, + out_image_type& out_img, + unsigned long lower_thresh, + unsigned long upper_thresh + ) + { + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + COMPILE_TIME_ASSERT( pixel_traits::has_alpha == false ); + + COMPILE_TIME_ASSERT(pixel_traits::grayscale); + + DLIB_ASSERT( lower_thresh <= upper_thresh, + "\tvoid hysteresis_threshold(in_img, out_img, lower_thresh, upper_thresh)" + << "\n\tYou can't use an upper_thresh that is less than your lower_thresh" + << "\n\tlower_thresh: " << lower_thresh + << "\n\tupper_thresh: " << upper_thresh + ); + + // if there isn't any input image then don't do anything + if (in_img.size() == 0) + { + out_img.clear(); + return; + } + + out_img.set_size(in_img.nr(),in_img.nc()); + assign_all_pixels(out_img,0); + + const long size = 50; + long rstack[size]; + long cstack[size]; + + // now do the thresholding + for (long r = 0; r < in_img.nr(); ++r) + { + for (long c = 0; c < in_img.nc(); ++c) + { + typename out_image_type::type p; + assign_pixel(p,in_img[r][c]); + if (p >= upper_thresh) + { + // now do line following for pixels >= lower_thresh. + // set the stack position to 0. + long pos = 1; + rstack[0] = r; + cstack[0] = c; + + while (pos > 0) + { + --pos; + const long r = rstack[pos]; + const long c = cstack[pos]; + + // This is the base case of our recursion. We want to stop if we hit a + // pixel we have already visited. + if (out_img[r][c] == on_pixel) + continue; + + out_img[r][c] = on_pixel; + + // put the neighbors of this pixel on the stack if they are bright enough + if (r-1 >= 0) + { + if (pos < size && get_pixel_intensity(in_img[r-1][c]) >= lower_thresh) + { + rstack[pos] = r-1; + cstack[pos] = c; + ++pos; + } + if (pos < size && c-1 >= 0 && get_pixel_intensity(in_img[r-1][c-1]) >= lower_thresh) + { + rstack[pos] = r-1; + cstack[pos] = c-1; + ++pos; + } + if (pos < size && c+1 < in_img.nc() && get_pixel_intensity(in_img[r-1][c+1]) >= lower_thresh) + { + rstack[pos] = r-1; + cstack[pos] = c+1; + ++pos; + } + } + + if (pos < size && c-1 >= 0 && get_pixel_intensity(in_img[r][c-1]) >= lower_thresh) + { + rstack[pos] = r; + cstack[pos] = c-1; + ++pos; + } + if (pos < size && c+1 < in_img.nc() && get_pixel_intensity(in_img[r][c+1]) >= lower_thresh) + { + rstack[pos] = r; + cstack[pos] = c+1; + ++pos; + } + + if (r+1 < in_img.nr()) + { + if (pos < size && get_pixel_intensity(in_img[r+1][c]) >= lower_thresh) + { + rstack[pos] = r+1; + cstack[pos] = c; + ++pos; + } + if (pos < size && c-1 >= 0 && get_pixel_intensity(in_img[r+1][c-1]) >= lower_thresh) + { + rstack[pos] = r+1; + cstack[pos] = c-1; + ++pos; + } + if (pos < size && c+1 < in_img.nc() && get_pixel_intensity(in_img[r+1][c+1]) >= lower_thresh) + { + rstack[pos] = r+1; + cstack[pos] = c+1; + ++pos; + } + } + + } // end while (pos >= 0) + + } + else + { + out_img[r][c] = off_pixel; + } + + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THRESHOLDINg_ + diff --git a/dlib/image_transforms/thresholding_abstract.h b/dlib/image_transforms/thresholding_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..cfcab716cac9fc3ed2d9b8e8c4b35e06938b6555 --- /dev/null +++ b/dlib/image_transforms/thresholding_abstract.h @@ -0,0 +1,106 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_THRESHOLDINg_ABSTRACT_ +#ifdef DLIB_THRESHOLDINg_ABSTRACT_ + +#include "../pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + const unsigned char on_pixel = 255; + const unsigned char off_pixel = 0; + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void threshold_image ( + const in_image_type& in_img, + out_image_type& out_img, + unsigned long thresh + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + ensures + - #out_img == the thresholded version of in_img (in_img is converted to a grayscale + intensity image if it is color). Pixels in in_img with grayscale values >= thresh + have an output value of on_pixel and all others have a value of off_pixel. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void auto_threshold_image ( + const in_image_type& in_img, + out_image_type& out_img + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + ensures + - #out_img == the thresholded version of in_img (in_img is converted to a grayscale + intensity image if it is color). Pixels in in_img with grayscale values >= thresh + have an output value of on_pixel and all others have a value of off_pixel. + - The thresh value used is determined by performing a k-means clustering + on the input image histogram with a k of 2. The point between the two + means found is used as the thresh value. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename in_image_type, + typename out_image_type + > + void hysteresis_threshold ( + const in_image_type& in_img, + const out_image_type& out_img, + unsigned long lower_thresh, + unsigned long upper_thresh + ); + /*! + requires + - in_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - out_image_type == is an implementation of array2d/array2d_kernel_abstract.h + - pixel_traits::grayscale == true + - pixel_traits::has_alpha == false + - pixel_traits::has_alpha == false + - lower_thresh <= upper_thresh + ensures + - #out_img == the hysteresis thresholded version of in_img (in_img is converted to a + grayscale intensity image if it is color). Pixels in in_img with grayscale + values >= upper_thresh have an output value of on_pixel and all others have a + value of off_pixel unless they are >= lower_thresh and are adjacent to a pixel + with a value >= upper_thresh in which case they have a value of on_pixel. + - #out_img.nc() == in_img.nc() + - #out_img.nr() == in_img.nr() + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THRESHOLDINg_ABSTRACT_ + + diff --git a/dlib/interfaces/cmd_line_parser_option.h b/dlib/interfaces/cmd_line_parser_option.h new file mode 100644 index 0000000000000000000000000000000000000000..32a47aea014697125791580117646711918ea448 --- /dev/null +++ b/dlib/interfaces/cmd_line_parser_option.h @@ -0,0 +1,99 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_OPTIOn_ +#define DLIB_CMD_LINE_PARSER_OPTIOn_ + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT + > + class cmd_line_parser_option + { + /*! + POINTERS AND REFERENCES TO INTERNAL DATA + None of the functions in cmd_line_parser_option will invalidate + pointers or references to internal data when called. + + WHAT THIS OBJECT REPRESENTS + This object represents a command line option. + !*/ + + public: + + typedef charT char_type; + typedef std::basic_string string_type; + + virtual ~cmd_line_parser_option ( + ) = 0; + + virtual const string_type& name ( + ) const = 0; + /*! + ensures + - returns the name of this option + !*/ + + virtual const string_type& description ( + ) const = 0; + /*! + ensures + - returns the description for this option + !*/ + + virtual unsigned long number_of_arguments( + ) const = 0; + /*! + ensures + - returns the number of arguments for this option + !*/ + + virtual unsigned long count( + ) const = 0; + /*! + ensures + - returns the number of times this option appears on the command line. + !*/ + + virtual const string_type& argument ( + unsigned long arg = 0, + unsigned long N = 0 + ) const = 0; + /*! + requires + - arg < number_of_arguments() + - N < count() + ensures + - returns the argth argument to the Nth occurance of this + option on the command line. + !*/ + + inline operator bool ( + ) const { return count() > 0; } + /*! + ensures + - returns true if this option appears on the command line at all + !*/ + + protected: + + // restricted functions + cmd_line_parser_option& operator=(const cmd_line_parser_option&){return *this;} + + }; + + // destructor does nothing + template < typename charT > + cmd_line_parser_option::~cmd_line_parser_option() {} + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CMD_LINE_PARSER_OPTIOn_ + diff --git a/dlib/interfaces/enumerable.h b/dlib/interfaces/enumerable.h new file mode 100644 index 0000000000000000000000000000000000000000..892b64260e4f36d287f1f38c3c446c40418f72df --- /dev/null +++ b/dlib/interfaces/enumerable.h @@ -0,0 +1,130 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_ENUMERABLe_INTERFACE_ +#define DLIB_ENUMERABLe_INTERFACE_ + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class enumerable + { + /*! + POINTERS AND REFERENCES TO INTERNAL DATA + - if (at_start()) then + - all pointers and references to data returned via element() are + invalid. + - calling move_next() or reset() invalidates pointers and references to + data returned via element() and only data returned via element(). + - calling at_start(), current_element_valid(), size(), or element() + does NOT invalidate pointers or references to any internal data. + + INITIAL VALUE + current_element_valid() == false + at_start() == true + + WHAT THIS OBJECT REPRESENTS + This object represent an interface for iterating through the + elements in a container. It starts out one before the first element + in the container. + + + EXAMPLE: The following loops though all elements in the container + and prints them to cout. + + container.reset(); + while(container.move_next()) { + cout << container.element(); + } + !*/ + + public: + typedef T type; + + inline virtual ~enumerable( + ) = 0; + + virtual bool at_start ( + ) const = 0; + /*! + ensures + - returns true if *this represents one position before the first element + in the container (this would also make the current element invalid) + else returns false + !*/ + + virtual void reset ( + ) const = 0; + /*! + ensures + - #current_element_valid() == false + - #at_start() == true + !*/ + + virtual bool current_element_valid ( + ) const = 0; + /*! + ensures + - returns true if we are currently at a valid element else + returns false + !*/ + + virtual const T& element ( + ) const = 0; + /*! + requires + - current_element_valid() == true + ensures + - returns a const reference to the current element + !*/ + + virtual T& element ( + ) = 0; + /*! + requires + - current_element_valid() == true + ensures + - returns a non-const reference to the current element + !*/ + + virtual bool move_next ( + ) const = 0; + /*! + ensures + - moves to the next element. i.e. #element() will now + return the next element in the container + - the return value will be equal to #current_element_valid() + - #at_start() == false + + - returns true if there is another element + - returns false if there are no more elements in the container + !*/ + + virtual unsigned long size ( + ) const = 0; + /*! + ensures + - returns the number of elements in *this + !*/ + + protected: + + // restricted functions + enumerable& operator=(const enumerable&) {return *this;} // no assignment operator + + }; + + // destructor does nothing + template + enumerable::~enumerable() {} + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_ENUMERABLe_INTERFACE_ + diff --git a/dlib/interfaces/map_pair.h b/dlib/interfaces/map_pair.h new file mode 100644 index 0000000000000000000000000000000000000000..f5f688a3024947f2c8484ac53cf7e214a2989163 --- /dev/null +++ b/dlib/interfaces/map_pair.h @@ -0,0 +1,74 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MAP_PAIr_INTERFACE_ +#define DLIB_MAP_PAIr_INTERFACE_ + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T1, + typename T2 + > + class map_pair + { + /*! + POINTERS AND REFERENCES TO INTERNAL DATA + None of the functions in map_pair will invalidate + pointers or references to internal data when called. + + WHAT THIS OBJECT REPRESENTS + this object is used to return the key/value pair used in the + map and hash_map containers when using the enumerable interface. + + note that the enumerable interface is defined in + interfaces/enumerable.h + !*/ + + public: + typedef T1 key_type; + typedef T2 value_type; + + virtual ~map_pair( + )=0; + + virtual const T1& key( + ) const =0; + /*! + ensures + - returns a const reference to the key + !*/ + + virtual const T2& value( + ) const =0; + /*! + ensures + - returns a const reference to the value associated with key + !*/ + + virtual T2& value( + )=0; + /*! + ensures + - returns a non-const reference to the value associated with key + !*/ + + protected: + + // restricted functions + map_pair& operator=(const map_pair&) {return *this;} // no assignment operator + + }; + + // destructor does nothing + template + map_pair::~map_pair () {} + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MAP_PAIr_INTERFACE_ + diff --git a/dlib/interfaces/remover.h b/dlib/interfaces/remover.h new file mode 100644 index 0000000000000000000000000000000000000000..6e85ed6124e2b19f5b3085ad952493a503bf6a18 --- /dev/null +++ b/dlib/interfaces/remover.h @@ -0,0 +1,220 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_REMOVER_KERNEl_INTERFACE_ +#define DLIB_REMOVER_KERNEl_INTERFACE_ + +#include + + +namespace dlib +{ + + template < + typename T + > + class remover + { + + /*! + REQUIREMENTS ON T + T is swappable by a global swap() and + T must have a default constructor + + POINTERS AND REFERENCES TO INTERNAL DATA + The size() function does not invalidate pointers or + references to internal data. All other functions have no such + guarantee. + + WHAT THIS OBJECT REPRESENTS + This object represents some generalized interface for removing + single items from container classes. + !*/ + + + public: + typedef T type; + + virtual ~remover( + ); + /*! + ensures + - all resources associated with *this have been released. + !*/ + + virtual void remove_any ( + T& item + ) = 0; + /*! + requires + - size() != 0 + ensures + - #size() == size() - 1 + - removes an element from *this and swaps it into item. + - if (*this implements the enumerable interface) then + - #at_start() == true + !*/ + + virtual unsigned long size ( + ) const = 0; + /*! + ensures + - returns the number of elements in *this + !*/ + + protected: + + // restricted functions + remover& operator=(const remover&) {return *this;} // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + class asc_remover : public remover + { + /*! + REQUIREMENTS ON T + T is swappable by a global swap() and + T must have a default constructor and + T must be comparable by compare where compare is a functor compatible with std::less + + WHAT THIS OBJECT REPRESENTS + This object represents the same thing as remover except + that remove_any() will remove elements in ascending order + according to the compare functor. + !*/ + public: + typedef compare compare_type; + + protected: + // restricted functions + asc_remover& operator=(const asc_remover&) {return *this;} // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range + > + class pair_remover + { + + /*! + REQUIREMENTS ON domain + domain is swappable by a global swap() and + domain must have a default constructor + + REQUIREMENTS ON range + range is swappable by a global swap() and + range must have a default constructor + + POINTERS AND REFERENCES TO INTERNAL DATA + The size() function does not invalidate pointers or + references to internal data. All other functions have no such + guarantee. + + WHAT THIS OBJECT REPRESENTS + This object represents some generalized interface for removing + pairs from container classes which enforce some kind of pairing on + the elements that they contain. + !*/ + + public: + typedef domain domain_type; + typedef range range_type; + + virtual ~pair_remover( + ); + /*! + ensures + - all resources associated with *this have been released. + !*/ + + virtual void remove_any ( + domain& d, + range& r + ) = 0; + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + - size() != 0 + ensures + - #size() == size() - 1 + - removes an element from the domain of *this and swaps it + into d. + - removes the element in *this's range that is associated + with #d and swaps it into r. + - if (*this implements the enumerable interface) then + - #at_start() == true + !*/ + + virtual unsigned long size ( + ) const = 0; + /*! + ensures + - returns the number of elements in *this + !*/ + + + protected: + + // restricted functions + pair_remover& operator=(const pair_remover&) {return *this;} // assignment operator + + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + class asc_pair_remover : public pair_remover + { + /*! + REQUIREMENTS ON domain + domain is swappable by a global swap() and + domain must have a default constructor and + domain must be comparable by compare where compare is a functor compatible with std::less + + REQUIREMENTS ON range + range is swappable by a global swap() and + range must have a default constructor + + WHAT THIS OBJECT REPRESENTS + This object represents the same thing as pair_remover except + that remove_any() will remove domain elements in ascending + order according to the compare functor. + !*/ + public: + typedef compare compare_type; + + protected: + // restricted functions + asc_pair_remover& operator=(const asc_pair_remover&) {return *this;} // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + // destructor does nothing + template + remover::~remover() {} + + // destructor does nothing + template + pair_remover::~pair_remover() {} + + +// ---------------------------------------------------------------------------------------- + + +} + +#endif // DLIB_REMOVER_KERNEl_INTERFACE_ + diff --git a/dlib/iomanip b/dlib/iomanip new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/iomanip @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/iosfwd b/dlib/iosfwd new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/iosfwd @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/iostream b/dlib/iostream new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/iostream @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/is_kind.h b/dlib/is_kind.h new file mode 100644 index 0000000000000000000000000000000000000000..4a5a6ed870951cca7f16fce304905e84e8aea498 --- /dev/null +++ b/dlib/is_kind.h @@ -0,0 +1,62 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_IS_KINd_H_ +#define DLIB_IS_KINd_H_ + +namespace dlib +{ + /*! + This file contains a set of templates that enable you to determine if + a given type implements an abstract interface defined in one of the + dlib *_abstract.h files. + !*/ + +// ---------------------------------------------------------------------------------------- + + struct default_is_kind_value { static const bool value = false; }; + +// ---------------------------------------------------------------------------------------- + + template + struct is_graph : public default_is_kind_value + { + /*! + - if (T is an implementation of graph/graph_kernel_abstract.h) then + - is_graph::value == true + - else + - is_graph::value == false + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template + struct is_directed_graph : public default_is_kind_value + { + /*! + - if (T is an implementation of directed_graph/directed_graph_kernel_abstract.h) then + - is_directed_graph::value == true + - else + - is_directed_graph::value == false + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template + struct is_matrix : public default_is_kind_value + { + /*! + - if (T is an implementation of matrix/matrix_abstract.h) then + - is_matrix::value == true + - else + - is_matrix::value == false + !*/ + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_IS_KINd_H_ + diff --git a/dlib/istream b/dlib/istream new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/istream @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/linker.h b/dlib/linker.h new file mode 100644 index 0000000000000000000000000000000000000000..98532d43d65d851f4d8987a5fcf036c0f4b60911 --- /dev/null +++ b/dlib/linker.h @@ -0,0 +1,37 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LINKEr_ +#define DLIB_LINKEr_ + +#include "linker/linker_kernel_1.h" +#include "linker/linker_kernel_c.h" + +#include "algs.h" + + + +namespace dlib +{ + + + class linker + { + linker() {} + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef linker_kernel_1 + kernel_1a; + typedef linker_kernel_c + kernel_1a_c; + + + }; + +} + +#endif // DLIB_LINKEr_ + diff --git a/dlib/linker/linker_kernel_1.cpp b/dlib/linker/linker_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4aea7bd78e9cd4dac9f561f6158e358a839b9d26 --- /dev/null +++ b/dlib/linker/linker_kernel_1.cpp @@ -0,0 +1,325 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LINKER_KERNEL_1_CPp_ +#define DLIB_LINKER_KERNEL_1_CPp_ +#include "linker_kernel_1.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + linker_kernel_1:: + linker_kernel_1 ( + ) : + running(false), + running_signaler(running_mutex), + A(0), + B(0), + service_connection_running_signaler(service_connection_running_mutex) + { + } + +// ---------------------------------------------------------------------------------------- + + linker_kernel_1:: + ~linker_kernel_1 ( + ) + { + clear(); + } + +// ---------------------------------------------------------------------------------------- + + void linker_kernel_1:: + clear ( + ) + { + + // shutdown the connections + cons_mutex.lock(); + if (A != 0 ) + { + A->shutdown(); + A = 0; + } + if (B != 0) + { + B->shutdown(); + B = 0; + } + cons_mutex.unlock(); + + + // wait for the other threads to signal that they have ended + running_mutex.lock(); + while (running == true) + { + running_signaler.wait(); + } + running_mutex.unlock(); + + } + +// ---------------------------------------------------------------------------------------- + + bool linker_kernel_1:: + is_running ( + ) const + { + running_mutex.lock(); + bool temp = running; + running_mutex.unlock(); + return temp; + } + +// ---------------------------------------------------------------------------------------- + + void linker_kernel_1:: + link ( + connection& a, + connection& b + ) + { + running_mutex.lock(); + running = true; + running_mutex.unlock(); + + cons_mutex.lock(); + A = &a; + B = &b; + cons_mutex.unlock(); + + + + service_connection_running_mutex.lock(); + service_connection_running = true; + service_connection_running_mutex.unlock(); + + service_connection_error_mutex.lock(); + service_connection_error = false; + service_connection_error_mutex.unlock(); + + // if we fail to make the thread + if (!create_new_thread(service_connection,this)) + { + a.shutdown(); + b.shutdown(); + + service_connection_running_mutex.lock(); + service_connection_running = false; + service_connection_running_mutex.unlock(); + + cons_mutex.lock(); + A = 0; + B = 0; + cons_mutex.unlock(); + + running_mutex.lock(); + running = false; + running_mutex.unlock(); + + + + throw dlib::thread_error ( + ECREATE_THREAD, + "failed to make new thread in linker_kernel_1::link()" + ); + } + + + + // forward data from a to b + char buf[200]; + int status; + bool error = false; // becomes true if one of the connections returns an error + while (true) + { + status = a.read(buf,sizeof(buf)); + // if there was an error reading from the socket + if (status == OTHER_ERROR) + { + error = true; + break; + } + + if (status <= 0) + { + // if a has closed normally + if (status == 0) + b.shutdown_outgoing(); + break; + } + + status = b.write(buf,status); + // if there was an error writing to the socket then break + if (status == OTHER_ERROR) + { + error = true; + break; + } + + if (status <= 0) + break; + } + + + // if there was an error then shutdown both connections + if (error) + { + a.shutdown(); + b.shutdown(); + } + + + + + // wait for the other thread to end + service_connection_running_mutex.lock(); + while(service_connection_running) + { + service_connection_running_signaler.wait(); + } + service_connection_running_mutex.unlock(); + + + // make sure connections are shutdown + a.shutdown(); + b.shutdown(); + + + // both threads have ended so the connections are no longer needed + cons_mutex.lock(); + A = 0; + B = 0; + cons_mutex.unlock(); + + + // if service_connection terminated due to an error then set error to true + service_connection_error_mutex.lock(); + if (service_connection_error) + error = true; + service_connection_error_mutex.unlock(); + + + // if we are ending becaues of an error + if (error) + { + + // signal that the link() function is ending + running_mutex.lock(); + running = false; + running_signaler.broadcast(); + running_mutex.unlock(); + + // throw the exception for this error + throw dlib::socket_error ( + ECONNECTION, + "a connection returned an error in linker_kernel_1::link()" + ); + + } + + // signal that the link() function is ending + running_mutex.lock(); + running = false; + running_signaler.broadcast(); + running_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + void linker_kernel_1:: + service_connection ( + void* param + ) + { + linker_kernel_1& p = *reinterpret_cast(param); + + p.cons_mutex.lock(); + // if the connections are gone for whatever reason then return + if (p.A == 0 || p.B == 0) + { + // signal that this function is ending + p.service_connection_running_mutex.lock(); + p.service_connection_running = false; + p.service_connection_running_signaler.broadcast(); + p.service_connection_running_mutex.unlock(); + return; + } + connection& a = *p.A; + connection& b = *p.B; + p.cons_mutex.unlock(); + + + + // forward data from b to a + char buf[200]; + int status; + bool error = false; + while (true) + { + status = b.read(buf,sizeof(buf)); + // if there was an error reading from the socket + if (status == OTHER_ERROR) + { + error = true; + break; + } + + + if (status <= 0) + { + // if b has closed normally + if (status == 0) + a.shutdown_outgoing(); + break; + } + + + status = a.write(buf,status); + // if there was an error writing to the socket then break + if (status == OTHER_ERROR) + { + error = true; + break; + } + + if (status <= 0) + break; + } + + + // if there was an error then shutdown both connections + if (error) + { + a.shutdown(); + b.shutdown(); + } + + + // if there was an error then signal that + if (error) + { + p.service_connection_error_mutex.lock(); + p.service_connection_error = true; + p.service_connection_error_mutex.lock(); + } + + // signal that this function is ending + p.service_connection_running_mutex.lock(); + p.service_connection_running = false; + p.service_connection_running_signaler.broadcast(); + p.service_connection_running_mutex.unlock(); + + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_LINKER_KERNEL_1_CPp_ + diff --git a/dlib/linker/linker_kernel_1.h b/dlib/linker/linker_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..23b953de82ed895e450534291e5a313ef8b6fc20 --- /dev/null +++ b/dlib/linker/linker_kernel_1.h @@ -0,0 +1,132 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LINKER_KERNEl_1_ +#define DLIB_LINKER_KERNEl_1_ + +#include "linker_kernel_abstract.h" +#include "../threads.h" +#include "../sockets.h" +#include "../algs.h" + + +namespace dlib +{ + + class linker_kernel_1 + { + + /*! + INITIAL VALUE + running == false + A == 0 + B == 0 + running_mutex == a mutex + running_signaler == a signaler assocaited with running_mutex + cons_mutex == a mutex + service_connection_running == false + service_connection_running_mutex == a mutex + service_connection_running_signaler == a signaler associated with + service_connection_running_mutex + + service_connection_error == false + service_connection_error_mutex == a mutex + + + + CONVENTION + running == is_running() + running_mutex == a mutex for running + running_signaler == a signaler for signaling when + running becomes false and is associated with + running_mutex + cons_mutex == a mutex for A and B + + service_connection_running == true when service_connection() is + running or is about to run else + false + service_connection_running_mutex == a mutex for service_connection_running + service_connection_running_signaler == a signaler associated with + service_connection_running_mutex + + if (running) then + A == address of a from link() + B == address of b from link() + else + A == 0 + B == 0 + + service_connection_error == service_connection uses this bool + to indicate if it terminated due to + an error or not + service_connection_error_mutex == a mutex for service_connection_error + + + !*/ + + public: + + + linker_kernel_1( + ); + + virtual ~linker_kernel_1( + ); + + void clear( + ); + + bool is_running( + ) const; + + void link ( + connection& a, + connection& b + ); + + + private: + + static void service_connection ( + void* param + ); + /*! + requires + param == pointer to a linker_kernel_1 object + ensures + waits for data from b and forwards it to a and + if (b closes normally or is shutdown()) service_connection ends and + if (b closes normally) then a.shutdown_outgoing() is called and + if (a or b returns an error) then a and b are shutdown() + !*/ + + + // data members + bool running; + mutex running_mutex; + signaler running_signaler; + connection* A; + connection* B; + mutex cons_mutex; + + bool service_connection_running; + mutex service_connection_running_mutex; + signaler service_connection_running_signaler; + + bool service_connection_error; + mutex service_connection_error_mutex; + + // restricted functions + linker_kernel_1(linker_kernel_1&); // copy constructor + linker_kernel_1& operator=(linker_kernel_1&); // assignment operator + }; + + + +} + +#ifdef NO_MAKEFILE +#include "linker_kernel_1.cpp" +#endif + +#endif // DLIB_LINKER_KERNEl_1_ + diff --git a/dlib/linker/linker_kernel_abstract.h b/dlib/linker/linker_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c50dd71894eb75dc172fa12107a0968263789e39 --- /dev/null +++ b/dlib/linker/linker_kernel_abstract.h @@ -0,0 +1,128 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LINKER_KERNEl_ABSTRACT_ +#ifdef DLIB_LINKER_KERNEl_ABSTRACT_ + +// non-templateable dependencies +#include "../threads/threads_kernel_abstract.h" +#include "../sockets/sockets_kernel_abstract.h" + +namespace dlib +{ + + class linker + { + + /*! + INITIAL VALUE + is_running() == false + + + WHAT THIS OBJECT REPRESENTS + This object represents something that takes two connections and lets + them talk to each other. i.e. any incoming data from one connection is + passed unaltered to the other and vice versa. + + note that linker objects are not swappable. + + Also note that when one connection is closed shutdown_outgoing() + is called on the other to signal that no more data will be sent + in that direction on the connection. + (i.e. the FIN packet is effectively also forwarded by the linker object) + + THREAD SAFETY + all member functions are thread-safe. + + !*/ + + public: + + + linker( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~linker( + ); + /*! + ensures + - all resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - if (is_running()) then + - the two connections being linked will be shutdown() + throws + - std::bad_alloc + if this exception is thrown then the linker object is unusable + until clear() is called and succeeds and + if is_running() then the connections will STILL be shutdown() + even though an exception is being thrown + !*/ + + bool is_running( + ) const; + /*! + ensures + - returns true if link() is running else + - returns false if link() is not running or has released all its + resources and is about to terminate + throws + - std::bad_alloc + !*/ + + + void link ( + connection& a, + connection& b + ); + /*! + requires + - is_running() == false + ensures + - all incoming data from connection a will be forwarded to b + - all incoming data from connection b will be forwarded to a + - #a and #b will have been shutdown() + - link() will block until both of the connections have ended + or an error occurs + throws + - std::bad_alloc + link() may throw this exception and if it does then the object + will be unusable until clear() is called and succeeds and + connections a and b will be shutdown() + - dlib::socket_error + link() will throw a this exception if one of the connections + returns an error value (being shutdown is not an error). + If this happens then the linker object will be cleared and + have its initial value. note that if this happens then the + connections being linked will be shutdown() + - dlib::thread_error + link() will throw a this exception if there is a problem + creating new threads. Or it may throw this exception if there + is a problem creating threading objects. If this happens + then the linker object will be cleared and have its initial value. + note that if this happens then the connections being linked will + be shutdown(). + !*/ + + private: + + // restricted functions + linker(linker&); // copy constructor + linker& operator=(linker&); // assignment operator + }; + +} + +#endif // DLIB_LINKER_KERNEl_ABSTRACT_ + diff --git a/dlib/linker/linker_kernel_c.h b/dlib/linker/linker_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..3f2ec445b0d60ae4e040cdafefb0feec374378a8 --- /dev/null +++ b/dlib/linker/linker_kernel_c.h @@ -0,0 +1,63 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LINKER_KERNEl_C_ +#define DLIB_LINKER_KERNEl_C_ + +#include "linker_kernel_abstract.h" +#include "../sockets.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + + template < + typename linker_base + > + class linker_kernel_c : public linker_base + { + + public: + + void link ( + connection& a, + connection& b + ); + + }; + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename linker_base + > + void linker_kernel_c:: + link ( + connection& a, + connection& b + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( + this->is_running() == false , + "\tvoid linker::link" + << "\n\tis_running() == " << this->is_running() + << "\n\tthis: " << this + ); + + // call the real function + linker_base::link(a,b); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LINKER_KERNEl_C_ + diff --git a/dlib/locale b/dlib/locale new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/locale @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/logger.h b/dlib/logger.h new file mode 100644 index 0000000000000000000000000000000000000000..35b40fab84dc40530e1f9286c0e7898c3032bdd5 --- /dev/null +++ b/dlib/logger.h @@ -0,0 +1,11 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LOGGEr_ +#define DLIB_LOGGEr_ + +#include "logger/logger_kernel_1.h" +#include "logger/extra_logger_headers.h" +#include "logger/logger_config_file.h" + +#endif // DLIB_LOGGEr_ + diff --git a/dlib/logger/extra_logger_headers.cpp b/dlib/logger/extra_logger_headers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05ee42582ce464e3213a5d1a5c79f7f3193d542d --- /dev/null +++ b/dlib/logger/extra_logger_headers.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_EXTRA_LOGGER_HEADERs_CPP_ +#define DLIB_EXTRA_LOGGER_HEADERs_CPP_ + +#include "extra_logger_headers.h" +#include +#include + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + + void print_datetime_logger_header ( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ) + { + using namespace std; + char* buf; + + time_t t = time(0); + buf = ctime(&t); + // remove the trailing '\n' + size_t size = strlen(buf); + buf[size-1] = '\0'; + + out << l.name << " (" << buf << ") [" << thread_id << "] " << logger_name << ": "; + } + +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_EXTRA_LOGGER_HEADERs_CPP_ + + diff --git a/dlib/logger/extra_logger_headers.h b/dlib/logger/extra_logger_headers.h new file mode 100644 index 0000000000000000000000000000000000000000..4126d010c1c200a13ad0327e3e31512368fece51 --- /dev/null +++ b/dlib/logger/extra_logger_headers.h @@ -0,0 +1,41 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_EXTRA_LOGGER_HEADERs_ +#define DLIB_EXTRA_LOGGER_HEADERs_ + +#include "logger_kernel_abstract.h" +#include "logger_kernel_1.h" +#include +#include +#include "../uintn.h" + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + + void print_datetime_logger_header ( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + /*! + requires + - is not called more than once at a time (i.e. is not called from multiple + threads at the same time). + ensures + - let DATE be the current date and time (e.g. Thu Aug 31 16:41:52 2006). + - prints a string to out in the form: "l.name (DATE) [thread_id] logger_name:" + !*/ + +} + +// ---------------------------------------------------------------------------------------- + +#ifdef NO_MAKEFILE +#include "extra_logger_headers.cpp" +#endif + +#endif // DLIB_EXTRA_LOGGER_HEADERs_ + diff --git a/dlib/logger/logger_config_file.cpp b/dlib/logger/logger_config_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96074e8e631aa364f83ea2f9e61f06b606941d1f --- /dev/null +++ b/dlib/logger/logger_config_file.cpp @@ -0,0 +1,203 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LOGGER_CONFIg_FILE_CPP +#define DLIB_LOGGER_CONFIg_FILE_CPP + +#include "logger_config_file.h" +#include +#include "../config_reader.h" +#include +#include +#include "../error.h" +#include "../map.h" +#include "../string.h" + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + + namespace logger_config_file_helpers + { + typedef config_reader::kernel_1a_c cr_type; + +// ---------------------------------------------------------------------------------------- + + std::ostream& get_file_stream ( + const std::string& file_name + ) + { + using namespace std; + static dlib::mutex m; + auto_mutex M(m); + static dlib::map::kernel_1a_c file_map; + + if (file_map.is_in_domain(file_name) == false) + { + // We won't ever delete this output stream. It should be around for the + // entire life of the program so just let the OS take care of it. + ostream* fout = new ofstream(file_name.c_str()); + if (!(*fout)) + { + delete fout; + throw error("logger_config: unable to open output file " + file_name); + } + + // add this file to our file map + string temp(file_name); + file_map.add(temp,fout); + } + + return *file_map[file_name]; + } + +// ---------------------------------------------------------------------------------------- + + log_level string_to_log_level ( + const std::string& level + ) + { + using namespace std; + if (level == "LALL" || level == "ALL" || level == "all") + return LALL; + else if (level == "LNONE" || level == "NONE" || level == "none") + return LNONE; + else if (level == "LTRACE" || level == "TRACE" || level == "trace") + return LTRACE; + else if (level == "LDEBUG" || level == "DEBUG" || level == "debug") + return LDEBUG; + else if (level == "LINFO" || level == "INFO" || level == "info") + return LINFO; + else if (level == "LWARN" || level == "WARN" || level == "warn") + return LWARN; + else if (level == "LERROR" || level == "ERROR" || level == "error") + return LERROR; + else if (level == "LFATAL" || level == "FATAL" || level == "fatal") + return LFATAL; + else + { + const int priority = string_cast(level); + return log_level(priority,"CONFIG_FILE_DEFINED"); + } + } + +// ---------------------------------------------------------------------------------------- + + void configure_sub_blocks ( + const cr_type& cr, + const std::string& name + ) + { + using namespace std; + + logger dlog(name.c_str()); + + if (cr.is_key_defined("logging_level")) + { + dlog.set_level(string_to_log_level(cr["logging_level"])); + } + + if (cr.is_key_defined("output")) + { + string output = cr["output"]; + if (output == "cout") + dlog.set_output_stream(cout); + else if (output == "cerr") + dlog.set_output_stream(cerr); + else if (output == "clog") + dlog.set_output_stream(clog); + else + { + istringstream sin(output); + string one, two, three; + sin >> one; + sin >> two; + sin >> three; + if (one == "file" && three.size() == 0) + dlog.set_output_stream(get_file_stream(two)); + else + throw error("logger_config: invalid argument to output option: " + output); + } + + } // if (cr.is_key_defined("output")) + + // now configure all the sub-blocks + cr.reset(); + while (cr.move_next()) + configure_sub_blocks(cr.element(), name + "." + cr.current_block_name()); + + } + +// ---------------------------------------------------------------------------------------- + + } // namespace + +// ---------------------------------------------------------------------------------------- + + void configure_loggers_from_file ( + const std::string& file_name + ) + { + using namespace logger_config_file_helpers; + using namespace std; + ifstream fin(file_name.c_str()); + + if (!fin) + throw error("logger_config: unable to open config file " + file_name); + + + cr_type main_cr; + main_cr.load_from(fin); + + + if (main_cr.is_block_defined("logger_config")) + { + const cr_type& cr = main_cr.block("logger_config"); + + if (cr.is_key_defined("logging_level")) + { + set_all_logging_levels(string_to_log_level(cr["logging_level"])); + } + + if (cr.is_key_defined("output")) + { + string output = cr["output"]; + if (output == "cout") + set_all_logging_output_streams(cout); + else if (output == "cerr") + set_all_logging_output_streams(cerr); + else if (output == "clog") + set_all_logging_output_streams(clog); + else + { + istringstream sin(output); + string one, two, three; + sin >> one; + sin >> two; + sin >> three; + if (one == "file" && three.size() == 0) + set_all_logging_output_streams(get_file_stream(two)); + else + throw error("logger_config: invalid argument to output option: " + output); + } + + } // if (cr.is_key_defined("output")) + + // now configure all the sub-blocks + cr.reset(); + while (cr.move_next()) + configure_sub_blocks(cr.element(),cr.current_block_name()); + + } + } + +// ---------------------------------------------------------------------------------------- + +} + +// ---------------------------------------------------------------------------------------- + +#endif // DLIB_LOGGER_CONFIg_FILE_CPP + + + diff --git a/dlib/logger/logger_config_file.h b/dlib/logger/logger_config_file.h new file mode 100644 index 0000000000000000000000000000000000000000..c5be137f93c8d06b8071e7ab3cab644ff8968c85 --- /dev/null +++ b/dlib/logger/logger_config_file.h @@ -0,0 +1,112 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LOGGER_CONFIg_FILE_ +#define DLIB_LOGGER_CONFIg_FILE_ + +#include "logger_kernel_abstract.h" +#include "logger_kernel_1.h" +#include +#include "../config_reader.h" + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + + void configure_loggers_from_file ( + const std::string& file_name + ); + /*! + ensures + - configures the loggers with the contents of the file_name file + throws + - dlib::error + this exception is thrown if there is a problem reading the config file + !*/ + +// ---------------------------------------------------------------------------------------- + + /*! + # ----------------------------------------------- + # ------------- EXAMPLE CONFIG FILE ------------- + # ----------------------------------------------- + + # The overall format of the config file is the same as the one defined by + # the config_reader component of this library. + + # This line is a comment line + + # The config file always has block named logger_config. This is where all the + # config data for the loggers resides. + logger_config + { + # This sets all loggers to the level LINFO since it is just inside the + # logger_config block + logging_level = info + + # Alternatively we could specify a user defined logging level by + # supplying a priority number. The following line would specify + # that only logging levels at or above 100 are printed. (note that + # you would have to comment out the logging_level statement above + # to avoid a conflict). + # logging_level = 100 + + parent_logger + { + # This sets all loggers named "parent_logger" or children of + # loggers with that name to not log at all (i.e. to logging level + # LNONE). + logging_level = none + } + + + parent_logger2 + { + # set loggers named "parent_logger2" and its children loggers + # to write their output to a file named out.txt + output = file out.txt + + child_logger + { + # Set loggers named "parent_logger2.child_logger" and children of loggers + # with this name to logging level LALL + logging_level = all + + # Note that this logger will also log to out.txt because that is what + # its parent does and we haven't overridden it here with something else. + # if we wanted this logger to write to cout instead we could uncomment + # the following line: + # output = cout + } + } + } + + # So in summary, all logger config stuff goes inside a block named logger_config. Then + # inside that block all blocks must be the names of loggers. There are only two keys, + # logging_level and output. + # + # The valid values of logging_level are: + # "LALL", "LNONE", "LTRACE", "LDEBUG", "LINFO", "LWARN", "LERROR", "LFATAL", + # "ALL", "NONE", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", + # "all", "none", "trace", "debug", "info", "warn", "error", "fatal", or + # any integral value + # + # The valid values of output are: + # "cout", "cerr", "clog", or a string of the form "file some_file_name" + # which causes the output to be logged to the specified file. + # + !*/ + + +} + +// ---------------------------------------------------------------------------------------- + +#ifdef NO_MAKEFILE +#include "logger_config_file.cpp" +#endif + +#endif // DLIB_LOGGER_CONFIg_FILE_ + + + diff --git a/dlib/logger/logger_kernel_1.cpp b/dlib/logger/logger_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dae6e69b7a90f6a80953c6d49f29732aeb2a0627 --- /dev/null +++ b/dlib/logger/logger_kernel_1.cpp @@ -0,0 +1,414 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LOGGER_KERNEL_1_CPp_ +#define DLIB_LOGGER_KERNEL_1_CPp_ + +#include "logger_kernel_1.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + void set_all_logging_output_streams ( + std::ostream& out_ + ) + { + logger::global_data& gd = logger::get_global_data(); + auto_mutex M(gd.m); + gd.loggers.reset(); + while (gd.loggers.move_next()) + { + gd.loggers.element()->out.rdbuf(out_.rdbuf()); + } + + gd.set_output_stream("",out_); + } + + void set_all_logging_levels ( + const log_level& new_level + ) + { + logger::global_data& gd = logger::get_global_data(); + auto_mutex M(gd.m); + gd.loggers.reset(); + while (gd.loggers.move_next()) + { + gd.loggers.element()->cur_level = new_level; + } + + gd.set_level("",new_level); + } + +// ---------------------------------------------------------------------------------------- + + namespace logger_helper_stuff + { + class helper + { + public: + helper() + { + std::ostringstream sout; + print_default_logger_header(sout,"some_name",LDEBUG,0); + } + }; + // do this to make sure all the static members of print_default_logger_header get + // initialized when the program turns on. + static helper a; + // make a logger to make extra sure the static global_data object gets + // initialized before any threads start up. Also do this so that there is always + // at least one logger so that the global data won't be deleted until the + // program is terminating. + static logger log("dlib"); + } + +// ---------------------------------------------------------------------------------------- + + void print_default_logger_header ( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ) + { + using namespace std; + static timestamper ts; + static const uint64 first_time = ts.get_timestamp(); + + const uint64 cur_time = (ts.get_timestamp() - first_time)/1000; + streamsize old_width = out.width(); out.width(5); + out << cur_time << " " << l.name; + out.width(old_width); + + out << " [" << thread_id << "] " << logger_name << ": "; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// global_data stuff +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + logger::global_data:: + ~global_data ( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + logger::global_data:: + global_data( + ) : + next_thread_name(1) + { + // make sure the main program thread always has id 0. Since there is + // a global logger object declared in this file we should expect that + // the global_data object will be initialized in the main program thread + // so if we call get_thread_id() now we should get the main thread id. + thread_id_type main_id = get_thread_id(); + uint64 id_zero = 0; + thread_names.add(main_id,id_zero); + + // set up the defaults + auto_flush_table.val = true; + streambuf_table.val = std::cout.rdbuf(); + header_table.val = print_default_logger_header; + } + + logger::global_data::level_container:: + level_container ( + ) : val(300,"ERROR") {} + +// ---------------------------------------------------------------------------------------- + + template + const T& search_tables ( + const T& c, + const std::string& name + ) + { + if (c.table.size() == 0 || name.size() == 0) + return c; + + const std::string::size_type pos = name.find_first_of("."); + const std::string first = name.substr(0,pos); + std::string last; + if (pos != std::string::npos) + last = name.substr(pos+1); + + if (c.table.is_in_domain(first)) + { + return search_tables(*c.table[first], last); + } + else + { + return c; + } + } + +// ---------------------------------------------------------------------------------------- + + template + void assign_tables ( + T& c, + const std::string& name, + const U& val + ) + { + if (name.size() == 0) + { + c.val = val; + c.table.clear(); + return; + } + + const std::string::size_type pos = name.find_first_of("."); + std::string first = name.substr(0,pos); + std::string last; + if (pos != std::string::npos) + last = name.substr(pos+1); + + if (c.table.is_in_domain(first)) + { + assign_tables(*c.table[first], last, val); + } + else + { + scoped_ptr temp (new T); + temp->val = c.val; + assign_tables(*temp, last, val); + c.table.add(first,temp); + } + } + +// ---------------------------------------------------------------------------------------- + + const log_level logger::global_data:: + level ( + const std::string& name + ) const + { + auto_mutex M(m); + return search_tables(level_table, name).val; + } + +// ---------------------------------------------------------------------------------------- + + void logger::global_data:: + set_level ( + const std::string& name, + const log_level& new_level + ) + { + auto_mutex M(m); + assign_tables(level_table, name, new_level); + } + +// ---------------------------------------------------------------------------------------- + + bool logger::global_data:: + auto_flush ( + const std::string& name + ) const + { + auto_mutex M(m); + return search_tables(auto_flush_table, name).val; + } + +// ---------------------------------------------------------------------------------------- + + void logger::global_data:: + set_auto_flush ( + const std::string& name, + bool enabled + ) + { + auto_mutex M(m); + assign_tables(auto_flush_table, name, enabled); + } + +// ---------------------------------------------------------------------------------------- + + std::streambuf* logger::global_data:: + output_streambuf ( + const std::string& name + ) + { + auto_mutex M(m); + return search_tables(streambuf_table, name).val; + } + +// ---------------------------------------------------------------------------------------- + + void logger::global_data:: + set_output_stream ( + const std::string& name, + std::ostream& out_ + ) + { + auto_mutex M(m); + assign_tables( streambuf_table, name, out_.rdbuf()); + } + +// ---------------------------------------------------------------------------------------- + + logger::print_header_type logger::global_data:: + logger_header ( + const std::string& name + ) + { + auto_mutex M(m); + return search_tables(header_table, name).val; + } + +// ---------------------------------------------------------------------------------------- + + void logger::global_data:: + set_logger_header ( + const std::string& name, + print_header_type ph + ) + { + auto_mutex M(m); + assign_tables(header_table, name, ph); + } + +// ---------------------------------------------------------------------------------------- + + logger::global_data& logger::get_global_data() + { + // Allocate the global_data on the heap rather than on the stack because + // we want to guard against the case where this static object would be destroyed + // during program termination BEFORE all logger objects are destroyed. + static global_data* gd = new global_data; + return *gd; + } + +// ---------------------------------------------------------------------------------------- + + void logger::global_data:: + thread_end_handler ( + ) + { + auto_mutex M(m); + thread_id_type id = get_thread_id(); + thread_id_type junkd; + uint64 junkr; + thread_names.remove(id,junkd,junkr); + } + +// ---------------------------------------------------------------------------------------- + + uint64 logger::global_data:: + get_thread_name ( + ) + { + thread_id_type id = get_thread_id(); + uint64 thread_name; + if (thread_names.is_in_domain(id)) + { + thread_name = thread_names[id]; + } + else + { + if (is_dlib_thread(id)) + register_thread_end_handler(*this,&global_data::thread_end_handler); + thread_name = next_thread_name; + thread_names.add(id,thread_name); + thread_name = next_thread_name; + ++next_thread_name; + } + return thread_name; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// logger_stream stuff +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + void logger::logger_stream:: + print_header_and_stuff ( + ) + { + if (!been_used) + { + log.gd.m.lock(); + log.logger_header()(log.out,log.name(),l,log.gd.get_thread_name()); + been_used = true; + } + } + +// ---------------------------------------------------------------------------------------- + + void logger::logger_stream:: + print_end_of_line ( + ) + { + auto_unlock M(log.gd.m); + if (log.auto_flush_enabled) + log.out << std::endl; + else + log.out << "\n"; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// logger stuff +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + logger:: + logger ( + const char* name_ + ) : + gd(get_global_data()), + logger_name(name_), + out(gd.output_streambuf(logger_name)), + cur_level(gd.level(logger_name)) + { + DLIB_ASSERT(name_[0] != '\0', + "\tlogger::logger()" + << "\n\tYou can't make a logger with an empty name" + << "\n\tthis: " << this + ); + + auto_mutex M(gd.m); + logger* temp = this; + gd.loggers.add(temp); + + // load the appropriate settings + print_header = gd.logger_header(logger_name); + auto_flush_enabled = gd.auto_flush(logger_name); + } + +// ---------------------------------------------------------------------------------------- + + logger:: + ~logger ( + ) + { + gd.m.lock(); + gd.loggers.destroy(this); + // if this was the last logger then delete the global data + if (gd.loggers.size() == 0) + { + gd.m.unlock(); + delete &gd; + } + else + { + gd.m.unlock(); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LOGGER_KERNEL_1_CPp_ + diff --git a/dlib/logger/logger_kernel_1.h b/dlib/logger/logger_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..25d4b54a56ac855b937c01998cea596734cf130d --- /dev/null +++ b/dlib/logger/logger_kernel_1.h @@ -0,0 +1,476 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LOGGER_KERNEl_1_ +#define DLIB_LOGGER_KERNEl_1_ + +#include "../threads.h" +#include "../misc_api.h" +#include "../set.h" +#include "logger_kernel_abstract.h" +#include +#include +#include "../algs.h" +#include "../assert.h" +#include "../uintn.h" +#include "../map.h" +#include "../smart_pointers.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class log_level + { + public: + log_level( + int priority_, + const char* name_ + ) : + priority(priority_) + { + strncpy(name,name_,19); + name[19] = '\0'; + } + + int priority; + char name[20]; + }; + + const log_level LALL (std::numeric_limits::min(),"ALL"); + const log_level LNONE (std::numeric_limits::max(),"NONE"); + const log_level LTRACE(-100,"TRACE"); + const log_level LDEBUG(0 ,"DEBUG"); + const log_level LINFO (100,"INFO "); + const log_level LWARN (200,"WARN "); + const log_level LERROR(300,"ERROR"); + const log_level LFATAL(400,"FATAL"); + +// ---------------------------------------------------------------------------------------- + + void set_all_logging_output_streams ( + std::ostream& out + ); + + void set_all_logging_levels ( + const log_level& new_level + ); + +// ---------------------------------------------------------------------------------------- + + void print_default_logger_header ( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + +// ---------------------------------------------------------------------------------------- + + class logger + { + /*! + INITIAL VALUE + - print_header == print_default_logger_header + - out.rdbuf() == std::cout.rdbuf() + - cur_level == LERROR + - auto_flush_enabled == true + + CONVENTION + - print_header == logger_header() + - out.rdbuf() == output_streambuf() + - cur_level == level() + - logger_name == name() + - auto_flush_enabled == auto_flush() + + - logger::gd::loggers == a set containing all currently existing loggers. + - logger::gd::m == the mutex used to lock everything in the logger + - logger::gd::thread_names == a map of thread ids to thread names. + - logger::gd::next_thread_name == the next thread name that will be given out + to a thread when we find that it isn't already in thread_names. + !*/ + + class logger_stream + { + /*! + INITIAL VALUE + - been_used == false + + CONVENTION + - enabled == is_enabled() + - if (been_used) then + - logger::gd::m is locked + - someone has used the << operator to write something to the + output stream. + !*/ + public: + logger_stream ( + const log_level& l_, + logger& log_ + ) : + l(l_), + log(log_), + been_used(false), + enabled (l.priority >= log.cur_level.priority) + {} + + inline ~logger_stream( + ) + { + if (!been_used) + { + return; + } + else + { + print_end_of_line(); + } + } + + bool is_enabled ( + ) const { return enabled; } + + template + inline logger_stream& operator << ( + const T& item + ) + { + if (!enabled) + { + return *this; + } + else + { + print_header_and_stuff(); + log.out << item; + return *this; + } + } + + private: + + void print_header_and_stuff ( + ); + /*! + ensures + - if (!been_used) then + - prints the logger header + - locks log.gd.m + - #been_used == true + !*/ + + void print_end_of_line ( + ); + /*! + ensures + - prints a newline to log.out + - unlocks log.gd.m + !*/ + + const log_level& l; + logger& log; + bool been_used; + const bool enabled; + }; + + friend class logger_stream; + public: + + logger ( + const char* name_ + ); + + virtual ~logger ( + ); + + const std::string& name ( + ) const { return logger_name; } + + logger_stream operator << ( + const log_level& l + ) const { return logger_stream(l,const_cast(*this)); } + + bool is_child_of ( + const logger& log + ) const + { + return (name().find(log.name() + ".") == 0) || (log.name() == name()); + } + + const log_level level ( + ) const + { + auto_mutex M(gd.m); + return log_level(cur_level); + }; + + void set_level ( + const log_level& new_level + ) + { + auto_mutex M(gd.m); + gd.loggers.reset(); + while (gd.loggers.move_next()) + { + if (gd.loggers.element()->is_child_of(*this)) + gd.loggers.element()->cur_level = new_level; + } + + gd.set_level(logger_name, new_level); + } + + bool auto_flush ( + ) const + { + auto_mutex M(gd.m); + return auto_flush_enabled; + }; + + void set_auto_flush ( + bool enabled + ) + { + auto_mutex M(gd.m); + gd.loggers.reset(); + while (gd.loggers.move_next()) + { + if (gd.loggers.element()->is_child_of(*this)) + gd.loggers.element()->auto_flush_enabled = enabled; + } + + gd.set_auto_flush(logger_name, enabled); + } + + std::streambuf* output_streambuf ( + ) + { + auto_mutex M(gd.m); + return out.rdbuf(); + } + + void set_output_stream ( + std::ostream& out_ + ) + { + auto_mutex M(gd.m); + gd.loggers.reset(); + while (gd.loggers.move_next()) + { + if (gd.loggers.element()->is_child_of(*this)) + gd.loggers.element()->out.rdbuf(out_.rdbuf()); + } + + gd.set_output_stream(logger_name, out_); + } + + typedef void (*print_header_type)( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + + print_header_type logger_header ( + ) const { return print_header; } + + void set_logger_header ( + print_header_type ph + ) + { + auto_mutex M(gd.m); + gd.loggers.reset(); + while (gd.loggers.move_next()) + { + if (gd.loggers.element()->is_child_of(*this)) + gd.loggers.element()->print_header = ph; + } + + gd.set_logger_header(logger_name, ph); + } + + private: + + + struct global_data + { + rmutex m; + set::kernel_1b loggers; + map::kernel_1b thread_names; + uint64 next_thread_name; + + global_data ( + ); + + ~global_data( + ); + + uint64 get_thread_name ( + ); + /*! + requires + - m is locked + ensures + - returns a unique id for the calling thread. also makes the number + small and nice unlike what you get from get_thread_id() + !*/ + + void thread_end_handler ( + ); + /*! + ensures + - removes the terminated thread from thread_names + !*/ + + struct level_container + { + level_container (); + + log_level val; + map >::kernel_1b_c table; + } level_table; + + const log_level level ( + const std::string& name + ) const; + /*! + ensures + - returns the level loggers with the given name are supposed + to have + !*/ + + void set_level ( + const std::string& name, + const log_level& new_level + ); + /*! + ensures + - for all children C of name: + - #level(C) == new_level + - if name == "" then + - for all loggers L: + - #level(L) == new_level + !*/ + + struct auto_flush_container + { + bool val; + map >::kernel_1b_c table; + } auto_flush_table; + + bool auto_flush ( + const std::string& name + ) const; + /*! + ensures + - returns the auto_flush value loggers with the given name are supposed + to have + !*/ + + void set_auto_flush ( + const std::string& name, + bool enabled + ); + /*! + ensures + - for all children C of name: + - #auto_flush_enabled(C) == enabled + - if name == "" then + - for all loggers L: + - #auto_flush_enabled(L) == enabled + !*/ + + struct output_streambuf_container + { + std::streambuf* val; + map >::kernel_1b_c table; + } streambuf_table; + + std::streambuf* output_streambuf ( + const std::string& name + ); + /*! + ensures + - returns the streambuf loggers with the given name are supposed + to have + !*/ + + void set_output_stream ( + const std::string& name, + std::ostream& out_ + ); + /*! + ensures + - for all children C of name: + - #output_streambuf(C) == out_.rdbuf() + - if name == "" then + - for all loggers L: + - #output_streambuf(L) == out_.rdbuf() + !*/ + + struct logger_header_container + { + print_header_type val; + map >::kernel_1b_c table; + } header_table; + + print_header_type logger_header ( + const std::string& name + ); + /*! + ensures + - returns the header function loggers with the given name are supposed + to have + !*/ + + void set_logger_header ( + const std::string& name, + print_header_type ph + ); + /*! + ensures + - for all children C of name: + - #logger_header(C) == ph + - if name == "" then + - for all loggers L: + - #logger_header(L) == ph + !*/ + + }; // end of struct global_data + + static global_data& get_global_data(); + + friend void set_all_logging_levels ( + const log_level& new_level + ); + + friend void set_all_logging_output_streams ( + std::ostream& out + ); + + + global_data& gd; + + const std::string logger_name; + + print_header_type print_header; + bool auto_flush_enabled; + std::ostream out; + log_level cur_level; + + + // restricted functions + logger(const logger&); // copy constructor + logger& operator=(const logger&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "logger_kernel_1.cpp" +#endif + +#endif // DLIB_LOGGER_KERNEl_1_ + diff --git a/dlib/logger/logger_kernel_abstract.h b/dlib/logger/logger_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..0005e18d3a556a188e06752185513c35b1179122 --- /dev/null +++ b/dlib/logger/logger_kernel_abstract.h @@ -0,0 +1,313 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LOGGER_KERNEl_ABSTRACT_ +#ifdef DLIB_LOGGER_KERNEl_ABSTRACT_ + +#include "../threads.h" +#include +#include +#include +#include "../uintn.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class log_level + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple named level to log at. It contains a numeric + priority and a name to use in the logging messages. + !*/ + public: + log_level( + int priority_, + const char* name_ + ); + /*! + ensures + - #priority = priority_ + - the first 19 characters of name_ are copied into name and name + is null terminated. + !*/ + + int priority; + char name[20]; + }; + + const log_level LALL (std::numeric_limits::min(),"ALL"); + const log_level LNONE (std::numeric_limits::max(),"NONE"); + const log_level LTRACE(-100,"TRACE"); + const log_level LDEBUG(0 ,"DEBUG"); + const log_level LINFO (100 ,"INFO "); + const log_level LWARN (200 ,"WARN "); + const log_level LERROR(300 ,"ERROR"); + const log_level LFATAL(400 ,"FATAL"); + +// ---------------------------------------------------------------------------------------- + + void set_all_logging_output_streams ( + std::ostream& out + ); + /*! + ensures + - for all loggers L: + - #L.output_streambuf() == out.rdbuf() + throws + - std::bad_alloc + !*/ + + void set_all_logging_levels ( + const log_level& new_level + ); + /*! + ensures + - for all loggers L: + - #L.level() == new_level + throws + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + + void print_default_logger_header ( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + /*! + requires + - is not called more than once at a time (i.e. is not called from multiple + threads at the same time). + ensures + - let MS be the number of milliseconds since program start. + - prints a string to out in the form: "MS l.name [thread_id] logger_name:" + !*/ + +// ---------------------------------------------------------------------------------------- + + class logger + { + /*! + INITIAL VALUE + - name() == a user supplied value given to the constructor + - The values of level(), output_streambuf(), logger_header(), and + auto_flush() are inherited from the parent of this logger. + + WHAT THIS OBJECT REPRESENTS + This object represents a logging output stream in the style of the log4j + logger available for Java. + + Also note that unlike most other objects in this library there is only + one implementation of this object at a time. Thus, to create instances + of the logger you would simply write logger my_logger("some_name"); + + DEFAULTS + If the user hasn't specified values for the four inherited values level(), + output_streambuf(), logger_header(), or auto_flush() then the default + values will be used. The defaults are as follows: + - level() == LERROR + - output_streambuf() == std::cout.rdbuf() (i.e. the default is to log + to standard output). + - logger_header() == print_default_logger_header + - auto_flush() == true + + THREAD SAFETY + All methods of this class are thread safe. Note that it is safe to + chain calls to operator << such as: + log << LINFO << "message " << variable << " more message"; + The logger ensures that the entire statement executes atomically so the + message won't be broken up by other loggers in other threads. + !*/ + + class logger_stream + { + public: + + bool is_enabled ( + ) const; + /*! + ensures + - returns true if this logger stream will print out items + given to it by the << operator. returns false otherwise. + !*/ + + template + logger_stream& operator << ( + const T& item + ); + /*! + ensures + - if (is_enabled()) then + - writes item to this output stream + - returns *this + !*/ + }; + + public: + + logger ( + const char* name_ + ); + /*! + requires + - name_ != "" + ensures + - #*this is properly initialized + - #name() == name_ + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~logger ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + const std::string& name ( + ) const; + /*! + ensures + - returns the name of this logger + !*/ + + logger_stream operator << ( + const log_level& l + ) const; + /*! + ensures + - if (l.priority >= level().priority) then + - returns a logger stream with is_enabled() == true and this + stream will write its output to the streambuf given by + output_streambuf(). + - else + - returns a logger stream with is_enabled() == false + throws + - std::bad_alloc + !*/ + + bool is_child_of ( + const logger& log + ) const; + /*! + ensures + - if ( (name().find(log.name() + ".") == 0) || (log.name() == name()) ) then + - returns true + (i.e. if log.name() + "." is a prefix of name() or if both *this and log + have the same name then return true) + - else + - returns false + !*/ + + const log_level level ( + ) const; + /*! + ensures + - returns the current log level of this logger. + !*/ + + void set_level ( + const log_level& new_level + ); + /*! + ensures + - for all loggers L such that L.is_child_of(*this) == true: + - #L.level() == new_level + throws + - std::bad_alloc + !*/ + + bool auto_flush ( + ); + /*! + ensures + - returns true if the output stream is flushed after every logged message. + returns false otherwise. + !*/ + + void set_auto_flush ( + bool enabled + ); + /*! + ensures + - for all loggers L such that L.is_child_of(*this) == true: + - #L.auto_flush() == enabled + throws + - std::bad_alloc + !*/ + + std::streambuf* output_streambuf ( + ); + /*! + ensures + - returns the output stream buffer that this logger writes all + messages to. + !*/ + + void set_output_stream ( + std::ostream& out + ); + /*! + ensures + - for all loggers L such that L.is_child_of(*this) == true: + - #L.output_streambuf() == out.rdbuf() + throws + - std::bad_alloc + !*/ + + typedef void (*print_header_type)( + std::ostream& out, + const std::string& logger_name, + const log_level& l, + const uint64 thread_id + ); + + print_header_type logger_header ( + ) const; + /*! + ensures + - returns the function that is called to print the header information + onto each logged message. The arguments to the function have the following + meanings: + - out == The output stream this function writes the header to. + - logger_name == The name of the logger that is printing the log message. + - l == The level of the logger that is printing the log message. + - thread_id == A number that uniquely identifies the thread trying to log + the message. Note that this number is unique among all threads, past and + present. Also note that this id is not the same one returned by + get_thread_id(). + - This logger_header function will also only be called once at a time. This means + the logger_header function doesn't need to be thread safe. + !*/ + + void set_logger_header ( + print_header_type print_header + ); + /*! + ensures + - for all loggers L such that L.is_child_of(*this) == true: + - #L.logger_header() == print_header + throws + - std::bad_alloc + !*/ + + private: + + // restricted functions + logger(const logger&); // copy constructor + logger& operator=(const logger&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LOGGER_KERNEl_ABSTRACT_ + diff --git a/dlib/lz77_buffer.h b/dlib/lz77_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..f6788d34fb94b56cec54cabe9453b2a4ccc46455 --- /dev/null +++ b/dlib/lz77_buffer.h @@ -0,0 +1,47 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZ77_BUFFEr_ +#define DLIB_LZ77_BUFFEr_ + + +#include "lz77_buffer/lz77_buffer_kernel_1.h" +#include "lz77_buffer/lz77_buffer_kernel_2.h" +#include "lz77_buffer/lz77_buffer_kernel_c.h" + +#include "sliding_buffer.h" + + +namespace dlib +{ + + + class lz77_buffer + { + + lz77_buffer() {} + + typedef sliding_buffer::kernel_1a sb1; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef lz77_buffer_kernel_1 + kernel_1a; + typedef lz77_buffer_kernel_c + kernel_1a_c; + + + // kernel_2a + typedef lz77_buffer_kernel_2 + kernel_2a; + typedef lz77_buffer_kernel_c + kernel_2a_c; + + + }; +} + +#endif // DLIB_LZ77_BUFFEr_ + diff --git a/dlib/lz77_buffer/lz77_buffer_kernel_1.h b/dlib/lz77_buffer/lz77_buffer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..ceaf53ee90765e509453275ac2ace5bf9bb2ccc7 --- /dev/null +++ b/dlib/lz77_buffer/lz77_buffer_kernel_1.h @@ -0,0 +1,263 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZ77_BUFFER_KERNEl_1_ +#define DLIB_LZ77_BUFFER_KERNEl_1_ + +#include "lz77_buffer_kernel_abstract.h" +#include "../algs.h" + + + +namespace dlib +{ + + template < + typename sliding_buffer + > + class lz77_buffer_kernel_1 + { + /*! + REQUIREMENTS ON sliding_buffer + sliding_buffer must be an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h + + INITIAL VALUE + history_limit == defined by constructor arguments + lookahead_limit == defined by constructor arguments + history_size == 0 + lookahead_size == 0 + buffer.size() == history_limit + lookahead_limit + + + CONVENTION + history_limit == get_history_buffer_limit() + lookahead_limit == get_lookahead_buffer_limit() + history_size == get_history_buffer_size() + lookahead_limit == get_lookahead_buffer_size() + + buffer.size() == history_limit + lookahead_limit + + lookahead_buffer(i) == buffer[lookahead_limit-1-i] + history_buffer(i) == buffer[lookahead_limit+i] + !*/ + + public: + + lz77_buffer_kernel_1 ( + unsigned long total_limit_, + unsigned long lookahead_limit_ + ); + + virtual ~lz77_buffer_kernel_1 ( + ) {} + + void clear( + ); + + void add ( + unsigned char symbol + ); + + void find_match ( + unsigned long& index, + unsigned long& length, + unsigned long min_match_length + ); + + inline unsigned long get_history_buffer_limit ( + ) const { return history_limit; } + + inline unsigned long get_lookahead_buffer_limit ( + ) const { return lookahead_limit; } + + inline unsigned long get_history_buffer_size ( + ) const { return history_size; } + + inline unsigned long get_lookahead_buffer_size ( + ) const { return lookahead_size; } + + inline unsigned char lookahead_buffer ( + unsigned long index + ) const { return buffer[lookahead_limit-1-index]; } + + inline unsigned char history_buffer ( + unsigned long index + ) const { return buffer[lookahead_limit+index]; } + + + inline void shift_buffers ( + unsigned long N + ) { shift_buffer(N); } + + private: + + + inline void shift_buffer ( + unsigned long N + ) + /*! + requires + - N <= lookahead_size + ensuers + - #lookahead_size == lookahead_size - N + - if (history_size+N < history_limit) then + - #history_size == history_size+N + - else + - #history_size == history_limit + - for all i where 0 <= i < N: + #history_buffer(N-1-i) == lookahead_buffer(i) + - for all i where 0 <= i < #history_size-N: + #history_buffer(N+i) == history_buffer(i) + - for all i where 0 <= i < #lookahead_size + #lookahead_buffer(i) == lookahead_buffer(N+i) + !*/ + { + unsigned long temp = history_size+N; + buffer.rotate_left(N); + lookahead_size -= N; + if (temp < history_limit) + history_size = temp; + else + history_size = history_limit; + } + + + // member data + sliding_buffer buffer; + unsigned long lookahead_limit; + unsigned long history_limit; + + + unsigned long lookahead_size; + unsigned long history_size; + + + // restricted functions + lz77_buffer_kernel_1(lz77_buffer_kernel_1&); // copy constructor + lz77_buffer_kernel_1& operator=(lz77_buffer_kernel_1&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + lz77_buffer_kernel_1:: + lz77_buffer_kernel_1 ( + unsigned long total_limit_, + unsigned long lookahead_limit_ + ) : + lookahead_size(0), + history_size(0) + { + buffer.set_size(total_limit_); + lookahead_limit = lookahead_limit_; + history_limit = buffer.size() - lookahead_limit_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_1:: + clear( + ) + { + lookahead_size = 0; + history_size = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_1:: + add ( + unsigned char symbol + ) + { + if (lookahead_size == lookahead_limit) + { + shift_buffer(1); + } + buffer[lookahead_limit-1-lookahead_size] = symbol; + ++lookahead_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_1:: + find_match ( + unsigned long& index, + unsigned long& length, + unsigned long min_match_length + ) + { + unsigned long hpos = history_size; // current position in the history buffer + unsigned long lpos = 0; // current position in the lookahead buffer + + unsigned long match_length = 0; // the length of the longest match we find + unsigned long match_index = 0; // the index of the longest match we find + + // try to find a match + while (hpos != 0) + { + --hpos; + // if we are finding a match + if (history_buffer(hpos) == lookahead_buffer(lpos)) + { + ++lpos; + // if we have found a match that is as long as the lookahead buffer + // then we are done + if (lpos == lookahead_size) + break; + } + // else if we found the end of a match + else if (lpos > 0) + { + // if this match is longer than the last match we saw + if (lpos > match_length) + { + match_length = lpos; + match_index = hpos + lpos; + } + lpos = 0; + } + } // while (hpos != 0) + + // if we found a match at the end of the loop that is greater than + // the match in match_index + if (lpos > match_length) + { + match_length = lpos; + match_index = hpos + lpos - 1; + } + + + // if we found a match that was long enough then report it + if (match_length >= min_match_length) + { + shift_buffer(match_length); + index = match_index; + length = match_length; + } + else + { + length = 0; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LZ77_BUFFER_KERNEl_1_ + diff --git a/dlib/lz77_buffer/lz77_buffer_kernel_2.h b/dlib/lz77_buffer/lz77_buffer_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..22b3b4b051df2d526224faca153fdd269359dd4d --- /dev/null +++ b/dlib/lz77_buffer/lz77_buffer_kernel_2.h @@ -0,0 +1,504 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZ77_BUFFER_KERNEl_2_ +#define DLIB_LZ77_BUFFER_KERNEl_2_ + +#include "lz77_buffer_kernel_abstract.h" +#include "../algs.h" + + + +namespace dlib +{ + + template < + typename sliding_buffer + > + class lz77_buffer_kernel_2 + { + /*! + REQUIREMENTS ON sliding_buffer + sliding_buffer must be an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h + and must be instantiated to contain unsigned char data + + INITIAL VALUE + history_limit == defined by constructor arguments + lookahead_limit == defined by constructor arguments + history_size == 0 + lookahead_size == 0 + buffer.size() == history_limit + lookahead_limit + buffer[i] == 0 for all valid i + + nodes == an array of history_limit-3 nodes + id_table == an array of buffer.size() pointers + hash_table == an array of buffer.size() pointers and all are set to 0 + mask == buffer.size() - 1 + next_free_node == 0 + + + CONVENTION + history_limit == get_history_buffer_limit() + lookahead_limit == get_lookahead_buffer_limit() + history_size == get_history_buffer_size() + lookahead_limit == get_lookahead_buffer_size() + + buffer.size() == history_limit + lookahead_limit + + lookahead_buffer(i) == buffer[lookahead_limit-1-i] + history_buffer(i) == buffer[lookahead_limit+i] + + + hash_table[hash(a,b,c,d)] points to the head of a linked list. + Each node in this linked list tells the location in the buffer + of a string that begins with abcd or a string who's first four + letters have the same hash. The linked list is terminated by a + node with a null next pointer. + + hash_table[i] == 0 if there is no linked list for this element of the hash + table. + + each node in the hash table is allocated from the array nodes. + When adding a node to hash_table: + if (if all nodes aren't already in the hash_table) then + { + the next node to use is nodes[next_free_node]. + } + else + { + recycle nodes from the hash_table itself. This works because + when we add new nodes we also have to remove nodes. + } + + if (there is a node defined with an id of i) then + { + if (id_table[i] != 0) then + id_table[i]->next->id == i + else + hash_table[some_hash]->id == i + } + !*/ + + public: + + lz77_buffer_kernel_2 ( + unsigned long total_limit_, + unsigned long lookahead_limit_ + ); + + virtual ~lz77_buffer_kernel_2 ( + ); + + void clear( + ); + + void add ( + unsigned char symbol + ); + + void find_match ( + unsigned long& index, + unsigned long& length, + unsigned long min_match_length + ); + + inline unsigned long get_history_buffer_limit ( + ) const { return history_limit; } + + inline unsigned long get_lookahead_buffer_limit ( + ) const { return lookahead_limit; } + + inline unsigned long get_history_buffer_size ( + ) const { return history_size; } + + inline unsigned long get_lookahead_buffer_size ( + ) const { return lookahead_size; } + + inline unsigned char lookahead_buffer ( + unsigned long index + ) const { return buffer[lookahead_limit-1-index]; } + + inline unsigned char history_buffer ( + unsigned long index + ) const { return buffer[lookahead_limit+index]; } + + + inline void shift_buffers ( + unsigned long N + ) { shift_buffer(N); } + + private: + + inline unsigned long hash ( + unsigned char a, + unsigned char b, + unsigned char c, + unsigned char d + ) const + /*! + ensures + - returns a hash of the 4 arguments and the hash is in the range + !*/ + { + unsigned long B = b << 3; + unsigned long C = c << 6; + unsigned long D = d << 9; + + unsigned long temp = a + B; + temp += C; + temp += D; + + return (temp&mask); /**/ + } + + void shift_buffer ( + unsigned long N + ); + /*! + requires + - N <= lookahead_size + ensuers + - #lookahead_size == lookahead_size - N + - if (history_size+N < history_limit) then + - #history_size == history_size+N + - else + - #history_size == history_limit + - for all i where 0 <= i < N: + #history_buffer(N-1-i) == lookahead_buffer(i) + - for all i where 0 <= i < #history_size-N: + #history_buffer(N+i) == history_buffer(i) + - for all i where 0 <= i < #lookahead_size + #lookahead_buffer(i) == lookahead_buffer(N+i) + !*/ + + + + // member data + sliding_buffer buffer; + unsigned long lookahead_limit; + unsigned long history_limit; + + struct node + { + unsigned long id; + node* next; + }; + + node** hash_table; + node* nodes; + node** id_table; + unsigned long next_free_node; + unsigned long mask; + + unsigned long lookahead_size; + unsigned long history_size; + + + // restricted functions + lz77_buffer_kernel_2(lz77_buffer_kernel_2&); // copy constructor + lz77_buffer_kernel_2& operator=(lz77_buffer_kernel_2&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + lz77_buffer_kernel_2:: + lz77_buffer_kernel_2 ( + unsigned long total_limit_, + unsigned long lookahead_limit_ + ) : + lookahead_size(0), + history_size(0) + { + buffer.set_size(total_limit_); + lookahead_limit = lookahead_limit_; + history_limit = buffer.size() - lookahead_limit_; + + nodes = new node[history_limit-3]; + + try { id_table = new node*[buffer.size()]; } + catch (...) { delete [] nodes; throw; } + + try { hash_table = new node*[buffer.size()]; } + catch (...) { delete [] id_table; delete [] nodes; throw; } + + mask = buffer.size()-1; + next_free_node = 0; + + + node** start = hash_table; + node** end = hash_table + buffer.size(); + while (start != end) + { + *start = 0; + ++start; + } + + for (unsigned long i = 0; i < buffer.size(); ++i) + buffer[i] = 0; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + lz77_buffer_kernel_2:: + ~lz77_buffer_kernel_2 ( + ) + { + delete [] nodes; + delete [] hash_table; + delete [] id_table; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_2:: + clear( + ) + { + lookahead_size = 0; + history_size = 0; + next_free_node = 0; + + node** start = hash_table; + node** end = hash_table + buffer.size(); + while (start != end) + { + *start = 0; + ++start; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_2:: + shift_buffer ( + unsigned long N + ) + { + unsigned long old_history_size = history_size; + unsigned long temp = history_size+N; + unsigned long new_nodes; // the number of nodes to pull from the nodes array + unsigned long recycled_nodes; // the number of nodes to pull from hash_table + lookahead_size -= N; + if (temp <= history_limit) + { + if (history_size <= 3) + { + if ((3-history_size) >= N) + new_nodes = 0; + else + new_nodes = N - (3-history_size); + } + else + { + new_nodes = N; + } + + recycled_nodes = 0; + history_size = temp; + } + else + { + if (history_size != history_limit) + { + new_nodes = history_limit - history_size; + recycled_nodes = temp - history_limit; + history_size = history_limit; + } + else + { + new_nodes = 0; + recycled_nodes = N; + } + } + + unsigned long i = lookahead_limit + 2; + + // if there are any "new" nodes to add to the hash table + if (new_nodes != 0) + { + unsigned long stop = i - new_nodes; + for (; i > stop; --i) + { + nodes[next_free_node].next = 0; + nodes[next_free_node].id = buffer.get_element_id(i); + id_table[nodes[next_free_node].id] = 0; + + unsigned long new_hash = hash(buffer[i],buffer[i-1],buffer[i-2],buffer[i-3]); + + if (hash_table[new_hash] != 0) + id_table[hash_table[new_hash]->id] = &nodes[next_free_node]; + nodes[next_free_node].next = hash_table[new_hash]; + hash_table[new_hash] = &nodes[next_free_node]; + + ++next_free_node; + } + } // if (new_nodes != 0) + + + + unsigned long stop = i - recycled_nodes; + unsigned long old = old_history_size-1+lookahead_limit; + for (; i > stop; --i) + { + // find the next node to recycle in hash_table + node* recycled_node; + + + unsigned long old_id = buffer.get_element_id(old); + + // find the node with id old_id + if (id_table[old_id] == 0) + { + unsigned long old_hash = hash(buffer[old],buffer[old-1],buffer[old-2],buffer[old-3]); + recycled_node = hash_table[old_hash]; + + // fill the gap left by removing this node + hash_table[old_hash] = recycled_node->next; + } + else + { + recycled_node = id_table[old_id]->next; + + // fill the gap left by removing this node + id_table[old_id]->next = recycled_node->next; + } + + --old; + + + + + + + recycled_node->next = 0; + recycled_node->id = buffer.get_element_id(i); + id_table[recycled_node->id] = 0; + + unsigned long new_hash = hash(buffer[i],buffer[i-1],buffer[i-2],buffer[i-3]); + + if (hash_table[new_hash] != 0) + id_table[hash_table[new_hash]->id] = recycled_node; + + recycled_node->next = hash_table[new_hash]; + hash_table[new_hash] = recycled_node; + + } // for (; i > stop; --i) + + + + + buffer.rotate_left(N); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_2:: + add ( + unsigned char symbol + ) + { + if (lookahead_size == lookahead_limit) + { + shift_buffer(1); + } + buffer[lookahead_limit-1-lookahead_size] = symbol; + ++lookahead_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sliding_buffer + > + void lz77_buffer_kernel_2:: + find_match ( + unsigned long& index, + unsigned long& length, + unsigned long min_match_length + ) + { + unsigned long match_length = 0; // the length of the longest match we find + unsigned long match_index = 0; // the index of the longest match we find + + + const unsigned long hash_value = hash(lookahead_buffer(0), + lookahead_buffer(1), + lookahead_buffer(2), + lookahead_buffer(3) + ); + + + + node* temp = hash_table[hash_value]; + while (temp != 0) + { + // current position in the history buffer + unsigned long hpos = buffer.get_element_index(temp->id)-lookahead_limit; + // current position in the lookahead buffer + unsigned long lpos = 0; + + // find length of this match + while (history_buffer(hpos) == lookahead_buffer(lpos)) + { + ++lpos; + if (hpos == 0) + break; + --hpos; + if (lpos == lookahead_size) + break; + } + + if (lpos > match_length) + { + match_length = lpos; + match_index = buffer.get_element_index(temp->id)-lookahead_limit; + // if this is the longest possible match then stop looking + if (lpos == lookahead_limit) + break; + } + + + temp = temp->next; + } // while (temp != 0) + + + + + // if we found a match that was long enough then report it + if (match_length >= min_match_length) + { + shift_buffer(match_length); + index = match_index; + length = match_length; + } + else + { + length = 0; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LZ77_BUFFER_KERNEl_2_ + diff --git a/dlib/lz77_buffer/lz77_buffer_kernel_abstract.h b/dlib/lz77_buffer/lz77_buffer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..181201a594ae8f0a7fcbbb608f38b6cee7515830 --- /dev/null +++ b/dlib/lz77_buffer/lz77_buffer_kernel_abstract.h @@ -0,0 +1,210 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_ +#ifdef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + class lz77_buffer + { + /*! + INITIAL VALUE + get_history_buffer_limit() == defined by constructor arguments + get_lookahead_buffer_limit() == defined by constructor arguments + get_history_buffer_size() == 0 + get_lookahead_buffer_size() == 0 + + + WHAT THIS OBJECT REPRESENTS + This object represents a pair of buffers (history and lookahead buffers) + used during lz77 style compression. + + It's main function is to search the history buffer for long strings which + match the contents (or a part of the contents) of the lookahead buffer. + + + HISTORY AND LOOKAHEAD BUFFERS + The buffers have the following structure: + | history buffer | lookahead buffer | <-- contents of buffers + | ...9876543210 | 0123456789... | <-- index numbers + + So this means that history_buffer(0) == 'r', history_buffer(1) == 'e' + and so on. And lookahead_buffer(0) == 'l', lookahead_buffer(1) == 'o' + and so on. + + + What shift_buffers() does in english: + This function just means that the buffers have their contents shifted + left by N elements and that elements shifted out of the lookahead buffer + go into the history buffer. An example will make it clearer. + + Suppose that we have the following buffers before we apply shift_buffers() + history_buffer() == "hey" and + lookahead_buffer() == "lookahead buffer" + And in the same format as the above diagram it would be + | hey | lookahead buffer | <-- contents of buffers + | 210 | 0123456789... | <-- index numbers + + Applying shift_buffers(4) will give + lookahead_buffer() == "ahead buffer" + history_buffer() == "heylook" or "eylook" or "ylook" or "look" + + You might be wondering why the history_buffer can resize itself in + such a nondeterministic way. It is just to allow a lot of freedom in the + implementations of this object. + !*/ + + public: + + lz77_buffer ( + unsigned long total_limit, + unsigned long lookahead_limit + ); + /*! + requires + - 6 < total_limit < 32 + - 15 < lookahead_limit <= 2^(total_limit-2) + ensures + - #*this is properly initialized + - #get_history_buffer_limit() == 2^total_limit - lookahead_limit + - #get_lookahead_buffer_limit() == lookahead_limit + throws + - std::bad_alloc + !*/ + + virtual ~lz77_buffer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void shift_buffers ( + unsigned long N + ); + /*! + requires + - N <= get_lookahead_buffer_size() + ensures + - #get_lookahead_buffer_size() == get_lookahead_buffer_size() - N + - #get_history_buffer_size() >= N + - #get_history_buffer_size() <= get_history_buffer_size()+N + - #get_history_buffer_size() <= get_history_buffer_limit() + - for all i where 0 <= i < N: + #history_buffer(N-1-i) == lookahead_buffer(i) + - for all i where 0 <= i < #get_history_buffer_size()-N: + #history_buffer(N+i) == history_buffer(i) + - for all i where 0 <= i < #get_lookahead_buffer_size() + #lookahead_buffer(i) == lookahead_buffer(N+i) + !*/ + + void add ( + unsigned char symbol + ); + /*! + ensures + - if (get_lookahead_buffer_size() == get_lookahead_buffer_limit()) then + - performs shift_buffers(1) + - #lookahead_buffer(get_lookahead_buffer_limit()-1) == symbol + - #get_lookahead_buffer_size() == get_lookahead_buffer_size() + - else + - #lookahead_buffer(get_lookahead_buffer_size()) == symbol + - #get_lookahead_buffer_size() == get_lookahead_buffer_size() + 1 + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void find_match ( + unsigned long& index, + unsigned long& length, + unsigned long min_match_length + ); + /*! + ensures + - if (#length != 0) then + - #length >= min_match_length + - for all i where 0 <= i < #length: + history_buffer(#index-i) == lookahead_buffer(i) + - performs shift_buffers(#length) + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + unsigned long get_history_buffer_limit ( + ) const; + /*! + ensures + - returns the max number of symbols that can fit in the history buffer + !*/ + + unsigned long get_lookahead_buffer_limit ( + ) const; + /*! + ensures + - returns the max number of symbols that can fit in the lookahead buffer + !*/ + + unsigned long get_history_buffer_size ( + ) const; + /*! + ensures + - returns the number of symbols currently in the history buffer + !*/ + + unsigned long get_lookahead_buffer_size ( + ) const; + /*! + ensures + - returns the number of symbols currently in the lookahead buffer + !*/ + + unsigned char lookahead_buffer ( + unsigned long index + ) const; + /*! + requires + - index < get_lookahead_buffer_size() + ensures + - returns the symbol in the lookahead buffer at location index + !*/ + + unsigned char history_buffer ( + unsigned long index + ) const; + /*! + requires + - index < get_history_buffer_size() + ensures + - returns the symbol in the history buffer at location index + !*/ + + + private: + + // restricted functions + lz77_buffer(lz77_buffer&); // copy constructor + lz77_buffer& operator=(lz77_buffer&); // assignment operator + + }; +} + +#endif // DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_ + diff --git a/dlib/lz77_buffer/lz77_buffer_kernel_c.h b/dlib/lz77_buffer/lz77_buffer_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..7411927aa6a2a97e0792cfb6130bc31b399945c7 --- /dev/null +++ b/dlib/lz77_buffer/lz77_buffer_kernel_c.h @@ -0,0 +1,169 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZ77_BUFFER_KERNEl_C_ +#define DLIB_LZ77_BUFFER_KERNEl_C_ + +#include "lz77_buffer_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename lz77_base + > + class lz77_buffer_kernel_c : public lz77_base + { + + public: + lz77_buffer_kernel_c ( + unsigned long total_limit, + unsigned long lookahead_limit + ); + + unsigned char lookahead_buffer ( + unsigned long index + ) const; + + unsigned char history_buffer ( + unsigned long index + ) const; + + void shift_buffers ( + unsigned long N + ); + + + + unsigned long make_safe ( + unsigned long total_limit, + unsigned long lookahead_limit + ) + /*! + ensures + - if ( 6 < total_limit < 32 && + 15 < lookahead_limit <= 2^(total_limit-2) + ) then + - returns total_limit + - else + - throws due to failed CASSERT + !*/ + { + unsigned long exp_size = (total_limit!=0)?total_limit-2:0; + unsigned long two_pow_total_limit_minus_2 = 1; + while (exp_size != 0) + { + --exp_size; + two_pow_total_limit_minus_2 <<= 1; + } + + // make sure requires clause is not broken + DLIB_CASSERT( 6 < total_limit && total_limit < 32 && + 15 < lookahead_limit && lookahead_limit <= two_pow_total_limit_minus_2, + "\tlz77_buffer::lz77_buffer(unsigned long,unsigned long)" + << "\n\ttotal_limit must be in the range 7 to 31 and \n\tlookahead_limit in the range 15 to 2^(total_limit-2)" + << "\n\tthis: " << this + << "\n\ttotal_limit: " << total_limit + << "\n\tlookahead_limit: " << lookahead_limit + ); + + return total_limit; + } + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename lz77_base + > + void lz77_buffer_kernel_c:: + shift_buffers ( + unsigned long N + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( N <= this->get_lookahead_buffer_size(), + "\tvoid lz77_buffer::shift_buffers(unsigned long)" + << "\n\tN must be <= the number of chars in the lookahead buffer" + << "\n\tthis: " << this + << "\n\tget_lookahead_buffer_size(): " << this->get_lookahead_buffer_size() + << "\n\tN: " << N + ); + + // call the real function + lz77_base::shift_buffers(N); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename lz77_base + > + unsigned char lz77_buffer_kernel_c:: + history_buffer ( + unsigned long index + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( index < this->get_history_buffer_size(), + "\tunsigned char lz77_buffer::history_buffer(unsigned long) const" + << "\n\tindex must be in the range 0 to get_history_buffer_size()-1" + << "\n\tthis: " << this + << "\n\tget_history_buffer_size(): " << this->get_history_buffer_size() + << "\n\tindex: " << index + ); + + // call the real function + return lz77_base::history_buffer(index); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename lz77_base + > + unsigned char lz77_buffer_kernel_c:: + lookahead_buffer ( + unsigned long index + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( index < this->get_lookahead_buffer_size(), + "\tunsigned char lz77_buffer::lookahead_buffer(unsigned long) const" + << "\n\tindex must be in the range 0 to get_lookahead_buffer_size()-1" + << "\n\tthis: " << this + << "\n\tget_lookahead_buffer_size(): " << this->get_lookahead_buffer_size() + << "\n\tindex: " << index + ); + + // call the real function + return lz77_base::lookahead_buffer(index); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename lz77_base + > + lz77_buffer_kernel_c:: + lz77_buffer_kernel_c ( + unsigned long total_limit, + unsigned long lookahead_limit + ) : + lz77_base(make_safe(total_limit,lookahead_limit),lookahead_limit) + { + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LZ77_BUFFER_KERNEl_C_ + diff --git a/dlib/lzp_buffer.h b/dlib/lzp_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..4c8388430725f39777387e0b81084bddeba6ad55 --- /dev/null +++ b/dlib/lzp_buffer.h @@ -0,0 +1,46 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZP_BUFFEr_ +#define DLIB_LZP_BUFFEr_ + + +#include "lzp_buffer/lzp_buffer_kernel_1.h" +#include "lzp_buffer/lzp_buffer_kernel_2.h" +#include "lzp_buffer/lzp_buffer_kernel_c.h" + +#include "sliding_buffer.h" + + +namespace dlib +{ + + + class lzp_buffer + { + + lzp_buffer() {} + + typedef sliding_buffer::kernel_1a sb1; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef lzp_buffer_kernel_1 + kernel_1a; + typedef lzp_buffer_kernel_c + kernel_1a_c; + + // kernel_2a + typedef lzp_buffer_kernel_2 + kernel_2a; + typedef lzp_buffer_kernel_c + kernel_2a_c; + + + }; +} + +#endif // DLIB_LZP_BUFFEr_ + diff --git a/dlib/lzp_buffer/lzp_buffer_kernel_1.h b/dlib/lzp_buffer/lzp_buffer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..0eb6f1638cb4ee3c818e6f5505a3c5ab899470ce --- /dev/null +++ b/dlib/lzp_buffer/lzp_buffer_kernel_1.h @@ -0,0 +1,236 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZP_BUFFER_KERNEl_1_ +#define DLIB_LZP_BUFFER_KERNEl_1_ + +#include "../algs.h" +#include "lzp_buffer_kernel_abstract.h" + +namespace dlib +{ + + template < + typename sbuf + > + class lzp_buffer_kernel_1 + { + /*! + REQUIREMENTS ON sbuf + sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h + T == unsigned char + + INITIAL VALUE + - buffer.size() == the size as defined by the constructor + - table_size == the number of elements in the table array + - for all i: buffer[i] == 0 + - for all i: table[i] == buffer.size() + + CONVENTION + - table_size == the number of elements in the table array + - size() == buffer.size() + - operator[](i) == buffer[i] + + - if (table[hash()] != buffer.size()) then + - buffer.get_element_index(table[hash()]) == the index we will + predict for the current context + - else + - there is no prediction for the current context + + - last_element == buffer.size()-1 + + + This is LZP with just an order-3 model without context confirmation. + + !*/ + + public: + + explicit lzp_buffer_kernel_1 ( + unsigned long buffer_size + ); + + virtual ~lzp_buffer_kernel_1 ( + ); + + void clear( + ); + + inline void add ( + unsigned char symbol + ); + + inline unsigned long predict_match ( + unsigned long& index + ); + + inline unsigned long size ( + ) const; + + inline unsigned char operator[] ( + unsigned long index + ) const; + + private: + + inline unsigned long hash ( + ) const + /*! + ensures + - returns a hash computed from the current context. This hash + is always in the range for table. + !*/ + { + unsigned long temp = buffer[0]; + temp <<= 16; + unsigned long temp2 = buffer[1]; + temp2 <<= 8; + unsigned long temp3 = buffer[2]; + temp = temp|temp2|temp3; + + temp = ((temp>>11)^temp)&0xFFFF; + + return temp; + } + + sbuf buffer; + const unsigned long table_size; + unsigned long* const table; + unsigned long last_element; + + // restricted functions + lzp_buffer_kernel_1(const lzp_buffer_kernel_1&); // copy constructor + lzp_buffer_kernel_1& operator=(const lzp_buffer_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + lzp_buffer_kernel_1:: + lzp_buffer_kernel_1 ( + unsigned long buffer_size + ) : + table_size(65536), + table(new unsigned long[table_size]) + { + buffer.set_size(buffer_size); + + for (unsigned long i = 0; i < buffer.size(); ++i) + buffer[i] = 0; + + for (unsigned long i = 0; i < table_size; ++i) + table[i] = buffer.size(); + + last_element = buffer.size()-1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + lzp_buffer_kernel_1:: + ~lzp_buffer_kernel_1 ( + ) + { + delete [] table; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + void lzp_buffer_kernel_1:: + clear( + ) + { + for (unsigned long i = 0; i < buffer.size(); ++i) + buffer[i] = 0; + + for (unsigned long i = 0; i < table_size; ++i) + table[i] = buffer.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + void lzp_buffer_kernel_1:: + add ( + unsigned char symbol + ) + { + buffer.rotate_left(1); + buffer[0] = symbol; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + unsigned long lzp_buffer_kernel_1:: + predict_match ( + unsigned long& index + ) + { + const unsigned long i = hash(); + + if (table[i] != buffer.size()) + { + index = buffer.get_element_index(table[i]); + + if (index > 20) + { + // update the prediction for this context + table[i] = buffer.get_element_id(last_element); + } + return 3; + } + else + { + // update the prediction for this context + table[i] = buffer.get_element_id(last_element); + return 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + unsigned long lzp_buffer_kernel_1:: + size ( + ) const + { + return buffer.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + unsigned char lzp_buffer_kernel_1:: + operator[] ( + unsigned long index + ) const + { + return buffer[index]; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LZP_BUFFER_KERNEl_1_ + diff --git a/dlib/lzp_buffer/lzp_buffer_kernel_2.h b/dlib/lzp_buffer/lzp_buffer_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..d13044176ffd4a7b612c92af225f64b4a49eaa81 --- /dev/null +++ b/dlib/lzp_buffer/lzp_buffer_kernel_2.h @@ -0,0 +1,319 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZP_BUFFER_KERNEl_2_ +#define DLIB_LZP_BUFFER_KERNEl_2_ + +#include "../algs.h" +#include "lzp_buffer_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename sbuf + > + class lzp_buffer_kernel_2 + { + /*! + REQUIREMENTS ON sbuf + sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h + T == unsigned char + + INITIAL VALUE + - buffer.size() == the size as defined by the constructor + - table_size == the number of elements in the table3 and table4 arrays + - for all i: buffer[i] == 0 + - for all i: table3[i] == buffer.size() + - for all i: table4[i] == buffer.size() + + CONVENTION + - table_size == the number of elements in the table3 and table4 arrays + - size() == buffer.size() + - operator[](i) == buffer[i] + + + + - last_element == buffer.size()-1 + + + This is LZP with an order-5-4-3 model with context confirmation. + To save memory the order5 and order3 predictions exist in the same + table, that is, table3. + + !*/ + + public: + + explicit lzp_buffer_kernel_2 ( + unsigned long buffer_size + ); + + virtual ~lzp_buffer_kernel_2 ( + ); + + void clear( + ); + + inline void add ( + unsigned char symbol + ); + + inline unsigned long predict_match ( + unsigned long& index + ); + + inline unsigned long size ( + ) const; + + inline unsigned char operator[] ( + unsigned long index + ) const; + + private: + + inline bool verify ( + unsigned long index + ) const + /*! + ensures + - returns true if buffer[index]'s context matches the current context + !*/ + { + if (index+3 < buffer.size()) + { + if (buffer[0] != buffer[index+1]) + return false; + if (buffer[1] != buffer[index+2]) + return false; + if (buffer[2] != buffer[index+3]) + return false; + return true; + } + else + { + // just call this a match + return true; + } + } + + + sbuf buffer; + unsigned long* table3; + unsigned long* table4; + unsigned long last_element; + const unsigned long table_size; + + // restricted functions + lzp_buffer_kernel_2(const lzp_buffer_kernel_2&); // copy constructor + lzp_buffer_kernel_2& operator=(const lzp_buffer_kernel_2&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + lzp_buffer_kernel_2:: + lzp_buffer_kernel_2 ( + unsigned long buffer_size + ) : + table3(0), + table4(0), + table_size(65536) + { + buffer.set_size(buffer_size); + + table3 = new (std::nothrow) unsigned long[table_size]; + table4 = new (std::nothrow) unsigned long[table_size]; + + if (!table3 || !table4) + { + if (!table3) + delete [] table3; + if (!table4) + delete [] table4; + + throw std::bad_alloc(); + } + + + + for (unsigned long i = 0; i < buffer.size(); ++i) + buffer[i] = 0; + + for (unsigned long i = 0; i < table_size; ++i) + { + table3[i] = buffer.size(); + table4[i] = buffer.size(); + } + + last_element = buffer.size()-1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + lzp_buffer_kernel_2:: + ~lzp_buffer_kernel_2 ( + ) + { + delete [] table3; + delete [] table4; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + void lzp_buffer_kernel_2:: + clear( + ) + { + for (unsigned long i = 0; i < buffer.size(); ++i) + buffer[i] = 0; + + for (unsigned long i = 0; i < table_size; ++i) + { + table3[i] = buffer.size(); + table4[i] = buffer.size(); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + void lzp_buffer_kernel_2:: + add ( + unsigned char symbol + ) + { + buffer.rotate_left(1); + buffer[0] = symbol; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + unsigned long lzp_buffer_kernel_2:: + predict_match ( + unsigned long& index + ) + { + unsigned long temp1 = buffer[0]; + unsigned long temp2 = buffer[1]; + temp2 <<= 8; + unsigned long temp3 = buffer[2]; + temp3 <<= 16; + unsigned long temp4 = buffer[3]; + temp4 <<= 24; + unsigned long temp5 = buffer[4]; + temp5 <<= 12; + + unsigned long context1 = temp1|temp2|temp3; + unsigned long context2 = context1|temp4; + + + const unsigned long i5 = ((temp5|(context2>>20))^context2)&0xFFFF; + const unsigned long i4 = ((context2>>15)^context2)&0xFFFF; + const unsigned long i3 = ((context1>>11)^context1)&0xFFFF; + + + + // check the 5-order context's prediction + if (table3[i5] != buffer.size() && + verify(buffer.get_element_index(table3[i5])) ) + { + index = buffer.get_element_index(table3[i5]); + if (index > 20) + { + // update the prediction for this context + table3[i3] = buffer.get_element_id(last_element); + table4[i4] = table3[i3]; + table3[i5] = table3[i3]; + } + return 5; + } + // check the 4-order context's prediction + else if (table4[i4] != buffer.size() && + verify(buffer.get_element_index(table4[i4])) ) + { + index = buffer.get_element_index(table4[i4]); + if (index > 20) + { + // update the prediction for this context + table3[i3] = buffer.get_element_id(last_element); + table4[i4] = table3[i3]; + table3[i5] = table3[i3]; + } + return 4; + } + // check the 3-order context's prediction + else if (table3[i3] != buffer.size() && + verify(buffer.get_element_index(table3[i3]))) + { + index = buffer.get_element_index(table3[i3]); + + if (index > 20) + { + // update the prediction for this context + table3[i3] = buffer.get_element_id(last_element); + table4[i4] = table3[i3]; + table3[i5] = table3[i3]; + } + return 3; + } + else + { + // update the prediction for this context + table3[i3] = buffer.get_element_id(last_element); + table4[i4] = table3[i3]; + table3[i5] = table3[i3]; + + return 0; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + unsigned long lzp_buffer_kernel_2:: + size ( + ) const + { + return buffer.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sbuf + > + unsigned char lzp_buffer_kernel_2:: + operator[] ( + unsigned long index + ) const + { + return buffer[index]; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LZP_BUFFER_KERNEl_2_ + diff --git a/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h b/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..71e5994fa06752f6fde76c7b96c1a73e29f6d690 --- /dev/null +++ b/dlib/lzp_buffer/lzp_buffer_kernel_abstract.h @@ -0,0 +1,130 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_LZP_BUFFER_KERNEl_ABSTRACT_ +#ifdef DLIB_LZP_BUFFER_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + class lzp_buffer + { + /*! + INITIAL VALUE + size() == some value defined by the constructor argument + Initially this object is at some predefined empty or ground state. + for all i: (*this)[i] == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents some varation on the LZP algorithm + described by Charles Bloom in his paper "LZP: a new data + compression algorithm" + + The LZP algorithm is a lot like lz77 except there is no need to pass + the location of matches in the history buffer to the decoder because + LZP uses the data it has already seen to predict the location of the + next match. + + NOTE + The add() and predict_match() functions must be called in the same + order by the coder and decoder. If they aren't the state of the + lzp_buffer objects in the coder and decoder may differ and the decoder + won't be able to correctly decode the data stream. + !*/ + + public: + + explicit lzp_buffer ( + unsigned long buffer_size + ); + /*! + requires + - 10 < buffer_size < 32 + ensures + - #*this is properly initialized + - #size() == 2^buffer_size + throws + - std::bad_alloc + !*/ + + virtual ~lzp_buffer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void add ( + unsigned char symbol + ); + /*! + ensures + - shifts everything in the history buffer left 1. + (i.e. #(*this)[i+1] == (*this)[i]) + - #(*this)[0] == symbol + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + unsigned long predict_match ( + unsigned long& index + ); + /*! + ensures + - updates the prediction for the current context. + (the current context is the last few symbols seen. i.e. (*this)[0], + (*this)[1], etc...) + - if (*this can generate a prediction) then + - #index == the predicted location of a match in the history buffer. + (i.e. (*this)[#index] is the first symbol of the predicted match) + - returns the order this prediction came from + - else + - returns 0 + throws + - std::bad_alloc + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + unsigned long size ( + ) const; + /*! + ensures + - returns the size of the history buffer + !*/ + + unsigned char operator[] ( + unsigned long index + ) const; + /*! + requires + - index < size() + ensures + - returns the symbol at the given index in the history buffer + !*/ + + private: + + // restricted functions + lzp_buffer(const lzp_buffer&); // copy constructor + lzp_buffer& operator=(const lzp_buffer&); // assignment operator + + }; +} + +#endif // DLIB_LZP_BUFFER_KERNEl_ABSTRACT_ + diff --git a/dlib/lzp_buffer/lzp_buffer_kernel_c.h b/dlib/lzp_buffer/lzp_buffer_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..4edd439eff2120b2572ed0ed20ca0848b6f82636 --- /dev/null +++ b/dlib/lzp_buffer/lzp_buffer_kernel_c.h @@ -0,0 +1,101 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_LZP_BUFFER_KERNEl_C_ +#define DLIB_LZP_BUFFER_KERNEl_C_ + +#include "lzp_buffer_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename lzp_base + > + class lzp_buffer_kernel_c : public lzp_base + { + + public: + lzp_buffer_kernel_c ( + unsigned long buffer_size + ); + + + unsigned char operator[] ( + unsigned long index + ) const; + + + unsigned long make_safe ( + unsigned long buffer_size + ) + /*! + ensures + - if ( 10 < buffer_size < 32) then + - returns buffer_size + - else + - throws due to failed CASSERT + !*/ + { + + // make sure requires clause is not broken + DLIB_CASSERT( 10 < buffer_size && buffer_size < 32, + "\tlzp_buffer::lzp_buffer(unsigned long)" + << "\n\tbuffer_size must be in the range 11 to 31." + << "\n\tthis: " << this + << "\n\tbuffer_size: " << buffer_size + ); + + return buffer_size; + } + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename lzp_base + > + unsigned char lzp_buffer_kernel_c:: + operator[] ( + unsigned long index + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( index < this->size(), + "\tunsigned char lzp_buffer::operator[](unsigned long) const" + << "\n\tindex must be in the range 0 to size()()-1" + << "\n\tthis: " << this + << "\n\tsize(): " << this->size() + << "\n\tindex: " << index + ); + + // call the real function + return lzp_base::operator[](index); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename lzp_base + > + lzp_buffer_kernel_c:: + lzp_buffer_kernel_c ( + unsigned long buffer_size + ) : + lzp_base(make_safe(buffer_size)) + { + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_LZP_BUFFER_KERNEl_C_ + diff --git a/dlib/map.h b/dlib/map.h new file mode 100644 index 0000000000000000000000000000000000000000..095269a464698ec1db4a6233862860fa0829e73d --- /dev/null +++ b/dlib/map.h @@ -0,0 +1,59 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MAp_ +#define DLIB_MAp_ + +#include "map/map_kernel_1.h" +#include "map/map_kernel_c.h" + +#include "binary_search_tree.h" + + +#include "memory_manager.h" +#include + + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class map + { + map() {} + + + // a typedef for the binary search tree used by kernel_2 + typedef typename binary_search_tree::kernel_1a + binary_search_tree_1; + + // a typedef for the binary search tree used by kernel_2 + typedef typename binary_search_tree::kernel_2a + binary_search_tree_2; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef map_kernel_1 + kernel_1a; + typedef map_kernel_c + kernel_1a_c; + + // kernel_1b + typedef map_kernel_1 + kernel_1b; + typedef map_kernel_c + kernel_1b_c; + + + }; +} + +#endif // DLIB_MAp_ + diff --git a/dlib/map/map_kernel_1.h b/dlib/map/map_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..d0ce308ad16562191da5baf01538450bed3adec9 --- /dev/null +++ b/dlib/map/map_kernel_1.h @@ -0,0 +1,437 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MAP_KERNEl_1_ +#define DLIB_MAP_KERNEl_1_ + +#include "map_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager = memory_manager::kernel_1a + > + class map_kernel_1 : public enumerable >, + public asc_pair_remover + { + + /*! + REQUIREMENTS ON BST_BASE + bst_base is instantiated with domain and range and + implements binary_search_tree/binary_search_tree_kernel_abstract.h + + INITIAL VALUE + bst has its initial value + + CONVENTION + bst.size() == the number of elements in the map and + the elements in map are stored in bst_base + !*/ + + public: + + typedef domain domain_type; + typedef range range_type; + typedef typename bst_base::compare_type compare_type; + typedef mem_manager mem_manager_type; + + map_kernel_1( + ) + {} + + virtual ~map_kernel_1( + ) + {} + + inline void clear( + ); + + inline void add ( + domain& d, + range& r + ); + + inline bool is_in_domain ( + const domain& d + ) const; + + inline void remove_any ( + domain& d, + range& r + ); + + inline void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + inline void destroy ( + const domain& d + ); + + inline range& operator[] ( + const domain& d + ); + + inline const range& operator[] ( + const domain& d + ) const; + + inline void swap ( + map_kernel_1& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + inline bool current_element_valid ( + ) const; + + inline const map_pair& element ( + ) const; + + inline map_pair& element ( + ); + + inline bool move_next ( + ) const; + + + private: + + bst_base bst; + + // restricted functions + map_kernel_1(map_kernel_1&); + map_kernel_1& operator= ( map_kernel_1&); + }; + + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + inline void swap ( + map_kernel_1& a, + map_kernel_1& b + ) { a.swap(b); } + + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void deserialize ( + map_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item.add(d,r); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type map_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + clear ( + ) + { + bst.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + add( + domain& d, + range& r + ) + { + // try to add pair to bst_base + bst.add(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + bool map_kernel_1:: + is_in_domain( + const domain& d + ) const + { + return (bst[d] != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + remove_any( + domain& d, + range& r + ) + { + bst.remove_any(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + bst.remove(d,d_copy,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + destroy ( + const domain& d + ) + { + bst.destroy(d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + range& map_kernel_1:: + operator[]( + const domain& d + ) + { + return *bst[d]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + const range& map_kernel_1:: + operator[]( + const domain& d + ) const + { + return *bst[d]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + unsigned long map_kernel_1:: + size ( + ) const + { + return bst.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + swap ( + map_kernel_1& item + ) + { + bst.swap(item.bst); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + bool map_kernel_1:: + at_start ( + ) const + { + return bst.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + void map_kernel_1:: + reset ( + ) const + { + bst.reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + bool map_kernel_1:: + current_element_valid ( + ) const + { + return bst.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + const map_pair& map_kernel_1:: + element ( + ) const + { + return bst.element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + map_pair& map_kernel_1:: + element ( + ) + { + return bst.element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename bst_base, + typename mem_manager + > + bool map_kernel_1:: + move_next ( + ) const + { + return bst.move_next(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MAP_KERNEl_1_ + diff --git a/dlib/map/map_kernel_abstract.h b/dlib/map/map_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..d4c365eef012162d535bae442e061d31a53ebf44 --- /dev/null +++ b/dlib/map/map_kernel_abstract.h @@ -0,0 +1,232 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MAP_KERNEl_ABSTRACT_ +#ifdef DLIB_MAP_KERNEl_ABSTRACT_ + +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class map : public enumerable >, + public asc_pair_remover + { + + /*! + REQUIREMENTS ON domain + domain must be comparable by compare where compare is a functor compatible with std::less and + domain is swappable by a global swap() and + domain must have a default constructor + + REQUIREMENTS ON range + range is swappable by a global swap() and + range must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap(), is_in_domain(), and operator[] functions do not invalidate + pointers or references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the domain (and each associated + range element) elements in ascending order according to the compare functor. + (i.e. the elements are enumerated in sorted order) + + WHAT THIS OBJECT REPRESENTS + map contains items of type domain and range + + This object is similar an array. It maps items of type domain on to + items of type range. + + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + map( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + !*/ + + virtual ~map( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void add ( + domain& d, + range& r + ); + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + - is_in_domain(d) == false + ensures + - #is_in_domain(d) == true + - #operator[](d) == r + - #d and #r have initial values for their types + - #size() == size() + 1 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + if add() throws then it has no effect + !*/ + + bool is_in_domain ( + const domain& d + ) const; + /*! + ensures + - returns whether or not an element equivalent to d is in the + domain of *this + !*/ + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + /*! + requires + - &d != &r (i.e. d and r cannot be the same variable) + - &d != &d_copy (i.e. d and d_copy cannot be the same variable) + - &r != &d_copy (i.e. r and d_copy cannot be the same variable) + - is_in_domain(d) == true + ensures + - #is_in_domain(d) == false + - #d_copy is equivalent to d + - the element in the range of *this associated with #d_copy has been + swapped into #r + - #size() == size() - 1 + - #at_start() == true + !*/ + + void destroy ( + const domain& d + ); + /*! + requires + - is_in_domain(d) == true + ensures + - #is_in_domain(d) == false + - #size() == size() - 1 + - #at_start() == true + !*/ + + range& operator[] ( + const domain& d + ); + /*! + requires + - is_in_domain(d) == true + ensures + - returns a non-const reference to the element in the range of *this + associated with the element equivalent to d + !*/ + + const range& operator[] ( + const domain& d + ) const; + /*! + requires + - is_in_domain(d) == true + ensures + - returns a const reference to the element in the range of *this + associated with the element equivalent to d + !*/ + + void swap ( + map& item + ); + /*! + ensures + - swaps *this and item + !*/ + + + private: + + // restricted functions + map(map&); // copy constructor + map& operator=(map&); // assignment operator + }; + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + inline void swap ( + map& a, + map& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename domain, + typename range, + typename mem_manager, + typename compare + > + void deserialize ( + map& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_MAP_KERNEl_ABSTRACT_ + diff --git a/dlib/map/map_kernel_c.h b/dlib/map/map_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..b1c7aed9718d9432289c908233ee631bcb5ee3e1 --- /dev/null +++ b/dlib/map/map_kernel_c.h @@ -0,0 +1,266 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MAP_KERNEl_C_ +#define DLIB_MAP_KERNEl_C_ + +#include "map_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include "../interfaces/map_pair.h" + +namespace dlib +{ + + template < + typename map_base + > + class map_kernel_c : public map_base + { + + typedef typename map_base::domain_type domain; + typedef typename map_base::range_type range; + + public: + void add ( + domain& d, + range& r + ); + + void remove_any ( + domain& d, + range& r + ); + + void remove ( + const domain& d, + domain& d_copy, + range& r + ); + + void destroy ( + const domain& d + ); + + range& operator[] ( + const domain& d + ); + + const range& operator[] ( + const domain& d + ) const; + + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + }; + + template < + typename map_base + > + inline void swap ( + map_kernel_c& a, + map_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + void map_kernel_c:: + add ( + domain& d, + range& r + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (!is_in_domain(d)) && + (reinterpret_cast(&d) != reinterpret_cast(&r)), + "\tvoid map::add" + << "\n\tdomain element being added must not already be in the map" + << "\n\tand d and r must not be the same variable" + << "\n\tis_in_domain(d): " << (is_in_domain(d) ? "true" : "false") + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + << "\n\t&r: " << reinterpret_cast(&r) + ); + + // call the real function + map_base::add(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + void map_kernel_c:: + remove_any ( + domain& d, + range& r + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (this->size() > 0) && + (reinterpret_cast(&d) != reinterpret_cast(&r)), + "\tvoid map::remove_any" + << "\n\tsize() must be greater than zero if something is going to be removed" + << "\n\tand d and r must not be the same variable." + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + << "\n\t&r: " << reinterpret_cast(&r) + ); + + // call the real function + map_base::remove_any(d,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + void map_kernel_c:: + remove ( + const domain& d, + domain& d_copy, + range& r + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (is_in_domain(d)) && + (reinterpret_cast(&d) != reinterpret_cast(&r)) && + (reinterpret_cast(&r) != reinterpret_cast(&d_copy)) && + (reinterpret_cast(&d) != reinterpret_cast(&d_copy)), + "\tvoid map::remove" + << "\n\tcan't remove something that isn't in the map or if the paremeters actually" + << "\n\tare the same variable. Either way can't remove." + << "\n\tis_in_domain(d): " << (is_in_domain(d) ? "true" : "false") + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + << "\n\t&r: " << reinterpret_cast(&r) + << "\n\t&d_copy: " << reinterpret_cast(&d_copy) + ); + + // call the real function + map_base::remove(d,d_copy,r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + void map_kernel_c:: + destroy ( + const domain& d + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_in_domain(d), + "\tvoid map::destroy" + << "\n\tcan't remove something that isn't in the map" + << "\n\tthis: " << this + << "\n\t&d: " << reinterpret_cast(&d) + ); + + // call the real function + map_base::destroy(d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + typename map_base::range_type& map_kernel_c:: + operator[] ( + const domain& d + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_in_domain(d), + "\trange& map::operator[]" + << "\n\td must be in the domain of the map" + << "\n\tthis: " << this + ); + + // call the real function + return map_base::operator[](d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + const typename map_base::range_type& map_kernel_c:: + operator[] ( + const domain& d + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( is_in_domain(d), + "\tconst range& map::operator[]" + << "\n\td must be in the domain of the map" + << "\n\tthis: " << this + ); + + // call the real function + return map_base::operator[](d); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + const map_pair& map_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst map_pair& map::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return map_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + map_pair& map_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tmap_pair& map::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return map_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MAP_KERNEl_C_ + diff --git a/dlib/matrix.h b/dlib/matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..09a74564aaeaa56968bc8c8fe4a06f07461cec32 --- /dev/null +++ b/dlib/matrix.h @@ -0,0 +1,12 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MATRIx_HEADER +#define DLIB_MATRIx_HEADER + +#include "matrix/matrix.h" +#include "matrix/matrix_utilities.h" +#include "matrix/matrix_math_functions.h" + +#endif // DLIB_MATRIx_HEADER + + diff --git a/dlib/matrix/matrix.h b/dlib/matrix/matrix.h new file mode 100644 index 0000000000000000000000000000000000000000..4a5e83c8fdf6e166e3a91b456b205dd1ca0831bc --- /dev/null +++ b/dlib/matrix/matrix.h @@ -0,0 +1,2086 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MATRIx_ +#define DLIB_MATRIx_ + +#include "matrix_abstract.h" +#include "../algs.h" +#include "../serialize.h" +#include "../enable_if.h" +#include +#include +#include "../memory_manager.h" + +#ifdef _MSC_VER +// Disable the following warnings for Visual Studio + +// This warning is: +// "warning C4355: 'this' : used in base member initializer list" +// Which we get from this code but it is not an error so I'm turning this +// warning off and then turning it back on at the end of the file. +#pragma warning(disable : 4355) + +#endif + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows = 0, + long num_cols = 0, + typename mem_manager = memory_manager::kernel_1a + > + class matrix; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template + inline typename enable_if_c::type matrix_nr ( + const M1& m1, + const M2& m2 + ) { return m2.nr(); } + template + inline typename enable_if_c::type matrix_nr ( + const M1& m1, + const M2& m2 + ) { return m1.nr(); } + /*! + ensures + - if (M1::NR != 0) then + - returns m1.nr() + - else + - returns m2.nr() + !*/ + + template + inline typename enable_if_c::type matrix_nc ( + const M1& m1, + const M2& m2 + ) { return m2.nc(); } + template + inline typename enable_if_c::type matrix_nc ( + const M1& m1, + const M2& m2 + ) { return m1.nc(); } + /*! + ensures + - if (M1::NC != 0) then + - returns m1.nc() + - else + - returns m2.nc() + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_ref + { + public: + typedef T type; + typedef matrix_ref ref_type; + typedef mem_manager mem_manager_type; + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_ref ( + const matrix& m_ + ) : m(m_) {} + + matrix_ref ( + const matrix_ref& i_ + ) : m(i_.m) {} + + const T& operator() ( + long r, + long c + ) const { return m(r,c); } + + long nr ( + ) const { return m.nr(); } + + long nc ( + ) const { return m.nc(); } + + long size ( + ) const { return m.size(); } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + bool aliases ( + const matrix& item + ) const { return (&m == &item); } + + const matrix_ref ref( + ) const { return *this; } + + private: + // no assignment operator + matrix_ref& operator=(const matrix_ref&); + + const matrix& m; // This is the item contained by this expression. + }; + +// ---------------------------------------------------------------------------------------- + + // this is a hack to avoid a compile time error in visual studio 8. I would just + // use sizeof(T) and be done with it but that won't compile. The idea here + // is to avoid using the stack allocation of the matrix_data object if it + // is going to contain another matrix and also avoid asking for the sizeof() + // the contained matrix. + template + struct get_sizeof_helper + { + const static std::size_t val = sizeof(T); + }; + + template + struct get_sizeof_helper > + { + const static std::size_t val = 1000000; + }; + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager, + int val = static_switch < + // when the sizes are all non zero and small + (num_rows*num_cols*get_sizeof_helper::val <= 64) && (num_rows != 0 && num_cols != 0), + // when the sizes are all non zero and big + (num_rows*num_cols*get_sizeof_helper::val >= 65) && (num_rows != 0 && num_cols != 0), + num_rows == 0 && num_cols != 0, + num_rows != 0 && num_cols == 0, + num_rows == 0 && num_cols == 0 + >::value + > + class matrix_data ; + /*! + WHAT THIS OBJECT REPRESENTS + This object represents the actual allocation of space for a matrix. + Small matrices allocate all their data on the stack and bigger ones + use a memory_manager to get their memory. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_data : noncopyable // when the sizes are all non zero and small + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_data() {} + + T& operator() ( + long r, + long c + ) { return data[r][c]; } + + const T& operator() ( + long r, + long c + ) const { return data[r][c]; } + + T& operator() ( + long i + ) { return *(*data + i); } + + const T& operator() ( + long i + ) const { return *(*data + i); } + + void swap( + matrix_data& item + ) + { + for (long r = 0; r < num_rows; ++r) + { + for (long c = 0; c < num_cols; ++c) + { + exchange((*this)(r,c),item(r,c)); + } + } + } + + long nr ( + ) const { return num_rows; } + + long nc ( + ) const { return num_cols; } + + void set_size ( + long nr, + long nc + ) + { + } + + void consume( + matrix_data& item + ) + /*! + ensures + - #*this == item + - #item is in an untouchable state. no one should do anything + to it other than let it destruct. + !*/ + { + for (long r = 0; r < num_rows; ++r) + { + for (long c = 0; c < num_cols; ++c) + { + (*this)(r,c) = item(r,c); + } + } + } + + private: + T data[num_rows][num_cols]; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_data : noncopyable // when the sizes are all non zero and big + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_data ( + ) { data = pool.allocate_array(num_rows*num_cols); } + + ~matrix_data () + { pool.deallocate_array(data); } + + T& operator() ( + long r, + long c + ) { return data[r*num_cols + c]; } + + const T& operator() ( + long r, + long c + ) const { return data[r*num_cols + c]; } + + T& operator() ( + long i + ) { return data[i]; } + + const T& operator() ( + long i + ) const { return data[i]; } + + void swap( + matrix_data& item + ) + { + std::swap(item.data,data); + pool.swap(item.pool); + } + + long nr ( + ) const { return num_rows; } + + long nc ( + ) const { return num_cols; } + + void set_size ( + long nr, + long nc + ) + { + } + + void consume( + matrix_data& item + ) + /*! + ensures + - #*this == item + - #item is in an untouchable state. no one should do anything + to it other than let it destruct. + !*/ + { + pool.deallocate_array(data); + data = item.data; + item.data = 0; + pool.swap(item.pool); + } + + private: + + T* data; + typename mem_manager::template rebind::other pool; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_data : noncopyable // when num_rows == 0 && num_cols != 0, + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_data ( + ):data(0), nr_(0) { } + + ~matrix_data () + { + if (data) + pool.deallocate_array(data); + } + + T& operator() ( + long r, + long c + ) { return data[r*num_cols + c]; } + + const T& operator() ( + long r, + long c + ) const { return data[r*num_cols + c]; } + + T& operator() ( + long i + ) { return data[i]; } + + const T& operator() ( + long i + ) const { return data[i]; } + + void swap( + matrix_data& item + ) + { + std::swap(item.data,data); + std::swap(item.nr_,nr_); + pool.swap(item.pool); + } + + long nr ( + ) const { return nr_; } + + long nc ( + ) const { return num_cols; } + + void set_size ( + long nr, + long nc + ) + { + if (data) + { + pool.deallocate_array(data); + } + data = pool.allocate_array(nr*nc); + nr_ = nr; + } + + void consume( + matrix_data& item + ) + /*! + ensures + - #*this == item + - #item is in an untouchable state. no one should do anything + to it other than let it destruct. + !*/ + { + pool.deallocate_array(data); + data = item.data; + nr_ = item.nr_; + item.data = 0; + pool.swap(item.pool); + } + + private: + + T* data; + long nr_; + typename mem_manager::template rebind::other pool; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_data : noncopyable // when num_rows != 0 && num_cols == 0 + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_data ( + ):data(0), nc_(0) { } + + ~matrix_data () + { + if (data) + { + pool.deallocate_array(data); + } + } + + T& operator() ( + long r, + long c + ) { return data[r*nc_ + c]; } + + const T& operator() ( + long r, + long c + ) const { return data[r*nc_ + c]; } + + T& operator() ( + long i + ) { return data[i]; } + + const T& operator() ( + long i + ) const { return data[i]; } + + void swap( + matrix_data& item + ) + { + std::swap(item.data,data); + std::swap(item.nc_,nc_); + pool.swap(item.pool); + } + + long nr ( + ) const { return num_rows; } + + long nc ( + ) const { return nc_; } + + void set_size ( + long nr, + long nc + ) + { + if (data) + { + pool.deallocate_array(data); + } + data = pool.allocate_array(nr*nc); + nc_ = nc; + } + + void consume( + matrix_data& item + ) + /*! + ensures + - #*this == item + - #item is in an untouchable state. no one should do anything + to it other than let it destruct. + !*/ + { + pool.deallocate_array(data); + data = item.data; + nc_ = item.nc_; + item.data = 0; + pool.swap(item.pool); + } + + private: + + T* data; + long nc_; + typename mem_manager::template rebind::other pool; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_data : noncopyable // when num_rows == 0 && num_cols == 0 + { + public: + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_data ( + ):data(0), nr_(0), nc_(0) { } + + ~matrix_data () + { + if (data) + { + pool.deallocate_array(data); + } + } + + T& operator() ( + long r, + long c + ) { return data[r*nc_ + c]; } + + const T& operator() ( + long r, + long c + ) const { return data[r*nc_ + c]; } + + T& operator() ( + long i + ) { return data[i]; } + + const T& operator() ( + long i + ) const { return data[i]; } + + void swap( + matrix_data& item + ) + { + std::swap(item.data,data); + std::swap(item.nc_,nc_); + std::swap(item.nr_,nr_); + pool.swap(item.pool); + } + + long nr ( + ) const { return nr_; } + + long nc ( + ) const { return nc_; } + + void set_size ( + long nr, + long nc + ) + { + if (data) + { + pool.deallocate_array(data); + } + data = pool.allocate_array(nr*nc); + nr_ = nr; + nc_ = nc; + } + + void consume( + matrix_data& item + ) + /*! + ensures + - #*this == item + - #item is in an untouchable state. no one should do anything + to it other than let it destruct. + !*/ + { + pool.deallocate_array(data); + data = item.data; + nc_ = item.nc_; + nr_ = item.nr_; + item.data = 0; + pool.swap(item.pool); + } + + private: + T* data; + long nr_; + long nc_; + typename mem_manager::template rebind::other pool; + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + // We want to return the compile time constant if our NR and NC dimensions + // aren't zero but if they are then we want to call ref_.nx() and return + // the correct values. + template < typename ref_type, long NR > + struct get_nr_helper + { + static inline long get(const ref_type&) { return NR; } + }; + + template < typename ref_type > + struct get_nr_helper + { + static inline long get(const ref_type& m) { return m.nr(); } + }; + + template < typename ref_type, long NC > + struct get_nc_helper + { + static inline long get(const ref_type&) { return NC; } + }; + + template < typename ref_type > + struct get_nc_helper + { + static inline long get(const ref_type& m) { return m.nc(); } + }; + + + // the matrix_exp for statically sized matrices + template < + typename EXP + > + class matrix_exp + { + public: + typedef typename EXP::type type; + typedef typename EXP::ref_type ref_type; + typedef typename EXP::mem_manager_type mem_manager_type; + const static long NR = EXP::NR; + const static long NC = EXP::NC; + typedef matrix matrix_type; + + matrix_exp ( + const EXP& exp + ) : ref_(exp.ref()) {} + + inline const type operator() ( + long r, + long c + ) const + { + DLIB_ASSERT(r < nr() && c < nc() && r >= 0 && c >= c, + "\tconst type matrix_exp::operator(r,c)" + << "\n\tYou must give a valid row and column" + << "\n\tr: " << r + << "\n\tc: " << c + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return ref_(r,c); + } + + const type operator() ( + long i + ) const + { + COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0); + DLIB_ASSERT(nc() == 1 || nr() == 1, + "\tconst type matrix_exp::operator(i)" + << "\n\tYou can only use this operator on column or row vectors" + << "\n\ti: " << i + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + DLIB_ASSERT( ((nc() == 1 && i < nr()) || (nr() == 1 && i < nc())) && i >= 0, + "\tconst type matrix_exp::operator(i)" + << "\n\tYou must give a valid row/column number" + << "\n\ti: " << i + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + if (nc() == 1) + return ref_(i,0); + else + return ref_(0,i); + } + + long size ( + ) const { return nr()*nc(); } + + long nr ( + ) const { return get_nr_helper::get(ref_); } + + long nc ( + ) const { return get_nc_helper::get(ref_); } + + template + bool aliases ( + const matrix& item + ) const { return ref_.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return ref_.destructively_aliases(item); } + + const ref_type& ref ( + ) const { return ref_; } + + inline operator const type ( + ) const + { + COMPILE_TIME_ASSERT(NC == 1 || NC == 0); + COMPILE_TIME_ASSERT(NR == 1 || NR == 0); + DLIB_ASSERT(nr() == 1 && nc() == 1, + "\tmatrix_exp::operator const type&() const" + << "\n\tYou can only use this operator on a 1x1 matrix" + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return ref_(0,0); + } + + + private: + + + const ref_type ref_; + }; + + // ---------------------------------------------------------------------------------------- + + // This template will perform the needed loop for element multiplication using whichever + // dimension is provided as a compile time constant (if one is at all). + template < + typename LHS, + typename RHS, + long lhs_nc = LHS::NC, + long rhs_nr = RHS::NR + > + struct matrix_multiply_helper + { + typedef typename LHS::type type; + inline const static type eval ( + const RHS& rhs, + const LHS& lhs, + long r, + long c + ) + { + type temp = type(); + for (long i = 0; i < rhs.nr(); ++i) + { + temp += lhs(r,i)*rhs(i,c); + } + return temp; + } + }; + + template < + typename LHS, + typename RHS, + long lhs_nc + > + struct matrix_multiply_helper + { + typedef typename LHS::type type; + inline const static type eval ( + const RHS& rhs, + const LHS& lhs, + long r, + long c + ) + { + type temp = type(); + for (long i = 0; i < lhs.nc(); ++i) + { + temp += lhs(r,i)*rhs(i,c); + } + return temp; + } + }; + + template < + typename LHS, + typename RHS, + unsigned long count = 0 + > + class matrix_multiply_exp + { + /*! + REQUIREMENTS ON LHS AND RHS + - they must be matrix_exp or matrix_ref objects (or + objects with a compatible interface). + !*/ + public: + typedef typename LHS::type type; + typedef matrix_multiply_exp ref_type; + typedef typename LHS::mem_manager_type mem_manager_type; + const static long NR = LHS::NR; + const static long NC = RHS::NC; + + matrix_multiply_exp ( + const matrix_multiply_exp& item + ) : lhs(item.lhs), rhs(item.rhs) {} + + inline matrix_multiply_exp ( + const LHS& lhs_, + const RHS& rhs_ + ) : + lhs(lhs_), + rhs(rhs_) + { + // You are trying to multiply two incompatible matrices together. The number of columns + // in the matrix on the left must match the number of rows in the matrix on the right. + COMPILE_TIME_ASSERT(LHS::NC == RHS::NR || LHS::NC*RHS::NR == 0); + DLIB_ASSERT(lhs.nc() == rhs.nr(), + "\tconst matrix_exp operator*(const matrix_exp& lhs, const matrix_exp& rhs)" + << "\n\tYou are trying to multiply two incompatible matrices together" + << "\n\tlhs.nr(): " << lhs.nr() + << "\n\tlhs.nc(): " << lhs.nc() + << "\n\trhs.nr(): " << rhs.nr() + << "\n\trhs.nc(): " << rhs.nc() + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + ); + + // You can't multiply matrices together if they don't both contain the same type of elements. + COMPILE_TIME_ASSERT((is_same_type::value == true)); + } + + inline const type operator() ( + long r, + long c + ) const + { + return matrix_multiply_helper::eval(rhs,lhs,r,c); + } + + long nr ( + ) const { return lhs.nr(); } + + long nc ( + ) const { return rhs.nc(); } + + template + bool aliases ( + const matrix& item + ) const { return lhs.aliases(item) || rhs.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return aliases(item); } + + const ref_type& ref( + ) const { return *this; } + + const LHS lhs; + const RHS rhs; + }; + + template < + typename T, + long NR, + long NC, + typename EXP1, + typename EXP2, + typename MM + > + inline const matrix_exp::ref_type >,0 > > operator* ( + const matrix_exp >& m1, + const matrix& m2 + ) + { + // We are going to reorder the order of evaluation of the terms here. This way the + // multiplication will go faster. + typedef matrix_multiply_exp::ref_type > exp_inner; + typedef matrix_multiply_exp exp_outer; + return matrix_exp(exp_outer(m1.ref().lhs,exp_inner(m1.ref().rhs,m2))); + } + + template < + typename EXP1, + typename EXP2 + > + inline const matrix_exp > operator* ( + const matrix_exp& m1, + const matrix_exp& m2 + ) + { + typedef matrix_multiply_exp exp; + return matrix_exp(exp(m1.ref(),m2.ref())); + } + + template < + typename T, + long NR, + long NC, + typename EXP, + typename MM + > + inline const matrix_exp::ref_type, matrix_exp > > operator* ( + const matrix& m1, + const matrix_exp& m2 + ) + { + typedef matrix_multiply_exp::ref_type, matrix_exp > exp; + return matrix_exp(exp(m1,m2)); + } + + template < + typename T, + long NR, + long NC, + typename EXP, + typename MM + > + inline const matrix_exp, typename matrix::ref_type, 1> > operator* ( + const matrix_exp& m1, + const matrix& m2 + ) + { + typedef matrix_multiply_exp< matrix_exp, typename matrix::ref_type, 1 > exp; + return matrix_exp(exp(m1,m2)); + } + + template < + typename T, + long NR1, + long NC1, + long NR2, + long NC2, + typename MM1, + typename MM2 + > + inline const matrix_exp::ref_type,typename matrix::ref_type > > operator* ( + const matrix& m1, + const matrix& m2 + ) + { + typedef matrix_multiply_exp::ref_type, typename matrix::ref_type > exp; + return matrix_exp(exp(m1,m2)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename LHS, + typename RHS + > + class matrix_add_expression + { + /*! + REQUIREMENTS ON LHS AND RHS + - they must be matrix_exp or matrix_ref objects (or + objects with a compatible interface). + !*/ + public: + typedef typename LHS::type type; + typedef typename LHS::mem_manager_type mem_manager_type; + typedef matrix_add_expression ref_type; + const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR; + const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC; + + matrix_add_expression ( + const matrix_add_expression& item + ) : lhs(item.lhs), rhs(item.rhs) {} + + matrix_add_expression ( + const LHS& lhs_, + const RHS& rhs_ + ) : + lhs(lhs_), + rhs(rhs_) + { + // You can only add matrices together if they both have the same number of rows and columns. + COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0); + COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0); + DLIB_ASSERT(lhs.nc() == rhs.nc() && + lhs.nr() == rhs.nr(), + "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)" + << "\n\tYou are trying to add two incompatible matrices together" + << "\n\tlhs.nr(): " << lhs.nr() + << "\n\tlhs.nc(): " << lhs.nc() + << "\n\trhs.nr(): " << rhs.nr() + << "\n\trhs.nc(): " << rhs.nc() + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + ); + + // You can only add matrices together if they both contain the same types of elements. + COMPILE_TIME_ASSERT((is_same_type::value == true)); + } + + const type operator() ( + long r, + long c + ) const { return lhs(r,c) + rhs(r,c); } + + template + bool aliases ( + const matrix& item + ) const { return lhs.aliases(item) || rhs.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return lhs.nr(); } + + long nc ( + ) const { return lhs.nc(); } + + const LHS lhs; + const RHS rhs; + }; + + template < + typename EXP1, + typename EXP2 + > + inline const matrix_exp > operator+ ( + const matrix_exp& m1, + const matrix_exp& m2 + ) + { + typedef matrix_add_expression exp; + return matrix_exp(exp(m1.ref(),m2.ref())); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename LHS, + typename RHS + > + class matrix_subtract_exp + { + /*! + REQUIREMENTS ON LHS AND RHS + - they must be matrix_exp or matrix_ref objects (or + objects with a compatible interface). + !*/ + public: + typedef typename LHS::type type; + typedef typename LHS::mem_manager_type mem_manager_type; + typedef matrix_subtract_exp ref_type; + const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR; + const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC; + + matrix_subtract_exp ( + const LHS& lhs_, + const RHS& rhs_ + ) : + lhs(lhs_), + rhs(rhs_) + { + // You can only subtract one matrix from another if they both have the same number of rows and columns. + COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0); + COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0); + DLIB_ASSERT(lhs.nc() == rhs.nc() && + lhs.nr() == rhs.nr(), + "\tconst matrix_exp operator-(const matrix_exp& lhs, const matrix_exp& rhs)" + << "\n\tYou are trying to add two incompatible matrices together" + << "\n\tlhs.nr(): " << lhs.nr() + << "\n\tlhs.nc(): " << lhs.nc() + << "\n\trhs.nr(): " << rhs.nr() + << "\n\trhs.nc(): " << rhs.nc() + << "\n\t&lhs: " << &lhs + << "\n\t&rhs: " << &rhs + ); + + // You can only subtract one matrix from another if they both contain elements of the same type. + COMPILE_TIME_ASSERT((is_same_type::value == true)); + } + + const type operator() ( + long r, + long c + ) const { return lhs(r,c) - rhs(r,c); } + + template + bool aliases ( + const matrix& item + ) const { return lhs.aliases(item) || rhs.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return lhs.nr(); } + + long nc ( + ) const { return lhs.nc(); } + + const LHS lhs; + const RHS rhs; + }; + + template < + typename EXP1, + typename EXP2 + > + inline const matrix_exp > operator- ( + const matrix_exp& m1, + const matrix_exp& m2 + ) + { + typedef matrix_subtract_exp exp; + return matrix_exp(exp(m1.ref(),m2.ref())); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename M, + typename S + > + class matrix_divscal_exp + { + /*! + REQUIREMENTS ON M + - must be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + + REQUIREMENTS ON S + - must be some kind of scalar type + !*/ + public: + typedef typename M::type type; + typedef typename M::mem_manager_type mem_manager_type; + typedef matrix_divscal_exp ref_type; + const static long NR = M::NR; + const static long NC = M::NC; + + matrix_divscal_exp ( + const M& m_, + const S& s_ + ) : + m(m_), + s(s_) + {} + + const type operator() ( + long r, + long c + ) const { return m(r,c)/s; } + + template + bool aliases ( + const matrix& item + ) const { return m.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return m.destructively_aliases(item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return m.nr(); } + + long nc ( + ) const { return m.nc(); } + + const M m; + const S s; + }; + + template < + typename EXP, + typename S + > + inline const matrix_exp, S> > operator/ ( + const matrix_exp& m, + const S& s + ) + { + typedef matrix_divscal_exp,S > exp; + return matrix_exp(exp(m,s)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename M, + typename S + > + class matrix_mulscal_exp + { + /*! + REQUIREMENTS ON M + - must be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + + REQUIREMENTS ON S + - must be some kind of scalar type + !*/ + public: + typedef typename M::type type; + typedef typename M::mem_manager_type mem_manager_type; + typedef matrix_mulscal_exp ref_type; + const static long NR = M::NR; + const static long NC = M::NC; + + matrix_mulscal_exp ( + const M& m_, + const S& s_ + ) : + m(m_), + s(s_) + {} + + const type operator() ( + long r, + long c + ) const { return m(r,c)*s; } + + template + bool aliases ( + const matrix& item + ) const { return m.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return m.destructively_aliases(item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return m.nr(); } + + long nc ( + ) const { return m.nc(); } + + const M m; + const S s; + }; + + template < + typename EXP, + typename S + > + inline const matrix_exp, S> > operator* ( + const matrix_exp& m, + const S& s + ) + { + typedef matrix_mulscal_exp,S > exp; + return matrix_exp(exp(m,s)); + } + + template < + typename EXP, + typename S + > + inline const matrix_exp, S> > operator* ( + const S& s, + const matrix_exp& m + ) + { + typedef matrix_mulscal_exp,S > exp; + return matrix_exp(exp(m,s)); + } + + template < + typename EXP + > + inline const matrix_exp, float> > operator/ ( + const matrix_exp& m, + const float& s + ) + { + typedef matrix_mulscal_exp,float > exp; + return matrix_exp(exp(m,1.0/s)); + } + + template < + typename EXP + > + inline const matrix_exp, double> > operator/ ( + const matrix_exp& m, + const double& s + ) + { + typedef matrix_mulscal_exp,double > exp; + return matrix_exp(exp(m,1.0/s)); + } + + template < + typename EXP + > + inline const matrix_exp, long double> > operator/ ( + const matrix_exp& m, + const long double& s + ) + { + typedef matrix_mulscal_exp,long double > exp; + return matrix_exp(exp(m,1.0/s)); + } + + template < + typename EXP + > + inline const matrix_exp, int> > operator- ( + const matrix_exp& m + ) + { + typedef matrix_mulscal_exp,int > exp; + return matrix_exp(exp(m,-1)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2 + > + bool operator== ( + const matrix_exp& m1, + const matrix_exp& m2 + ) + { + if (m1.nr() == m2.nr() && m1.nc() == m2.nc()) + { + for (long r = 0; r < m1.nr(); ++r) + { + for (long c = 0; c < m1.nc(); ++c) + { + if (m1(r,c) != m2(r,c)) + return false; + } + } + return true; + } + return false; + } + + template < + typename EXP1, + typename EXP2 + > + inline bool operator!= ( + const matrix_exp& m1, + const matrix_exp& m2 + ) { return !(m1 == m2); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix : public matrix_exp > + { + + COMPILE_TIME_ASSERT(num_rows >= 0 && num_cols >= 0); + + public: + typedef T type; + typedef matrix_ref ref_type; + typedef mem_manager mem_manager_type; + const static long NR = num_rows; + const static long NC = num_cols; + + matrix () : matrix_exp >(ref_type(*this)) + { + } + + explicit matrix ( + long length + ) : matrix_exp >(ref_type(*this)) + { + // This object you are trying to call matrix(length) on is not a column or + // row vector. + COMPILE_TIME_ASSERT(NR == 1 || NC == 1); + DLIB_ASSERT( length >= 0, + "\tmatrix::matrix(length)" + << "\n\tlength must be at least 0" + << "\n\tlength: " << length + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + + if (NR == 1) + { + DLIB_ASSERT(NC == 0 || NC == length, + "\tmatrix::matrix(length)" + << "\n\tSince this is a staticly sized matrix length must equal NC" + << "\n\tlength: " << length + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + + data.set_size(1,length); + } + else + { + DLIB_ASSERT(NR == 0 || NR == length, + "\tvoid matrix::set_size(length)" + << "\n\tSince this is a staticly sized matrix length must equal NR" + << "\n\tlength: " << length + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + + data.set_size(length,1); + } + } + + matrix ( + long rows, + long cols + ) : matrix_exp >(ref_type(*this)) + { + DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) && + rows >= 0 && cols >= 0, + "\tvoid matrix::matrix(rows, cols)" + << "\n\tYou have supplied conflicting matrix dimensions" + << "\n\trows: " << rows + << "\n\tcols: " << cols + << "\n\tNR: " << NR + << "\n\tNC: " << NC + ); + data.set_size(rows,cols); + } + + template + matrix ( + const matrix_exp& m + ): matrix_exp >(ref_type(*this)) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + // The matrix you are trying to assign m to is a statically sized matrix and + // m's dimensions don't match that of *this. + COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0); + COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0); + DLIB_ASSERT((NR == 0 || NR == m.nr()) && (NC == 0 || NC == m.nc()), + "\tmatrix& matrix::matrix(const matrix_exp& m)" + << "\n\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size" + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tthis: " << this + ); + + data.set_size(m.nr(),m.nc()); + + for (long r = 0; r < matrix_nr(*this,m); ++r) + { + for (long c = 0; c < matrix_nc(*this,m); ++c) + { + data(r,c) = m(r,c); + } + } + } + + matrix ( + const matrix& m + ): matrix_exp >(ref_type(*this)) + { + data.set_size(m.nr(),m.nc()); + for (long r = 0; r < matrix_nr(*this,m); ++r) + { + for (long c = 0; c < matrix_nc(*this,m); ++c) + { + data(r,c) = m(r,c); + } + } + } + + template + matrix ( + U (&array)[len] + ): matrix_exp >(ref_type(*this)) + { + COMPILE_TIME_ASSERT(NR*NC == len && len > 0); + size_t idx = 0; + for (long r = 0; r < NR; ++r) + { + for (long c = 0; c < NC; ++c) + { + data(r,c) = static_cast(array[idx]); + ++idx; + } + } + } + + T& operator() ( + long r, + long c + ) + { + DLIB_ASSERT(r < nr() && c < nc() && + r >= 0 && c >= 0, + "\tT& matrix::operator(r,c)" + << "\n\tYou must give a valid row and column" + << "\n\tr: " << r + << "\n\tc: " << c + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return data(r,c); + } + + const T& operator() ( + long r, + long c + ) const + { + DLIB_ASSERT(r < nr() && c < nc() && + r >= 0 && c >= 0, + "\tconst T& matrix::operator(r,c)" + << "\n\tYou must give a valid row and column" + << "\n\tr: " << r + << "\n\tc: " << c + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return data(r,c); + } + + T& operator() ( + long i + ) + { + // You can only use this operator on column vectors. + COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0); + DLIB_ASSERT(nc() == 1 || nr() == 1, + "\tconst type matrix::operator(i)" + << "\n\tYou can only use this operator on column or row vectors" + << "\n\ti: " << i + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + DLIB_ASSERT( ((nc() == 1 && i < nr()) || (nr() == 1 && i < nc())) && i >= 0, + "\tconst type matrix::operator(i)" + << "\n\tYou must give a valid row/column number" + << "\n\ti: " << i + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return data(i); + } + + const T& operator() ( + long i + ) const + { + // You can only use this operator on column vectors. + COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0); + DLIB_ASSERT(nc() == 1 || nr() == 1, + "\tconst type matrix::operator(i)" + << "\n\tYou can only use this operator on column or row vectors" + << "\n\ti: " << i + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + DLIB_ASSERT( ((nc() == 1 && i < nr()) || (nr() == 1 && i < nc())) && i >= 0, + "\tconst type matrix::operator(i)" + << "\n\tYou must give a valid row/column number" + << "\n\ti: " << i + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return data(i); + } + + inline operator const type ( + ) const + { + COMPILE_TIME_ASSERT(NC == 1 || NC == 0); + COMPILE_TIME_ASSERT(NR == 1 || NR == 0); + DLIB_ASSERT( nr() == 1 && nc() == 1 , + "\tmatrix::operator const type" + << "\n\tYou can only attempt to implicity convert a matrix to a scalar if" + << "\n\tthe matrix is a 1x1 matrix" + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tthis: " << this + ); + return data(0); + } + + void set_size ( + long rows, + long cols + ) + { + DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) && + rows >= 0 && cols >= 0, + "\tvoid matrix::set_size(rows, cols)" + << "\n\tYou have supplied conflicting matrix dimensions" + << "\n\trows: " << rows + << "\n\tcols: " << cols + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + if (nr() != rows || nc() != cols) + data.set_size(rows,cols); + } + + void set_size ( + long length + ) + { + // This object you are trying to call set_size(length) on is not a column or + // row vector. + COMPILE_TIME_ASSERT(NR == 1 || NC == 1); + DLIB_ASSERT( length >= 0, + "\tvoid matrix::set_size(length)" + << "\n\tlength must be at least 0" + << "\n\tlength: " << length + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + + if (NR == 1) + { + DLIB_ASSERT(NC == 0 || NC == length, + "\tvoid matrix::set_size(length)" + << "\n\tSince this is a staticly sized matrix length must equal NC" + << "\n\tlength: " << length + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + + if (nc() != length) + data.set_size(1,length); + } + else + { + DLIB_ASSERT(NR == 0 || NR == length, + "\tvoid matrix::set_size(length)" + << "\n\tSince this is a staticly sized matrix length must equal NR" + << "\n\tlength: " << length + << "\n\tNR: " << NR + << "\n\tNC: " << NC + << "\n\tthis: " << this + ); + + if (nr() != length) + data.set_size(length,1); + } + } + + long nr ( + ) const { return data.nr(); } + + long nc ( + ) const { return data.nc(); } + + long size ( + ) const { return data.nr()*data.nc(); } + + template + matrix& operator= ( + U (&array)[len] + ) + { + COMPILE_TIME_ASSERT(NR*NC == len && len > 0); + size_t idx = 0; + for (long r = 0; r < NR; ++r) + { + for (long c = 0; c < NC; ++c) + { + data(r,c) = static_cast(array[idx]); + ++idx; + } + } + return *this; + } + + template + matrix& operator= ( + const matrix_exp& m + ) + { + // The matrix you are trying to assign m to is a statically sized matrix and + // m's dimensions don't match that of *this. + COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0); + COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0); + DLIB_ASSERT((NR == 0 || nr() == m.nr()) && + (NC == 0 || nc() == m.nc()), + "\tmatrix& matrix::operator=(const matrix_exp& m)" + << "\n\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size" + << "\n\tnr(): " << nr() + << "\n\tnc(): " << nc() + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tthis: " << this + ); + COMPILE_TIME_ASSERT((is_same_type::value == true)); + if (m.destructively_aliases(*this) == false) + { + set_size(m.nr(),m.nc()); + for (long r = 0; r < matrix_nr(*this,m); ++r) + { + for (long c = 0; c < matrix_nc(*this,m); ++c) + { + data(r,c) = m(r,c); + } + } + } + else + { + // we have to use a temporary matrix_data object here because + // this->data is aliased inside the matrix_exp m somewhere. + matrix_data temp; + temp.set_size(m.nr(),m.nc()); + for (long r = 0; r < matrix_nr(temp,m); ++r) + { + for (long c = 0; c < matrix_nc(temp,m); ++c) + { + temp(r,c) = m(r,c); + } + } + data.consume(temp); + } + return *this; + } + + template + matrix& operator += ( + const matrix_exp& m + ) + { + // The matrix you are trying to assign m to is a statically sized matrix and + // m's dimensions don't match that of *this. + COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0); + COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0); + DLIB_ASSERT(this->nr() == m.nr() && this->nc() == m.nc(), + "\tmatrix& matrix::operator+=(const matrix_exp& m)" + << "\n\tYou are trying to add a dynamically sized matrix to a statically sized matrix with the wrong size" + << "\n\tthis->nr(): " << nr() + << "\n\tthis->nc(): " << nc() + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tthis: " << this + ); + COMPILE_TIME_ASSERT((is_same_type::value == true)); + if (m.destructively_aliases(*this) == false) + { + for (long r = 0; r < matrix_nr(*this,m); ++r) + { + for (long c = 0; c < matrix_nc(*this,m); ++c) + { + data(r,c) += m(r,c); + } + } + } + else + { + // we have to use a temporary matrix_data object here because + // this->data is aliased inside the matrix_exp m somewhere. + matrix_data temp; + temp.set_size(m.nr(),m.nc()); + for (long r = 0; r < matrix_nr(temp,m); ++r) + { + for (long c = 0; c < matrix_nc(temp,m); ++c) + { + temp(r,c) = m(r,c) + data(r,c); + } + } + data.consume(temp); + } + return *this; + } + + + template + matrix& operator -= ( + const matrix_exp& m + ) + { + // The matrix you are trying to assign m to is a statically sized matrix and + // m's dimensions don't match that of *this. + COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0); + COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0); + DLIB_ASSERT(this->nr() == m.nr() && this->nc() == m.nc(), + "\tmatrix& matrix::operator-=(const matrix_exp& m)" + << "\n\tYou are trying to subtract a dynamically sized matrix from a statically sized matrix with the wrong size" + << "\n\tthis->nr(): " << nr() + << "\n\tthis->nc(): " << nc() + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tthis: " << this + ); + COMPILE_TIME_ASSERT((is_same_type::value == true)); + if (m.destructively_aliases(*this) == false) + { + for (long r = 0; r < matrix_nr(*this,m); ++r) + { + for (long c = 0; c < matrix_nc(*this,m); ++c) + { + data(r,c) -= m(r,c); + } + } + } + else + { + // we have to use a temporary matrix_data object here because + // this->data is aliased inside the matrix_exp m somewhere. + matrix_data temp; + temp.set_size(m.nr(),m.nc()); + for (long r = 0; r < matrix_nr(temp,m); ++r) + { + for (long c = 0; c < matrix_nc(temp,m); ++c) + { + temp(r,c) = data(r,c) - m(r,c); + } + } + data.consume(temp); + } + return *this; + } + + matrix& operator += ( + const matrix& m + ) + { + const long size = m.nr()*m.nc(); + for (long i = 0; i < size; ++i) + data(i) += m.data(i); + return *this; + } + + matrix& operator -= ( + const matrix& m + ) + { + const long size = m.nr()*m.nc(); + for (long i = 0; i < size; ++i) + data(i) -= m.data(i); + return *this; + } + + matrix& operator *= ( + const T& a + ) + { + const long size = data.nr()*data.nc(); + for (long i = 0; i < size; ++i) + data(i) *= a; + return *this; + } + + matrix& operator /= ( + const T& a + ) + { + const long size = data.nr()*data.nc(); + for (long i = 0; i < size; ++i) + data(i) /= a; + return *this; + } + + matrix& operator= ( + const matrix& m + ) + { + if (this != &m) + { + set_size(m.nr(),m.nc()); + const long size = m.nr()*m.nc(); + for (long i = 0; i < size; ++i) + data(i) = m.data(i); + } + return *this; + } + + void swap ( + matrix& item + ) + { + data.swap(item.data); + } + + private: + matrix_data data; + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + + template < + typename T, + long NR, + long NC, + typename mm + > + void swap( + matrix& a, + matrix& b + ) { a.swap(b); } + + template < + typename T, + long NR, + long NC, + typename mm + > + void serialize ( + const matrix& item, + std::ostream& out + ) + { + try + { + serialize(item.nr(),out); + serialize(item.nc(),out); + for (long r = 0; r < item.nr(); ++r) + { + for (long c = 0; c < item.nc(); ++c) + { + serialize(item(r,c),out); + } + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing dlib::matrix"); + } + } + + template < + typename T, + long NR, + long NC, + typename mm + > + void deserialize ( + matrix& item, + std::istream& in + ) + { + try + { + long nr, nc; + deserialize(nr,in); + deserialize(nc,in); + + if (NR != 0 && nr != NR) + throw serialization_error("Error while deserializing a dlib::matrix. Invalid rows"); + if (NC != 0 && nc != NC) + throw serialization_error("Error while deserializing a dlib::matrix. Invalid columns"); + + item.set_size(nr,nc); + for (long r = 0; r < nr; ++r) + { + for (long c = 0; c < nc; ++c) + { + deserialize(item(r,c),in); + } + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing a dlib::matrix"); + } + } + + template < + typename EXP + > + std::ostream& operator<< ( + std::ostream& out, + const matrix_exp& m + ) + { + using namespace std; + const streamsize old = out.width(); + + // first figure out how wide we should make each field + string::size_type w = 0; + ostringstream sout; + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + sout << m(r,c); + w = std::max(sout.str().size(),w); + sout.str(""); + } + } + + // now actually print it + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + out.width(static_cast(w)); + out << m(r,c) << " "; + } + out << "\n"; + } + out.width(old); + return out; + } + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef _MSC_VER +// put that warning back to its default setting +#pragma warning(default : 4355) +#endif + +#endif // DLIB_MATRIx_ + diff --git a/dlib/matrix/matrix_abstract.h b/dlib/matrix/matrix_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..41bf38acda4cab367227ee8d0262ee0401d29357 --- /dev/null +++ b/dlib/matrix/matrix_abstract.h @@ -0,0 +1,802 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MATRIx_ABSTRACT_ +#ifdef DLIB_MATRIx_ABSTRACT_ + +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows, + long num_cols, + typename mem_manager + > + class matrix_ref + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a copyable (via the copy constructor but not + operator=) reference to a matrix object. + !*/ + public: + typedef T type; + typedef matrix_ref ref_type; + typedef mem_manager mem_manager_type; + const static long NR = num_rows; + const static long NC = num_cols; + + matrix_ref ( + const matrix& m + ); + /*! + ensures + - #aliases(m) == true + (i.e. #*this references/aliases the matrix m.) + !*/ + + matrix_ref ( + const matrix_ref& r + ); + /*! + ensures + - #*this references/aliases the same matrix as r does. + !*/ + + const T& operator() ( + long r, + long c + ) const; + /*! + requires + - 0 <= r < nr() + - 0 <= c < nc() + ensures + - returns a const reference to the value at the given row and column in + this matrix. + !*/ + + long nr ( + ) const; + /*! + ensures + - returns the number of rows in the matrix referenced by *this + !*/ + + long nc ( + ) const; + /*! + ensures + - returns the number of columns in the matrix referenced by *this + !*/ + + long size ( + ) const; + /*! + ensures + - returns nr()*nc() + !*/ + + template + bool destructively_aliases ( + const matrix& item + ) const; + /*! + ensures + - returns false + !*/ + + template + bool aliases ( + const matrix& item + ) const; + /*! + ensures + - if (item is the matrix referenced by *this) then + - returns true + - else + - returns false + !*/ + + const ref_type& ref( + ) const { return *this; } + /*! + ensures + - returns *this + !*/ + + private: + // no assignment operator + matrix_ref& operator=(const matrix_ref&); + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + class matrix_exp + { + /*! + REQUIREMENTS ON EXP + - must be a matrix_exp or matrix_ref object (or an object with + a compatible interface) + + WHAT THIS OBJECT REPRESENTS + This object represents an expression that evaluates to a matrix + of nr() rows and nc() columns. + + The reason for having an object that represents an expression is that it + allows us to use the "expression templates" technique to eliminate the + temporary matrix objects that would normally be returned from expressions + such as M = A+B+C+D; Normally each invocation of the + operator would + construct and return a temporary matrix object but using this technique we + can avoid creating all of these temporary objects and receive a large + speed boost. + + Note that every time you invoke operator() on this object it recomputes + its result which may not be what you want to do. For example, if you + are going to be accessing the same element over and over it might + be faster to assign the matrix_exp to a temporary matrix and then + use that temporary. + !*/ + + public: + typedef typename EXP::type type; + typedef typename EXP::ref_type ref_type; + typedef typename EXP::mem_manager_type mem_manager_type; + const static long NR = EXP::NR; + const static long NC = EXP::NC; + typedef matrix matrix_type; + + matrix_exp ( + const EXP& exp + ); + /*! + ensures + - #ref() == exp.ref() + !*/ + + const type operator() ( + long r, + long c + ) const; + /*! + requires + - 0 <= r < nr() + - 0 <= c < nc() + ensures + - returns ref()(r,c) + (i.e. returns the value at the given row and column that would be in + the matrix represented by this matrix expression) + !*/ + + const type operator() ( + long i + ) const; + /*! + requires + - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector) + - if (nc() == 1) then + - 0 <= i < nr() + - else + - 0 <= i < nc() + ensures + - if (nc() == 1) then + - returns (*this)(i,0) + - else + - returns (*this)(0,i) + !*/ + + operator const type ( + ) const; + /*! + requires + - nr() == 1 + - nc() == 1 + ensures + - returns (*this)(0,0) + !*/ + + long nr ( + ) const; + /*! + ensures + - returns the number of rows in this matrix expression. + !*/ + + long nc ( + ) const; + /*! + ensures + - returns the number of columns in this matrix expression. + !*/ + + long size ( + ) const; + /*! + ensures + - returns nr()*nc() + !*/ + + template + bool aliases ( + const matrix& item + ) const; + /*! + ensures + - if (this matrix expression contains/aliases the given matrix or contains + any subexpressions that contain/alias the given matrix) then + - returns true + - else + - returns false + !*/ + + template + bool destructively_aliases ( + const matrix& item + ) const; + /*! + ensures + - returns true if the following expression would evaluate incorrectly and false otherwise: + for (long r = 0; r < nr(); ++r) + for (long c = 0; c < nc(); ++c) + item(r,c) = (*this)(r,c) + - That is, if this matrix expression aliases item in such a way that a modification + to element item(r,c) causes a change in the value of something other than + (*this)(r,c) then this function returns true. Otherwise, returns false + !*/ + + const ref_type& ref ( + ) const; + /*! + ensures + - returns a copyable reference to the subexpression contained in *this. + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + /* + Note that these operator prototypes are not correct C++ (the real versions, which + you can see in the implementation are really complex and so probably would + distract/confuse people if shown here). Think of this as just a list of the + operators available to you and what they do. + */ + + const matrix_exp operator* ( + const matrix_exp& m1, + const matrix_exp& m2 + ); + /*! + requires + - m1.nc() == m2.nr() + - m1 and m2 both contain elements of the same type + ensures + - returns the result of doing the matrix multiplication m1*m2. The resulting + matrix will have m1.nr() rows and m2.nc() columns. + !*/ + + const matrix_exp operator+ ( + const matrix_exp& m1, + const matrix_exp& m2 + ); + /*! + requires + - m1.nr() == m2.nr() + - m1.nc() == m2.nc() + - m1 and m2 both contain elements of the same type + ensures + - returns a matrix R such that for all valid r and c: + R(r,c) == m1(r,c) + m2(r,c) + (i.e. returns the result of doing a pairwise addition of the matrices m1 and m2.) + The resulting matrix will have the same dimensions as the originals. + !*/ + + const matrix_exp operator- ( + const matrix_exp& m1, + const matrix_exp& m2 + ); + /*! + requires + - m1.nr() == m2.nr() + - m1.nc() == m2.nc() + - m1 and m2 both contain elements of the same type + ensures + - returns a matrix R such that for all valid r and c: + R(r,c) == m1(r,c) - m2(r,c) + (i.e. returns the result of doing a pairwise subtraction of the matrices m1 and m2.) + The resulting matrix will have the same dimensions as the originals. + !*/ + + template + const matrix_exp operator* ( + const matrix_exp& m, + const T& value + ); + /*! + ensures + - returns the result of multiplying all the elements of matrix m by the given + scalar value. The resulting matrix will have the same dimensions as m. + !*/ + + template + const matrix_exp operator* ( + const T& value, + const matrix_exp& m + ); + /*! + ensures + - returns the result of multiplying all the elements of matrix m by the given + scalar value. The resulting matrix will have the same dimensions as m. + !*/ + + const matrix_exp operator- ( + const matrix_exp& m + ); + /*! + ensures + - returns -1*m + !*/ + + template + const matrix_exp operator/ ( + const matrix_exp& m, + const T& value + ); + /*! + ensures + - returns the result of dividing all the elements of matrix m by the given + scalar value. The resulting matrix will have the same dimensions as m. + !*/ + + bool operator== ( + const matrix_exp& m1, + const matrix_exp& m2 + ); + /*! + ensures + - if (m1.nr() == m2.nr() && m1.nc() == m2.nc() && + for all valid r and c: m1(r,c) == m2(r,c) ) then + - returns true + - else + - returns false + !*/ + + bool operator!= ( + const matrix_exp& m1, + const matrix_exp& m2 + ); + /*! + ensures + - returns !(m1 == m2) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long num_rows = 0, + long num_cols = 0, + typename mem_manager = memory_manager::kernel_1a + > + class matrix : public matrix_exp > + { + /*! + REQUIREMENTS ON num_rows and num_cols + both must be bigger than or equal to 0 + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + INITIAL VALUE + - if (num_rows > 0) then + - nr() == num_rows + - else + - nr() == 0 + + - if (num_cols > 0) then + - nc() == num_cols + - else + - nc() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a matrix of nr() rows and nc() columns. This object + is also a matrix_exp. Thus it can be used in all of the above + global operators. + + The number of rows and columns of this object are determined by the template + arguments num_rows and num_cols. If num_rows or num_cols are 0 then + the matrix starts out empty (i.e. nr() == 0 and nc() == 0) and you may change + its size via the set_size() member function. + + Setting num_rows or num_cols to something other than 0 causes that dimension + to have a fixed size. Setting a fixed size at compile time is useful because + any errors related to operating on matrices with incompatible dimensions will + be detected at compile time. It also allows the compiler to perform loop + unrolling which can result in substantially faster code. + + Also note that the elements of this matrix are contiguous in memory and + stored in row major order. Additionally, all memory allocations are + performed using the memory manager object supplied as template argument. + !*/ + + public: + typedef T type; + typedef matrix_ref ref_type; + typedef mem_manager mem_manager_type; + const static long NR = num_rows; + const static long NC = num_cols; + + matrix ( + ); + /*! + ensures + - #*this is properly initialized + - #aliases(*this) == true + - #ref().aliases(*this) == true + !*/ + + explicit matrix ( + long length + ); + /*! + requires + - NR == 1 || NC == 1 (i.e. this must be a column or row vector) + - length >= 0 + - if (NR == 1 && NC > 0) then + - length == NC + - if (NC == 1 && NR > 0) then + - length == NR + ensures + - #*this is properly initialized + - #aliases(*this) == true + - #ref().aliases(*this) == true + - if (NR == 1) then + - #nr() == 1 + - #nc() == length + - else + - #nr() == length + - #nc() == 1 + !*/ + + matrix ( + long rows, + long cols + ); + /*! + requires + - rows == NR || NR == 0 + - cols == NC || NC == 0 + - rows >= 0 && cols >= 0 + ensures + - #*this is properly initialized + - #aliases(*this) == true + - #ref().aliases(*this) == true + - #nr() == rows + - #nc() == cols + !*/ + + template + matrix ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == T + (i.e. m contains the same type as *this does) + - if (NR != 0) then NR == m.nr() + - if (NC != 0) then NC == m.nc() + ensures + - #*this == m + - #aliases(*this) == true + - #ref().aliases(*this) == true + !*/ + + template + matrix ( + U (&array)[len] + ); + /*! + requires + - NR != 0 && NC != 0 (i.e. you can only use this constructor on statically sized matrices) + - len == nr()*nc() (i.e. the array you give here must be the right size) + ensures + - for all valid r and c: + #(*this)(r,c) == array[r*nc() + c] + (i.e. initializes this matrix with the contents of the given array) + - #aliases(*this) == true + - #ref().aliases(*this) == true + !*/ + + T& operator() ( + long r, + long c + ); + /*! + requires + - 0 <= r < nr() + - 0 <= c < nc() + ensures + - returns a reference to the value at the given row and column in + this matrix. + !*/ + + const T& operator() ( + long r, + long c + ) const; + /*! + requires + - 0 <= r < nr() + - 0 <= c < nc() + ensures + - returns a const reference to the value at the given row and column in + this matrix. + !*/ + + T& operator() ( + long i + ); + /*! + requires + - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector) + - if (nc() == 1) then + - 0 <= i < nr() + - else + - 0 <= i < nc() + ensures + - if (nc() == 1) then + - returns a reference to (*this)(i,0) + - else + - returns a reference to (*this)(0,i) + !*/ + + const T& operator() ( + long i + ) const; + /*! + requires + - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector) + - if (nc() == 1) then + - 0 <= i < nr() + - else + - 0 <= i < nc() + ensures + - if (nc() == 1) then + - returns a reference to (*this)(i,0) + - else + - returns a reference to (*this)(0,i) + !*/ + + operator const type ( + ) const; + /*! + requires + - nr() == 1 + - nc() == 1 + ensures + - returns (*this)(0,0) + !*/ + + long nr( + ) const; + /*! + ensures + - returns the number of rows in this matrix + !*/ + + long nc( + ) const; + /*! + ensures + - returns the number of columns in this matrix + !*/ + + long size ( + ) const; + /*! + ensures + - returns nr()*nc() + !*/ + + void set_size ( + long rows, + long cols + ); + /*! + requires + - rows == NR || NR == 0 + - cols == NC || NC == 0 + - rows >= 0 && cols >= 0 + ensures + - #nr() == rows + - #nc() == cols + !*/ + + void set_size ( + long length + ); + /*! + requires + - NR == 1 || NC == 1 (i.e. this must be a column or row vector) + - length >= 0 + - if (NR == 1 && NC > 0) then + - length == NC + - if (NC == 1 && NR > 0) then + - length == NR + ensures + - if (NR == 1) then + - #nr() == 1 + - #nc() == length + - else + - #nr() == length + - #nc() == 1 + !*/ + + template + matrix& operator= ( + U (&array)[len] + ); + /*! + requires + - len == nr()*nc() (i.e. the array you give here must be the right size) + ensures + - for all valid r and c: + #(*this)(r,c) == array[r*nc() + c] + (i.e. loads this matrix with the contents of the given array) + - returns *this + !*/ + + template + matrix& operator= ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == T + (i.e. m contains the same type as *this does) + - if (NR != 0) then NR == m.nr() + - if (NC != 0) then NC == m.nc() + ensures + - copies the given matrix expression m to *this + - returns *this + !*/ + + template + matrix& operator += ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == T + - nr() == m.nr() + - nc() == m.nc() + ensures + - #(*this) == *this + m + - returns *this + !*/ + + template + matrix& operator -= ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == T + - nr() == m.nr() + - nc() == m.nc() + ensures + - #(*this) == *this - m + - returns *this + !*/ + + matrix& operator *= ( + const T& a + ); + /*! + ensures + - #(*this) == *this * a + - returns *this + !*/ + + matrix& operator /= ( + const T& a + ); + /*! + ensures + - #(*this) == *this / a + - returns *this + !*/ + + void swap ( + matrix& item + ); + /*! + ensures + - swaps *this and item + !*/ + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename mm + > + void swap( + matrix& a, + matrix& b + ) { a.swap(b); } + /*! + Provides a global swap function + !*/ + + template < + typename T, + long NR, + long NC, + typename mm + > + void serialize ( + const matrix& item, + std::ostream& out + ); + /*! + Provides serialization support + !*/ + + template < + typename T, + long NR, + long NC, + typename mm + > + void deserialize ( + matrix& item, + std::istream& in + ); + /*! + Provides deserialization support + !*/ + + template < + typename EXP + > + std::ostream& operator<< ( + std::ostream& out, + const matrix_exp& m + ); + /*! + ensures + - writes m to the given out stream in a form suitable for human consumption. + - returns out + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MATRIx_ABSTRACT_ + diff --git a/dlib/matrix/matrix_math_functions.h b/dlib/matrix/matrix_math_functions.h new file mode 100644 index 0000000000000000000000000000000000000000..8f7f67fe9405032c930b6f2928fb7c74d6e54ede --- /dev/null +++ b/dlib/matrix/matrix_math_functions.h @@ -0,0 +1,418 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MATRIx_MATH_FUNCTIONS +#define DLIB_MATRIx_MATH_FUNCTIONS + +#include "matrix_utilities.h" +#include "matrix.h" +#include "../algs.h" +#include +#include +#include + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + +#define DLIB_MATRIX_SIMPLE_STD_FUNCTION(name) template \ + struct op_##name : has_nondestructive_aliasing, preserves_dimensions \ + { \ + typedef typename EXP::type type; \ + template \ + static type apply ( const M& m, long r, long c) \ + { return static_cast(std::name(m(r,c))); } \ + }; \ + template < typename EXP > \ + const matrix_exp,op_##name > > name ( \ + const matrix_exp& m) \ + { \ + typedef matrix_unary_exp,op_##name > exp; \ + return matrix_exp(exp(m)); \ + } + +// ---------------------------------------------------------------------------------------- + +DLIB_MATRIX_SIMPLE_STD_FUNCTION(abs) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(sqrt) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(log) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(log10) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(exp) + +DLIB_MATRIX_SIMPLE_STD_FUNCTION(conj) + +DLIB_MATRIX_SIMPLE_STD_FUNCTION(ceil) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(floor) + +DLIB_MATRIX_SIMPLE_STD_FUNCTION(sin) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(cos) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(tan) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(sinh) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(cosh) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(tanh) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(asin) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(acos) +DLIB_MATRIX_SIMPLE_STD_FUNCTION(atan) + +// ---------------------------------------------------------------------------------------- + + template + struct op_sigmoid : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, long r, long c) + { + const double e = 2.718281828459045235360287471352; + double temp = std::pow(e,-m(r,c)); + return static_cast(1.0/(1.0 + temp)); + } + }; + + template < + typename EXP + > + const matrix_exp,op_sigmoid > > sigmoid ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_sigmoid > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_round_zeros : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, const T& eps, long r, long c) + { + const type temp = m(r,c); + if (temp >= eps || temp <= -eps) + return temp; + else + return 0; + } + }; + + template < + typename EXP + > + const matrix_exp,typename EXP::type,op_round_zeros > > round_zeros ( + const matrix_exp& m + ) + { + // you can only round matrices that contain floats, doubles or long doubles. + COMPILE_TIME_ASSERT(( + is_same_type::value == true || + is_same_type::value == true || + is_same_type::value == true + )); + typedef matrix_scalar_binary_exp,typename EXP::type, op_round_zeros > exp; + return matrix_exp(exp(m,10*std::numeric_limits::epsilon())); + } + + template < + typename EXP + > + const matrix_exp,typename EXP::type,op_round_zeros > > round_zeros ( + const matrix_exp& m, + typename EXP::type eps + ) + { + // you can only round matrices that contain floats, doubles or long doubles. + COMPILE_TIME_ASSERT(( + is_same_type::value == true || + is_same_type::value == true || + is_same_type::value == true + )); + typedef matrix_scalar_binary_exp,typename EXP::type, op_round_zeros > exp; + return matrix_exp(exp(m,eps)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_cubed : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, long r, long c) + { return m(r,c)*m(r,c)*m(r,c); } + }; + + template < + typename EXP + > + const matrix_exp,op_cubed > > cubed ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_cubed > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_squared : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, long r, long c) + { return m(r,c)*m(r,c); } + }; + + template < + typename EXP + > + const matrix_exp,op_squared > > squared ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_squared > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_pow : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, const S& s, long r, long c) + { return static_cast(std::pow(m(r,c),s)); } + }; + + template < + typename EXP, + typename S + > + const matrix_exp,typename EXP::type,op_pow > > pow ( + const matrix_exp& m, + const S& s + ) + { + // you can only round matrices that contain floats, doubles or long doubles. + COMPILE_TIME_ASSERT(( + is_same_type::value == true || + is_same_type::value == true || + is_same_type::value == true + )); + typedef matrix_scalar_binary_exp,typename EXP::type,op_pow > exp; + return matrix_exp(exp(m,s)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_reciprocal : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, long r, long c) + { + const type temp = m(r,c); + if (temp != 0) + return static_cast(1.0/temp); + else + return 0; + } + }; + + template < + typename EXP + > + const matrix_exp,op_reciprocal > > reciprocal ( + const matrix_exp& m + ) + { + // you can only compute reciprocal matrices that contain floats, doubles or long doubles. + COMPILE_TIME_ASSERT(( + is_same_type::value == true || + is_same_type::value == true || + is_same_type::value == true + )); + typedef matrix_unary_exp,op_reciprocal > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_normalize : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, const type& s, long r, long c) + { + return m(r,c)*s; + } + }; + + template < + typename EXP + > + const matrix_exp,typename EXP::type,op_normalize > > normalize ( + const matrix_exp& m + ) + { + // you can only compute normalized matrices that contain floats, doubles or long doubles. + COMPILE_TIME_ASSERT(( + is_same_type::value == true || + is_same_type::value == true || + is_same_type::value == true + )); + typedef matrix_scalar_binary_exp,typename EXP::type, op_normalize > exp; + + typename EXP::type temp = std::sqrt(sum(squared(m))); + if (temp != 0.0) + temp = 1.0/temp; + + return matrix_exp(exp(m,temp)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_round : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, long r, long c) + { + return static_cast(std::floor(m(r,c)+0.5)); + } + }; + + template < + typename EXP + > + const matrix_exp,op_round > > round ( + const matrix_exp& m + ) + { + // you can only round matrices that contain floats, doubles or long doubles. + COMPILE_TIME_ASSERT(( + is_same_type::value == true || + is_same_type::value == true || + is_same_type::value == true + )); + typedef matrix_unary_exp,op_round > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_complex_matrix : has_nondestructive_aliasing, preserves_dimensions + { + typedef std::complex type; + + template + static type apply ( const M1& m1, const M2& m2 , long r, long c) + { return type(m1(r,c),m2(r,c)); } + }; + + template < + typename EXP1, + typename EXP2 + > + const matrix_exp,matrix_exp,op_complex_matrix > > complex_matrix ( + const matrix_exp& real_part, + const matrix_exp& imag_part + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0); + + DLIB_ASSERT(real_part.nr() == imag_part.nr() && + real_part.nc() == imag_part.nc(), + "\tconst matrix_exp::type complex_matrix(real_part, imag_part)" + << "\n\tYou can only make a complex matrix from two equally sized matrices" + << "\n\treal_part.nr(): " << real_part.nr() + << "\n\treal_part.nc(): " << real_part.nc() + << "\n\timag_part.nr(): " << imag_part.nr() + << "\n\timag_part.nc(): " << imag_part.nc() + ); + typedef matrix_binary_exp,matrix_exp,op_complex_matrix > exp; + return matrix_exp(exp(real_part,imag_part)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_norm : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type::value_type type; + template + static type apply ( const M& m, long r, long c) + { return std::norm(m(r,c)); } + }; + + template < + typename EXP + > + const matrix_exp,op_norm > > norm ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_norm > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_real : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type::value_type type; + template + static type apply ( const M& m, long r, long c) + { return std::real(m(r,c)); } + }; + + template < + typename EXP + > + const matrix_exp,op_real > > real ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_real > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_imag : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type::value_type type; + template + static type apply ( const M& m, long r, long c) + { return std::imag(m(r,c)); } + }; + + template < + typename EXP + > + const matrix_exp,op_imag > > imag ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_imag > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MATRIx_MATH_FUNCTIONS + diff --git a/dlib/matrix/matrix_math_functions_abstract.h b/dlib/matrix/matrix_math_functions_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b94ad3fde104d0efd903e0096bd4f45fb0f24235 --- /dev/null +++ b/dlib/matrix/matrix_math_functions_abstract.h @@ -0,0 +1,515 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_ +#ifdef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_ + +#include "matrix_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Exponential Functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp exp ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::exp(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp log10 ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::log10(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp log ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::log(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp sqrt ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == sqrt(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template + const matrix_exp pow ( + const matrix_exp& m, + const T& e + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == pow(m(r,c),e) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp squared ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == m(r,c)*m(r,c) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp cubed ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == m(r,c)*m(r,c)*m(r,c) + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Miscellaneous +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp sigmoid ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == 1/(1 + pow(e,-m(r,c))) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp abs ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::abs(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp reciprocal ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + - if (m(r,c) != 0) then + - R(r,c) == 1.0/m(r,c) + - else + - R(r,c) == 0 + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp normalize ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - if (sqrt(sum(squared(m))) != 0) then + - returns m/sqrt(sum(squared(m))) + - else + - returns m + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Rounding numbers one way or another +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp round ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == m(r,c) rounded to the nearest integral value + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp ceil ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::ceil(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp floor ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::floor(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp round_zeros ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - let eps == 10*std::numeric_limits::epsilon() + - for all valid r and c: + - if (m(r,c) >= eps || m(r,c) <= eps) then + - R(r,c) == m(r,c) + - else + - R(r,c) == 0 + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp round_zeros ( + const matrix_exp& m, + matrix_exp::type eps + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + - if (m(r,c) >= eps || m(r,c) <= eps) then + - R(r,c) == m(r,c) + - else + - R(r,c) == 0 + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Complex number utility functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp conj ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == std::complex + ensures + - returns a matrix R such that: + - R::type == std::complex + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::conj(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp norm ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == std::complex + ensures + - returns a matrix R such that: + - R::type == T + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::norm(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp imag ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == std::complex + ensures + - returns a matrix R such that: + - R::type == T + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::imag(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp real ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == std::complex + ensures + - returns a matrix R such that: + - R::type == T + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::real(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp complex_matrix ( + const matrix_exp& real_part, + const matrix_exp& imag_part + ); + /*! + requires + - real_part.nr() == imag_part.nr() + - real_part.nc() == imag_part.nc() + - real_part and imag_part both contain the same type of element + ensures + - returns a matrix R such that: + - R::type == std::complex where T is whatever type real_part and imag_part used. + - R has the same dimensions as real_part and imag_part + - for all valid r and c: + R(r,c) == std::complex(real_part(r,c),imag_part(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Trigonometric Functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp sin ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::sin(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp cos ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::cos(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp tan ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::tan(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp asin ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::asin(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp acos ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::acos(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp atan ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::atan(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp sinh ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::sinh(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp cosh ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::cosh(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp tanh ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == float, double, or long double + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R(r,c) == std::tanh(m(r,c)) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_ + diff --git a/dlib/matrix/matrix_utilities.h b/dlib/matrix/matrix_utilities.h new file mode 100644 index 0000000000000000000000000000000000000000..f9f6de0f5fe0583e986e984662e4fcc67631c237 --- /dev/null +++ b/dlib/matrix/matrix_utilities.h @@ -0,0 +1,2888 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MATRIx_UTILITIES_ +#define DLIB_MATRIx_UTILITIES_ + +#include "matrix_utilities_abstract.h" +#include "matrix.h" +#include +#include +#include +#include "../pixel.h" +#include "../geometry.h" +#include "../is_kind.h" +#include "../stl_checked.h" +#include + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template + struct is_matrix > { static const bool value = true; }; + template + struct is_matrix > { static const bool value = true; }; + template + struct is_matrix > { static const bool value = true; }; + /* + is_matrix::value == 1 if T is a matrix type else 0 + */ + +// ---------------------------------------------------------------------------------------- + + /* + templates for finding the max of two matrix expressions' dimensions + */ + + template + struct max_nr; + + template + struct max_nr + { + const static long val = EXP1::NR; + }; + + template + struct max_nr + { + const static long val = (EXP1::NR > EXP2::NR) ? (EXP1::NR) : (EXP2::NR); + }; + + template + struct max_nr + { + private: + const static long max12 = (EXP1::NR > EXP2::NR) ? (EXP1::NR) : (EXP2::NR); + public: + const static long val = (max12 > EXP3::NR) ? (max12) : (EXP3::NR); + }; + + template + struct max_nr + { + private: + const static long max12 = (EXP1::NR > EXP2::NR) ? (EXP1::NR) : (EXP2::NR); + const static long max34 = (EXP3::NR > EXP4::NR) ? (EXP3::NR) : (EXP4::NR); + public: + const static long val = (max12 > max34) ? (max12) : (max34); + }; + + + template + struct max_nc; + + template + struct max_nc + { + const static long val = EXP1::NC; + }; + + template + struct max_nc + { + const static long val = (EXP1::NC > EXP2::NC) ? (EXP1::NC) : (EXP2::NC); + }; + + template + struct max_nc + { + private: + const static long max12 = (EXP1::NC > EXP2::NC) ? (EXP1::NC) : (EXP2::NC); + public: + const static long val = (max12 > EXP3::NC) ? (max12) : (EXP3::NC); + }; + + template + struct max_nc + { + private: + const static long max12 = (EXP1::NC > EXP2::NC) ? (EXP1::NC) : (EXP2::NC); + const static long max34 = (EXP3::NC > EXP4::NC) ? (EXP3::NC) : (EXP4::NC); + public: + const static long val = (max12 > max34) ? (max12) : (max34); + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename OP + > + class matrix_zeroary_exp; + + template < + typename M, + typename OP + > + class matrix_unary_exp; + + template < + typename M1, + typename M2, + typename OP + > + class matrix_binary_exp; + + struct has_destructive_aliasing + { + template + static bool destructively_aliases ( + const M& m, + const matrix& item + ) { return m.aliases(item); } + + template + static bool destructively_aliases ( + const M1& m1, + const M2& m2, + const matrix& item + ) { return m1.aliases(item) || m2.aliases(item) ; } + }; + + struct has_nondestructive_aliasing + { + template + static bool destructively_aliases ( + const M& m, + const matrix& item + ) { return m.destructively_aliases(item); } + + template + static bool destructively_aliases ( + const M1& m1, + const M2& m2, + const matrix& item + ) { return m1.destructively_aliases(item) || m2.destructively_aliases(item) ; } + }; + + template + struct preserves_dimensions + { + const static long NR = max_nr::val; + const static long NC = max_nc::val; + + typedef typename EXP1::mem_manager_type mem_manager_type; + + template + static long nr (const M& m) { return m.nr(); } + template + static long nc (const M& m) { return m.nc(); } + template + static long nr (const M1& m1, const M2& ) { return m1.nr(); } + template + static long nc (const M1& m1, const M2& ) { return m1.nc(); } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const typename matrix_exp::type max ( + const matrix_exp& m + ) + { + typedef typename matrix_exp::type type; + + type val = m(0,0); + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + type temp = m(r,c); + if (temp > val) + val = temp; + } + } + return val; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const typename matrix_exp::type min ( + const matrix_exp& m + ) + { + typedef typename matrix_exp::type type; + + type val = m(0,0); + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + type temp = m(r,c); + if (temp < val) + val = temp; + } + } + return val; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace nric + { + // This namespace contains stuff from Numerical Recipes in C + + template + inline T pythag(const T& a, const T& b) + { + T absa,absb; + absa=std::abs(a); + absb=std::abs(b); + if (absa > absb) + { + T val = absb/absa; + val *= val; + return absa*std::sqrt(1.0+val); + } + else + { + if (absb == 0.0) + { + return 0.0; + } + else + { + T val = absa/absb; + val *= val; + return absb*std::sqrt(1.0+val); + } + } + } + + template + inline T sign(const T& a, const T& b) + { + if (b < 0) + { + return -std::abs(a); + } + else + { + return std::abs(a); + } + } + + + template < + typename T, + long M, long N, + long wN, long wX, + long vN, + long rN, long rX, + typename MM1, + typename MM2, + typename MM3, + typename MM4 + > + bool svdcmp( + matrix& a, + matrix& w, + matrix& v, + matrix& rv1 + ) + /*! ( this function is derived from the one in numerical recipes in C chapter 2.6) + requires + - w.nr() == a.nc() + - w.nc() == 1 + - v.nr() == a.nc() + - v.nc() == a.nc() + - rv1.nr() == a.nc() + - rv1.nc() == 1 + ensures + - computes the singular value decomposition of a + - let W be the matrix such that diag(W) == #w then: + - a == #a*W*trans(#v) + - trans(#a)*#a == identity matrix + - trans(#v)*#v == identity matrix + - #rv1 == some undefined value + - returns true for success and false for failure + !*/ + { + + DLIB_ASSERT( + w.nr() == a.nc() && + w.nc() == 1 && + v.nr() == a.nc() && + v.nc() == a.nc() && + rv1.nr() == a.nc() && + rv1.nc() == 1, ""); + + COMPILE_TIME_ASSERT(wX == 0 || wX == 1); + COMPILE_TIME_ASSERT(rX == 0 || rX == 1); + + const T one = 1.0; + const long max_iter = 30; + const long n = a.nc(); + const long m = a.nr(); + const T eps = std::numeric_limits::epsilon(); + long nm = 0, l = 0; + bool flag; + T anorm,c,f,g,h,s,scale,x,y,z; + g = 0.0; + scale = 0.0; + anorm = 0.0; + + for (long i = 0; i < n; ++i) + { + l = i+1; + rv1(i) = scale*g; + g = s = scale = 0.0; + if (i < m) + { + for (long k = i; k < m; ++k) + scale += std::abs(a(k,i)); + + if (scale) + { + for (long k = i; k < m; ++k) + { + a(k,i) /= scale; + s += a(k,i)*a(k,i); + } + f = a(i,i); + g = -sign(std::sqrt(s),f); + h = f*g - s; + a(i,i) = f - g; + for (long j = l; j < n; ++j) + { + s = 0.0; + for (long k = i; k < m; ++k) + s += a(k,i)*a(k,j); + + f = s/h; + + for (long k = i; k < m; ++k) + a(k,j) += f*a(k,i); + } + for (long k = i; k < m; ++k) + a(k,i) *= scale; + } + } + + w(i) = scale *g; + + g=s=scale=0.0; + + if (i < m && i < n-1) + { + for (long k = l; k < n; ++k) + scale += std::abs(a(i,k)); + + if (scale) + { + for (long k = l; k < n; ++k) + { + a(i,k) /= scale; + s += a(i,k)*a(i,k); + } + f = a(i,l); + g = -sign(std::sqrt(s),f); + h = f*g - s; + a(i,l) = f - g; + + for (long k = l; k < n; ++k) + rv1(k) = a(i,k)/h; + + for (long j = l; j < m; ++j) + { + s = 0.0; + for (long k = l; k < n; ++k) + s += a(j,k)*a(i,k); + + for (long k = l; k < n; ++k) + a(j,k) += s*rv1(k); + } + for (long k = l; k < n; ++k) + a(i,k) *= scale; + } + } + anorm = std::max(anorm,(std::abs(w(i))+std::abs(rv1(i)))); + } + for (long i = n-1; i >= 0; --i) + { + if (i < n-1) + { + if (g != 0) + { + for (long j = l; j < n ; ++j) + v(j,i) = (a(i,j)/a(i,l))/g; + + for (long j = l; j < n; ++j) + { + s = 0.0; + for (long k = l; k < n; ++k) + s += a(i,k)*v(k,j); + + for (long k = l; k < n; ++k) + v(k,j) += s*v(k,i); + } + } + + for (long j = l; j < n; ++j) + v(i,j) = v(j,i) = 0.0; + } + + v(i,i) = 1.0; + g = rv1(i); + l = i; + } + + for (long i = std::min(m,n)-1; i >= 0; --i) + { + l = i + 1; + g = w(i); + + for (long j = l; j < n; ++j) + a(i,j) = 0.0; + + if (g != 0) + { + g = 1.0/g; + + for (long j = l; j < n; ++j) + { + s = 0.0; + for (long k = l; k < m; ++k) + s += a(k,i)*a(k,j); + + f=(s/a(i,i))*g; + + for (long k = i; k < m; ++k) + a(k,j) += f*a(k,i); + } + for (long j = i; j < m; ++j) + a(j,i) *= g; + } + else + { + for (long j = i; j < m; ++j) + a(j,i) = 0.0; + } + + ++a(i,i); + } + + for (long k = n-1; k >= 0; --k) + { + for (long its = 1; its <= max_iter; ++its) + { + flag = true; + for (l = k; l >= 1; --l) + { + nm = l - 1; + if (std::abs(rv1(l)) <= eps*anorm) + { + flag = false; + break; + } + if (std::abs(w(nm)) <= eps*anorm) + { + break; + } + } + + if (flag) + { + c = 0.0; + s = 1.0; + for (long i = l; i <= k; ++i) + { + f = s*rv1(i); + rv1(i) = c*rv1(i); + if (std::abs(f) <= eps*anorm) + break; + + g = w(i); + h = pythag(f,g); + w(i) = h; + h = 1.0/h; + c = g*h; + s = -f*h; + for (long j = 0; j < m; ++j) + { + y = a(j,nm); + z = a(j,i); + a(j,nm) = y*c + z*s; + a(j,i) = z*c - y*s; + } + } + } + + z = w(k); + if (l == k) + { + if (z < 0.0) + { + w(k) = -z; + for (long j = 0; j < n; ++j) + v(j,k) = -v(j,k); + } + break; + } + + if (its == max_iter) + return false; + + x = w(l); + nm = k - 1; + y = w(nm); + g = rv1(nm); + h = rv1(k); + f = ((y-z)*(y+z) + (g-h)*(g+h))/(2.0*h*y); + g = pythag(f,one); + f = ((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x; + c = s = 1.0; + for (long j = l; j <= nm; ++j) + { + long i = j + 1; + g = rv1(i); + y = w(i); + h = s*g; + g = c*g; + z = pythag(f,h); + rv1(j) = z; + c = f/z; + s = h/z; + f = x*c + g*s; + g = g*c - x*s; + h = y*s; + y *= c; + for (long jj = 0; jj < n; ++jj) + { + x = v(jj,j); + z = v(jj,i); + v(jj,j) = x*c + z*s; + v(jj,i) = z*c - x*s; + } + z = pythag(f,h); + w(j) = z; + if (z != 0) + { + z = 1.0/z; + c = f*z; + s = h*z; + } + f = c*g + s*y; + x = c*y - s*g; + for (long jj = 0; jj < m; ++jj) + { + y = a(jj,j); + z = a(jj,i); + a(jj,j) = y*c + z*s; + a(jj,i) = z*c - y*s; + } + } + rv1(l) = 0.0; + rv1(k) = f; + w(k) = x; + } + } + return true; + } + + + template < + typename T, + long N, + long NX, + typename MM1, + typename MM2, + typename MM3 + > + bool ludcmp ( + matrix& a, + matrix& indx, + T& d, + matrix vv + ) + /*! + ( this function is derived from the one in numerical recipes in C chapter 2.3) + ensures + - #a == both the L and U matrices + - #indx == the permutation vector (see numerical recipes in C) + - #d == some other thing (see numerical recipes in C) + - #vv == some undefined value. this is just used for scratch space + - if (the matrix is singular and we can't do anything) then + - returns false + - else + - returns true + !*/ + { + DLIB_ASSERT(indx.nc() == 1,"in dlib::nric::ludcmp() the indx matrix must be a column vector"); + DLIB_ASSERT(vv.nc() == 1,"in dlib::nric::ludcmp() the vv matrix must be a column vector"); + const long n = a.nr(); + long imax = 0; + T big, dum, sum, temp; + + d = 1.0; + for (long i = 0; i < n; ++i) + { + big = 0; + for (long j = 0; j < n; ++j) + { + if ((temp=std::abs(a(i,j))) > big) + big = temp; + } + if (big == 0.0) + { + return false; + } + vv(i) = 1/big; + } + + for (long j = 0; j < n; ++j) + { + for (long i = 0; i < j; ++i) + { + sum = a(i,j); + for (long k = 0; k < i; ++k) + sum -= a(i,k)*a(k,j); + a(i,j) = sum; + } + big = 0; + for (long i = j; i < n; ++i) + { + sum = a(i,j); + for (long k = 0; k < j; ++k) + sum -= a(i,k)*a(k,j); + a(i,j) = sum; + if ( (dum=vv(i)*std::abs(sum)) >= big) + { + big = dum; + imax = i; + } + } + if (j != imax) + { + for (long k = 0; k < n; ++k) + { + dum = a(imax,k); + a(imax,k) = a(j,k); + a(j,k) = dum; + } + d = -d; + vv(imax) = vv(j); + } + indx(j) = imax; + + if (j < n-1) + { + dum = 1/a(j,j); + for (long i = j+1; i < n; ++i) + a(i,j) *= dum; + } + } + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long N, + long NX, + typename MM1, + typename MM2, + typename MM3 + > + void lubksb ( + const matrix& a, + const matrix& indx, + matrix& b + ) + /*! + ( this function is derived from the one in numerical recipes in C chapter 2.3) + requires + - a == the LU decomposition you get from ludcmp() + - indx == the indx term you get out of ludcmp() + - b == the right hand side vector from the expression a*x = b + ensures + - #b == the solution vector x from the expression a*x = b + (basically, this function solves for x given b and a) + !*/ + { + DLIB_ASSERT(indx.nc() == 1,"in dlib::nric::lubksb() the indx matrix must be a column vector"); + DLIB_ASSERT(b.nc() == 1,"in dlib::nric::lubksb() the b matrix must be a column vector"); + const long n = a.nr(); + long i, ii = -1, ip, j; + T sum; + + for (i = 0; i < n; ++i) + { + ip = indx(i); + sum=b(ip); + b(ip) = b(i); + if (ii != -1) + { + for (j = ii; j < i; ++j) + sum -= a(i,j)*b(j); + } + else if (sum) + { + ii = i; + } + b(i) = sum; + } + for (i = n-1; i >= 0; --i) + { + sum = b(i); + for (j = i+1; j < n; ++j) + sum -= a(i,j)*b(j); + b(i) = sum/a(i,i); + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename OP + > + class matrix_zeroary_exp + { + public: + typedef typename OP::type type; + typedef matrix_zeroary_exp ref_type; + typedef typename OP::mem_manager_type mem_manager_type; + const static long NR = OP::NR; + const static long NC = OP::NC; + + const typename OP::type operator() ( + long r, + long c + ) const { return OP::apply(r,c); } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + long nr ( + ) const { return NR; } + + long nc ( + ) const { return NC; } + + const ref_type& ref( + ) const { return *this; } + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename S, + typename OP + > + class dynamic_matrix_scalar_unary_exp + { + /*! + REQUIREMENTS ON S + - must NOT be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + !*/ + public: + typedef typename OP::type type; + typedef dynamic_matrix_scalar_unary_exp ref_type; + typedef typename OP::mem_manager_type mem_manager_type; + const static long NR = OP::NR; + const static long NC = OP::NC; + + dynamic_matrix_scalar_unary_exp ( + long nr__, + long nc__, + const S& s_ + ) : + nr_(nr__), + nc_(nc__), + s(s_) + { + COMPILE_TIME_ASSERT(is_matrix::value == false); + } + + const typename OP::type operator() ( + long r, + long c + ) const { return OP::apply(s,r,c); } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return nr_; } + + long nc ( + ) const { return nc_; } + + private: + + const long nr_; + const long nc_; + const S s; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename S, + typename OP + > + class matrix_scalar_unary_exp + { + /*! + REQUIREMENTS ON S + - must NOT be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + !*/ + public: + typedef typename OP::type type; + typedef matrix_scalar_unary_exp ref_type; + typedef typename OP::mem_manager_type mem_manager_type; + const static long NR = OP::NR; + const static long NC = OP::NC; + + matrix_scalar_unary_exp ( + const S& s_ + ) : + s(s_) + { + COMPILE_TIME_ASSERT(is_matrix::value == false); + } + + const typename OP::type operator() ( + long r, + long c + ) const { return OP::apply(s,r,c); } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return NR; } + + long nc ( + ) const { return NC; } + + private: + + const S s; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename M, + typename OP + > + class matrix_unary_exp + { + /*! + REQUIREMENTS ON M + - must be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + !*/ + public: + typedef typename OP::type type; + typedef matrix_unary_exp ref_type; + typedef typename OP::mem_manager_type mem_manager_type; + const static long NR = OP::NR; + const static long NC = OP::NC; + + matrix_unary_exp ( + const M& m_ + ) : + m(m_) + {} + + const typename OP::type operator() ( + long r, + long c + ) const { return OP::apply(m,r,c); } + + template + bool aliases ( + const matrix& item + ) const { return m.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return OP::destructively_aliases(m,item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return OP::nr(m); } + + long nc ( + ) const { return OP::nc(m); } + + private: + + const M m; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename M + > + class matrix_std_vector_exp + { + /*! + REQUIREMENTS ON M + - must be a std::vector object (or + an object with a compatible interface). + !*/ + public: + typedef typename M::value_type type; + typedef matrix_std_vector_exp ref_type; + typedef typename memory_manager::kernel_1a mem_manager_type; + const static long NR = 0; + const static long NC = 1; + + matrix_std_vector_exp ( + const M& m_ + ) : + m(m_) + { + } + + const typename M::value_type operator() ( + long r, + long + ) const { return m[r]; } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return m.size(); } + + long nc ( + ) const { return 1; } + + private: + const M& m; + }; + +// ---------------------------------------------------------------------------------------- + + + template < + typename M + > + class matrix_vector_exp + { + /*! + REQUIREMENTS ON M + - must be a dlib::array object (or + an object with a compatible interface). + !*/ + public: + typedef typename M::type type; + typedef matrix_vector_exp ref_type; + typedef typename M::mem_manager_type mem_manager_type; + const static long NR = 0; + const static long NC = 1; + + matrix_vector_exp ( + const M& m_ + ) : + m(m_) + { + } + + const typename M::type operator() ( + long r, + long + ) const { return m[r]; } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return m.size(); } + + long nc ( + ) const { return 1; } + + private: + const M& m; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename M + > + class matrix_array_exp + { + /*! + REQUIREMENTS ON M + - must be a dlib::array2d object (or + an object with a compatible interface). + !*/ + public: + typedef typename M::type type; + typedef matrix_array_exp ref_type; + typedef typename M::mem_manager_type mem_manager_type; + const static long NR = 0; + const static long NC = 0; + + matrix_array_exp ( + const M& m_ + ) : + m(m_) + { + } + + const typename M::type operator() ( + long r, + long c + ) const { return m[r][c]; } + + template + bool aliases ( + const matrix& item + ) const { return false; } + + template + bool destructively_aliases ( + const matrix& item + ) const { return false; } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return m.nr(); } + + long nc ( + ) const { return m.nc(); } + + private: + const M& m; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename M + > + class matrix_sub_exp + { + /*! + REQUIREMENTS ON M + - must be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + !*/ + public: + typedef typename M::type type; + typedef matrix_sub_exp ref_type; + typedef typename M::mem_manager_type mem_manager_type; + const static long NR = 0; + const static long NC = 0; + + matrix_sub_exp ( + const M& m_, + const long& r__, + const long& c__, + const long& nr__, + const long& nc__ + ) : + m(m_), + r_(r__), + c_(c__), + nr_(nr__), + nc_(nc__) + { + } + + const typename M::type operator() ( + long r, + long c + ) const { return m(r+r_,c+c_); } + + template + bool aliases ( + const matrix& item + ) const { return m.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return m.aliases(item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return nr_; } + + long nc ( + ) const { return nc_; } + + private: + + const M m; + const long r_, c_, nr_, nc_; + }; + +// ---------------------------------------------------------------------------------------- + + + template < + typename M, + typename S, + typename OP + > + class matrix_scalar_binary_exp + { + /*! + REQUIREMENTS ON M + - must be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + !*/ + public: + typedef typename OP::type type; + typedef matrix_scalar_binary_exp ref_type; + typedef typename OP::mem_manager_type mem_manager_type; + const static long NR = OP::NR; + const static long NC = OP::NC; + + matrix_scalar_binary_exp ( + const M& m_, + const S& s_ + ) : + m(m_), + s(s_) + { + COMPILE_TIME_ASSERT(is_matrix::value == false); + } + + const typename OP::type operator() ( + long r, + long c + ) const { return OP::apply(m,s,r,c); } + + template + bool aliases ( + const matrix& item + ) const { return m.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return OP::destructively_aliases(m,item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return OP::nr(m); } + + long nc ( + ) const { return OP::nc(m); } + + private: + + const M m; + const S s; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename M1, + typename M2, + typename OP + > + class matrix_binary_exp + { + /*! + REQUIREMENTS ON M1 AND M2 + - must be a matrix_exp or matrix_ref object (or + an object with a compatible interface). + !*/ + public: + typedef typename OP::type type; + typedef matrix_binary_exp ref_type; + typedef typename OP::mem_manager_type mem_manager_type; + const static long NR = OP::NR; + const static long NC = OP::NC; + + matrix_binary_exp ( + const M1& m1_, + const M2& m2_ + ) : + m1(m1_), + m2(m2_) + {} + + const typename OP::type operator() ( + long r, + long c + ) const { return OP::apply(m1,m2,r,c); } + + template + bool aliases ( + const matrix& item + ) const { return m1.aliases(item) || m2.aliases(item); } + + template + bool destructively_aliases ( + const matrix& item + ) const { return OP::destructively_aliases(m1,m2,item); } + + const ref_type& ref( + ) const { return *this; } + + long nr ( + ) const { return OP::nr(m1,m2); } + + long nc ( + ) const { return OP::nc(m1,m2); } + + private: + + const M1 m1; + const M2 m2; + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename array_type + > + const matrix_exp > array_to_matrix ( + const array_type& array + ) + { + typedef matrix_array_exp exp; + return matrix_exp(exp(array)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename vector_type + > + const matrix_exp > vector_to_matrix ( + const vector_type& vector + ) + { + typedef matrix_vector_exp exp; + return matrix_exp(exp(vector)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename value_type + > + const matrix_exp > > vector_to_matrix ( + const std::vector& vector + ) + { + typedef matrix_std_vector_exp > exp; + return matrix_exp(exp(vector)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename value_type + > + const matrix_exp > > vector_to_matrix ( + const std_vector_c& vector + ) + { + typedef matrix_std_vector_exp > exp; + return matrix_exp(exp(vector)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const rectangle get_rect ( + const matrix_exp& m + ) + { + return rectangle(0, 0, m.nc()-1, m.nr()-1); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const matrix_exp > > subm ( + const matrix_exp& m, + long r, + long c, + long nr, + long nc + ) + { + DLIB_ASSERT(r >= 0 && c >= 0 && r+nr < m.nr() && c+nc < m.nc(), + "\tconst matrix_exp subm(const matrix_exp& m, r, c, nr, nc)" + << "\n\tYou have specified invalid sub matrix dimensions" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tr: " << r + << "\n\tc: " << c + << "\n\tnr: " << nr + << "\n\tnc: " << nc + ); + + typedef matrix_sub_exp > exp; + return matrix_exp(exp(m,r,c,nr,nc)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const matrix_exp > > subm ( + const matrix_exp& m, + const rectangle& rect + ) + { + DLIB_ASSERT(get_rect(m).contains(rect) == true, + "\tconst matrix_exp subm(const matrix_exp& m, const rectangle& rect)" + << "\n\tYou have specified invalid sub matrix dimensions" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\trect.left(): " << rect.left() + << "\n\trect.top(): " << rect.top() + << "\n\trect.right(): " << rect.right() + << "\n\trect.bottom(): " << rect.bottom() + ); + + typedef matrix_sub_exp > exp; + return matrix_exp(exp(m,rect.top(),rect.left(),rect.height(),rect.width())); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_rowm : has_destructive_aliasing + { + const static long NR = 1; + const static long NC = EXP::NC; + typedef typename EXP::type type; + typedef typename EXP::mem_manager_type mem_manager_type; + template + static type apply ( const M& m, long row, long, long c) + { return m(row,c); } + + template + static long nr (const M& m) { return 1; } + template + static long nc (const M& m) { return m.nc(); } + }; + + template < + typename EXP + > + const matrix_exp,long,op_rowm > > rowm ( + const matrix_exp& m, + long row + ) + { + DLIB_ASSERT(row >= 0 && row < m.nr(), + "\tconst matrix_exp rowm(const matrix_exp& m, row)" + << "\n\tYou have specified invalid sub matrix dimensions" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\trow: " << row + ); + + typedef matrix_scalar_binary_exp,long,op_rowm > exp; + return matrix_exp(exp(m,row)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_colm : has_destructive_aliasing + { + const static long NR = EXP::NR; + const static long NC = 1; + typedef typename EXP::type type; + typedef typename EXP::mem_manager_type mem_manager_type; + template + static type apply ( const M& m, long col, long r, long) + { return m(r,col); } + + template + static long nr (const M& m) { return m.nr(); } + template + static long nc (const M& m) { return 1; } + }; + + template < + typename EXP + > + const matrix_exp,long,op_colm > > colm ( + const matrix_exp& m, + long col + ) + { + DLIB_ASSERT(col >= 0 && col < m.nc(), + "\tconst matrix_exp colm(const matrix_exp& m, row)" + << "\n\tYou have specified invalid sub matrix dimensions" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tcol: " << col + ); + + typedef matrix_scalar_binary_exp,long,op_colm > exp; + return matrix_exp(exp(m,col)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_trans : has_destructive_aliasing + { + const static long NR = EXP::NC; + const static long NC = EXP::NR; + typedef typename EXP::type type; + typedef typename EXP::mem_manager_type mem_manager_type; + template + static type apply ( const M& m, long r, long c) + { return m(c,r); } + + template + static long nr (const M& m) { return m.nc(); } + template + static long nc (const M& m) { return m.nr(); } + }; + + template < + typename EXP + > + const matrix_exp,op_trans > > trans ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_trans > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_removerc : has_destructive_aliasing + { + const static long NR = EXP::NR - 1; + const static long NC = EXP::NC - 1; + typedef typename EXP::type type; + typedef typename EXP::mem_manager_type mem_manager_type; + template + static type apply ( const M& m, long r, long c) + { + if (r < R) + { + if (c < C) + return m(r,c); + else + return m(r,c+1); + } + else + { + if (c < C) + return m(r+1,c); + else + return m(r+1,c+1); + } + } + + template + static long nr (const M& m) { return m.nr() - 1; } + template + static long nc (const M& m) { return m.nc() - 1; } + }; + + template < + long R, + long C, + typename EXP + > + const matrix_exp,op_removerc > > removerc ( + const matrix_exp& m + ) + { + // you can't remove a row from a matrix with only one row + COMPILE_TIME_ASSERT(EXP::NR > 1 || EXP::NR == 0); + // you can't remove a column from a matrix with only one column + COMPILE_TIME_ASSERT(EXP::NC > 1 || EXP::NR == 0); + DLIB_ASSERT(m.nr() > 1 && m.nc() > 1, + "\tconst matrix_exp removerc(const matrix_exp& m)" + << "\n\tYou can't remove a row/column from a matrix with only one row/column" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tR: " << R + << "\n\tC: " << C + ); + typedef matrix_unary_exp,op_removerc > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_diag : has_destructive_aliasing + { + const static long NR = EXP::NC; + const static long NC = 1; + typedef typename EXP::type type; + typedef typename EXP::mem_manager_type mem_manager_type; + template + static type apply ( const M& m, long r, long c) + { return m(r,r); } + + template + static long nr (const M& m) { return m.nr(); } + template + static long nc (const M& m) { return 1; } + }; + + template < + typename EXP + > + const matrix_exp,op_diag > > diag ( + const matrix_exp& m + ) + { + // You can only get the diagonal for square matrices. + COMPILE_TIME_ASSERT(EXP::NR == EXP::NC); + DLIB_ASSERT(m.nr() == m.nc(), + "\tconst matrix_exp diag(const matrix_exp& m)" + << "\n\tYou can only apply diag() to a square matrix" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); + typedef matrix_unary_exp,op_diag > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_cast : has_nondestructive_aliasing, preserves_dimensions + { + typedef target_type type; + template + static type apply ( const M& m, long r, long c) + { return static_cast(m(r,c)); } + }; + + template < + typename target_type, + typename EXP + > + const matrix_exp,op_cast > > matrix_cast ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_cast > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename MM, + typename U + > + void set_all_elements ( + matrix& m, + U value + ) + { + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m(r,c) = static_cast(value); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP, + long uNR, + long uNC, + long wN, + long vN, + typename MM1, + typename MM2, + typename MM3 + > + inline void svd ( + const matrix_exp& m, + matrix::type, uNR, uNC,MM1>& u, + matrix::type, wN, wN,MM2>& w, + matrix::type, vN, vN,MM3>& v + ) + { + typedef typename matrix_exp::type T; + const long NR = matrix_exp::NR; + const long NC = matrix_exp::NC; + + // make sure the output matrices have valid dimensions if they are statically dimensioned + COMPILE_TIME_ASSERT(NR == 0 || uNR == 0 || NR == uNR); + COMPILE_TIME_ASSERT(NC == 0 || uNC == 0 || NC == uNC); + COMPILE_TIME_ASSERT(NC == 0 || wN == 0 || NC == wN); + COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN); + COMPILE_TIME_ASSERT(NR >= NC || NR == 0); + + w.set_size(m.nc(),m.nc()); + v.set_size(m.nc(),m.nc()); + + typedef typename matrix_exp::type T; + u = m; + + matrix::NC,1,MM1> W(m.nc(),1); + matrix::NC,1,MM1> rv1(m.nc(),1); + set_all_elements(w,0); + + nric::svdcmp(u,W,v,rv1); + + for (long r = 0; r < W.nr(); ++r) + w(r,r) = W(r); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + inline const typename matrix_exp::matrix_type pinv ( + const matrix_exp& m + ) + { + typename matrix_exp::matrix_type u; + matrix w, v; + svd(m,u,w,v); + + const double machine_eps = std::numeric_limits::epsilon(); + // compute a reasonable epsilon below which we round to zero before doing the + // reciprocal + const double eps = machine_eps*std::max(m.nr(),m.nc())*max(diag(w)); + + // compute the reciprocal of the diagonal of w + matrix w_diag = reciprocal(round_zeros(diag(w),eps)); + + // now compute the pseudoinverse + return tmp(scale_columns(v,w_diag))*trans(u); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP, + long N + > + struct inv_helper + { + static const typename matrix_exp::matrix_type inv ( + const matrix_exp& m + ) + { + using namespace nric; + typedef typename EXP::mem_manager_type MM; + // you can't invert a non-square matrix + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC || + matrix_exp::NR == 0 || + matrix_exp::NC == 0); + DLIB_ASSERT(m.nr() == m.nc(), + "\tconst matrix_exp::type inv(const matrix_exp& m)" + << "\n\tYou can only apply inv() to a square matrix" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); + typedef typename matrix_exp::type type; + + matrix a(m), y(m.nr(),m.nr()); + matrix indx(m.nr(),1); + matrix col(m.nr(),1); + matrix vv(m.nr(),1); + type d; + long i, j; + if (ludcmp(a,indx,d,vv)) + { + for (j = 0; j < m.nr(); ++j) + { + for (i = 0; i < m.nr(); ++i) + col(i) = 0; + col(j) = 1; + lubksb(a,indx,col); + for (i = 0; i < m.nr(); ++i) + y(i,j) = col(i); + } + } + else + { + // m is singular so lets just set y equal to m just so that + // it has some value + y = m; + } + return y; + } + }; + + template < + typename EXP + > + struct inv_helper + { + static const typename matrix_exp::matrix_type inv ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + matrix a; + a(0) = 1/m(0); + return a; + } + }; + + template < + typename EXP + > + struct inv_helper + { + static const typename matrix_exp::matrix_type inv ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + matrix a; + type d = static_cast(1.0/det(m)); + a(0,0) = m(1,1)*d; + a(0,1) = m(0,1)*-d; + a(1,0) = m(1,0)*-d; + a(1,1) = m(0,0)*d; + return a; + } + }; + + template < + typename EXP + > + struct inv_helper + { + static const typename matrix_exp::matrix_type inv ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + matrix ret; + const type de = static_cast(1.0/det(m)); + const type a = m(0,0); + const type b = m(0,1); + const type c = m(0,2); + const type d = m(1,0); + const type e = m(1,1); + const type f = m(1,2); + const type g = m(2,0); + const type h = m(2,1); + const type i = m(2,2); + + ret(0,0) = (e*i - f*h)*de; + ret(1,0) = (f*g - d*i)*de; + ret(2,0) = (d*h - e*g)*de; + + ret(0,1) = (c*h - b*i)*de; + ret(1,1) = (a*i - c*g)*de; + ret(2,1) = (b*g - a*h)*de; + + ret(0,2) = (b*f - c*e)*de; + ret(1,2) = (c*d - a*f)*de; + ret(2,2) = (a*e - b*d)*de; + + return ret; + } + }; + + template < + typename EXP + > + struct inv_helper + { + static const typename matrix_exp::matrix_type inv ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + matrix ret; + const type de = static_cast(1.0/det(m)); + ret(0,0) = det(removerc<0,0>(m)); + ret(0,1) = -det(removerc<0,1>(m)); + ret(0,2) = det(removerc<0,2>(m)); + ret(0,3) = -det(removerc<0,3>(m)); + + ret(1,0) = -det(removerc<1,0>(m)); + ret(1,1) = det(removerc<1,1>(m)); + ret(1,2) = -det(removerc<1,2>(m)); + ret(1,3) = det(removerc<1,3>(m)); + + ret(2,0) = det(removerc<2,0>(m)); + ret(2,1) = -det(removerc<2,1>(m)); + ret(2,2) = det(removerc<2,2>(m)); + ret(2,3) = -det(removerc<2,3>(m)); + + ret(3,0) = -det(removerc<3,0>(m)); + ret(3,1) = det(removerc<3,1>(m)); + ret(3,2) = -det(removerc<3,2>(m)); + ret(3,3) = det(removerc<3,3>(m)); + + return trans(ret)*de; + } + }; + + template < + typename EXP + > + inline const typename matrix_exp::matrix_type inv ( + const matrix_exp& m + ) { return inv_helper::NR>::inv(m); } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + inline const typename matrix_exp::matrix_type cholesky_decomposition ( + const matrix_exp& A + ) + { + DLIB_ASSERT(A.nr() == A.nc(), + "\tconst matrix cholesky_decomposition(const matrix_exp& A)" + << "\n\tYou can only apply the cholesky_decomposition to a square matrix" + << "\n\tA.nr(): " << A.nr() + << "\n\tA.nc(): " << A.nc() + ); + + typename matrix_exp::matrix_type L(A.nr(),A.nc()); + typedef typename EXP::type T; + set_all_elements(L,0); + + // do nothing if the matrix is empty + if (A.size() == 0) + return L; + + // compute the upper left corner + if (A(0,0) > 0) + L(0,0) = std::sqrt(A(0,0)); + + // compute the first column + for (long r = 1; r < A.nr(); ++r) + { + if (L(0,0) > 0) + L(r,0) = A(r,0)/L(0,0); + else + L(r,0) = A(r,0); + } + + // now compute all the other columns + for (long c = 1; c < A.nc(); ++c) + { + // compute the diagonal element + T temp = A(c,c); + for (long i = 0; i < c; ++i) + { + temp -= L(c,i)*L(c,i); + } + if (temp > 0) + L(c,c) = std::sqrt(temp); + + // compute the non diagonal elements + for (long r = c+1; r < A.nr(); ++r) + { + temp = A(r,c); + for (long i = 0; i < c; ++i) + { + temp -= L(r,i)*L(c,i); + } + if (L(c,c) > 0) + L(r,c) = temp/L(c,c); + else + L(r,c) = temp; + } + } + + return L; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + inline const typename matrix_exp::matrix_type tmp ( + const matrix_exp& m + ) + { + return typename matrix_exp::matrix_type (m); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const typename lazy_disable_if, EXP>::type sum ( + const matrix_exp& m + ) + { + typedef typename matrix_exp::type type; + + type val = 0; + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + val += m(r,c); + } + } + return val; + } + + template < + typename EXP + > + const typename lazy_enable_if, EXP>::type sum ( + const matrix_exp& m + ) + { + typedef typename matrix_exp::type type; + + type val; + set_all_elements(val,0); + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + val += m(r,c); + } + } + return val; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + inline const typename matrix_exp::type mean ( + const matrix_exp& m + ) + { + return sum(m)/(m.nr()*m.nc()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const typename lazy_disable_if, EXP>::type variance ( + const matrix_exp& m + ) + { + const typename matrix_exp::type avg = mean(m); + + typedef typename matrix_exp::type type; + + type val = 0; + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + val += std::pow(m(r,c) - avg,2); + } + } + + if (m.nr() * m.nc() == 1) + return val; + else + return val/(m.nr()*m.nc() - 1); + } + + template < + typename EXP + > + const typename lazy_enable_if, EXP >::type variance ( + const matrix_exp& m + ) + { + const typename matrix_exp::type avg = mean(m); + + typedef typename matrix_exp::type type; + + type val; + set_all_elements(val,0); + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + val += pow(m(r,c) - avg,2); + } + } + + if (m.nr() * m.nc() == 1) + return val; + else + return val/(m.nr()*m.nc() - 1); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const matrix covariance ( + const matrix_exp& m + ) + { + // perform static checks to make sure m is a column vector + COMPILE_TIME_ASSERT(EXP::NR == 0 || EXP::NR > 1); + COMPILE_TIME_ASSERT(EXP::NC == 1 || EXP::NC == 0); + + // perform static checks to make sure the matrices contained in m are column vectors + COMPILE_TIME_ASSERT(EXP::type::NC == 1 || EXP::type::NC == 0 ); + + DLIB_ASSERT(m.nr() > 1 && m.nc() == 1, + "\tconst matrix covariance(const matrix_exp& m)" + << "\n\tYou can only apply covariance() to a column matrix" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); +#ifdef ENABLE_ASSERTS + for (long i = 0; i < m.nr(); ++i) + { + DLIB_ASSERT(m(0).nr() == m(i).nr() && m(i).nr() > 0 && m(i).nc() == 1, + "\tconst matrix covariance(const matrix_exp& m)" + << "\n\tYou can only apply covariance() to a column matrix of column matrices" + << "\n\tm(0).nr(): " << m(0).nr() + << "\n\tm(i).nr(): " << m(i).nr() + << "\n\tm(i).nc(): " << m(i).nc() + << "\n\ti: " << i + ); + } +#endif + + // now perform the actual calculation of the covariance matrix. + matrix cov(m(0).nr(),m(0).nr()); + set_all_elements(cov,0); + + const matrix avg = mean(m); + + for (long r = 0; r < m.nr(); ++r) + { + cov += (m(r) - avg)*trans(m(r) - avg); + } + + cov *= 1.0 / (m.nr() - 1.0); + return cov; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP + > + const typename matrix_exp::type prod ( + const matrix_exp& m + ) + { + typedef typename matrix_exp::type type; + + type val = 1; + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + val *= m(r,c); + } + } + return val; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP, + long N = EXP::NR + > + struct det_helper + { + static const typename matrix_exp::type det ( + const matrix_exp& m + ) + { + using namespace nric; + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC || + matrix_exp::NR == 0 || + matrix_exp::NC == 0 + ); + DLIB_ASSERT(m.nr() == m.nc(), + "\tconst matrix_exp::type det(const matrix_exp& m)" + << "\n\tYou can only apply det() to a square matrix" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + ); + typedef typename matrix_exp::type type; + typedef typename matrix_exp::mem_manager_type MM; + + matrix lu(m); + matrix indx(m.nr(),1); + matrix vv(m.nr(),1); + type d; + if (ludcmp(lu,indx,d,vv) == false) + { + // the matrix is singular so its det is 0 + return 0; + } + + return prod(diag(lu))*d; + } + }; + + template < + typename EXP + > + struct det_helper + { + static const typename matrix_exp::type det ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + return m(0); + } + }; + + template < + typename EXP + > + struct det_helper + { + static const typename matrix_exp::type det ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + return m(0,0)*m(1,1) - m(0,1)*m(1,0); + } + }; + + template < + typename EXP + > + struct det_helper + { + static const typename matrix_exp::type det ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + type temp = m(0,0)*(m(1,1)*m(2,2) - m(1,2)*m(2,1)) - + m(0,1)*(m(1,0)*m(2,2) - m(1,2)*m(2,0)) + + m(0,2)*(m(1,0)*m(2,1) - m(1,1)*m(2,0)); + return temp; + } + }; + + + template < + typename EXP + > + inline const typename matrix_exp::type det ( + const matrix_exp& m + ) { return det_helper::det(m); } + + + template < + typename EXP + > + struct det_helper + { + static const typename matrix_exp::type det ( + const matrix_exp& m + ) + { + COMPILE_TIME_ASSERT(matrix_exp::NR == matrix_exp::NC); + typedef typename matrix_exp::type type; + + type temp = m(0,0)*(dlib::det(removerc<0,0>(m))) - + m(0,1)*(dlib::det(removerc<0,1>(m))) + + m(0,2)*(dlib::det(removerc<0,2>(m))) - + m(0,3)*(dlib::det(removerc<0,3>(m))); + return temp; + } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + struct op_uniform_matrix_3 : has_nondestructive_aliasing + { + const static long NR = 0; + const static long NC = 0; + typedef typename memory_manager::kernel_1a mem_manager_type; + typedef T type; + static type apply (const T& val, long r, long c) + { return val; } + }; + + template < + typename T + > + const matrix_exp > > uniform_matrix ( + long nr, + long nc, + const T& val + ) + { + DLIB_ASSERT(nr > 0 && nc > 0, + "\tconst matrix_exp uniform_matrix(nr, nc)" + << "\n\tnr and nc have to be bigger than 0" + << "\n\tnr: " << nr + << "\n\tnc: " << nc + ); + typedef dynamic_matrix_scalar_unary_exp > exp; + return matrix_exp(exp(nr,nc,val)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR_, + long NC_ + > + struct op_uniform_matrix_2 : has_nondestructive_aliasing + { + const static long NR = NR_; + const static long NC = NC_; + typedef typename memory_manager::kernel_1a mem_manager_type; + typedef T type; + static type apply (const T& val, long r, long c) + { return val; } + }; + + template < + typename T, + long NR, + long NC + > + const matrix_exp > > uniform_matrix ( + const T& val + ) + { + COMPILE_TIME_ASSERT(NR > 0 && NC > 0); + + typedef matrix_scalar_unary_exp > exp; + return matrix_exp(exp(val)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR_, + long NC_, + T val + > + struct op_uniform_matrix : has_nondestructive_aliasing + { + const static long NR = NR_; + const static long NC = NC_; + typedef typename memory_manager::kernel_1a mem_manager_type; + typedef T type; + static type apply ( long r, long c) + { return val; } + }; + + template < + typename T, + long NR, + long NC, + T val + > + const matrix_exp > > uniform_matrix ( + ) + { + COMPILE_TIME_ASSERT(NR > 0 && NC > 0); + typedef matrix_zeroary_exp > exp; + return matrix_exp(exp()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long N + > + struct op_identity_matrix : has_nondestructive_aliasing + { + const static long NR = N; + const static long NC = N; + typedef typename memory_manager::kernel_1a mem_manager_type; + typedef T type; + static type apply ( long r, long c) + { return static_cast(r == c); } + + template + static long nr (const M&) { return NR; } + template + static long nc (const M&) { return NC; } + }; + + template < + typename T, + long N + > + const matrix_exp > > identity_matrix ( + ) + { + COMPILE_TIME_ASSERT(N > 0); + + typedef matrix_zeroary_exp > exp; + return matrix_exp(exp()); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_rotate : has_destructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + template + static type apply ( const M& m, long r, long c) + { return m((r+R)%m.nr(),(c+C)%m.nc()); } + }; + + template < + long R, + long C, + typename EXP + > + const matrix_exp,op_rotate > > rotate ( + const matrix_exp& m + ) + { + // You can't rotate a matrix by more rows than it has. + COMPILE_TIME_ASSERT(R < EXP::NR || EXP::NR == 0); + // You can't rotate a matrix by more columns than it has. + COMPILE_TIME_ASSERT(C < EXP::NC || EXP::NC == 0); + DLIB_ASSERT( R < m.nr() && C < m.nc(), + "\tconst matrix_exp::type rotate(const matrix_exp& m)" + << "\n\tYou can't rotate a matrix by more rows or columns than it has" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tR: " << R + << "\n\tC: " << C + ); + typedef matrix_unary_exp,op_rotate > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_pointwise_multiply : public has_nondestructive_aliasing, public preserves_dimensions + { + typedef typename EXP1::type type; + + template + static type apply ( const M1& m1, const M2& m2 , long r, long c) + { return m1(r,c)*m2(r,c); } + }; + + template < + typename EXP1, + typename EXP2 + > + inline const matrix_exp,matrix_exp,op_pointwise_multiply > > pointwise_multiply ( + const matrix_exp& a, + const matrix_exp& b + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc(), + "\tconst matrix_exp::type pointwise_multiply(const matrix_exp& a, const matrix_exp& b)" + << "\n\tYou can only make a do a pointwise multiply with two equally sized matrices" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + ); + typedef matrix_binary_exp,matrix_exp,op_pointwise_multiply > exp; + return matrix_exp(exp(a,b)); + } + + template < + typename EXP1, + typename EXP2, + typename EXP3 + > + inline const matrix_exp< + matrix_binary_exp< matrix_binary_exp,matrix_exp,op_pointwise_multiply > , + matrix_exp, op_pointwise_multiply > > + pointwise_multiply ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0); + COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0); + COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc() && + b.nr() == c.nr() && + b.nc() == c.nc(), + "\tconst matrix_exp::type pointwise_multiply(a,b,c)" + << "\n\tYou can only make a do a pointwise multiply between equally sized matrices" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + << "\n\tc.nr(): " << c.nr() + << "\n\tc.nc(): " << c.nc() + ); + typedef matrix_binary_exp,matrix_exp,op_pointwise_multiply > exp; + typedef matrix_binary_exp< exp , matrix_exp, op_pointwise_multiply > exp2; + + return matrix_exp(exp2(exp(a,b),c)); + } + + template < + typename EXP1, + typename EXP2, + typename EXP3, + typename EXP4 + > + inline const matrix_exp< + matrix_binary_exp< matrix_binary_exp,matrix_exp,op_pointwise_multiply > , + matrix_binary_exp,matrix_exp,op_pointwise_multiply >, + op_pointwise_multiply > > + pointwise_multiply ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c, + const matrix_exp& d + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0 ); + COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0); + COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0); + COMPILE_TIME_ASSERT(EXP3::NR == EXP4::NR || EXP3::NR == 0 || EXP4::NR == 0); + COMPILE_TIME_ASSERT(EXP3::NC == EXP4::NC || EXP3::NC == 0 || EXP4::NC == 0); + DLIB_ASSERT(a.nr() == b.nr() && + a.nc() == b.nc() && + b.nr() == c.nr() && + b.nc() == c.nc() && + c.nr() == d.nr() && + c.nc() == d.nc(), + "\tconst matrix_exp::type pointwise_multiply(a,b,c,d)" + << "\n\tYou can only make a do a pointwise multiply between equally sized matrices" + << "\n\ta.nr(): " << a.nr() + << "\n\ta.nc(): " << a.nc() + << "\n\tb.nr(): " << b.nr() + << "\n\tb.nc(): " << b.nc() + << "\n\tc.nr(): " << c.nr() + << "\n\tc.nc(): " << c.nc() + << "\n\td.nr(): " << d.nr() + << "\n\td.nc(): " << d.nc() + ); + typedef matrix_binary_exp,matrix_exp,op_pointwise_multiply > exp1; + typedef matrix_binary_exp,matrix_exp,op_pointwise_multiply > exp2; + + typedef matrix_binary_exp< exp1 , exp2, op_pointwise_multiply > exp3; + return matrix_exp(exp3(exp1(a,b),exp2(c,d))); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename P, + int type = static_switch< + pixel_traits

::grayscale, + pixel_traits

::rgb, + pixel_traits

::hsi, + pixel_traits

::rgb_alpha + >::value + > + struct pixel_to_vector_helper; + + template + struct pixel_to_vector_helper + { + template + static void assign ( + M& m, + const P& pixel + ) + { + m(0) = static_cast(pixel); + } + }; + + template + struct pixel_to_vector_helper + { + template + static void assign ( + M& m, + const P& pixel + ) + { + m(0) = static_cast(pixel.red); + m(1) = static_cast(pixel.green); + m(2) = static_cast(pixel.blue); + } + }; + + template + struct pixel_to_vector_helper + { + template + static void assign ( + M& m, + const P& pixel + ) + { + m(0) = static_cast(pixel.h); + m(1) = static_cast(pixel.s); + m(2) = static_cast(pixel.i); + } + }; + + template + struct pixel_to_vector_helper + { + template + static void assign ( + M& m, + const P& pixel + ) + { + m(0) = static_cast(pixel.red); + m(1) = static_cast(pixel.green); + m(2) = static_cast(pixel.blue); + m(3) = static_cast(pixel.alpha); + } + }; + + + template < + typename T, + typename P + > + inline const matrix::num,1> pixel_to_vector ( + const P& pixel + ) + { + COMPILE_TIME_ASSERT(pixel_traits

::num > 0); + matrix::num,1> m; + pixel_to_vector_helper

::assign(m,pixel); + return m; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename P, + int type = static_switch< + pixel_traits

::grayscale, + pixel_traits

::rgb, + pixel_traits

::hsi, + pixel_traits

::rgb_alpha + >::value + > + struct vector_to_pixel_helper; + + template + struct vector_to_pixel_helper + { + template + static void assign ( + P& pixel, + const M& m + ) + { + pixel = static_cast(m(0)); + } + }; + + template + struct vector_to_pixel_helper + { + template + static void assign ( + P& pixel, + const M& m + ) + { + pixel.red = static_cast(m(0)); + pixel.green = static_cast(m(1)); + pixel.blue = static_cast(m(2)); + } + }; + + template + struct vector_to_pixel_helper + { + template + static void assign ( + P& pixel, + const M& m + ) + { + pixel.h = static_cast(m(0)); + pixel.s = static_cast(m(1)); + pixel.i = static_cast(m(2)); + } + }; + + template + struct vector_to_pixel_helper + { + template + static void assign ( + P& pixel, + const M& m + ) + { + pixel.red = static_cast(m(0)); + pixel.green = static_cast(m(1)); + pixel.blue = static_cast(m(2)); + pixel.alpha = static_cast(m(3)); + } + }; + + template < + typename P, + typename EXP + > + inline void vector_to_pixel ( + P& pixel, + const matrix_exp& vector + ) + { + COMPILE_TIME_ASSERT(pixel_traits

::num == matrix_exp::NR); + COMPILE_TIME_ASSERT(matrix_exp::NC == 1); + vector_to_pixel_helper

::assign(pixel,vector); + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_clamp : has_nondestructive_aliasing, preserves_dimensions + { + typedef typename EXP::type type; + + template + static type apply ( const M& m, long r, long c) + { + const type temp = m(r,c); + if (temp > static_cast(upper)) + return static_cast(upper); + else if (temp < static_cast(lower)) + return static_cast(lower); + else + return temp; + } + }; + + template < + long l, + long u, + typename EXP + > + const matrix_exp,op_clamp > > clamp ( + const matrix_exp& m + ) + { + typedef matrix_unary_exp,op_clamp > exp; + return matrix_exp(exp(m)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename EXP1, + typename EXP2 + > + bool equal ( + const matrix_exp& a, + const matrix_exp& b, + const typename EXP1::type eps = 100*std::numeric_limits::epsilon() + ) + { + // check if the dimensions don't match + if (a.nr() != b.nr() || a.nc() != b.nc()) + return false; + + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + if (std::abs(a(r,c)-b(r,c)) > eps) + return false; + } + } + + // no non-equal points found so we return true + return true; + } + +// ---------------------------------------------------------------------------------------- + + template + struct op_scale_columns : has_nondestructive_aliasing + { + typedef typename EXP1::type type; + typedef typename EXP1::mem_manager_type mem_manager_type; + const static long NR = EXP1::NR; + const static long NC = EXP1::NC; + + template + static type apply ( const M1& m1, const M2& m2 , long r, long c) + { return m1(r,c)*m2(c); } + + template + static long nr (const M1& m1, const M2& ) { return m1.nr(); } + template + static long nc (const M1& m1, const M2& ) { return m1.nc(); } + }; + + template < + typename EXP1, + typename EXP2 + > + const matrix_exp,matrix_exp,op_scale_columns > > scale_columns ( + const matrix_exp& m, + const matrix_exp& v + ) + { + COMPILE_TIME_ASSERT((is_same_type::value == true)); + COMPILE_TIME_ASSERT(EXP2::NC == 1 || EXP2::NC == 0); + COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NR || EXP1::NC == 0 || EXP2::NR == 0); + + DLIB_ASSERT(v.nc() == 1 && v.nr() == m.nc(), + "\tconst matrix_exp scale_columns(m, v)" + << "\n\tv must be a column vector and its length must match the number of columns in m" + << "\n\tm.nr(): " << m.nr() + << "\n\tm.nc(): " << m.nc() + << "\n\tv.nr(): " << v.nr() + << "\n\tv.nc(): " << v.nc() + ); + typedef matrix_binary_exp,matrix_exp,op_scale_columns > exp; + return matrix_exp(exp(m,v)); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MATRIx_UTILITIES_ + diff --git a/dlib/matrix/matrix_utilities_abstract.h b/dlib/matrix/matrix_utilities_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..a0c4f2a7fd2032c5a5830e44e60f967797026f97 --- /dev/null +++ b/dlib/matrix/matrix_utilities_abstract.h @@ -0,0 +1,659 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MATRIx_UTILITIES_ABSTRACT_ +#ifdef DLIB_MATRIx_UTILITIES_ABSTRACT_ + +#include "matrix_abstract.h" +#include +#include "pixel.h" +#include "../geometry.h" +#inclue + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Elementary matrix operations +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp diag ( + const matrix_exp& m + ); + /*! + requires + - m is a square matrix + ensures + - returns a column vector R that contains the elements from the diagonal + of m in the order R(0)==m(0,0), R(1)==m(1,1), R(2)==m(2,2) and so on. + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp trans ( + const matrix_exp& m + ); + /*! + ensures + - returns the transpose of the matrix m + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + T val + > + const matrix_exp uniform_matrix ( + ); + /*! + requires + - NR > 0 && NC > 0 + ensures + - returns an NR by NC matrix with elements of type T and all set to val. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + long NR, + long NC, + typename T + > + const matrix_exp uniform_matrix ( + const T& val + ); + /*! + requires + - NR > 0 && NC > 0 + ensures + - returns an NR by NC matrix with elements of type T and all set to val. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + const matrix_exp uniform_matrix ( + long nr, + long nc, + const T& val + ); + /*! + requires + - nr > 0 && nc > 0 + ensures + - returns an nr by nc matrix with elements of type T and all set to val. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long N + > + const matrix_exp identity_matrix ( + ); + /*! + requires + - N > 0 + ensures + - returns an N by N identity matrix with elements of type T. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + long R, + long C + > + const matrix_exp rotate ( + const matrix_exp& m + ); + /*! + requires + - R < m.nr() + - C < m.nc() + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + R( (r+R)%m.nr() , (c+C)%m.nc() ) == m(r,c) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename vector_type + > + const matrix_exp vector_to_matrix ( + const vector_type& vector + ); + /*! + requires + - vector_type is an implementation of array/array_kernel_abstract.h or + std::vector or dlib::std_vector_c + ensures + - returns a matrix R such that: + - R.nr() == vector.size() + - R.nc() == 1 + - for all valid r: + R(r) == vector[r] + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename array_type + > + const matrix_exp array_to_matrix ( + const array_type& array + ); + /*! + requires + - array_type is an implementation of array2d/array2d_kernel_abstract.h + ensures + - returns a matrix R such that: + - R.nr() == array.nr() + - R.nc() == array.nc() + - for all valid r and c: + R(r, c) == array[r][c] + !*/ + +// ---------------------------------------------------------------------------------------- + + const rectangle get_rect ( + const matrix_exp& m + ); + /*! + ensures + - returns rectangle(0, 0, m.nc()-1, m.nr()-1) + (i.e. returns a rectangle that has the same dimensions as + the matrix m) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp subm ( + const matrix_exp& m, + long row, + long col, + long nr, + long nc + ); + /*! + requires + - row >= 0 + - row + nr < m.nr() + - col >= 0 + - col + nc < m.nc() + ensures + - returns a matrix R such that: + - R.nr() == nr + - R.nc() == nc + - for all valid r and c: + R(r, c) == m(r+row,c+col) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp subm ( + const matrix_exp& m, + const rectangle& rect + ); + /*! + requires + - get_rect(m).contains(rect) == true + (i.e. rect is a region inside the matrix m) + ensures + - returns a matrix R such that: + - R.nr() == rect.height() + - R.nc() == rect.width() + - for all valid r and c: + R(r, c) == m(r+rect.top(), c+rect.left()) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp rowm ( + const matrix_exp& m, + long row + ); + /*! + requires + - 0 <= row < m.nr() + ensures + - returns a matrix R such that: + - R.nr() == 1 + - R.nc() == m.nc() + - for all valid i: + R(i) == m(row,i) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp colm ( + const matrix_exp& m, + long col + ); + /*! + requires + - 0 <= col < m.nr() + ensures + - returns a matrix R such that: + - R.nr() == m.nr() + - R.nc() == 1 + - for all valid i: + R(i) == m(i,col) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + long R, + long C + > + const matrix_exp removerc ( + const matrix_exp& m + ); + /*! + requires + - m.nr() > 1 + - m.nc() > 1 + ensures + - returns a matrix R such that: + - R.nr() == m.nr() - 1 + - R.nc() == m.nc() - 1 + - R == m with its R row and C column removed + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename target_type + > + const matrix_exp matrix_cast ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R where for all valid r and c: + R(r,c) == static_cast(m(r,c)) + also, R has the same dimensions as m. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename MM, + typename U + > + void set_all_elements ( + matrix& m, + U value + ); + /*! + ensures + - for all valid r and c: + m(r,c) == value + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::matrix_type tmp ( + const matrix_exp& m + ); + /*! + ensures + - returns a temporary matrix object that is a copy of m. + (This is useful because it allows you to easily force a matrix_exp to + fully evaluate before giving it to some other function that queries + the elements of the matrix more than once each, such as the matrix + multiplication operator.) + !*/ + +// ---------------------------------------------------------------------------------------- + + bool equal ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp::type epsilon = 100*std::numeric_limits::epsilon() + ); + /*! + ensures + - if (a and b don't have the same dimensions) then + - returns false + - else if (there exists an r and c such that abs(a(r,c)-b(r,c)) > epsilon) then + - returns false + - else + - returns true + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp pointwise_multiply ( + const matrix_exp& a, + const matrix_exp& b + ); + /*! + requires + - a.nr() == b.nr() + - a.nc() == b.nc() + - a and b both contain the same type of element + ensures + - returns a matrix R such that: + - R::type == the same type that was in a and b. + - R has the same dimensions as a and b. + - for all valid r and c: + R(r,c) == a(r,c) * b(r,c) + !*/ + + const matrix_exp pointwise_multiply ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c + ); + /*! + performs pointwise_multiply(a,pointwise_multiply(b,c)); + !*/ + + const matrix_exp pointwise_multiply ( + const matrix_exp& a, + const matrix_exp& b, + const matrix_exp& c, + const matrix_exp& d + ); + /*! + performs pointwise_multiply(pointwise_multiply(a,b),pointwise_multiply(c,d)); + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp scale_columns ( + const matrix_exp& m, + const matrix_exp& v + ); + /*! + requires + - v.nc() == 1 (i.e. v is a column vector) + - v.nr() == m.nc() + - m and v both contain the same type of element + ensures + - returns a matrix R such that: + - R::type == the same type that was in m and v. + - R has the same dimensions as m. + - for all valid r and c: + R(r,c) == m(r,c) * v(c) + - i.e. R is the result of multiplying each of m's columns by + the corresponding scalar in v. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Linear algebra functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp::matrix_type inv ( + const matrix_exp& m + ); + /*! + requires + - m is a square matrix + ensures + - returns the inverse of m + (Note that if m is singular or so close to being singular that there + is a lot of numerical error then the returned matrix will be bogus. + You can check by seeing if m*inv(m) is an identity matrix) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::matrix_type pinv ( + const matrix_exp& m + ); + /*! + ensures + - returns the Moore-Penrose pseudoinverse of m. + - The returned matrix has m.nr() columns and m.nc() rows. + !*/ + +// ---------------------------------------------------------------------------------------- + + void svd ( + const matrix_exp& m, + matrix& u, + matrix& w, + matrix& v + ); + /*! + ensures + - computes the singular value decomposition of m + - m == #u*#w*trans(#v) + - trans(#u)*#u == identity matrix + - trans(#v)*#v == identity matrix + - #u.nr() == m.nr() + - #u.nc() == m.nc() + - #w.nr() == m.nc() + - #w.nc() == m.nc() + - #v.nr() == m.nc() + - #v.nc() == m.nc() + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type det ( + const matrix_exp& m + ); + /*! + requires + - m is a square matrix + ensures + - returns the determinant of m + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::matrix_type cholesky_decomposition ( + const matrix_exp& A + ); + /*! + requires + - A is a square matrix + ensures + - if (A has a Cholesky Decomposition) then + - returns the decomposition of A. That is, returns a matrix L + such that L*trans(L) == A. L will also be lower triangular. + - else + - returns a matrix with the same dimensions as A but it + will have a bogus value. I.e. it won't be a decomposition. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Statistics +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type min ( + const matrix_exp& m + ); + /*! + ensures + - returns the value of the smallest element of m + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type max ( + const matrix_exp& m + ); + /*! + ensures + - returns the value of the biggest element of m + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type sum ( + const matrix_exp& m + ); + /*! + ensures + - returns the sum of all elements in m + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type prod ( + const matrix_exp& m + ); + /*! + ensures + - returns the results of multiplying all elements of m together. + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type mean ( + const matrix_exp& m + ); + /*! + ensures + - returns the mean of all elements in m. + (i.e. returns sum(m)/(m.nr()*m.nc())) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix_exp::type variance ( + const matrix_exp& m + ); + /*! + ensures + - returns the unbiased sample variance of all elements in m + (i.e. 1.0/(m.nr()*m.nc() - 1)*(sum of all pow(m(i,j) - mean(m),2))) + !*/ + +// ---------------------------------------------------------------------------------------- + + const matrix covariance ( + const matrix_exp& m + ); + /*! + requires + - matrix_exp::type == a dlib::matrix object + - m.nr() > 1 + - m.nc() == 1 (i.e. m is a column vector) + - for all valid i, j: + - m(i).nr() > 0 + - m(i).nc() == 1 + - m(i).nr() == m(j).nr() + - i.e. m contains only column vectors and all the column vectors + have the same non-zero length + ensures + - returns the unbiased sample covariance matrix for the set of samples + in m. + (i.e. 1.0/(m.nr()-1)*(sum of all (m(i) - mean(m))*trans(m(i) - mean(m)))) + - the returned matrix will contain elements of type matrix_exp::type::type. + - the returned matrix will have m(0).nr() rows and columns. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Pixel and Image Utilities +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename P + > + const matrix_exp pixel_to_vector ( + const P& pixel + ); + /*! + requires + - pixel_traits

::has_alpha == false + ensures + - returns a matrix M such that: + - M::type == T + - M::NC == 1 + - M::NR == pixel_traits

::num + - if (pixel_traits

::grayscale) then + - M(0) == pixel + - if (pixel_traits

::rgb) then + - M(0) == pixel.red + - M(1) == pixel.green + - M(2) == pixel.blue + - if (pixel_traits

::hsi) then + - M(0) == pixel.h + - M(1) == pixel.s + - M(2) == pixel.i + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + void vector_to_pixel ( + P& pixel, + const matrix_exp& vector + ); + /*! + requires + - pixel_traits

::has_alpha == false + - vector::NR == pixel_traits

::num + - vector::NC == 1 + (i.e. you have to use a statically dimensioned vector) + ensures + - if (pixel_traits

::grayscale) then + - pixel == M(0) + - if (pixel_traits

::rgb) then + - pixel.red == M(0) + - pixel.green == M(1) + - pixel.blue == M(2) + - if (pixel_traits

::hsi) then + - pixel.h == M(0) + - pixel.s == M(1) + - pixel.i == M(2) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + long lower, + long upper + > + const matrix_exp clamp ( + const matrix_exp& m + ); + /*! + ensures + - returns a matrix R such that: + - R::type == the same type that was in m + - R has the same dimensions as m + - for all valid r and c: + - if (m(r,c) > upper) then + - R(r,c) == upper + - else if (m(r,c) < lower) then + - R(r,c) == lower + - else + - R(r,c) == m(r,c) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MATRIx_UTILITIES_ABSTRACT_ + diff --git a/dlib/md5.h b/dlib/md5.h new file mode 100644 index 0000000000000000000000000000000000000000..a3b50ce52325b99b5609241165c8529832cad327 --- /dev/null +++ b/dlib/md5.h @@ -0,0 +1,3 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#include "md5/md5_kernel_1.h" diff --git a/dlib/md5/md5_kernel_1.cpp b/dlib/md5/md5_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62087a22a9b01c52adde89128373617ab21862f4 --- /dev/null +++ b/dlib/md5/md5_kernel_1.cpp @@ -0,0 +1,583 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MD5_KERNEL_1_CPp_ +#define DLIB_MD5_KERNEL_1_CPp_ +#include "md5_kernel_1.h" +#include "../uintn.h" + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace md5_stuff + { + + inline uint32 F ( + uint32 x, + uint32 y, + uint32 z + ) + { + return ( (x&y) | ((~x)&z) ); + } + + // ------------------------------------------------------------------------------------ + + inline uint32 G ( + uint32 x, + uint32 y, + uint32 z + ) + { + return ( (x&z) | (y&(~z)) ); + } + + // ------------------------------------------------------------------------------------ + + inline uint32 H ( + uint32 x, + uint32 y, + uint32 z + ) + { + return ( x^y^z ); + } + + // ------------------------------------------------------------------------------------ + + inline uint32 I ( + uint32 x, + uint32 y, + uint32 z + ) + { + return ( y ^ (x|(~z)) ); + } + + // ------------------------------------------------------------------------------------ + + inline uint32 rotate_left ( + uint32 x, + uint32 n + ) + { + return ( (x<>(32-n)) ); + } + + // ------------------------------------------------------------------------------------ + + inline void FF ( + uint32& a, + uint32 b, + uint32 c, + uint32 d, + uint32 x, + uint32 s, + uint32 ac + ) + { + a += F(b, c, d) + x + ac; + a = rotate_left(a, s); + a += b; + } + + // ------------------------------------------------------------------------------------ + + inline void GG ( + uint32& a, + uint32 b, + uint32 c, + uint32 d, + uint32 x, + uint32 s, + uint32 ac + ) + { + a += G(b, c, d) + x + ac; + a = rotate_left(a, s); + a += b; + } + + // ------------------------------------------------------------------------------------ + + inline void HH ( + uint32& a, + uint32 b, + uint32 c, + uint32 d, + uint32 x, + uint32 s, + uint32 ac + ) + { + a += H(b, c, d) + x + ac; + a = rotate_left(a, s); + a += b; + } + + // ------------------------------------------------------------------------------------ + + inline void II ( + uint32& a, + uint32 b, + uint32 c, + uint32 d, + uint32 x, + uint32 s, + uint32 ac + ) + { + a += I(b, c, d) + x + ac; + a = rotate_left(a, s); + a += b; + } + + // ------------------------------------------------------------------------------------ + + void scramble_block ( + uint32& a, + uint32& b, + uint32& c, + uint32& d, + uint32* x + ) + { + const uint32 S11 = 7; + const uint32 S12 = 12; + const uint32 S13 = 17; + const uint32 S14 = 22; + const uint32 S21 = 5; + const uint32 S22 = 9; + const uint32 S23 = 14; + const uint32 S24 = 20; + const uint32 S31 = 4; + const uint32 S32 = 11; + const uint32 S33 = 16; + const uint32 S34 = 23; + const uint32 S41 = 6; + const uint32 S42 = 10; + const uint32 S43 = 15; + const uint32 S44 = 21; + + + // round 1 + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1 + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2 + FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3 + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4 + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5 + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6 + FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7 + FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8 + FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9 + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10 + FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11 + FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12 + FF (a, b, c, d, x[12], S11, 0x6b901122); // 13 + FF (d, a, b, c, x[13], S12, 0xfd987193); // 14 + FF (c, d, a, b, x[14], S13, 0xa679438e); // 15 + FF (b, c, d, a, x[15], S14, 0x49b40821); // 16 + + // Round 2 + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17 + GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18 + GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19 + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20 + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21 + GG (d, a, b, c, x[10], S22, 0x2441453); // 22 + GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23 + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24 + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25 + GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26 + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27 + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28 + GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29 + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30 + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31 + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32 + + // Round 3 + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33 + HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34 + HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35 + HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36 + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37 + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38 + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39 + HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40 + HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41 + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42 + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43 + HH (b, c, d, a, x[ 6], S34, 0x4881d05); // 44 + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45 + HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46 + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47 + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48 + + // Round 4 + II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49 + II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50 + II (c, d, a, b, x[14], S43, 0xab9423a7); // 51 + II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52 + II (a, b, c, d, x[12], S41, 0x655b59c3); // 53 + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54 + II (c, d, a, b, x[10], S43, 0xffeff47d); // 55 + II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56 + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57 + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58 + II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59 + II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60 + II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61 + II (d, a, b, c, x[11], S42, 0xbd3af235); // 62 + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63 + II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64 + } + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + + const std::string md5 ( + const std::string& input + ) + { + unsigned char output[16]; + md5 ( + reinterpret_cast(input.data()), + static_cast(input.size()), + output + ); + + + std::stringstream temp; + for (int i = 0; i < 16; ++i) + { + temp.fill('0'); + temp.width(2); + temp << std::hex << static_cast(output[i]); + } + + return temp.str(); + } + +// ---------------------------------------------------------------------------------------- + + void md5 ( + const unsigned char* input, + unsigned long len, + unsigned char* output + ) + { + using namespace md5_stuff; + + + + + // make a temp version of input with enough space for padding and len appended + unsigned long extra_len = 64-len%64; + if (extra_len <= 8) + extra_len += 64; + unsigned char* temp = new unsigned char[extra_len + len]; + + // number of 16 word blocks + const unsigned long N = (extra_len + len)/64; + + const unsigned char* input2 = input; + unsigned char* temp2 = temp; + unsigned char* end = temp+len; + + // copy input into temp + while (temp2 != end) + { + *temp2 = *input2; + ++temp2; + ++input2; + } + + // pad temp + end += extra_len-8; + *temp2 = static_cast(0x80); + ++temp2; + while (temp2 != end) + { + *temp2 = 0; + ++temp2; + } + + // make len the number of bits in the original message + // but first multiply len by 8 and since len is only 32 bits the number might + // overflow so we will carry out the multiplication manually and end up with + // the result in the base 65536 number with three digits + // result = low + high*65536 + upper*65536*65536 + unsigned long low = len & 0xFFFF; + unsigned long high = len >> 16; + unsigned long upper; + unsigned long tmp; + tmp = low * 8; + low = tmp & 0xFFFF; + tmp = high * 8 + (tmp>>16); + high = tmp & 0xFFFF; + upper = tmp >> 16; + + + // append the length + *temp2 = static_cast(low&0xFF); + ++temp2; + *temp2 = static_cast((low>>8)&0xFF); + ++temp2; + *temp2 = static_cast((high)&0xFF); + ++temp2; + *temp2 = static_cast((high>>8)&0xFF); + ++temp2; + *temp2 = static_cast((upper)&0xFF);; + ++temp2; + *temp2 = static_cast((upper>>8)&0xFF);; + ++temp2; + *temp2 = 0; + ++temp2; + *temp2 = 0; + + + uint32 a = 0x67452301; + uint32 b = 0xefcdab89; + uint32 c = 0x98badcfe; + uint32 d = 0x10325476; + + + // an array of 16 words + uint32 x[16]; + + for (unsigned long i = 0; i < N; ++i) + { + + // copy a block of 16 words from m into x + for (unsigned long j = 0; j < 16; ++j) + { + x[j] = ( + (static_cast(temp[4*(j + 16*i) + 3]) << 24) | + (static_cast(temp[4*(j + 16*i) + 2]) << 16) | + (static_cast(temp[4*(j + 16*i) + 1]) << 8 ) | + (static_cast(temp[4*(j + 16*i) ]) ) + ); + } + + uint32 aa = a; + uint32 bb = b; + uint32 cc = c; + uint32 dd = d; + + + scramble_block(a,b,c,d,x); + + + a = a + aa; + b = b + bb; + c = c + cc; + d = d + dd; + + } + + + // put a, b, c, and d into output + output[0] = static_cast((a) &0xFF); + output[1] = static_cast((a>>8) &0xFF); + output[2] = static_cast((a>>16)&0xFF); + output[3] = static_cast((a>>24)&0xFF); + + output[4] = static_cast((b) &0xFF); + output[5] = static_cast((b>>8) &0xFF); + output[6] = static_cast((b>>16)&0xFF); + output[7] = static_cast((b>>24)&0xFF); + + output[8] = static_cast((c) &0xFF); + output[9] = static_cast((c>>8) &0xFF); + output[10] = static_cast((c>>16)&0xFF); + output[11] = static_cast((c>>24)&0xFF); + + output[12] = static_cast((d) &0xFF); + output[13] = static_cast((d>>8) &0xFF); + output[14] = static_cast((d>>16)&0xFF); + output[15] = static_cast((d>>24)&0xFF); + + delete [] temp; + } + +// ---------------------------------------------------------------------------------------- + + const std::string md5 ( + std::istream& input + ) + { + unsigned char output[16]; + md5 ( + input, + output + ); + + + std::stringstream temp; + for (int i = 0; i < 16; ++i) + { + temp.fill('0'); + temp.width(2); + temp << std::hex << static_cast(output[i]); + } + + return temp.str(); + } + +// ---------------------------------------------------------------------------------------- + + void md5 ( + std::istream& input, + unsigned char* output + ) + { + using namespace md5_stuff; + + + + + uint32 a = 0x67452301; + uint32 b = 0xefcdab89; + uint32 c = 0x98badcfe; + uint32 d = 0x10325476; + + + + unsigned long len = 0; + + // an array of 16 words + uint32 x[16]; + unsigned char temp[64]; + + + + bool at_end = false; + std::streambuf& inputbuf = *input.rdbuf(); + while(!at_end) + { + int num = inputbuf.sgetn(reinterpret_cast(temp),64); + len += num; + + // if we hit the end of the stream then pad and add length + if (num < 64) + { + at_end = true; + unsigned char* temp2 = temp; + unsigned char* end = temp+56; + temp2 += num; + + // apply padding + *temp2 = 0x80; + ++temp2; + while (temp2 != end) + { + *temp2 = 0; + ++temp2; + } + + + // make len the number of bits in the original message + // but first multiply len by 8 and since len is only 32 bits the number might + // overflow so we will carry out the multiplication manually and end up with + // the result in the base 65536 number with three digits + // result = low + high*65536 + upper*65536*65536 + unsigned long low = len & 0xFFFF; + unsigned long high = len >> 16; + unsigned long upper; + unsigned long tmp; + tmp = low * 8; + low = tmp & 0xFFFF; + tmp = high * 8 + (tmp>>16); + high = tmp & 0xFFFF; + upper = tmp >> 16; + + + // append the length + *temp2 = static_cast(low&0xFF); + ++temp2; + *temp2 = static_cast((low>>8)&0xFF); + ++temp2; + *temp2 = static_cast((high)&0xFF); + ++temp2; + *temp2 = static_cast((high>>8)&0xFF); + ++temp2; + *temp2 = static_cast((upper)&0xFF);; + ++temp2; + *temp2 = static_cast((upper>>8)&0xFF);; + ++temp2; + *temp2 = 0; + ++temp2; + *temp2 = 0; + + + } + + + // copy a block of 16 words from m into x + for (unsigned long i = 0; i < 16; ++i) + { + x[i] = ( + (static_cast(temp[4*i + 3]) << 24) | + (static_cast(temp[4*i + 2]) << 16) | + (static_cast(temp[4*i + 1]) << 8 ) | + (static_cast(temp[4*i ]) ) + ); + } + + + uint32 aa = a; + uint32 bb = b; + uint32 cc = c; + uint32 dd = d; + + + scramble_block(a,b,c,d,x); + + + a = a + aa; + b = b + bb; + c = c + cc; + d = d + dd; + + } + + + // put a, b, c, and d into output + output[0] = static_cast((a) &0xFF); + output[1] = static_cast((a>>8) &0xFF); + output[2] = static_cast((a>>16)&0xFF); + output[3] = static_cast((a>>24)&0xFF); + + output[4] = static_cast((b) &0xFF); + output[5] = static_cast((b>>8) &0xFF); + output[6] = static_cast((b>>16)&0xFF); + output[7] = static_cast((b>>24)&0xFF); + + output[8] = static_cast((c) &0xFF); + output[9] = static_cast((c>>8) &0xFF); + output[10] = static_cast((c>>16)&0xFF); + output[11] = static_cast((c>>24)&0xFF); + + output[12] = static_cast((d) &0xFF); + output[13] = static_cast((d>>8) &0xFF); + output[14] = static_cast((d>>16)&0xFF); + output[15] = static_cast((d>>24)&0xFF); + + input.clear(std::ios::eofbit); + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_MD5_KERNEL_1_CPp_ + diff --git a/dlib/md5/md5_kernel_1.h b/dlib/md5/md5_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..2387b63afa816f04447c57dd15b999b4d54ed16e --- /dev/null +++ b/dlib/md5/md5_kernel_1.h @@ -0,0 +1,50 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MD5_KERNEl_1_ +#define DLIB_MD5_KERNEl_1_ + +#include "md5_kernel_abstract.h" +#include +#include +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + const std::string md5 ( + const std::string& input + ); + +// ---------------------------------------------------------------------------------------- + + void md5 ( + const unsigned char* input, + unsigned long len, + unsigned char* output + ); + +// ---------------------------------------------------------------------------------------- + + const std::string md5 ( + std::istream& input + ); + +// ---------------------------------------------------------------------------------------- + + void md5 ( + std::istream& input, + unsigned char* output + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "md5_kernel_1.cpp" +#endif + +#endif // DLIB_MD5_KERNEl_1_ + diff --git a/dlib/md5/md5_kernel_abstract.h b/dlib/md5/md5_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..78d0dd038a01edd3ba0bd8382cb763742a17c73f --- /dev/null +++ b/dlib/md5/md5_kernel_abstract.h @@ -0,0 +1,83 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MD5_KERNEl_ABSTRACT_ +#ifdef DLIB_MD5_KERNEl_ABSTRACT_ + +#include +#include + +namespace dlib +{ + + /*! + NOTE: + This is the RSA Data Security, Inc. MD5 Message-Digest Algorithm + as described in rfc1321 + + For the functions which return a unsigned char*. The array contains + the 16 bytes of the digest and are in the correct order. + i.e. output[0], output[1], output[2], ... + !*/ + +// ---------------------------------------------------------------------------------------- + + const std::string md5 ( + const std::string& input + ); + /*! + ensures + - returns the md5 digest of input as a hexadecimal string + !*/ + +// ---------------------------------------------------------------------------------------- + + void md5 ( + const unsigned char* input, + unsigned long len, + unsigned char* output + ); + /*! + requires + - input == pointer to len bytes + - output == pointer to 16 bytes + - input != output + ensures + - #output == the md5 digest of input. + !*/ + +// ---------------------------------------------------------------------------------------- + + const std::string md5 ( + std::istream& input + ); + /*! + requires + - input.fail() == false + ensures + - returns the md5 digest of input as a hexadecimal string + - #input.eof() == true + - #input.fail() == false + !*/ + +// ---------------------------------------------------------------------------------------- + + void md5 ( + std::istream& input + unsigned char* output + ); + /*! + requires + - input.fail() == false + - output == pointer to 16 bytes + ensures + - #output == the md5 digest of input + - #input.eof() == true + - #input.fail() == false + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MD5_KERNEl_ABSTRACT_ + diff --git a/dlib/member_function_pointer.h b/dlib/member_function_pointer.h new file mode 100644 index 0000000000000000000000000000000000000000..21a83275aaba1381fafcb6a2566fd7b7c600c504 --- /dev/null +++ b/dlib/member_function_pointer.h @@ -0,0 +1,38 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMBER_FUNCTION_POINTEr_ +#define DLIB_MEMBER_FUNCTION_POINTEr_ + +#include "member_function_pointer/member_function_pointer_kernel_1.h" +#include "member_function_pointer/member_function_pointer_kernel_c.h" + +namespace dlib +{ + + template < + typename PARAM1 = void, + typename PARAM2 = void, + typename PARAM3 = void, + typename PARAM4 = void + > + class member_function_pointer + { + member_function_pointer() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef member_function_pointer_kernel_1 + kernel_1a; + typedef member_function_pointer_kernel_c + kernel_1a_c; + + + }; +} + +#endif // DLIB_MEMBER_FUNCTION_POINTEr_ + diff --git a/dlib/member_function_pointer/member_function_pointer_kernel_1.h b/dlib/member_function_pointer/member_function_pointer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..f934844df61ac96d8fa1397d0d9b8390f552feba --- /dev/null +++ b/dlib/member_function_pointer/member_function_pointer_kernel_1.h @@ -0,0 +1,821 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_ +#define DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_ + +#include "../algs.h" +#include "member_function_pointer_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1 = void, + typename PARAM2 = void, + typename PARAM3 = void, + typename PARAM4 = void + > + class member_function_pointer_kernel_1; + + template < + typename PARAM1, + typename PARAM2, + typename PARAM3, + typename PARAM4 + > + void swap ( + member_function_pointer_kernel_1& a, + member_function_pointer_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template <> + class member_function_pointer_kernel_1 + { + /*! + INITIAL VALUE + - mp == 0 + + CONVENTION + - is_set() == (mp != 0) + + + Note that I'm using reinterpret_cast rather than dynamic_cast here + in the is_same() function. It would be better if dynamic_cast was used + but some compilers don't enable RTTI by default so using it would make the + build process more complicated for users so I'm not using it. I'm + not aware of any platforms/compilers where reinterpret_cast won't end + up doing the right thing for us here so it should be ok. + !*/ + + class mp_base + { + public: + virtual ~mp_base(){} + virtual void call() const = 0; + virtual mp_base* clone() const = 0; + virtual bool is_same (const mp_base* item) const = 0; + }; + + template + class mp_impl : public mp_base + { + public: + mp_impl ( + T& object, + void (T::*cb)() + ) : + callback(cb), + o(&object) + { + } + + void call ( + ) const + { + (o->*callback)(); + } + + mp_base* clone() const { return new mp_impl(*o,callback); } + + bool is_same (const mp_base* item) const + { + const mp_impl* i = reinterpret_cast(item); + return (i != 0 && i->o == o && i->callback == callback); + } + + private: + void (T::*callback)(); + T* o; + }; + + public: + typedef void param1_type; + typedef void param2_type; + typedef void param3_type; + typedef void param4_type; + + member_function_pointer_kernel_1 ( + ) : + mp(0) + {} + + member_function_pointer_kernel_1( + const member_function_pointer_kernel_1& item + ) : + mp(0) + { + if (item.is_set()) + mp = item.mp->clone(); + } + + member_function_pointer_kernel_1& operator=( + const member_function_pointer_kernel_1& item + ) + { + if (this != &item) + { + clear(); + + if (item.is_set()) + mp = item.mp->clone(); + } + return *this; + } + + bool operator == ( + const member_function_pointer_kernel_1& item + ) const + { + if (is_set() != item.is_set()) + return false; + if (is_set() == false) + return true; + return mp->is_same(item.mp); + } + + bool operator != ( + const member_function_pointer_kernel_1& item + ) const { return !(*this == item); } + + ~member_function_pointer_kernel_1 ( + ) + { + if (mp) + delete mp; + } + + void clear( + ) + { + if (mp) + { + delete mp; + mp = 0; + } + } + + bool is_set ( + ) const { return mp != 0; } + + template < + typename T + > + void set ( + T& object, + void (T::*cb)() + ) + { + clear(); + mp = new mp_impl(object,cb); + } + + void operator () ( + ) const { mp->call(); } + + void swap ( + member_function_pointer_kernel_1& item + ) { exchange(mp,item.mp); } + + private: + + mp_base* mp; + + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1 + > + class member_function_pointer_kernel_1 + { + /*! + INITIAL VALUE + - mp == 0 + + CONVENTION + - is_set() == (mp != 0) + !*/ + + class mp_base + { + public: + virtual ~mp_base(){} + virtual void call(PARAM1) const = 0; + virtual mp_base* clone() const = 0; + virtual bool is_same (const mp_base* item) const = 0; + }; + + template + class mp_impl : public mp_base + { + public: + mp_impl ( + T& object, + void (T::*cb)(PARAM1) + ) : + callback(cb), + o(&object) + { + } + + void call ( + PARAM1 param1 + ) const + { + (o->*callback)(param1); + } + + mp_base* clone() const { return new mp_impl(*o,callback); } + + bool is_same (const mp_base* item) const + { + const mp_impl* i = reinterpret_cast(item); + return (i != 0 && i->o == o && i->callback == callback); + } + + private: + void (T::*callback)(PARAM1); + T* o; + }; + + public: + typedef PARAM1 param1_type; + typedef void param2_type; + typedef void param3_type; + typedef void param4_type; + + member_function_pointer_kernel_1 ( + ) : + mp(0) + {} + + member_function_pointer_kernel_1( + const member_function_pointer_kernel_1& item + ) : + mp(0) + { + if (item.is_set()) + mp = item.mp->clone(); + } + + member_function_pointer_kernel_1& operator=( + const member_function_pointer_kernel_1& item + ) + { + if (this != &item) + { + clear(); + + if (item.is_set()) + mp = item.mp->clone(); + } + return *this; + } + + bool operator == ( + const member_function_pointer_kernel_1& item + ) const + { + if (is_set() != item.is_set()) + return false; + if (is_set() == false) + return true; + return mp->is_same(item.mp); + } + + bool operator != ( + const member_function_pointer_kernel_1& item + ) const { return !(*this == item); } + + ~member_function_pointer_kernel_1 ( + ) + { + if (mp) + delete mp; + } + + void clear( + ) + { + if (mp) + { + delete mp; + mp = 0; + } + } + + bool is_set ( + ) const { return mp != 0; } + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1) + ) + { + clear(); + mp = new mp_impl(object,cb); + } + + void operator () ( + PARAM1 param1 + ) const { mp->call(param1); } + + void swap ( + member_function_pointer_kernel_1& item + ) { exchange(mp,item.mp); } + + private: + + mp_base* mp; + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1, + typename PARAM2 + > + class member_function_pointer_kernel_1 + { + /*! + INITIAL VALUE + - mp == 0 + + CONVENTION + - is_set() == (mp != 0) + !*/ + + class mp_base + { + public: + virtual ~mp_base(){} + virtual void call(PARAM1,PARAM2) const = 0; + virtual mp_base* clone() const = 0; + virtual bool is_same (const mp_base* item) const = 0; + }; + + template + class mp_impl : public mp_base + { + public: + mp_impl ( + T& object, + void (T::*cb)(PARAM1,PARAM2) + ) : + callback(cb), + o(&object) + { + } + + void call ( + PARAM1 param1, + PARAM2 param2 + ) const + { + (o->*callback)(param1,param2); + } + + mp_base* clone() const { return new mp_impl(*o,callback); } + + bool is_same (const mp_base* item) const + { + const mp_impl* i = reinterpret_cast(item); + return (i != 0 && i->o == o && i->callback == callback); + } + + private: + void (T::*callback)(PARAM1,PARAM2); + T* o; + }; + + public: + typedef PARAM1 param1_type; + typedef PARAM2 param2_type; + typedef void param3_type; + typedef void param4_type; + + member_function_pointer_kernel_1 ( + ) : + mp(0) + {} + + member_function_pointer_kernel_1( + const member_function_pointer_kernel_1& item + ) : + mp(0) + { + if (item.is_set()) + mp = item.mp->clone(); + } + + member_function_pointer_kernel_1& operator=( + const member_function_pointer_kernel_1& item + ) + { + if (this != &item) + { + clear(); + + if (item.is_set()) + mp = item.mp->clone(); + } + return *this; + } + + bool operator == ( + const member_function_pointer_kernel_1& item + ) const + { + if (is_set() != item.is_set()) + return false; + if (is_set() == false) + return true; + return mp->is_same(item.mp); + } + + bool operator != ( + const member_function_pointer_kernel_1& item + ) const { return !(*this == item); } + + ~member_function_pointer_kernel_1 ( + ) + { + if (mp) + delete mp; + } + + void clear( + ) + { + if (mp) + { + delete mp; + mp = 0; + } + } + + bool is_set ( + ) const { return mp != 0; } + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2) + ) + { + clear(); + mp = new mp_impl(object,cb); + } + + void operator () ( + PARAM1 param1, + PARAM2 param2 + ) const { mp->call(param1,param2); } + + void swap ( + member_function_pointer_kernel_1& item + ) { exchange(mp,item.mp); } + + private: + + mp_base* mp; + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1, + typename PARAM2, + typename PARAM3 + > + class member_function_pointer_kernel_1 + { + /*! + INITIAL VALUE + - mp == 0 + + CONVENTION + - is_set() == (mp != 0) + !*/ + + class mp_base + { + public: + virtual ~mp_base(){} + virtual void call(PARAM1,PARAM2,PARAM3) const = 0; + virtual mp_base* clone() const = 0; + virtual bool is_same (const mp_base* item) const = 0; + }; + + template + class mp_impl : public mp_base + { + public: + mp_impl ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3) + ) : + callback(cb), + o(&object) + { + } + + void call ( + PARAM1 param1, + PARAM2 param2, + PARAM3 param3 + ) const + { + (o->*callback)(param1,param2,param3); + } + + mp_base* clone() const { return new mp_impl(*o,callback); } + + bool is_same (const mp_base* item) const + { + const mp_impl* i = reinterpret_cast(item); + return (i != 0 && i->o == o && i->callback == callback); + } + + private: + void (T::*callback)(PARAM1,PARAM2,PARAM3); + T* o; + }; + + public: + typedef PARAM1 param1_type; + typedef PARAM2 param2_type; + typedef PARAM3 param3_type; + typedef void param4_type; + + member_function_pointer_kernel_1 ( + ) : + mp(0) + {} + + member_function_pointer_kernel_1( + const member_function_pointer_kernel_1& item + ) : + mp(0) + { + if (item.is_set()) + mp = item.mp->clone(); + } + + member_function_pointer_kernel_1& operator=( + const member_function_pointer_kernel_1& item + ) + { + if (this != &item) + { + clear(); + + if (item.is_set()) + mp = item.mp->clone(); + } + return *this; + } + + bool operator == ( + const member_function_pointer_kernel_1& item + ) const + { + if (is_set() != item.is_set()) + return false; + if (is_set() == false) + return true; + return mp->is_same(item.mp); + } + + bool operator != ( + const member_function_pointer_kernel_1& item + ) const { return !(*this == item); } + + ~member_function_pointer_kernel_1 ( + ) + { + if (mp) + delete mp; + } + + void clear( + ) + { + if (mp) + { + delete mp; + mp = 0; + } + } + + bool is_set ( + ) const { return mp != 0; } + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3) + ) + { + clear(); + mp = new mp_impl(object,cb); + } + + void operator () ( + PARAM1 param1, + PARAM2 param2, + PARAM3 param3 + ) const { mp->call(param1,param2,param3); } + + void swap ( + member_function_pointer_kernel_1& item + ) { exchange(mp,item.mp); } + + private: + + mp_base* mp; + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1, + typename PARAM2, + typename PARAM3, + typename PARAM4 + > + class member_function_pointer_kernel_1 + { + /*! + INITIAL VALUE + - mp == 0 + + CONVENTION + - is_set() == (mp != 0) + !*/ + + class mp_base + { + public: + virtual ~mp_base(){} + virtual void call(PARAM1,PARAM2,PARAM3,PARAM4) const = 0; + virtual mp_base* clone() const = 0; + virtual bool is_same (const mp_base* item) const = 0; + }; + + template + class mp_impl : public mp_base + { + public: + mp_impl ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4) + ) : + callback(cb), + o(&object) + { + } + + void call ( + PARAM1 param1, + PARAM2 param2, + PARAM3 param3, + PARAM4 param4 + ) const + { + (o->*callback)(param1,param2,param3,param4); + } + + mp_base* clone() const { return new mp_impl(*o,callback); } + + bool is_same (const mp_base* item) const + { + const mp_impl* i = reinterpret_cast(item); + return (i != 0 && i->o == o && i->callback == callback); + } + + private: + void (T::*callback)(PARAM1,PARAM2,PARAM3,PARAM4); + T* o; + }; + + public: + typedef PARAM1 param1_type; + typedef PARAM2 param2_type; + typedef PARAM3 param3_type; + typedef PARAM4 param4_type; + + member_function_pointer_kernel_1 ( + ) : + mp(0) + {} + + member_function_pointer_kernel_1( + const member_function_pointer_kernel_1& item + ) : + mp(0) + { + if (item.is_set()) + mp = item.mp->clone(); + } + + member_function_pointer_kernel_1& operator=( + const member_function_pointer_kernel_1& item + ) + { + if (this != &item) + { + clear(); + + if (item.is_set()) + mp = item.mp->clone(); + } + return *this; + } + + bool operator == ( + const member_function_pointer_kernel_1& item + ) const + { + if (is_set() != item.is_set()) + return false; + if (is_set() == false) + return true; + return mp->is_same(item.mp); + } + + bool operator != ( + const member_function_pointer_kernel_1& item + ) const { return !(*this == item); } + + ~member_function_pointer_kernel_1 ( + ) + { + if (mp) + delete mp; + } + + void clear( + ) + { + if (mp) + { + delete mp; + mp = 0; + } + } + + bool is_set ( + ) const { return mp != 0; } + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4) + ) + { + clear(); + mp = new mp_impl(object,cb); + } + + void operator () ( + PARAM1 param1, + PARAM2 param2, + PARAM3 param3, + PARAM4 param4 + ) const { mp->call(param1,param2,param3,param4); } + + void swap ( + member_function_pointer_kernel_1& item + ) { exchange(mp,item.mp); } + + private: + + mp_base* mp; + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_ + diff --git a/dlib/member_function_pointer/member_function_pointer_kernel_abstract.h b/dlib/member_function_pointer/member_function_pointer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b6b6c445bd53abacaf0abed5bedae5aa2728184e --- /dev/null +++ b/dlib/member_function_pointer/member_function_pointer_kernel_abstract.h @@ -0,0 +1,422 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_ +#ifdef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_ + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1 = void, + typename PARAM2 = void, + typename PARAM3 = void, + typename PARAM4 = void + > + class member_function_pointer; + + template < + typename PARAM1, + typename PARAM2, + typename PARAM3, + typename PARAM4 + > + void swap ( + member_function_pointer& a, + member_function_pointer& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template <> + class member_function_pointer + { + /*! + INITIAL VALUE + is_set() == false + + WHAT THIS OBJECT REPRESENTS + This object represents a member function pointer. It is useful because + instances of this object can be created without needing to know the type + of object whose member function we will be calling. + + There are five template specializations of this object. The first + represents a pointer to a member function taking no parameters, the + second represents a pointer to a member function taking one parameter, + the third to one taking two parameters, and so on. + + You specify the parameters to your member function pointer by filling in + the PARAM template parameters. For example: + + To use a pointer to a function with no parameters you would say: + member_function_pointer<> my_pointer; + To use a pointer to a function that takes a single int you would say: + member_function_pointer my_pointer; + To use a pointer to a function that takes an int and then a string + you would say: + member_function_pointer my_pointer; + + Also note that the formal comments are only present for the first + template specialization. They are all exactly the same except for the + number of parameters each takes in its member function pointer. + !*/ + + public: + typedef void param1_type; + typedef void param2_type; + typedef void param3_type; + typedef void param4_type; + + member_function_pointer ( + ); + /*! + ensures + - #*this is properly initialized + !*/ + + member_function_pointer( + const member_function_pointer& item + ); + /*! + ensures + - *this == item + throws + - std::bad_alloc + !*/ + + ~member_function_pointer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + member_function_pointer& operator=( + const member_function_pointer& item + ); + /*! + ensures + - *this == item + throws + - std::bad_alloc + If this exception is thrown then #is_set() == false + !*/ + + bool operator == ( + const member_function_pointer& item + ) const; + /*! + ensures + - if (is_set() == false && item.is_set() == false) then + - returns true + - else if (both *this and item point to the same member function + in the same object instance) then + - returns true + - else + - returns false + !*/ + + bool operator != ( + const member_function_pointer& item + ) const; + /*! + ensures + - returns !(*this == item) + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + !*/ + + bool is_set ( + ) const; + /*! + ensures + - if (this->set() has been called and succeeded) then + - returns true + - else + - returns false + !*/ + + template < + typename T + > + void set ( + T& object, + void (T::*cb)() + ); + /*! + requires + - cb == a valid member function pointer for class T + ensures + - #is_set() == true + - calls to this->operator() will call (object.*cb)() + throws + - std::bad_alloc + If this exception is thrown then #is_set() == false + !*/ + + void operator () ( + ) const; + /*! + requires + - is_set() == true + ensures + - calls the member function on the object specified by the last + call to this->set() + throws + - any exception thrown by the member function specified by + the previous call to this->set(). + If any of these exceptions are thrown then the call to this + function will have no effect on *this. + !*/ + + void swap ( + member_function_pointer& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1 + > + class member_function_pointer + { + public: + typedef PARAM1 param1_type; + typedef void param2_type; + typedef void param3_type; + typedef void param4_type; + + member_function_pointer (); + + member_function_pointer( + const member_function_pointer& item + ); + + ~member_function_pointer ( + ); + + member_function_pointer& operator=( + const member_function_pointer& item + ); + + bool operator == ( + const member_function_pointer& item + ) const; + + bool operator != ( + const member_function_pointer& item + ) const; + + void clear(); + + bool is_set () const; + + template + void set ( + T& object, + void (T::*cb)(PARAM1) + ); + + void operator () ( + PARAM1 param1 + ) const; + + void swap ( + member_function_pointer& item + ); + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1, + typename PARAM2 + > + class member_function_pointer + { + public: + typedef PARAM1 param1_type; + typedef PARAM2 param2_type; + typedef void param3_type; + typedef void param4_type; + + member_function_pointer (); + + member_function_pointer( + const member_function_pointer& item + ); + + ~member_function_pointer ( + ); + + member_function_pointer& operator=( + const member_function_pointer& item + ); + + bool operator == ( + const member_function_pointer& item + ) const; + + bool operator != ( + const member_function_pointer& item + ) const; + + void clear(); + + bool is_set () const; + + template + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2) + ); + + void operator () ( + PARAM1 param1, + PARAM2 param2 + ) const; + + void swap ( + member_function_pointer& item + ); + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1, + typename PARAM2, + typename PARAM3 + > + class member_function_pointer + { + public: + typedef PARAM1 param1_type; + typedef PARAM2 param2_type; + typedef PARAM3 param3_type; + typedef void param4_type; + + member_function_pointer (); + + member_function_pointer( + const member_function_pointer& item + ); + + ~member_function_pointer ( + ); + + member_function_pointer& operator=( + const member_function_pointer& item + ); + + bool operator == ( + const member_function_pointer& item + ) const; + + bool operator != ( + const member_function_pointer& item + ) const; + + void clear(); + + bool is_set () const; + + template + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3) + ); + + void operator () ( + PARAM1 param1, + PARAM2 param2, + PARAM2 param3 + ) const; + + void swap ( + member_function_pointer& item + ); + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename PARAM1, + typename PARAM2, + typename PARAM3, + typename PARAM4 + > + class member_function_pointer + { + public: + typedef PARAM1 param1_type; + typedef PARAM2 param2_type; + typedef PARAM3 param3_type; + typedef PARAM4 param4_type; + + member_function_pointer (); + + member_function_pointer( + const member_function_pointer& item + ); + + ~member_function_pointer ( + ); + + member_function_pointer& operator=( + const member_function_pointer& item + ); + + bool operator == ( + const member_function_pointer& item + ) const; + + bool operator != ( + const member_function_pointer& item + ) const; + + void clear(); + + bool is_set () const; + + template + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4) + ); + + void operator () ( + PARAM1 param1, + PARAM2 param2, + PARAM2 param3, + PARAM2 param4 + ) const; + + void swap ( + member_function_pointer& item + ); + + }; + +// ---------------------------------------------------------------------------------------- + + +} + +#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_ + diff --git a/dlib/member_function_pointer/member_function_pointer_kernel_c.h b/dlib/member_function_pointer/member_function_pointer_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..5d9c7ff145019c446a59c338147b32ed687af344 --- /dev/null +++ b/dlib/member_function_pointer/member_function_pointer_kernel_c.h @@ -0,0 +1,279 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_C_ +#define DLIB_MEMBER_FUNCTION_POINTER_KERNEl_C_ + +#include "member_function_pointer_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename mfpb,// is an implementation of member_function_pointer_kernel_abstract.h + typename PARAM1 = typename mfpb::param1_type, + typename PARAM2 = typename mfpb::param2_type, + typename PARAM3 = typename mfpb::param3_type, + typename PARAM4 = typename mfpb::param4_type + > + class member_function_pointer_kernel_c; + + template < + typename mfpb, + typename PARAM1, + typename PARAM2, + typename PARAM3, + typename PARAM4 + > + void swap ( + member_function_pointer_kernel_c& a, + member_function_pointer_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + + template < + typename mfpb + > + class member_function_pointer_kernel_c : + public mfpb + { + public: + + template < + typename T + > + void set ( + T& object, + void (T::*cb)() + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(cb != 0, + "\tvoid member_function_pointer::set" + << "\n\tthe member function pointer can't be null" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::set(object,cb); + } + + void operator () ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->is_set() == true , + "\tvoid member_function_pointer::operator()" + << "\n\tYou must call set() before you can use this function" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::operator()(); + } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename mfpb, + typename PARAM1 + > + class member_function_pointer_kernel_c : + public mfpb + { + public: + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1) + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(cb != 0, + "\tvoid member_function_pointer::set" + << "\n\tthe member function pointer can't be null" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::set(object,cb); + } + + void operator () ( + PARAM1 param1 + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->is_set() == true , + "\tvoid member_function_pointer::operator()" + << "\n\tYou must call set() before you can use this function" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::operator()(param1); + } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename mfpb, + typename PARAM1, + typename PARAM2 + > + class member_function_pointer_kernel_c : + public mfpb + { + public: + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2) + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(cb != 0, + "\tvoid member_function_pointer::set" + << "\n\tthe member function pointer can't be null" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::set(object,cb); + } + + void operator () ( + PARAM1 param1, + PARAM2 param2 + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->is_set() == true , + "\tvoid member_function_pointer::operator()" + << "\n\tYou must call set() before you can use this function" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::operator()(param1,param2); + } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename mfpb, + typename PARAM1, + typename PARAM2, + typename PARAM3 + > + class member_function_pointer_kernel_c : + public mfpb + { + public: + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3) + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(cb != 0, + "\tvoid member_function_pointer::set" + << "\n\tthe member function pointer can't be null" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::set(object,cb); + } + + void operator () ( + PARAM1 param1, + PARAM2 param2, + PARAM3 param3 + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->is_set() == true , + "\tvoid member_function_pointer::operator()" + << "\n\tYou must call set() before you can use this function" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::operator()(param1,param2,param3); + } + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename mfpb, + typename PARAM1, + typename PARAM2, + typename PARAM3, + typename PARAM4 + > + class member_function_pointer_kernel_c : + public mfpb + { + public: + + template < + typename T + > + void set ( + T& object, + void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4) + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(cb != 0, + "\tvoid member_function_pointer::set" + << "\n\tthe member function pointer can't be null" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::set(object,cb); + } + + void operator () ( + PARAM1 param1, + PARAM2 param2, + PARAM3 param3, + PARAM4 param4 + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->is_set() == true , + "\tvoid member_function_pointer::operator()" + << "\n\tYou must call set() before you can use this function" + << "\n\tthis: " << this + ); + + // call the real function + mfpb::operator()(param1,param2,param3,param4); + } + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_C_ + diff --git a/dlib/memory_manager.h b/dlib/memory_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d025c1d3f3e263e76fa0f0e3e6550b23f61d76ff --- /dev/null +++ b/dlib/memory_manager.h @@ -0,0 +1,73 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGEr_ +#define DLIB_MEMORY_MANAGEr_ + +#include "memory_manager/memory_manager_kernel_1.h" +#include "memory_manager/memory_manager_kernel_2.h" +#include "memory_manager/memory_manager_kernel_3.h" + + + +namespace dlib +{ + + template < + typename T + > + class memory_manager + { + memory_manager() {} + + + public: + + //----------- kernels --------------- + + // kernel_1 + typedef memory_manager_kernel_1 + kernel_1a; + typedef memory_manager_kernel_1 + kernel_1b; + typedef memory_manager_kernel_1 + kernel_1c; + typedef memory_manager_kernel_1 + kernel_1d; + typedef memory_manager_kernel_1 + kernel_1e; + typedef memory_manager_kernel_1 + kernel_1f; + + // kernel_2 + typedef memory_manager_kernel_2 + kernel_2a; + typedef memory_manager_kernel_2 + kernel_2b; + typedef memory_manager_kernel_2 + kernel_2c; + typedef memory_manager_kernel_2 + kernel_2d; + typedef memory_manager_kernel_2 + kernel_2e; + + + // kernel_3 + typedef memory_manager_kernel_3 + kernel_3a; + typedef memory_manager_kernel_3 + kernel_3b; + typedef memory_manager_kernel_3 + kernel_3c; + typedef memory_manager_kernel_3 + kernel_3d; + typedef memory_manager_kernel_3 + kernel_3e; + + + + + }; +} + +#endif // DLIB_MEMORY_MANAGEr_ + diff --git a/dlib/memory_manager/memory_manager_kernel_1.h b/dlib/memory_manager/memory_manager_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..cca5db37be43cb6a45357f4bf3ad50b125155147 --- /dev/null +++ b/dlib/memory_manager/memory_manager_kernel_1.h @@ -0,0 +1,305 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_KERNEl_1_ +#define DLIB_MEMORY_MANAGER_KERNEl_1_ + +#include "../algs.h" +#include "memory_manager_kernel_abstract.h" +#include "../assert.h" +#include + + +namespace dlib +{ + + template < + typename T, + unsigned long max_pool_size + > + class memory_manager_kernel_1 + { + /*! + INITIAL VALUE + allocations == 0 + next == 0 + pool_size == 0 + + REQUIREMENTS ON max_pool_size + max_pool_size is the maximum number of nodes we will keep in our linked list at once. + So you can put any value in for this argument. + + CONVENTION + This memory manager implementation allocates T objects one at a time when there are + allocation requests. Then when there is a deallocate request the returning T object + is place into a list of free blocks if that list has less than max_pool_size + blocks in it. subsequent allocation requests will be serviced by drawing from the + free list whenever it isn't empty. + + + allocations == get_number_of_allocations() + + - if (next != 0) then + - next == the next pointer to return from allocate() + and next == pointer to the first node in a linked list. each node + is one item in the memory pool. + - the last node in the linked list has next set to 0 + - pool_size == the number of nodes in the linked list + - pool_size <= max_pool_size + - else + - we need to call new to get the next pointer to return from allocate() + + !*/ + + union node + { + node* next; + char item[sizeof(T)]; + }; + + public: + + typedef T type; + + template + struct rebind { + typedef memory_manager_kernel_1 other; + }; + + + memory_manager_kernel_1( + ) : + allocations(0), + next(0), + pool_size(0) + { + } + + virtual ~memory_manager_kernel_1( + ) + { + + while (next != 0) + { + node* temp = next; + next = next->next; + ::operator delete ( reinterpret_cast(temp)); + } + } + + unsigned long get_number_of_allocations ( + ) const { return allocations; } + + T* allocate_array ( + unsigned long size + ) + { + T* temp = new T[size]; + ++allocations; + return temp; + } + + void deallocate_array ( + T* item + ) + { + --allocations; + delete [] item; + } + + T* allocate ( + ) + { + T* temp; + if (next != 0) + { + temp = reinterpret_cast(next); + + node* n = next->next; + + try + { + // construct this new T object with placement new. + new (reinterpret_cast(temp))T(); + } + catch (...) + { + next->next = n; + throw; + } + + next = n; + + --pool_size; + } + else + { + temp = reinterpret_cast(::operator new(sizeof(node))); + try + { + // construct this new T object with placement new. + new (reinterpret_cast(temp))T(); + } + catch (...) + { + // construction of the new object threw so delete the block of memory + ::operator delete ( reinterpret_cast(temp)); + throw; + } + } + + ++allocations; + return temp; + } + + void deallocate ( + T* item + ) + { + --allocations; + item->~T(); + + if (pool_size >= max_pool_size) + { + ::operator delete ( reinterpret_cast(item)); + return; + } + + // add this memory chunk into our linked list. + node* temp = reinterpret_cast(item); + temp->next = next; + next = temp; + ++pool_size; + } + + void swap ( + memory_manager_kernel_1& item + ) + { + exchange(allocations,item.allocations); + exchange(next,item.next); + exchange(pool_size,item.pool_size); + } + + private: + + // data members + unsigned long allocations; + node* next; + unsigned long pool_size; + + // restricted functions + memory_manager_kernel_1(memory_manager_kernel_1&); // copy constructor + memory_manager_kernel_1& operator=(memory_manager_kernel_1&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class memory_manager_kernel_1 + { + /*! + INITIAL VALUE + allocations == 0 + + CONVENTION + This memory manager just calls new and delete directly so it doesn't + really do anything. + + allocations == get_number_of_allocations() + !*/ + + public: + + typedef T type; + + template + struct rebind { + typedef memory_manager_kernel_1 other; + }; + + + memory_manager_kernel_1( + ) : + allocations(0) + { + } + + virtual ~memory_manager_kernel_1( + ) + { + } + + unsigned long get_number_of_allocations ( + ) const { return allocations; } + + T* allocate_array ( + unsigned long size + ) + { + T* temp = new T[size]; + ++allocations; + return temp; + } + + void deallocate_array ( + T* item + ) + { + --allocations; + delete [] item; + } + + T* allocate ( + ) + { + T* temp = new T; + ++allocations; + return temp; + } + + void deallocate ( + T* item + ) + { + delete item; + --allocations; + } + + void swap ( + memory_manager_kernel_1& item + ) + { + exchange(allocations,item.allocations); + } + + private: + + // data members + unsigned long allocations; + + // restricted functions + memory_manager_kernel_1(memory_manager_kernel_1&); // copy constructor + memory_manager_kernel_1& operator=(memory_manager_kernel_1&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long max_pool_size + > + inline void swap ( + memory_manager_kernel_1& a, + memory_manager_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MEMORY_MANAGER_KERNEl_1_ + + + diff --git a/dlib/memory_manager/memory_manager_kernel_2.h b/dlib/memory_manager/memory_manager_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..56e6287014938351014e2729e142eab7d860021c --- /dev/null +++ b/dlib/memory_manager/memory_manager_kernel_2.h @@ -0,0 +1,253 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_KERNEl_2_ +#define DLIB_MEMORY_MANAGER_KERNEl_2_ + +#include "../algs.h" +#include "memory_manager_kernel_abstract.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename T, + unsigned long chunk_size + > + class memory_manager_kernel_2 + { + /*! + INITIAL VALUE + allocations == 0 + next == 0 + first_chunk == 0 + + REQUIREMENTS ON chunk_size + chunk_size is the number of items of type T we will allocate at a time. so + it must be > 0. + + CONVENTION + This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T) + bytes. All the sizeof(T) subblocks are kept in a linked list of free memory blocks + and are given out whenever an allocation request occurs. Also, memory is not freed + until this object is destructed. + + Note that array allocations are not memory managed. + + + + allocations == get_number_of_allocations() + + - if (next != 0) then + - next == the next pointer to return from allocate() + and next == pointer to the first node in a linked list. each node + is one item in the memory pool. + - the last node in the linked list has next set to 0 + - else + - we need to call new to get the next pointer to return from allocate() + + + - if (first_chunk != 0) then + - first_chunk == the first node in a linked list that contains pointers + to all the chunks we have ever allocated. The last link in the list + has its next pointer set to 0. + !*/ + + union node + { + node* next; + char item[sizeof(T)]; + }; + + struct chunk_node + { + node* chunk; + chunk_node* next; + }; + + public: + + typedef T type; + + template + struct rebind { + typedef memory_manager_kernel_2 other; + }; + + + memory_manager_kernel_2( + ) : + allocations(0), + next(0), + first_chunk(0) + { + // You FOOL! You can't have a zero chunk_size. + COMPILE_TIME_ASSERT(chunk_size > 0); + } + + virtual ~memory_manager_kernel_2( + ) + { + if (allocations == 0) + { + while (first_chunk != 0) + { + chunk_node* temp = first_chunk; + first_chunk = first_chunk->next; + // delete the memory chunk + ::operator delete ( reinterpret_cast(temp->chunk)); + // delete the chunk_node + delete temp; + } + } + } + + unsigned long get_number_of_allocations ( + ) const { return allocations; } + + T* allocate_array ( + unsigned long size + ) + { + T* temp = new T[size]; + ++allocations; + return temp; + } + + void deallocate_array ( + T* item + ) + { + --allocations; + delete [] item; + } + + T* allocate ( + ) + { + T* temp = 0; + if (next != 0) + { + temp = reinterpret_cast(next); + node* n = next->next; + + try + { + // construct this new T object with placement new. + new (reinterpret_cast(temp))T(); + } + catch (...) + { + next->next = n; + throw; + } + + next = n; + } + else + { + // the linked list is empty so we need to allocate some more memory + node* block = 0; + block = reinterpret_cast(::operator new (sizeof(node)*chunk_size)); + + // the first part of this block can be our new object + temp = reinterpret_cast(block); + + try + { + // construct this new T object with placement new. + new (reinterpret_cast(temp))T(); + } + catch (...) + { + // construction of the new object threw so delete the block of memory + ::operator delete ( reinterpret_cast(block)); + throw; + } + + // allocate a new chunk_node + chunk_node* chunk; + try {chunk = new chunk_node; } + catch (...) + { + temp->~T(); + ::operator delete ( reinterpret_cast(block)); + throw; + } + + // add this block into the chunk list + chunk->chunk = block; + chunk->next = first_chunk; + first_chunk = chunk; + + + ++block; + // now add the rest of the block into the linked list of free nodes. + for (unsigned long i = 0; i < chunk_size-1; ++i) + { + block->next = next; + next = block; + ++block; + } + + } + + + ++allocations; + return temp; + } + + void deallocate ( + T* item + ) + { + --allocations; + item->~T(); + + // add this memory into our linked list. + node* temp = reinterpret_cast(item); + temp->next = next; + next = temp; + } + + void swap ( + memory_manager_kernel_2& item + ) + { + exchange(allocations,item.allocations); + exchange(next,item.next); + exchange(first_chunk,item.first_chunk); + } + + private: + + // data members + unsigned long allocations; + node* next; + + chunk_node* first_chunk; + + + + + // restricted functions + memory_manager_kernel_2(memory_manager_kernel_2&); // copy constructor + memory_manager_kernel_2& operator=(memory_manager_kernel_2&); // assignment operator + }; + + template < + typename T, + unsigned long chunk_size + > + inline void swap ( + memory_manager_kernel_2& a, + memory_manager_kernel_2& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MEMORY_MANAGER_KERNEl_2_ + diff --git a/dlib/memory_manager/memory_manager_kernel_3.h b/dlib/memory_manager/memory_manager_kernel_3.h new file mode 100644 index 0000000000000000000000000000000000000000..b1e63045c98294a3f76a1546dfb042782229d4c3 --- /dev/null +++ b/dlib/memory_manager/memory_manager_kernel_3.h @@ -0,0 +1,385 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_KERNEl_3_ +#define DLIB_MEMORY_MANAGER_KERNEl_3_ + +#include "../algs.h" +#include "memory_manager_kernel_abstract.h" +#include "../assert.h" +#include +#include "memory_manager_kernel_2.h" +#include "../binary_search_tree/binary_search_tree_kernel_2.h" + + +namespace dlib +{ + + template < + typename T, + unsigned long chunk_size + > + class memory_manager_kernel_3 + { + /*! + INITIAL VALUE + allocations == 0 + next == 0 + first_chunk == 0 + bst_of_arrays == 0 + + REQUIREMENTS ON chunk_size + chunk_size is the number of items of type T we will allocate at a time. so + it must be > 0. + + CONVENTION + This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T) + bytes. All the sizeof(T) subblocks are kept in a linked list of free memory blocks + and are given out whenever an allocation request occurs. Also, memory is not freed + until this object is destructed. + + + + allocations == get_number_of_allocations() + + - if (next != 0) then + - next == the next pointer to return from allocate() + and next == pointer to the first node in a linked list. each node + is one item in the memory pool. + - the last node in the linked list has next set to 0 + - else + - we need to call new to get the next pointer to return from allocate() + + - if (arrays != 0) then + - someone has called allocate_array() + - (*arrays)[size] == an array of size bytes of memory + + - if (first_chunk != 0) then + - first_chunk == the first node in a linked list that contains pointers + to all the chunks we have ever allocated. The last link in the list + has its next pointer set to 0. + !*/ + + union node + { + node* next; + char item[sizeof(T)]; + }; + + struct chunk_node + { + node* chunk; + chunk_node* next; + }; + + + typedef binary_search_tree_kernel_2< + size_t, + char*, + memory_manager_kernel_2 + > bst_of_arrays; + + public: + + typedef T type; + + template + struct rebind { + typedef memory_manager_kernel_3 other; + }; + + + memory_manager_kernel_3( + ) : + allocations(0), + next(0), + first_chunk(0), + arrays(0) + { + // You FOOL! You can't have a zero chunk_size. + COMPILE_TIME_ASSERT(chunk_size > 0); + } + + virtual ~memory_manager_kernel_3( + ) + { + if (allocations == 0) + { + while (first_chunk != 0) + { + chunk_node* temp = first_chunk; + first_chunk = first_chunk->next; + // delete the memory chunk + ::operator delete ( reinterpret_cast(temp->chunk)); + // delete the chunk_node + delete temp; + } + } + + if (arrays) + { + arrays->reset(); + while (arrays->move_next()) + { + ::operator delete (arrays->element().value()); + } + delete arrays; + } + } + + unsigned long get_number_of_allocations ( + ) const { return allocations; } + + T* allocate_array ( + unsigned long size + ) + { + size_t block_size = sizeof(T)*size + sizeof(size_t)*2; + + // make sure we have initialized the arrays object. + if (arrays == 0) + { + arrays = new bst_of_arrays; + } + + char* temp; + + // see if we have a suitable block of memory already. + arrays->position_enumerator(block_size); + if (arrays->current_element_valid()) + { + // we have a suitable block of memory already so use that one. + arrays->remove_current_element(block_size,temp); + } + else + { + temp = reinterpret_cast(::operator new(block_size)); + } + + reinterpret_cast(temp)[0] = block_size; + reinterpret_cast(temp)[1] = size; + temp += sizeof(size_t)*2; + + try + { + initialize_array(reinterpret_cast(temp),size); + } + catch (...) + { + // something was thrown while we were initializing the array so + // stick our memory block into arrays and rethrow the exception + temp -= sizeof(size_t)*2; + arrays->add(block_size,temp); + throw; + } + + ++allocations; + return reinterpret_cast(temp); + } + + void deallocate_array ( + T* item + ) + { + char* temp = reinterpret_cast(item); + temp -= sizeof(size_t)*2; + size_t block_size = reinterpret_cast(temp)[0]; + size_t size = reinterpret_cast(temp)[1]; + + deinitialize_array(item,size); + + arrays->add(block_size,temp); + + --allocations; + } + + T* allocate ( + ) + { + T* temp; + if (next != 0) + { + temp = reinterpret_cast(next); + node* n = next->next; + + try + { + // construct this new T object with placement new. + new (reinterpret_cast(temp))T(); + } + catch (...) + { + next->next = n; + throw; + } + + next = n; + } + else + { + // the linked list is empty so we need to allocate some more memory + node* block = reinterpret_cast(::operator new (sizeof(node)*chunk_size)); + + // the first part of this block can be our new object + temp = reinterpret_cast(block); + + try + { + // construct this new T object with placement new. + new (reinterpret_cast(temp))T(); + } + catch (...) + { + // construction of the new object threw so delete the block of memory + ::operator delete ( reinterpret_cast(block)); + throw; + } + + // allocate a new chunk_node + chunk_node* chunk; + try {chunk = new chunk_node; } + catch (...) + { + temp->~T(); + ::operator delete ( reinterpret_cast(block)); + throw; + } + + // add this block into the chunk list + chunk->chunk = block; + chunk->next = first_chunk; + first_chunk = chunk; + + + ++block; + // now add the rest of the block into the linked list of free nodes. + for (unsigned long i = 0; i < chunk_size-1; ++i) + { + block->next = next; + next = block; + ++block; + } + + } + + + ++allocations; + return temp; + } + + void deallocate ( + T* item + ) + { + --allocations; + item->~T(); + + // add this memory into our linked list. + node* temp = reinterpret_cast(item); + temp->next = next; + next = temp; + } + + void swap ( + memory_manager_kernel_3& item + ) + { + exchange(allocations,item.allocations); + exchange(next,item.next); + exchange(first_chunk,item.first_chunk); + exchange(arrays,item.arrays); + } + + private: + + // data members + unsigned long allocations; + node* next; + + chunk_node* first_chunk; + bst_of_arrays* arrays; + + + void initialize_array ( + T* array, + size_t size + ) const + { + size_t i; + try + { + for (i = 0; i < size; ++i) + { + // construct this new T object with placement new. + new (reinterpret_cast(array+i))T(); + } + } + catch (...) + { + // Catch any exceptions thrown during the construction process + // and then destruct any T objects that actually were successfully + // constructed. + for (size_t j = 0; j < i; ++j) + { + array[i].~T(); + } + throw; + } + } + + void deinitialize_array ( + T* array, + size_t size + ) const + { + for (size_t i = 0; i < size; ++i) + { + array[i].~T(); + } + } + + // don't do any initialization for the built in types + void initialize_array(unsigned char*, size_t) {} + void deinitialize_array(unsigned char*, size_t) {} + void initialize_array(signed char*, size_t) {} + void deinitialize_array(signed char*, size_t) {} + void initialize_array(char*, size_t) {} + void deinitialize_array(char*, size_t) {} + void initialize_array(int*, size_t) {} + void deinitialize_array(int*, size_t) {} + void initialize_array(unsigned int*, size_t) {} + void deinitialize_array(unsigned int*, size_t) {} + void initialize_array(unsigned long*, size_t) {} + void deinitialize_array(unsigned long*, size_t) {} + void initialize_array(long*, size_t) {} + void deinitialize_array(long*, size_t) {} + void initialize_array(float*, size_t) {} + void deinitialize_array(float*, size_t) {} + void initialize_array(double*, size_t) {} + void deinitialize_array(double*, size_t) {} + void initialize_array(short*, size_t) {} + void deinitialize_array(short*, size_t) {} + void initialize_array(unsigned short*, size_t) {} + void deinitialize_array(unsigned short*, size_t) {} + + + + // restricted functions + memory_manager_kernel_3(memory_manager_kernel_3&); // copy constructor + memory_manager_kernel_3& operator=(memory_manager_kernel_3&); // assignment operator + }; + + template < + typename T, + unsigned long chunk_size + > + inline void swap ( + memory_manager_kernel_3& a, + memory_manager_kernel_3& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MEMORY_MANAGER_KERNEl_3_ + diff --git a/dlib/memory_manager/memory_manager_kernel_abstract.h b/dlib/memory_manager/memory_manager_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..ba426713abb71f0e338668c992fa01d18234d2a5 --- /dev/null +++ b/dlib/memory_manager/memory_manager_kernel_abstract.h @@ -0,0 +1,146 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_ +#ifdef DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + template < + typename T + > + class memory_manager + { + /*! + REQUIREMENTS ON T + T must have a default constructor. + + INITIAL VALUE + get_number_of_allocations() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents some kind of memory manager or memory pool. + !*/ + + public: + + typedef T type; + + template + struct rebind { + typedef memory_manager other; + }; + + memory_manager( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~memory_manager( + ); + /*! + ensures + - if (get_number_of_allocations() == 0) then + - all resources associated with *this have been released. + - else + - The memory still allocated will not be deleted and this + causes a memory leak. + !*/ + + unsigned long get_number_of_allocations ( + ) const; + /*! + ensures + - returns the current number of outstanding allocations + !*/ + + T* allocate ( + ); + /*! + ensures + - allocates a new object of type T and returns a pointer to it. + - #get_number_of_allocations() == get_number_of_allocations() + 1 + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to allocate() + has no effect on #*this. + !*/ + + void deallocate ( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + this->allocate(). (i.e. you can't deallocate a pointer you + got from a different memory_manager instance.) + - the memory pointed to by item hasn't already been deallocated. + ensures + - deallocates the object pointed to by item + - #get_number_of_allocations() == get_number_of_allocations() - 1 + !*/ + + T* allocate_array ( + unsigned long size + ); + /*! + ensures + - allocates a new array of size objects of type T and returns a + pointer to it. + - #get_number_of_allocations() == get_number_of_allocations() + 1 + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to allocate() + has no effect on #*this. + !*/ + + void deallocate_array ( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + this->allocate_array(). (i.e. you can't deallocate a pointer you + got from a different memory_manager instance and it must be an + array.) + - the memory pointed to by item hasn't already been deallocated. + ensures + - deallocates the array pointed to by item + - #get_number_of_allocations() == get_number_of_allocations() - 1 + !*/ + + void swap ( + memory_manager& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + memory_manager(memory_manager&); // copy constructor + memory_manager& operator=(memory_manager&); // assignment operator + }; + + template < + typename T + > + inline void swap ( + memory_manager& a, + memory_manager& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_ + diff --git a/dlib/memory_manager_global.h b/dlib/memory_manager_global.h new file mode 100644 index 0000000000000000000000000000000000000000..09ec8d2c18fbb5705bfaed772deb2b3160d19f7f --- /dev/null +++ b/dlib/memory_manager_global.h @@ -0,0 +1,38 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_GLOBAl_ +#define DLIB_MEMORY_MANAGER_GLOBAl_ + +#include "memory_manager_global/memory_manager_global_kernel_1.h" +#include "memory_manager.h" + + + +namespace dlib +{ + + template < + typename T, + typename factory + > + class memory_manager_global + { + memory_manager_global() {} + + + public: + + //----------- kernels --------------- + + // kernel_1 + typedef memory_manager_global_kernel_1 + kernel_1a; + + + + + }; +} + +#endif // DLIB_MEMORY_MANAGER_GLOBAl_ + diff --git a/dlib/memory_manager_global/memory_manager_global_kernel_1.h b/dlib/memory_manager_global/memory_manager_global_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..017e1eee5de39145310156324be1ff3b5162a946 --- /dev/null +++ b/dlib/memory_manager_global/memory_manager_global_kernel_1.h @@ -0,0 +1,113 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_GLOBAl_1_ +#define DLIB_MEMORY_MANAGER_GLOBAl_1_ + +#include "../algs.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include "memory_manager_global_kernel_abstract.h" + +namespace dlib +{ + template < + typename T, + typename factory + > + class memory_manager_global_kernel_1 + { + /*! + INITIAL VALUE + - *global_mm == get_global_memory_manager() + + CONVENTION + - global_mm->get_number_of_allocations() == get_number_of_allocations() + - *global_mm == get_global_memory_manager() + !*/ + + public: + + typedef typename factory::template return_type::type mm_global_type; + + typedef T type; + + template + struct rebind { + typedef memory_manager_global_kernel_1 other; + }; + + memory_manager_global_kernel_1( + ) : + global_mm(factory::template get_instance()) + {} + + virtual ~memory_manager_global_kernel_1( + ) {} + + unsigned long get_number_of_allocations ( + ) const { return global_mm->get_number_of_allocations(); } + + mm_global_type& get_global_memory_manager ( + ) { return *global_mm; } + + T* allocate ( + ) + { + return global_mm->allocate(); + } + + void deallocate ( + T* item + ) + { + global_mm->deallocate(item); + } + + T* allocate_array ( + unsigned long size + ) + { + return global_mm->allocate_array(size); + } + + void deallocate_array ( + T* item + ) + { + global_mm->deallocate_array(item); + } + + void swap ( + memory_manager_global_kernel_1& item + ) + { + exchange(item.global_mm, global_mm); + } + + private: + + mm_global_type* global_mm; + + + // restricted functions + memory_manager_global_kernel_1(memory_manager_global_kernel_1&); // copy constructor + memory_manager_global_kernel_1& operator=(memory_manager_global_kernel_1&); // assignment operator + }; + + template < + typename T, + typename factory + > + inline void swap ( + memory_manager_global_kernel_1& a, + memory_manager_global_kernel_1& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_MEMORY_MANAGER_GLOBAl_1_ + + + diff --git a/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h b/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..dc4ca8200623d59bfa23145789830af41413027f --- /dev/null +++ b/dlib/memory_manager_global/memory_manager_global_kernel_abstract.h @@ -0,0 +1,182 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_ +#ifdef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_ + +#include "../algs.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" + +namespace dlib +{ + template < + typename T, + typename factory + > + class memory_manager_global + { + /*! + REQUIREMENTS ON T + T must have a default constructor. + + REQUIREMENTS ON factory + factory must be defined as follows: + struct factory + { + template + struct return_type { + typedef typename memory_manager_type type; + }; + + template + static typename return_type::type* get_instance ( + ); + / *! + ensures + - returns a pointer to an instance of a memory_manager object + where memory_manager_type is defined + by dlib/memory_manager/memory_manager_kernel_abstract.h + !* / + }; + + WHAT THIS OBJECT REPRESENTS + This object represents some kind of global memory manager or memory pool. + It is identical to the memory_manager object except that it gets all of + its allocations from a global instance of a memory_manager object which + is provided by the factory object's static member get_instance(). + + THREAD SAFETY + This object must be used with care in a threaded program. The exact + steps needed to ensure safe usage in a threaded program depend on + how the factory class is implemented though. + + Also note that only the constructor calls factory::get_instance(). + !*/ + + public: + + typedef typename factory::template return_type::type mm_global_type; + + typedef T type; + + template + struct rebind { + typedef memory_manager_global other; + }; + + memory_manager_global( + ); + /*! + ensures + - #*this is properly initialized + - #get_global_memory_manager() == the memory manager that was + returned by a call to factory::get_instance() + throws + - std::bad_alloc + !*/ + + virtual ~memory_manager_global( + ); + /*! + ensures + - This destructor has no effect on the global memory_manager + get_global_memory_manager(). + !*/ + + unsigned long get_number_of_allocations ( + ) const; + /*! + ensures + - returns get_global_memory_manager().get_number_of_allocations() + !*/ + + mm_global_type& get_global_memory_manager ( + ); + /*! + ensures + - returns a reference to the global memory manager instance being + used by *this. + !*/ + + T* allocate ( + ); + /*! + ensures + - #get_number_of_allocations() == get_number_of_allocations() + 1 + - returns get_global_memory_manager().allocate() + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to allocate() + has no effect on #*this. + !*/ + + void deallocate ( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + the get_global_memory_manager() object's allocate() method. + - the memory pointed to by item hasn't already been deallocated. + ensures + - calls get_global_memory_manager().deallocate(item) + - #get_number_of_allocations() == get_number_of_allocations() - 1 + !*/ + + T* allocate_array ( + unsigned long size + ); + /*! + ensures + - #get_number_of_allocations() == get_number_of_allocations() + 1 + - returns get_global_memory_manager().allocate_array() + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to allocate_array() + has no effect on #*this. + !*/ + + void deallocate_array ( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + the get_global_memory_manager() object's allocate_array() method. + - the memory pointed to by item hasn't already been deallocated. + ensures + - calls get_global_memory_manager().deallocate_array(item) + - #get_number_of_allocations() == get_number_of_allocations() - 1 + !*/ + + void swap ( + memory_manager_global& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + memory_manager_global(memory_manager_global&); // copy constructor + memory_manager_global& operator=(memory_manager_global&); // assignment operator + }; + + template < + typename T, + typename factory + > + inline void swap ( + memory_manager_global& a, + memory_manager_global& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_ + + diff --git a/dlib/memory_manager_stateless.h b/dlib/memory_manager_stateless.h new file mode 100644 index 0000000000000000000000000000000000000000..99748d5abfe705c67da12715817fb211435d02fd --- /dev/null +++ b/dlib/memory_manager_stateless.h @@ -0,0 +1,72 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_STATELESs_ +#define DLIB_MEMORY_MANAGER_STATELESs_ + +#include "memory_manager_stateless/memory_manager_stateless_kernel_1.h" +#include "memory_manager_stateless/memory_manager_stateless_kernel_2.h" +#include "memory_manager.h" + + + +namespace dlib +{ + + template < + typename T + > + class memory_manager_stateless + { + memory_manager_stateless() {} + + + public: + + //----------- kernels --------------- + + // kernel_1 + typedef memory_manager_stateless_kernel_1 + kernel_1a; + + // kernel_2 + typedef memory_manager_stateless_kernel_2::kernel_1a> + kernel_2_1a; + typedef memory_manager_stateless_kernel_2::kernel_1b> + kernel_2_1b; + typedef memory_manager_stateless_kernel_2::kernel_1c> + kernel_2_1c; + typedef memory_manager_stateless_kernel_2::kernel_1d> + kernel_2_1d; + typedef memory_manager_stateless_kernel_2::kernel_1e> + kernel_2_1e; + typedef memory_manager_stateless_kernel_2::kernel_1f> + kernel_2_1f; + + typedef memory_manager_stateless_kernel_2::kernel_2a> + kernel_2_2a; + typedef memory_manager_stateless_kernel_2::kernel_2b> + kernel_2_2b; + typedef memory_manager_stateless_kernel_2::kernel_2c> + kernel_2_2c; + typedef memory_manager_stateless_kernel_2::kernel_2d> + kernel_2_2d; + typedef memory_manager_stateless_kernel_2::kernel_2e> + kernel_2_2e; + + typedef memory_manager_stateless_kernel_2::kernel_3a> + kernel_2_3a; + typedef memory_manager_stateless_kernel_2::kernel_3b> + kernel_2_3b; + typedef memory_manager_stateless_kernel_2::kernel_3c> + kernel_2_3c; + typedef memory_manager_stateless_kernel_2::kernel_3d> + kernel_2_3d; + typedef memory_manager_stateless_kernel_2::kernel_3e> + kernel_2_3e; + + + }; +} + +#endif // DLIB_MEMORY_MANAGER_STATELESs_ + diff --git a/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h b/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..ff30c94f881d85b86ea860b82624b8ca492d3e32 --- /dev/null +++ b/dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h @@ -0,0 +1,87 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_STATELESs_1_ +#define DLIB_MEMORY_MANAGER_STATELESs_1_ + +#include "../algs.h" +#include "memory_manager_stateless_kernel_abstract.h" + +namespace dlib +{ + template < + typename T + > + class memory_manager_stateless_kernel_1 + { + /*! + this implementation just calls new and delete directly + !*/ + + public: + + typedef T type; + const static bool is_stateless = true; + + template + struct rebind { + typedef memory_manager_stateless_kernel_1 other; + }; + + memory_manager_stateless_kernel_1( + ) + {} + + virtual ~memory_manager_stateless_kernel_1( + ) {} + + T* allocate ( + ) + { + return new T; + } + + void deallocate ( + T* item + ) + { + delete item; + } + + T* allocate_array ( + unsigned long size + ) + { + return new T[size]; + } + + void deallocate_array ( + T* item + ) + { + delete [] item; + } + + void swap (memory_manager_stateless_kernel_1&) + {} + + private: + + // restricted functions + memory_manager_stateless_kernel_1(memory_manager_stateless_kernel_1&); // copy constructor + memory_manager_stateless_kernel_1& operator=(memory_manager_stateless_kernel_1&); // assignment operator + }; + + template < + typename T + > + inline void swap ( + memory_manager_stateless_kernel_1& a, + memory_manager_stateless_kernel_1& b + ) { a.swap(b); } + +} + +#endif // DLIB_MEMORY_MANAGER_STATELESs_1_ + + + diff --git a/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h b/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..07503a44d9a97e0936c7d91d486834b992a1f28c --- /dev/null +++ b/dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h @@ -0,0 +1,119 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MEMORY_MANAGER_STATELESs_2_ +#define DLIB_MEMORY_MANAGER_STATELESs_2_ + +#include "../algs.h" +#include "memory_manager_stateless_kernel_abstract.h" +#include "../threads.h" + +namespace dlib +{ + template < + typename T, + typename mem_manager + > + class memory_manager_stateless_kernel_2 + { + /*! + REQUIREMENTS ON mem_manager + mem_manager must be an implementation of memory_manager/memory_manager_kernel_abstract.h + + CONVENTION + this object has a single global instance of mem_manager + !*/ + + public: + + typedef T type; + const static bool is_stateless = true; + + template + struct rebind { + typedef memory_manager_stateless_kernel_2 other; + }; + + memory_manager_stateless_kernel_2( + ) + { + // call this just to make sure the mutex is is initialized before + // multiple threads start calling the member functions. + global_mutex(); + } + + virtual ~memory_manager_stateless_kernel_2( + ) {} + + T* allocate ( + ) + { + auto_mutex M(global_mutex()); + return global_mm().allocate(); + } + + void deallocate ( + T* item + ) + { + auto_mutex M(global_mutex()); + return global_mm().deallocate(item); + } + + T* allocate_array ( + unsigned long size + ) + { + auto_mutex M(global_mutex()); + return global_mm().allocate_array(size); + } + + void deallocate_array ( + T* item + ) + { + auto_mutex M(global_mutex()); + return global_mm().deallocate_array(item); + } + + void swap (memory_manager_stateless_kernel_2&) + {} + + private: + + static mutex& global_mutex ( + ) + { + static mutex lock; + return lock; + } + + typedef typename mem_manager::template rebind::other rebound_mm_type; + + static rebound_mm_type& global_mm ( + ) + { + static rebound_mm_type mm; + return mm; + } + + // restricted functions + memory_manager_stateless_kernel_2(memory_manager_stateless_kernel_2&); // copy constructor + memory_manager_stateless_kernel_2& operator=(memory_manager_stateless_kernel_2&); // assignment operator + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + memory_manager_stateless_kernel_2& a, + memory_manager_stateless_kernel_2& b + ) { a.swap(b); } + +} + +#endif // DLIB_MEMORY_MANAGER_STATELESs_2_ + + + + diff --git a/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h b/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..bd42881dc787c153fa7a27aaa330ead7bf4bf762 --- /dev/null +++ b/dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h @@ -0,0 +1,142 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_ +#ifdef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + template < + typename T + > + class memory_manager_stateless + { + /*! + REQUIREMENTS ON T + T must have a default constructor. + + WHAT THIS OBJECT REPRESENTS + This object represents some kind of stateless memory manager or memory pool. + Stateless means that all instances (instances of the same kernel implementation that is) + of this object are identical and can be used interchangeably. Note that + implementations are allowed to have some shared global state such as a + global memory pool. + + THREAD SAFETY + This object is thread safe. You may access it from any thread at any time + without synchronizing access. + !*/ + + public: + + typedef T type; + const static bool is_stateless = true; + + template + struct rebind { + typedef memory_manager_stateless other; + }; + + memory_manager_stateless( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~memory_manager_stateless( + ); + /*! + ensures + - frees any resources used by *this but has no effect on any shared global + resources used by the implementation. + !*/ + + T* allocate ( + ); + /*! + ensures + - allocates a new object of type T and returns a pointer to it. + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to allocate() + has no effect on #*this. + !*/ + + void deallocate ( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + allocate(). (i.e. The pointer you are deallocating must have + come from the same implementation of memory_manager_stateless + that is trying to deallocate it.) + - the memory pointed to by item hasn't already been deallocated. + ensures + - deallocates the object pointed to by item + !*/ + + T* allocate_array ( + unsigned long size + ); + /*! + ensures + - allocates a new array of size objects of type T and returns a + pointer to it. + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to allocate() + has no effect on #*this. + !*/ + + void deallocate_array ( + T* item + ); + /*! + requires + - item == is a pointer to memory that was obtained from a call to + allocate_array(). (i.e. The pointer you are deallocating must have + come from the same implementation of memory_manager_stateless + that is trying to deallocate it.) + - the memory pointed to by item hasn't already been deallocated. + ensures + - deallocates the array pointed to by item + !*/ + + void swap ( + memory_manager_stateless& item + ); + /*! + ensures + - this function has no effect on *this or item. It is just provided + to make this object's interface more compatable with the other + memory managers. + !*/ + + private: + + // restricted functions + memory_manager_stateless(memory_manager_stateless&); // copy constructor + memory_manager_stateless& operator=(memory_manager_stateless&); // assignment operator + }; + + template < + typename T + > + inline void swap ( + memory_manager_stateless& a, + memory_manager_stateless& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_ + + diff --git a/dlib/misc_api.h b/dlib/misc_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b7faaa084776bedd0a50423836934795f0cfefd4 --- /dev/null +++ b/dlib/misc_api.h @@ -0,0 +1,18 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_MISC_APi_ +#define DLIB_MISC_APi_ + +#include "platform.h" + +#ifdef WIN32 +#include "misc_api/windows.h" +#endif + +#ifndef WIN32 +#include "misc_api/posix.h" +#endif + +#endif // DLIB_MISC_APi_ + diff --git a/dlib/misc_api/misc_api_kernel_1.cpp b/dlib/misc_api/misc_api_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..621466dec09fbe1cf7c4cfd694ce720f602de13d --- /dev/null +++ b/dlib/misc_api/misc_api_kernel_1.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MISC_API_KERNEL_1_CPp_ +#define DLIB_MISC_API_KERNEL_1_CPp_ + +#include "../platform.h" + +#ifdef WIN32 + +#include "misc_api_kernel_1.h" + +#include "../windows_magic.h" +#include + +#ifdef __BORLANDC__ +// Apparently the borland compiler doesn't define this. +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif + +namespace dlib +{ +// ---------------------------------------------------------------------------------------- + + void sleep ( + unsigned long milliseconds + ) + { + ::Sleep(milliseconds); + } + +// ---------------------------------------------------------------------------------------- + + std::string get_current_dir ( + ) + { + char buf[1024]; + if (GetCurrentDirectoryA(sizeof(buf),buf) == 0) + { + return std::string(); + } + else + { + return std::string(buf); + } + } + +// ---------------------------------------------------------------------------------------- + + uint64 timestamper:: + get_timestamp ( + ) const + { + unsigned long temp = GetTickCount(); + if (temp >= last_time) + { + last_time = temp; + return (offset + temp)*1000; + } + else + { + last_time = temp; + + // there was overflow since the last call so we need to make the offset + // bigger to account for that + offset += dword_max; + return (offset + temp)*1000; + } + } + +// ---------------------------------------------------------------------------------------- + + void create_directory ( + const std::string& dir + ) + { + if (CreateDirectoryA(dir.c_str(),0) == 0) + { + // an error has occurred + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + // make sure this is actually a directory + DWORD attribs = GetFileAttributesA(dir.c_str()); + if (attribs == INVALID_FILE_ATTRIBUTES || + (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0) + { + // it isn't a directory + throw dir_create_error(dir); + } + } + else + { + throw dir_create_error(dir); + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // WIN32 + +#endif // DLIB_MISC_API_KERNEL_1_CPp_ + diff --git a/dlib/misc_api/misc_api_kernel_1.h b/dlib/misc_api/misc_api_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..3eea540618f7a88c591d574806556f931d10edf7 --- /dev/null +++ b/dlib/misc_api/misc_api_kernel_1.h @@ -0,0 +1,96 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MISC_API_KERNEl_1_ +#define DLIB_MISC_API_KERNEl_1_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + + +#include "misc_api_kernel_abstract.h" +#include "../algs.h" +#include +#include "../uintn.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + void sleep ( + unsigned long milliseconds + ); + +// ---------------------------------------------------------------------------------------- + + std::string get_current_dir ( + ); + +// ---------------------------------------------------------------------------------------- + + class timestamper + { + /*! + INITIAL VALUE + - last_time == 0 + - offset == 0 + - dword_max == 2^32 + + CONVENTION + - last_time == the time returned by GetTickCount() the last time we + called it. + - offset == the number of microseconds we should add to the result of + GetTickCount() so that it is correct. + - dword_max == 2^32. + This is the number of values representable by a DWORD. + !*/ + + mutable unsigned long last_time; + mutable uint64 offset; + mutable uint64 dword_max; + + public: + timestamper( + ) : + last_time(0), + offset(0) + { + dword_max = 0xFFFFFFFF; + ++dword_max; + } + + uint64 get_timestamp ( + ) const; + }; + +// ---------------------------------------------------------------------------------------- + + class dir_create_error : public error + { + public: + dir_create_error( + const std::string& dir_name + ) : + error(EDIR_CREATE,"Error creating directory '" + dir_name + "'."), + name(dir_name) + {} + + ~dir_create_error() throw() {} + const std::string name; + }; + + void create_directory ( + const std::string& dir + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "misc_api_kernel_1.cpp" +#endif + +#endif // DLIB_MISC_API_KERNEl_1_ + diff --git a/dlib/misc_api/misc_api_kernel_2.cpp b/dlib/misc_api/misc_api_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9473164953ac1b2fcb9833533e44d8139a4ae54 --- /dev/null +++ b/dlib/misc_api/misc_api_kernel_2.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MISC_API_KERNEL_2_CPp_ +#define DLIB_MISC_API_KERNEL_2_CPp_ +#include "../platform.h" + +#ifdef POSIX + +#include +#include "misc_api_kernel_2.h" +#include +#include +#include +#include + +namespace dlib +{ +// ---------------------------------------------------------------------------------------- + + void sleep ( + unsigned long milliseconds + ) + { + // in HP-UX you can only usleep for less than a second +#ifdef HPUX + if (milliseconds >= 1000) + { + ::sleep(milliseconds/1000); + unsigned long remaining = milliseconds%1000; + if (remaining > 0) + ::usleep(remaining*1000); + } + else + { + ::usleep(milliseconds*1000); + } +#else + ::usleep(milliseconds*1000); +#endif + } + +// ---------------------------------------------------------------------------------------- + + std::string get_current_dir ( + ) + { + char buf[PATH_MAX]; + if (getcwd(buf,sizeof(buf)) == 0) + { + return std::string(); + } + else + { + return std::string(buf); + } + } + +// ---------------------------------------------------------------------------------------- + + uint64 timestamper:: + get_timestamp ( + ) const + { + uint64 ts; + timeval curtime; + gettimeofday(&curtime,0); + + ts = curtime.tv_sec; + ts *= 1000000; + ts += curtime.tv_usec; + return ts; + } + +// ---------------------------------------------------------------------------------------- + + void create_directory ( + const std::string& dir + ) + { + if (mkdir(dir.c_str(),0777)) + { + // an error has occurred + if (errno == EEXIST) + { + struct stat buffer; + // now check that this is actually a valid directory + if (::stat(dir.c_str(),&buffer)) + { + // the directory was not found + throw dir_create_error(dir); + } + else if (S_ISDIR(buffer.st_mode) == 0) + { + // It is not a directory + throw dir_create_error(dir); + } + } + else + { + throw dir_create_error(dir); + } + } + } + +// ---------------------------------------------------------------------------------------- +} + +#endif // POSIX + +#endif // DLIB_MISC_API_KERNEL_2_CPp_ + diff --git a/dlib/misc_api/misc_api_kernel_2.h b/dlib/misc_api/misc_api_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..51acd51405573b6d93e21ca053b52ea18141ba2e --- /dev/null +++ b/dlib/misc_api/misc_api_kernel_2.h @@ -0,0 +1,67 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MISC_API_KERNEl_2_ +#define DLIB_MISC_API_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + + +#include "misc_api_kernel_abstract.h" +#include "../algs.h" +#include +#include "../uintn.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + void sleep ( + unsigned long milliseconds + ); + +// ---------------------------------------------------------------------------------------- + + std::string get_current_dir ( + ); + +// ---------------------------------------------------------------------------------------- + + class timestamper + { + public: + uint64 get_timestamp ( + ) const; + }; + +// ---------------------------------------------------------------------------------------- + + class dir_create_error : public error + { + public: + dir_create_error( + const std::string& dir_name + ) : + error(EDIR_CREATE,"Error creating directory '" + dir_name + "'."), + name(dir_name) + {} + const std::string& name; + }; + + + void create_directory ( + const std::string& dir + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "misc_api_kernel_2.cpp" +#endif + +#endif // DLIB_MISC_API_KERNEl_2_ + diff --git a/dlib/misc_api/misc_api_kernel_abstract.h b/dlib/misc_api/misc_api_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..203c2c7b866affab4fe7efcd448447f71be42bb7 --- /dev/null +++ b/dlib/misc_api/misc_api_kernel_abstract.h @@ -0,0 +1,101 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MISC_API_KERNEl_ABSTRACT_ +#ifdef DLIB_MISC_API_KERNEl_ABSTRACT_ + +#include +#include "../uintn.h" +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + GENERAL COMMENTS + This file just contains miscellaneous api functions + + GENERAL WARNING + Don't call any of these functions before main() has been entered. + !*/ + +// ---------------------------------------------------------------------------------------- + + void sleep ( + unsigned long milliseconds + ); + /*! + ensures + - causes the calling thread to sleep for the given number of + milliseconds. + !*/ + +// ---------------------------------------------------------------------------------------- + + std::string get_current_dir ( + ); + /*! + ensures + - if (no errors occurr) then + - returns the path to the current working directory + - else + - returns "" + throws + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + + class dir_create_error : public error { + public: + const std::string name + }; + + void create_directory ( + const std::string& dir + ); + /*! + ensures + - if (dir does not already exist) then + - creates the given directory. + - else + - the call to create_directory() has no effect. + throws + - dir_create_error + This exception is thrown if we were unable to create the requested + directory. The type member of the exception will bet set to + EDIR_CREATE and the name member will be set to dir. + !*/ + +// ---------------------------------------------------------------------------------------- + + class timestamper + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a timer that is capable of returning + timestamps. + + Note that the time is measured in microseconds but you are not + guaranteed to have that level of resolution. The actual resolution + is implementation dependent. + !*/ + + public: + uint64 get_timestamp ( + ) const; + /*! + ensures + - returns a timestamp that measures the time in microseconds since an + arbitrary point in the past. Note that this arbitray point remains + the same between all calls to get_timestamp(). + !*/ + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MISC_API_KERNEl_ABSTRACT_ + diff --git a/dlib/misc_api/posix.h b/dlib/misc_api/posix.h new file mode 100644 index 0000000000000000000000000000000000000000..51b03065bd4daa1067d28f2f24a81c74becc037c --- /dev/null +++ b/dlib/misc_api/posix.h @@ -0,0 +1,6 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MISC_API_KERNEl_1_ +#include "misc_api_kernel_2.h" +#endif + diff --git a/dlib/misc_api/windows.h b/dlib/misc_api/windows.h new file mode 100644 index 0000000000000000000000000000000000000000..5cb936b46d838ee997b820b8e4633ecd64616cd7 --- /dev/null +++ b/dlib/misc_api/windows.h @@ -0,0 +1,6 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MISC_API_KERNEl_2_ +#include "misc_api_kernel_1.h" +#endif + diff --git a/dlib/mlp.h b/dlib/mlp.h new file mode 100644 index 0000000000000000000000000000000000000000..32cdea96efb375abfcd78eddbf6c29a982acde19 --- /dev/null +++ b/dlib/mlp.h @@ -0,0 +1,30 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MLp_ +#define DLIB_MLp_ + +#include "mlp/mlp_kernel_1.h" +#include "mlp/mlp_kernel_c.h" + +namespace dlib +{ + + class mlp + { + mlp() {} + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef mlp_kernel_1 + kernel_1a; + typedef mlp_kernel_c + kernel_1a_c; + + }; +} + +#endif // DLIB_MLp_ + diff --git a/dlib/mlp/mlp_kernel_1.h b/dlib/mlp/mlp_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..8d36ebd4bbe50f951a237f4d5ca8569bdcc886da --- /dev/null +++ b/dlib/mlp/mlp_kernel_1.h @@ -0,0 +1,380 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MLp_KERNEL_1_ +#define DLIB_MLp_KERNEL_1_ + +#include "../algs.h" +#include "../serialize.h" +#include "../matrix.h" +#include "../rand.h" +#include "mlp_kernel_abstract.h" +#include +#include + +namespace dlib +{ + + class mlp_kernel_1 : noncopyable + { + /*! + INITIAL VALUE + The network is initially initialized with random weights + + CONVENTION + - input_layer_nodes() == input_nodes + - first_hidden_layer_nodes() == first_hidden_nodes + - second_hidden_layer_nodes() == second_hidden_nodes + - output_layer_nodes() == output_nodes + - get_alpha == alpha + - get_momentum() == momentum + + + - if (second_hidden_nodes == 0) then + - for all i and j: + - w1(i,j) == the weight on the link from node i in the first hidden layer + to input node j + - w3(i,j) == the weight on the link from node i in the output layer + to first hidden layer node j + - for all i and j: + - w1m == the momentum terms for w1 from the previous update + - w3m == the momentum terms for w3 from the previous update + - else + - for all i and j: + - w1(i,j) == the weight on the link from node i in the first hidden layer + to input node j + - w2(i,j) == the weight on the link from node i in the second hidden layer + to first hidden layer node j + - w3(i,j) == the weight on the link from node i in the output layer + to second hidden layer node j + - for all i and j: + - w1m == the momentum terms for w1 from the previous update + - w2m == the momentum terms for w2 from the previous update + - w3m == the momentum terms for w3 from the previous update + !*/ + + public: + + mlp_kernel_1 ( + long nodes_in_input_layer, + long nodes_in_first_hidden_layer, + long nodes_in_second_hidden_layer = 0, + long nodes_in_output_layer = 1, + double alpha_ = 0.1, + double momentum_ = 0.8 + ) : + input_nodes(nodes_in_input_layer), + first_hidden_nodes(nodes_in_first_hidden_layer), + second_hidden_nodes(nodes_in_second_hidden_layer), + output_nodes(nodes_in_output_layer), + alpha(alpha_), + momentum(momentum_) + { + + // seed the random number generator + std::ostringstream sout; + sout << time(0); + rand_nums.set_seed(sout.str()); + + w1.set_size(first_hidden_nodes+1, input_nodes+1); + w1m.set_size(first_hidden_nodes+1, input_nodes+1); + z.set_size(input_nodes+1,1); + + if (second_hidden_nodes != 0) + { + w2.set_size(second_hidden_nodes+1, first_hidden_nodes+1); + w3.set_size(output_nodes, second_hidden_nodes+1); + + w2m.set_size(second_hidden_nodes+1, first_hidden_nodes+1); + w3m.set_size(output_nodes, second_hidden_nodes+1); + } + else + { + w3.set_size(output_nodes, first_hidden_nodes+1); + + w3m.set_size(output_nodes, first_hidden_nodes+1); + } + + reset(); + } + + virtual ~mlp_kernel_1 ( + ) {} + + void reset ( + ) + { + // randomize the weights for the first layer + for (long r = 0; r < w1.nr(); ++r) + for (long c = 0; c < w1.nc(); ++c) + w1(r,c) = rand_nums.get_random_double(); + + // randomize the weights for the second layer + for (long r = 0; r < w2.nr(); ++r) + for (long c = 0; c < w2.nc(); ++c) + w2(r,c) = rand_nums.get_random_double(); + + // randomize the weights for the third layer + for (long r = 0; r < w3.nr(); ++r) + for (long c = 0; c < w3.nc(); ++c) + w3(r,c) = rand_nums.get_random_double(); + + // zero all the momentum terms + set_all_elements(w1m,0); + set_all_elements(w2m,0); + set_all_elements(w3m,0); + } + + long input_layer_nodes ( + ) const { return input_nodes; } + + long first_hidden_layer_nodes ( + ) const { return first_hidden_nodes; } + + long second_hidden_layer_nodes ( + ) const { return second_hidden_nodes; } + + long output_layer_nodes ( + ) const { return output_nodes; } + + double get_alpha ( + ) const { return alpha; } + + double get_momentum ( + ) const { return momentum; } + + template + const matrix operator() ( + const matrix_exp& in + ) const + { + for (long i = 0; i < in.nr(); ++i) + z(i) = in(i); + // insert the bias + z(z.nr()-1) = -1; + + tmp1 = sigmoid(w1*z); + // insert the bias + tmp1(tmp1.nr()-1) = -1; + + if (second_hidden_nodes == 0) + { + return sigmoid(w3*tmp1); + } + else + { + tmp2 = sigmoid(w2*tmp1); + // insert the bias + tmp2(tmp2.nr()-1) = -1; + + return sigmoid(w3*tmp2); + } + } + + template + void train ( + const matrix_exp& example_in, + const matrix_exp& example_out + ) + { + for (long i = 0; i < example_in.nr(); ++i) + z(i) = example_in(i); + // insert the bias + z(z.nr()-1) = -1; + + tmp1 = sigmoid(w1*z); + // insert the bias + tmp1(tmp1.nr()-1) = -1; + + + if (second_hidden_nodes == 0) + { + o = sigmoid(w3*tmp1); + + // now compute the errors and propagate them backwards though the network + e3 = pointwise_multiply(example_out-o, uniform_matrix(output_nodes,1,1.0)-o, o); + e1 = pointwise_multiply(tmp1, uniform_matrix(first_hidden_nodes+1,1,1.0) - tmp1, trans(w3)*e3 ); + + // compute the new weight updates + w3m = alpha * e3*trans(tmp1) + w3m*momentum; + w1m = alpha * e1*trans(z) + w1m*momentum; + + // now update the weights + w1 += w1m; + w3 += w3m; + } + else + { + tmp2 = sigmoid(w2*tmp1); + // insert the bias + tmp2(tmp2.nr()-1) = -1; + + o = sigmoid(w3*tmp2); + + + // now compute the errors and propagate them backwards though the network + e3 = pointwise_multiply(example_out-o, uniform_matrix(output_nodes,1,1.0)-o, o); + e2 = pointwise_multiply(tmp2, uniform_matrix(second_hidden_nodes+1,1,1.0) - tmp2, trans(w3)*e3 ); + e1 = pointwise_multiply(tmp1, uniform_matrix(first_hidden_nodes+1,1,1.0) - tmp1, trans(w2)*e2 ); + + // compute the new weight updates + w3m = alpha * e3*trans(tmp2) + w3m*momentum; + w2m = alpha * e2*trans(tmp1) + w2m*momentum; + w1m = alpha * e1*trans(z) + w1m*momentum; + + // now update the weights + w1 += w1m; + w2 += w2m; + w3 += w3m; + } + } + + template + void train ( + const matrix_exp& example_in, + double example_out + ) + { + matrix e_out; + e_out(0) = example_out; + train(example_in,e_out); + } + + double get_average_change ( + ) const + { + // sum up all the weight changes + double delta = sum(abs(w1m)) + sum(abs(w2m)) + sum(abs(w3m)); + + // divide by the number of weights + delta /= w1m.nr()*w1m.nc() + + w2m.nr()*w2m.nc() + + w3m.nr()*w3m.nc(); + + return delta; + } + + void swap ( + mlp_kernel_1& item + ) + { + exchange(input_nodes, item.input_nodes); + exchange(first_hidden_nodes, item.first_hidden_nodes); + exchange(second_hidden_nodes, item.second_hidden_nodes); + exchange(output_nodes, item.output_nodes); + exchange(alpha, item.alpha); + exchange(momentum, item.momentum); + + w1.swap(item.w1); + w2.swap(item.w2); + w3.swap(item.w3); + + w1m.swap(item.w1m); + w2m.swap(item.w2m); + w3m.swap(item.w3m); + + // even swap the temporary matrices because this may ultimately result in + // fewer calls to new and delete. + e1.swap(item.e1); + e2.swap(item.e2); + e3.swap(item.e3); + z.swap(item.z); + tmp1.swap(item.tmp1); + tmp2.swap(item.tmp2); + o.swap(item.o); + } + + + friend void serialize ( + const mlp_kernel_1& item, + std::ostream& out + ) + { + try + { + serialize(item.input_nodes, out); + serialize(item.first_hidden_nodes, out); + serialize(item.second_hidden_nodes, out); + serialize(item.output_nodes, out); + serialize(item.alpha, out); + serialize(item.momentum, out); + + serialize(item.w1, out); + serialize(item.w2, out); + serialize(item.w3, out); + + serialize(item.w1m, out); + serialize(item.w2m, out); + serialize(item.w3m, out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type mlp_kernel_1"); + } + } + + friend void deserialize ( + mlp_kernel_1& item, + std::istream& in + ) + { + try + { + deserialize(item.input_nodes, in); + deserialize(item.first_hidden_nodes, in); + deserialize(item.second_hidden_nodes, in); + deserialize(item.output_nodes, in); + deserialize(item.alpha, in); + deserialize(item.momentum, in); + + deserialize(item.w1, in); + deserialize(item.w2, in); + deserialize(item.w3, in); + + deserialize(item.w1m, in); + deserialize(item.w2m, in); + deserialize(item.w3m, in); + + item.z.set_size(item.input_nodes+1,1); + } + catch (serialization_error& e) + { + // give item a reasonable value since the deserialization failed + mlp_kernel_1(1,1).swap(item); + throw serialization_error(e.info + "\n while deserializing object of type mlp_kernel_1"); + } + } + + private: + + long input_nodes; + long first_hidden_nodes; + long second_hidden_nodes; + long output_nodes; + double alpha; + double momentum; + + matrix w1; + matrix w2; + matrix w3; + + matrix w1m; + matrix w2m; + matrix w3m; + + + rand::float_1a rand_nums; + + // temporary storage + mutable matrix e1, e2, e3; + mutable matrix z, tmp1, tmp2, o; + }; + + inline void swap ( + mlp_kernel_1& a, + mlp_kernel_1& b + ) { a.swap(b); } + +} + +#endif // DLIB_MLp_KERNEL_1_ + diff --git a/dlib/mlp/mlp_kernel_abstract.h b/dlib/mlp/mlp_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..da65fdf43eb8aa8dd4385167e4629cc457c37964 --- /dev/null +++ b/dlib/mlp/mlp_kernel_abstract.h @@ -0,0 +1,221 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MLp_ABSTRACT_ +#ifdef DLIB_MLp_ABSTRACT_ + +#include "../algs.h" +#include "../serialize.h" +#include "../matrix/matrix_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class mlp : noncopyable + { + /*! + INITIAL VALUE + The network is initially initialized with random weights + + WHAT THIS OBJECT REPRESENTS + This object represents a multilayer layer perceptron network that is + trained using the back propagation algorithm. The training algorithm also + incorporates the momentum method. That is, each round of back propagation + training also adds a fraction of the previous update. This fraction + is controlled by the momentum term set in the constructor. + + The activation function used at each node is the sigmoid function. I.e. + sigmoid(x) = 1/(1 + pow(e,-x)). Thus the output of the network is + always in the range [0,1] + !*/ + + public: + + mlp ( + long nodes_in_input_layer, + long nodes_in_first_hidden_layer, + long nodes_in_second_hidden_layer = 0, + long nodes_in_output_layer = 1, + double alpha = 0.1, + double momentum = 0.8 + ); + /*! + requires + - nodes_in_input_layer > 0 + - nodes_in_first_hidden_layer > 0 + - nodes_in_second_hidden_layer >= 0 + - nodes_in_output_layer > 0 + ensures + - #*this is properly initialized + - #input_layer_nodes() == nodes_in_input_layer + - #first_hidden_layer_nodes() == nodes_in_first_hidden_layer + - #second_hidden_layer_nodes() == nodes_in_second_hidden_layer + - #output_layer_nodes() == nodes_in_output_layer + - #get_alpha() == alpha + - #get_momentum() == momentum + throws + - std::bad_alloc + if this is thrown the mlp will be unusable but + will not leak memory + !*/ + + virtual ~mlp ( + ); + /*! + ensures + - all resources associated with #*this have been released + !*/ + + void reset ( + ) const; + /*! + ensures + - reinitialize the network with random weights + !*/ + + long input_layer_nodes ( + ) const; + /*! + ensures + - returns the number of nodes in the input layer + !*/ + + long first_hidden_layer_nodes ( + ) const; + /*! + ensures + - returns the number of nodes in the first hidden layer. This is + the hidden layer that is directly connected to the input layer. + !*/ + + long second_hidden_layer_nodes ( + ) const; + /*! + ensures + - if (this network has a second hidden layer) then + - returns the number of nodes in the second hidden layer. This is + the hidden layer that is directly connected to the output layer. + - else + - returns 0 + !*/ + + long output_layer_nodes ( + ) const; + /*! + ensures + - returns the number of nodes in the output layer + !*/ + + double get_alpha ( + ) const; + /*! + ensures + - returns the back propagation learning rate used by this object. + !*/ + + double get_momentum ( + ) const; + /*! + ensures + - returns the momentum term used by this object during back propagation + training. The momentum is is the fraction of a previous update to + carry forward to the next call to train() + !*/ + + template + const matrix operator() ( + const matrix_exp& in + ) const; + /*! + requires + - in.nr() == input_layer_nodes() + - in.nc() == 1 + ensures + - returns the output of the network when it is given the + input in. The output's elements are always in the range + of 0.0 to 1.0 + !*/ + + template + void train ( + const matrix_exp& example_in, + const matrix_exp& example_out + ); + /*! + requires + - example_in.nr() == input_layer_nodes() + - example_in.nc() == 1 + - example_out.nr() == output_layer_nodes() + - example_out.nc() == 1 + - max(example_out) <= 1.0 && min(example_out) >= 0.0 + ensures + - trains the network that the correct output when given example_in + should be example_out. + !*/ + + template + void train ( + const matrix_exp& example_in, + double example_out + ); + /*! + requires + - example_in.nr() == input_layer_nodes() + - example_in.nc() == 1 + - output_layer_nodes() == 1 + - example_out <= 1.0 && example_out >= 0.0 + ensures + - trains the network that the correct output when given example_in + should be example_out. + !*/ + + double get_average_change ( + ) const; + /*! + ensures + - returns the average change in the node weights in the + neural network during the last call to train() + !*/ + + void swap ( + mlp& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + inline void swap ( + mlp& a, + mlp& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + void serialize ( + const mlp& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + void deserialize ( + mlp& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MLp_ABSTRACT_ + + diff --git a/dlib/mlp/mlp_kernel_c.h b/dlib/mlp/mlp_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..36ec41196859c65ad82bd85726a0843b49cc6b5f --- /dev/null +++ b/dlib/mlp/mlp_kernel_c.h @@ -0,0 +1,151 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MLP_KERNEl_C_ +#define DLIB_MLP_KERNEl_C_ + +#include "mlp_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + + template < + typename mlp_base // is an implementation of mlp_kernel_abstract.h + > + class mlp_kernel_c : public mlp_base + { + long verify_constructor_args ( + long nodes_in_input_layer, + long nodes_in_first_hidden_layer, + long nodes_in_second_hidden_layer, + long nodes_in_output_layer + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(nodes_in_input_layer > 0 && + nodes_in_first_hidden_layer > 0 && + nodes_in_second_hidden_layer >= 0 && + nodes_in_output_layer > 0, + "\tconst mlp::constructor()" + << "\n\tinvalid constructor arguments" + << "\n\tnodes_in_input_layer: " << nodes_in_input_layer + << "\n\tnodes_in_first_hidden_layer: " << nodes_in_first_hidden_layer + << "\n\tnodes_in_second_hidden_layer: " << nodes_in_second_hidden_layer + << "\n\tnodes_in_output_layer: " << nodes_in_output_layer + ); + + return nodes_in_input_layer; + } + + public: + + mlp_kernel_c ( + long nodes_in_input_layer, + long nodes_in_first_hidden_layer, + long nodes_in_second_hidden_layer = 0, + long nodes_in_output_layer = 1, + double alpha = 0.1, + double momentum = 0.8 + ) : mlp_base( verify_constructor_args( + nodes_in_input_layer, + nodes_in_input_layer, + nodes_in_second_hidden_layer, + nodes_in_output_layer), + nodes_in_first_hidden_layer, + nodes_in_second_hidden_layer, + nodes_in_output_layer, + alpha, + momentum) + { + } + + template + const matrix operator() ( + const matrix_exp& in + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(in.nr() == this->input_layer_nodes() && + in.nc() == 1, + "\tconst matrix mlp::operator()(matrix_exp)" + << "\n\tthe input matrix dimensions are not correct" + << "\n\tin.nr(): " << in.nr() + << "\n\tin.nc(): " << in.nc() + << "\n\tinput_layer_nodes(): " << this->input_layer_nodes() + << "\n\tthis: " << this + ); + + return mlp_base::operator()(in); + } + + template + void train ( + const matrix_exp& example_in, + const matrix_exp& example_out + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(example_in.nr() == this->input_layer_nodes() && + example_in.nc() == 1 && + example_out.nr() == this->output_layer_nodes() && + example_out.nc() == 1 && + max(example_out) <= 1.0 && min(example_out) >= 0.0, + "\tvoid mlp::train(matrix_exp, matrix_exp)" + << "\n\tthe training example dimensions are not correct" + << "\n\texample_in.nr(): " << example_in.nr() + << "\n\texample_in.nc(): " << example_in.nc() + << "\n\texample_out.nr(): " << example_out.nr() + << "\n\texample_out.nc(): " << example_out.nc() + << "\n\tmax(example_out): " << max(example_out) + << "\n\tmin(example_out): " << min(example_out) + << "\n\tinput_layer_nodes(): " << this->input_layer_nodes() + << "\n\toutput_layer_nodes(): " << this->output_layer_nodes() + << "\n\tthis: " << this + ); + + mlp_base::train(example_in,example_out); + } + + template + void train ( + const matrix_exp& example_in, + double example_out + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(example_in.nr() == this->input_layer_nodes() && + example_in.nc() == 1 && + this->output_layer_nodes() == 1 && + example_out <= 1.0 && example_out >= 0.0, + "\tvoid mlp::train(matrix_exp, double)" + << "\n\tthe training example dimensions are not correct" + << "\n\texample_in.nr(): " << example_in.nr() + << "\n\texample_in.nc(): " << example_in.nc() + << "\n\texample_out: " << example_out + << "\n\tinput_layer_nodes(): " << this->input_layer_nodes() + << "\n\toutput_layer_nodes(): " << this->output_layer_nodes() + << "\n\tthis: " << this + ); + + mlp_base::train(example_in,example_out); + } + + }; + + template < + typename mlp_base + > + inline void swap ( + mlp_kernel_c& a, + mlp_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MLP_KERNEl_C_ + + diff --git a/dlib/noncopyable.h b/dlib/noncopyable.h new file mode 100644 index 0000000000000000000000000000000000000000..04e6c72b5a071ab0e10bc6bbd390f2ae2c8001ef --- /dev/null +++ b/dlib/noncopyable.h @@ -0,0 +1,47 @@ +// (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 +// See http://www.boost.org/libs/utility for documentation. + +#ifndef DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED +#define DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED + +#ifndef BOOST_NONCOPYABLE_HPP_INCLUDED +#define BOOST_NONCOPYABLE_HPP_INCLUDED + +namespace boost +{ + + namespace noncopyable_ // protection from unintended ADL + { + class noncopyable + { + /*! + This class makes it easier to declare a class as non-copyable. + If you want to make an object that can't be copied just inherit + from this object. + !*/ + + protected: + noncopyable() {} + ~noncopyable() {} + private: // emphasize the following members are private + noncopyable( const noncopyable& ); + const noncopyable& operator=( const noncopyable& ); + }; + } + + typedef noncopyable_::noncopyable noncopyable; + +} // namespace boost + +#endif // BOOST_NONCOPYABLE_HPP_INCLUDED + +namespace dlib +{ + using boost::noncopyable; +} + +#endif // DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED + diff --git a/dlib/ostream b/dlib/ostream new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/ostream @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/pipe.h b/dlib/pipe.h new file mode 100644 index 0000000000000000000000000000000000000000..2f13d242dd3dfcf1374458ce5260f6ffbff5f9e2 --- /dev/null +++ b/dlib/pipe.h @@ -0,0 +1,32 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PIPe_ +#define DLIB_PIPe_ + +#include "pipe/pipe_kernel_1.h" + + +namespace dlib +{ + + template < + typename T + > + class pipe + { + pipe() {} + public: + + + //----------- kernels --------------- + + // kernel_1a + typedef pipe_kernel_1 + kernel_1a; + + + }; +} + +#endif // DLIB_PIPe_ + diff --git a/dlib/pipe/pipe_kernel_1.h b/dlib/pipe/pipe_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..c60c40494d7121c6624f46b46968930d57e72a96 --- /dev/null +++ b/dlib/pipe/pipe_kernel_1.h @@ -0,0 +1,691 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PIPE_KERNEl_1_ +#define DLIB_PIPE_KERNEl_1_ + +#include "../algs.h" +#include "../threads.h" +#include "pipe_kernel_abstract.h" + +namespace dlib +{ + + template < + typename T + > + class pipe_kernel_1 + { + /*! + INITIAL VALUE + - pipe_size == 0 + - pipe_max_size == defined by constructor + - enabled == true + - data == a pointer to an array of ((pipe_max_size>0)?pipe_max_size:1) T objects. + - dequeue_waiters == 0 + - enqueue_waiters == 0 + - first == 1 + - last == 1 + - unblock_sig_waiters == 0 + + CONVENTION + - size() == pipe_size + - max_size() == pipe_max_size + - is_enabled() == enabled + + - m == the mutex used to lock access to all the members of this class + + - dequeue_waiters == the number of threads blocked on calls to dequeue() + - enqueue_waiters == the number of threads blocked on calls to enqueue() and + wait_until_empty() + - unblock_sig_waiters == the number of threads blocked on calls to + wait_for_num_blocked_dequeues() and the destructor. (i.e. the number of + blocking calls to unblock_sig.wait()) + + - dequeue_sig == the signaler that threads blocked on calls to dequeue() wait on + - enqueue_sig == the signaler that threads blocked on calls to enqueue() + or wait_until_empty() wait on. + - unblock_sig == the signaler that is signaled when a thread stops blocking on a call + to enqueue() or dequeue(). It is also signaled when a dequeue that will probably + block is called. The destructor and wait_for_num_blocked_dequeues are the only + things that will wait on this signaler. + + - if (pipe_size > 0) then + - data[first] == the next item to dequeue + - data[last] == the item most recently added via enqueue, so the last to dequeue. + - else if (pipe_max_size == 0) + - if (first == 0 && last == 0) then + - data[0] == the next item to dequeue + - else if (first == 0 && last == 1) then + - data[0] has been taken out already by a dequeue + !*/ + + public: + + explicit pipe_kernel_1 ( + unsigned long maximum_size + ); + + virtual ~pipe_kernel_1 ( + ); + + void empty ( + ); + + void wait_until_empty ( + ) const; + + void wait_for_num_blocked_dequeues ( + unsigned long num + )const; + + void enable ( + ); + + void disable ( + ); + + bool is_enqueue_enabled ( + ) const; + + void disable_enqueue ( + ); + + void enable_enqueue ( + ); + + bool is_enabled ( + ) const; + + unsigned long max_size ( + ) const; + + unsigned long size ( + ) const; + + bool enqueue ( + T& item + ); + + bool dequeue ( + T& item + ); + + bool enqueue_or_timeout ( + T& item, + unsigned long timeout + ); + + bool dequeue_or_timeout ( + T& item, + unsigned long timeout + ); + + private: + + unsigned long pipe_size; + const unsigned long pipe_max_size; + bool enabled; + + T* const data; + + unsigned long first; + unsigned long last; + + mutex m; + signaler dequeue_sig; + signaler enqueue_sig; + signaler unblock_sig; + + unsigned long dequeue_waiters; + mutable unsigned long enqueue_waiters; + mutable unsigned long unblock_sig_waiters; + bool enqueue_enabled; + + // restricted functions + pipe_kernel_1(const pipe_kernel_1&); // copy constructor + pipe_kernel_1& operator=(const pipe_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + pipe_kernel_1:: + pipe_kernel_1 ( + unsigned long maximum_size + ) : + pipe_size(0), + pipe_max_size(maximum_size), + enabled(true), + data(new T[(maximum_size>0) ? maximum_size : 1]), + first(1), + last(1), + dequeue_sig(m), + enqueue_sig(m), + unblock_sig(m), + dequeue_waiters(0), + enqueue_waiters(0), + unblock_sig_waiters(0), + enqueue_enabled(true) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + pipe_kernel_1:: + ~pipe_kernel_1 ( + ) + { + auto_mutex M(m); + ++unblock_sig_waiters; + + // first make sure no one is blocked on any calls to enqueue() or dequeue() + enabled = false; + dequeue_sig.broadcast(); + enqueue_sig.broadcast(); + unblock_sig.broadcast(); + + // wait for all threads to unblock + while (dequeue_waiters > 0 || enqueue_waiters > 0 || unblock_sig_waiters > 1) + unblock_sig.wait(); + + delete [] data; + --unblock_sig_waiters; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + empty ( + ) + { + auto_mutex M(m); + pipe_size = 0; + + // let any calls to enqueue() know that the pipe is now empty + if (enqueue_waiters > 0) + enqueue_sig.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + wait_until_empty ( + ) const + { + auto_mutex M(m); + // this function is sort of like a call to enqueue so treat it like that + ++enqueue_waiters; + + while (pipe_size > 0 && enabled ) + enqueue_sig.wait(); + + // let the destructor know we are ending if it is blocked waiting + if (enabled == false) + unblock_sig.broadcast(); + + --enqueue_waiters; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + enable ( + ) + { + auto_mutex M(m); + enabled = true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + disable ( + ) + { + auto_mutex M(m); + enabled = false; + dequeue_sig.broadcast(); + enqueue_sig.broadcast(); + unblock_sig.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool pipe_kernel_1:: + is_enabled ( + ) const + { + auto_mutex M(m); + return enabled; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + unsigned long pipe_kernel_1:: + max_size ( + ) const + { + auto_mutex M(m); + return pipe_max_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + unsigned long pipe_kernel_1:: + size ( + ) const + { + auto_mutex M(m); + return pipe_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool pipe_kernel_1:: + enqueue ( + T& item + ) + { + auto_mutex M(m); + ++enqueue_waiters; + + // wait until there is room or we are disabled + while (pipe_size == pipe_max_size && enabled && enqueue_enabled && + !(pipe_max_size == 0 && first == 1) ) + enqueue_sig.wait(); + + if (enabled == false || enqueue_enabled == false) + { + --enqueue_waiters; + // let the destructor know we are unblocking + unblock_sig.broadcast(); + return false; + } + + // set the appropriate values for first and last + if (pipe_size == 0) + { + first = 0; + last = 0; + } + else + { + last = (last+1)%pipe_max_size; + } + + + exchange(item,data[last]); + + // wake up a call to dequeue() if there are any currently blocked + if (dequeue_waiters > 0) + dequeue_sig.signal(); + + if (pipe_max_size > 0) + { + ++pipe_size; + } + else + { + // wait for a dequeue to take the item out + while (last == 0 && enabled && enqueue_enabled) + enqueue_sig.wait(); + + if (last == 0 && (enabled == false || enqueue_enabled == false)) + { + last = 1; + first = 1; + + // no one dequeued this object to put it back into item + exchange(item,data[0]); + + --enqueue_waiters; + // let the destructor know we are unblocking + if (unblock_sig_waiters > 0) + unblock_sig.broadcast(); + return false; + } + + last = 1; + first = 1; + + // tell any waiting calls to enqueue() that one of them can proceed + if (enqueue_waiters > 1) + enqueue_sig.broadcast(); + + // let the destructor know we are unblocking + if (enabled == false && unblock_sig_waiters > 0) + unblock_sig.broadcast(); + } + + --enqueue_waiters; + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool pipe_kernel_1:: + dequeue ( + T& item + ) + { + auto_mutex M(m); + ++dequeue_waiters; + + if (pipe_size == 0) + { + // notify wait_for_num_blocked_dequeues() + if (unblock_sig_waiters > 0) + unblock_sig.broadcast(); + + // notify any blocked enqueue_or_timeout() calls + if (enqueue_waiters > 0) + enqueue_sig.broadcast(); + } + + // wait until there is something in the pipe or we are disabled + while (pipe_size == 0 && enabled && + !(pipe_max_size == 0 && first == 0 && last == 0) ) + dequeue_sig.wait(); + + if (enabled == false) + { + --dequeue_waiters; + // let the destructor know we are unblocking + unblock_sig.broadcast(); + return false; + } + + exchange(item,data[first]); + + if (pipe_max_size > 0) + { + // set the appropriate values for first + first = (first+1)%pipe_max_size; + + --pipe_size; + } + else + { + // let the enqueue waiting on us know that we took the + // item out already. + last = 1; + } + + // wake up a call to enqueue() if there are any currently blocked + if (enqueue_waiters > 0) + enqueue_sig.broadcast(); + + --dequeue_waiters; + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool pipe_kernel_1:: + enqueue_or_timeout ( + T& item, + unsigned long timeout + ) + { + auto_mutex M(m); + ++enqueue_waiters; + + // wait until there is room or we are disabled or + // we run out of time. + bool timed_out = false; + while (pipe_size == pipe_max_size && enabled && enqueue_enabled && + !(pipe_max_size == 0 && dequeue_waiters > 0 && first == 1) ) + { + if (timeout == 0 || enqueue_sig.wait_or_timeout(timeout) == false) + { + timed_out = true; + break; + } + } + + if (enabled == false || timed_out || enqueue_enabled == false) + { + --enqueue_waiters; + // let the destructor know we are unblocking + unblock_sig.broadcast(); + return false; + } + + // set the appropriate values for first and last + if (pipe_size == 0) + { + first = 0; + last = 0; + } + else + { + last = (last+1)%pipe_max_size; + } + + + exchange(item,data[last]); + + // wake up a call to dequeue() if there are any currently blocked + if (dequeue_waiters > 0) + dequeue_sig.signal(); + + if (pipe_max_size > 0) + { + ++pipe_size; + } + else + { + // wait for a dequeue to take the item out + while (last == 0 && enabled && enqueue_enabled) + enqueue_sig.wait(); + + if (last == 0 && (enabled == false || enqueue_enabled == false)) + { + last = 1; + first = 1; + + // no one dequeued this object to put it back into item + exchange(item,data[0]); + + --enqueue_waiters; + // let the destructor know we are unblocking + if (unblock_sig_waiters > 0) + unblock_sig.broadcast(); + return false; + } + + last = 1; + first = 1; + + // tell any waiting calls to enqueue() that one of them can proceed + if (enqueue_waiters > 1) + enqueue_sig.broadcast(); + + // let the destructor know we are unblocking + if (enabled == false && unblock_sig_waiters > 0) + unblock_sig.broadcast(); + } + + --enqueue_waiters; + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool pipe_kernel_1:: + dequeue_or_timeout ( + T& item, + unsigned long timeout + ) + { + auto_mutex M(m); + ++dequeue_waiters; + + if (pipe_size == 0) + { + // notify wait_for_num_blocked_dequeues() + if (unblock_sig_waiters > 0) + unblock_sig.broadcast(); + + // notify any blocked enqueue_or_timeout() calls + if (enqueue_waiters > 0) + enqueue_sig.broadcast(); + } + + bool timed_out = false; + // wait until there is something in the pipe or we are disabled or we timeout. + while (pipe_size == 0 && enabled && + !(pipe_max_size == 0 && first == 0 && last == 0) ) + { + if (timeout == 0 || dequeue_sig.wait_or_timeout(timeout) == false) + { + timed_out = true; + break; + } + } + + if (enabled == false || timed_out) + { + --dequeue_waiters; + // let the destructor know we are unblocking + unblock_sig.broadcast(); + return false; + } + + exchange(item,data[first]); + + if (pipe_max_size > 0) + { + // set the appropriate values for first + first = (first+1)%pipe_max_size; + + --pipe_size; + } + else + { + // let the enqueue waiting on us know that we took the + // item out already. + last = 1; + } + + // wake up a call to enqueue() if there are any currently blocked + if (enqueue_waiters > 0) + enqueue_sig.broadcast(); + + --dequeue_waiters; + return true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + wait_for_num_blocked_dequeues ( + unsigned long num + )const + { + auto_mutex M(m); + ++unblock_sig_waiters; + + while ( (dequeue_waiters < num || pipe_size != 0) && enabled) + unblock_sig.wait(); + + // let the destructor know we are ending if it is blocked waiting + if (enabled == false) + unblock_sig.broadcast(); + + --unblock_sig_waiters; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool pipe_kernel_1:: + is_enqueue_enabled ( + ) const + { + auto_mutex M(m); + return enqueue_enabled; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + disable_enqueue ( + ) + { + auto_mutex M(m); + enqueue_enabled = false; + enqueue_sig.broadcast(); + } + + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void pipe_kernel_1:: + enable_enqueue ( + ) + { + auto_mutex M(m); + enqueue_enabled = true; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_PIPE_KERNEl_1_ + diff --git a/dlib/pipe/pipe_kernel_abstract.h b/dlib/pipe/pipe_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..c71755ad1592f1baa6558ed4284e09333110ff3a --- /dev/null +++ b/dlib/pipe/pipe_kernel_abstract.h @@ -0,0 +1,275 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_PIPE_KERNEl_ABSTRACT_ +#ifdef DLIB_PIPE_KERNEl_ABSTRACT_ + +#include "../threads.h" + +namespace dlib +{ + + template < + typename T + > + class pipe + { + /*! + REQUIREMENTS ON T + T must be swappable by a global swap() + T must have a default constructor + + INITIAL VALUE + size() == 0 + is_enabled() == true + is_enqueue_enabled() == true + + WHAT THIS OBJECT REPRESENTS + This is a first in first out queue with a fixed maximum size containing + items of type T. It is suitable for passing objects between threads. + + THREAD SAFETY + All methods of this class are thread safe. You may call them from any + thread and any number of threads my call them at once. + !*/ + + public: + + typedef T type; + + explicit pipe ( + unsigned long maximum_size + ); + /*! + ensures + - #*this is properly initialized + - #max_size() == maximum_size + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~pipe ( + ); + /*! + ensures + - any resources associated with *this have been released + - disables (i.e. sets is_enabled() == false) this object so that + all calls currently blocking on it will return immediately. + !*/ + + void enable ( + ); + /*! + ensures + - #is_enabled() == true + !*/ + + void empty ( + ); + /*! + ensures + - #size() == 0 + !*/ + + void wait_until_empty ( + ) const; + /*! + ensures + - blocks until one of the following is the case: + - size() == 0 + - is_enabled() == false + !*/ + + void wait_for_num_blocked_dequeues ( + unsigned long num + ) const; + /*! + ensures + - blocls until one of the following is the case: + - size() == 0 and the number of threads blocked on calls + to dequeue() and dequeue_or_timeout() is greater than + or equal to num. + - is_enabled() == false + !*/ + + bool is_enqueue_enabled ( + ) const; + /*! + ensures + - returns true if the enqueue() and enqueue_or_timeout() functions are + currently enabled, returns false otherwise. (note that the higher + level is_enabled() function can overrule this one. So if + is_enabled() == false then enqueue functions are still disabled. + But if is_enqueue_enabled() == false then enqueue functions are always + disabled no matter the state of is_enabled()) + !*/ + + void disable_enqueue ( + ); + /*! + ensures + - #is_enqueue_enabled() == false + - causes all current and future calls to enqueue() and + enqueue_or_timeout() to not block but to return false + immediately until enable_enqueue() is called. + !*/ + + void enable_enqueue ( + ); + /*! + ensures + - #is_enqueue_enabled() == true + !*/ + + void disable ( + ); + /*! + ensures + - #is_enabled() == false + - causes all current and future calls to enqueue(), dequeue(), + enqueue_or_timeout() and dequeue_or_timeout() to not block but + to return false immediately until enable() is called. + - causes all current and future calls to wait_until_empty() and + wait_for_num_blocked_dequeues() to not block but return + immediately until enable() is called. + !*/ + + bool is_enabled ( + ) const; + /*! + ensures + - returns true if this pipe is currently enabled, false otherwise. + !*/ + + unsigned long max_size ( + ) const; + /*! + ensures + - returns the maximum number of objects of type T that this + pipe can contain. + !*/ + + unsigned long size ( + ) const; + /*! + ensures + - returns the number of objects of type T that this + object currently contains. + !*/ + + bool enqueue ( + T& item + ); + /*! + ensures + - if (size() == max_size()) then + - this call to enqueue() blocks until one of the following is the case: + - there is room in the pipe for another item + - another thread is trying to dequeue from this pipe and we can pass + our item object directly to that thread. + - someone calls disable() + - someone calls disable_enqueue() + - else + - this call does not block. + - if (this call to enqueue() returns true) then + - #is_enabled() == true + - #is_enqueue_enabled() == true + - if (max_size() == 0) then + - using global swap, item was passed directly to a + thread attempting to dequeue from this pipe + - else + - using global swap, item was added into this pipe. + - #item is in an undefined but valid state for its type + - else + - item was NOT added into the pipe + - #item == item (i.e. the value of item is unchanged) + !*/ + + bool enqueue_or_timeout ( + T& item, + unsigned long timeout + ); + /*! + ensures + - if (size() == max_size() && timeout > 0) then + - this call to enqueue() blocks until one of the following is the case: + - there is room in the pipe to add another item + - another thread is trying to dequeue from this pipe and we can pass + our item object directly to that thread. + - someone calls disable() + - someone calls disable_enqueue() + - timeout milliseconds passes + - else + - this call does not block. + - if (this call to enqueue() returns true) then + - #is_enabled() == true + - #is_enqueue_enabled() == true + - if (max_size() == 0) then + - using global swap, item was passed directly to a + thread attempting to dequeue from this pipe + - else + - using global swap, item was added into this pipe. + - #item is in an undefined but valid state for its type + - else + - item was NOT added into the pipe + - #item == item (i.e. the value of item is unchanged) + !*/ + + bool dequeue ( + T& item + ); + /*! + ensures + - if (size() == 0) then + - this call to dequeue() blocks until one of the following is the case: + - there is something in the pipe we can dequeue + - another thread is trying to enqueue an item onto this pipe + and we can receive our item directly from that thread. + - someone calls disable() + - else + - this call does not block. + - if (this call to dequeue() returns true) then + - #is_enabled() == true + - the oldest item that was enqueued into this pipe has been + swapped into #item. + - else + - nothing was dequeued from this pipe. + - #item == item (i.e. the value of item is unchanged) + !*/ + + bool dequeue_or_timeout ( + T& item, + unsigned long timeout + ); + /*! + ensures + - if (size() == 0 && timeout > 0) then + - this call to dequeue() blocks until one of the following is the case: + - there is something in the pipe we can dequeue + - another thread is trying to enqueue an item onto this pipe + and we can receive our item directly from that thread. + - someone calls disable() + - timeout milliseconds passes + - else + - this call does not block. + - if (this call to dequeue_or_timeout() returns true) then + - #is_enabled() == true + - the oldest item that was enqueued into this pipe has been + swapped into #item. + - else + - nothing was dequeued from this pipe. + - #item == item (i.e. the value of item is unchanged) + !*/ + + private: + + // restricted functions + pipe(const pipe&); // copy constructor + pipe& operator=(const pipe&); // assignment operator + + }; + +} + +#endif // DLIB_PIPE_KERNEl_ABSTRACT_ + diff --git a/dlib/pixel.cpp b/dlib/pixel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b81dac0be0b25b5d98e2280949f7a71a5b7d0622 --- /dev/null +++ b/dlib/pixel.cpp @@ -0,0 +1,219 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PIXEL_CPp_ +#define DLIB_PIXEL_CPp_ + +#include "pixel.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const rgb_alpha_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.red,out); + serialize(item.green,out); + serialize(item.blue,out); + serialize(item.alpha,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type rgb_alpha_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + rgb_alpha_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.red,in); + deserialize(item.green,in); + deserialize(item.blue,in); + deserialize(item.alpha,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type rgb_alpha_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const rgb_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.red,out); + serialize(item.green,out); + serialize(item.blue,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type rgb_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + rgb_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.red,in); + deserialize(item.green,in); + deserialize(item.blue,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type rgb_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const hsi_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.h,out); + serialize(item.s,out); + serialize(item.i,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type hsi_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + hsi_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.h,in); + deserialize(item.s,in); + deserialize(item.i,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type hsi_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + namespace assign_pixel_helpers + { + /* + I found this excellent bit of code at + http://local.wasp.uwa.edu.au/~pbourke/colour/hsl/ + */ + + /* + Calculate HSL from RGB + Hue is in degrees + Lightness is between 0 and 1 + Saturation is between 0 and 1 + */ + HSL RGB2HSL(COLOUR c1) + { + double themin,themax,delta; + HSL c2; + using namespace std; + + themin = min(c1.r,min(c1.g,c1.b)); + themax = max(c1.r,max(c1.g,c1.b)); + delta = themax - themin; + c2.l = (themin + themax) / 2; + c2.s = 0; + if (c2.l > 0 && c2.l < 1) + c2.s = delta / (c2.l < 0.5 ? (2*c2.l) : (2-2*c2.l)); + c2.h = 0; + if (delta > 0) { + if (themax == c1.r && themax != c1.g) + c2.h += (c1.g - c1.b) / delta; + if (themax == c1.g && themax != c1.b) + c2.h += (2 + (c1.b - c1.r) / delta); + if (themax == c1.b && themax != c1.r) + c2.h += (4 + (c1.r - c1.g) / delta); + c2.h *= 60; + } + return(c2); + } + + /* + Calculate RGB from HSL, reverse of RGB2HSL() + Hue is in degrees + Lightness is between 0 and 1 + Saturation is between 0 and 1 + */ + COLOUR HSL2RGB(HSL c1) + { + COLOUR c2,sat,ctmp; + using namespace std; + + if (c1.h < 120) { + sat.r = (120 - c1.h) / 60.0; + sat.g = c1.h / 60.0; + sat.b = 0; + } else if (c1.h < 240) { + sat.r = 0; + sat.g = (240 - c1.h) / 60.0; + sat.b = (c1.h - 120) / 60.0; + } else { + sat.r = (c1.h - 240) / 60.0; + sat.g = 0; + sat.b = (360 - c1.h) / 60.0; + } + sat.r = min(sat.r,1.0); + sat.g = min(sat.g,1.0); + sat.b = min(sat.b,1.0); + + ctmp.r = 2 * c1.s * sat.r + (1 - c1.s); + ctmp.g = 2 * c1.s * sat.g + (1 - c1.s); + ctmp.b = 2 * c1.s * sat.b + (1 - c1.s); + + if (c1.l < 0.5) { + c2.r = c1.l * ctmp.r; + c2.g = c1.l * ctmp.g; + c2.b = c1.l * ctmp.b; + } else { + c2.r = (1 - c1.l) * ctmp.r + 2 * c1.l - 1; + c2.g = (1 - c1.l) * ctmp.g + 2 * c1.l - 1; + c2.b = (1 - c1.l) * ctmp.b + 2 * c1.l - 1; + } + + return(c2); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_PIXEL_CPp_ + diff --git a/dlib/pixel.h b/dlib/pixel.h new file mode 100644 index 0000000000000000000000000000000000000000..6e732c586e83c3415d3946f2a7d24d0074eb57a0 --- /dev/null +++ b/dlib/pixel.h @@ -0,0 +1,929 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PIXEl_ +#define DLIB_PIXEl_ + +#include +#include "serialize.h" +#include +#include "algs.h" +#include "uintn.h" +#include +#include "enable_if.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + This file contains definitions of pixel objects and related classes and + functionality. + !*/ + +// ---------------------------------------------------------------------------------------- + + template + struct pixel_traits; + /*! + WHAT THIS OBJECT REPRESENTS + As the name implies, this is a traits class for pixel types. + It defines the properties of a pixel (duah). + + This traits class will define the following public static members: + - bool grayscale + - bool rgb + - bool rgb_alpha + - bool hsi + + - bool has_alpha + + - long num + - unsigned long max() + + The above public constants are subject to the following constraints: + - only one of grayscale, rgb, rgb_alpha, or hsi is true + - if (rgb == true) then + - The type T will be a struct with 3 public members of type + unsigned char named "red" "green" and "blue". + - This type of pixel represents the RGB color space. + - num == 3 + - has_alpha == false + - max() == 255 + - if (rgb_alpha == true) then + - The type T will be a struct with 4 public members of type + unsigned char named "red" "green" "blue" and "alpha". + - This type of pixel represents the RGB color space with + an alpha channel where an alpha of 0 represents a pixel + that is totally transparent and 255 represents a pixel + with maximum opacity. + - num == 4 + - has_alpha == true + - max() == 255 + - else if (hsi == true) then + - The type T will be a struct with 3 public members of type + unsigned char named "h" "s" and "i". + - This type of pixel represents the HSI color space. + - num == 3 + - has_alpha == false + - max() == 255 + - else + - grayscale == true + - The type T will be an unsigned integral type. + - This type of pixel represents a grayscale color space + - num == 1 + - has_alpha == false + - max() == std::numeric_limits::max() + !*/ + +// ---------------------------------------------------------------------------------------- + + struct rgb_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an RGB colored graphical pixel. + !*/ + + rgb_pixel ( + ) {} + + rgb_pixel ( + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) : red(red_), green(green_), blue(blue_) {} + + unsigned char red; + unsigned char green; + unsigned char blue; + }; + +// ---------------------------------------------------------------------------------------- + + struct rgb_alpha_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an RGB colored graphical pixel + with an alpha channel. + !*/ + + rgb_alpha_pixel ( + ) {} + + rgb_alpha_pixel ( + unsigned char red_, + unsigned char green_, + unsigned char blue_, + unsigned char alpha_ + ) : red(red_), green(green_), blue(blue_), alpha(alpha_) {} + + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; + }; + +// ---------------------------------------------------------------------------------------- + + struct hsi_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an HSI colored graphical pixel. + !*/ + + hsi_pixel ( + ) {} + + hsi_pixel ( + unsigned char h_, + unsigned char s_, + unsigned char i_ + ) : h(h_), s(s_), i(i_) {} + + unsigned char h; + unsigned char s; + unsigned char i; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename P1, + typename P2 + > + inline void assign_pixel ( + P1& dest, + const P2& src + ); + /*! + requires + - pixel_traits must be defined + - pixel_traits must be defined + ensures + - if (P1 and P2 are the same type of pixel) then + - simply coppies the value of src into dest. In other words, + dest will be identical to src after this function returns. + - else if (P1 and P2 are not the same type of pixel) then + - assigns pixel src to pixel dest and does any necessary color space + conversions. + - When converting from a grayscale color space with more than 255 values the + pixel intensity is saturated at pixel_traits::max(). + - if (the dest pixel has an alpha channel and the src pixel doesn't) then + - #dest.alpha == 255 + - else if (the src pixel has an alpha channel but the dest pixel doesn't) then + - #dest == the original dest value blended with the src value according + to the alpha channel in src. + (i.e. #dest == src*(alpha/255) + dest*(1-alpha/255)) + !*/ + + template < + typename P + > + inline void assign_pixel ( + P& dest, + const int src + ); + /*! + requires + - pixel_traits

must be defined + ensures + - performs assign_pixel(dest, static_cast(max(0,src))) + !*/ + + template < + typename P + > + inline void assign_pixel ( + P& dest, + const long src + ); + /*! + requires + - pixel_traits

must be defined + ensures + - performs assign_pixel(dest, static_cast(max(0,src))) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + inline unsigned long get_pixel_intensity ( + const P& src + ); + /*! + requires + - pixel_traits

must be defined + ensures + - if (pixel_traits

::grayscale == true) then + - returns src + - else + - converts src to the HSI color space and returns the intensity + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + inline void assign_pixel_intensity ( + P& dest, + const unsigned long new_intensity + ); + /*! + requires + - pixel_traits

must be defined + ensures + - let val == min(new_intensity, pixel_traits

::max()) + - #get_pixel_intensity(dest) == val + - if (the dest pixel has an alpha channel) then + - #dest.alpha == dest.alpha + !*/ + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const rgb_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the rgb_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + rgb_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the rgb_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const rgb_alpha_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the rgb_alpha_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + rgb_alpha_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the rgb_alpha_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const hsi_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the hsi_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + hsi_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the hsi_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + template <> + struct pixel_traits + { + const static bool rgb = true; + const static bool rgb_alpha = false; + const static bool grayscale = false; + const static bool hsi = false; + const static long num = 3; + static unsigned long max() { return 255;} + const static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + template <> + struct pixel_traits + { + const static bool rgb = false; + const static bool rgb_alpha = true; + const static bool grayscale = false; + const static bool hsi = false; + const static long num = 4; + static unsigned long max() { return 255; } + const static bool has_alpha = true; + }; + +// ---------------------------------------------------------------------------------------- + + + template <> + struct pixel_traits + { + const static bool rgb = false; + const static bool rgb_alpha = false; + const static bool grayscale = false; + const static bool hsi = true; + const static long num = 3; + static unsigned long max() { return 255;} + const static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + template + struct grayscale_pixel_traits + { + const static bool rgb = false; + const static bool rgb_alpha = false; + const static bool grayscale = true; + const static bool hsi = false; + const static long num = 1; + const static bool has_alpha = false; + static unsigned long max() { return std::numeric_limits::max();} + }; + + template <> struct pixel_traits : public grayscale_pixel_traits {}; + template <> struct pixel_traits : public grayscale_pixel_traits {}; + template <> struct pixel_traits : public grayscale_pixel_traits {}; + template <> struct pixel_traits : public grayscale_pixel_traits {}; + +// ---------------------------------------------------------------------------------------- + + // The following is a bunch of conversion stuff for the assign_pixel function. + + namespace assign_pixel_helpers + { + enum + { + grayscale = 1, + rgb, + hsi, + rgb_alpha + }; + + template < + typename P1, + typename P2, + int p1_type = static_switch< + pixel_traits::grayscale, + pixel_traits::rgb, + pixel_traits::hsi, + pixel_traits::rgb_alpha >::value, + int p2_type = static_switch< + pixel_traits::grayscale, + pixel_traits::rgb, + pixel_traits::hsi, + pixel_traits::rgb_alpha >::value + > + struct helper; + + // ----------------------------- + // all the same kind + + template < typename P > + struct helper + { + static void assign(P& dest, const P& src) + { + dest = src; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + if (src <= pixel_traits::max()) + dest = static_cast(src); + else + dest = static_cast(pixel_traits::max()); + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + dest.alpha = src.alpha; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest.h = src.h; + dest.s = src.s; + dest.i = src.i; + } + }; + + // ----------------------------- + // dest is a grayscale + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest = static_cast((static_cast(src.red) + + static_cast(src.green) + + static_cast(src.blue))/3); + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + + const unsigned char avg = static_cast((static_cast(src.red) + + static_cast(src.green) + + static_cast(src.blue))/3); + + if (src.alpha == 255) + { + dest = avg; + } + else + { + // perform this assignment using fixed point arithmetic: + // dest = src*(alpha/255) + src*(1 - alpha/255); + // dest = src*(alpha/255) + dest*1 - dest*(alpha/255); + // dest = dest*1 + src*(alpha/255) - dest*(alpha/255); + // dest = dest*1 + (src - dest)*(alpha/255); + // dest += (src - dest)*(alpha/255); + + unsigned int temp = avg; + + temp -= dest; + + temp *= src.alpha; + + temp >>= 8; + + dest += static_cast(temp&0xFF); + } + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest = static_cast(src.i); + } + }; + + + // ----------------------------- + + struct HSL + { + double h; + double s; + double l; + }; + + struct COLOUR + { + double r; + double g; + double b; + }; + + /* + Calculate HSL from RGB + Hue is in degrees + Lightness is between 0 and 1 + Saturation is between 0 and 1 + */ + HSL RGB2HSL(COLOUR c1); + + /* + Calculate RGB from HSL, reverse of RGB2HSL() + Hue is in degrees + Lightness is between 0 and 1 + Saturation is between 0 and 1 + */ + COLOUR HSL2RGB(HSL c1); + + + // ----------------------------- + // dest is a color rgb_pixel + + template < typename P1 > + struct helper + { + static void assign(P1& dest, const unsigned char& src) + { + dest.red = src; + dest.green = src; + dest.blue = src; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + unsigned char p; + if (src <= 255) + p = static_cast(src); + else + p = 255; + + dest.red = p; + dest.green = p; + dest.blue = p; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + if (src.alpha == 255) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + } + else + { + // perform this assignment using fixed point arithmetic: + // dest = src*(alpha/255) + src*(1 - alpha/255); + // dest = src*(alpha/255) + dest*1 - dest*(alpha/255); + // dest = dest*1 + src*(alpha/255) - dest*(alpha/255); + // dest = dest*1 + (src - dest)*(alpha/255); + // dest += (src - dest)*(alpha/255); + + unsigned int temp_r = src.red; + unsigned int temp_g = src.green; + unsigned int temp_b = src.blue; + + temp_r -= dest.red; + temp_g -= dest.green; + temp_b -= dest.blue; + + temp_r *= src.alpha; + temp_g *= src.alpha; + temp_b *= src.alpha; + + temp_r >>= 8; + temp_g >>= 8; + temp_b >>= 8; + + dest.red += static_cast(temp_r&0xFF); + dest.green += static_cast(temp_g&0xFF); + dest.blue += static_cast(temp_b&0xFF); + } + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + COLOUR c; + HSL h; + h.h = src.h; + h.h = h.h/255.0*360; + h.s = src.s/255.0; + h.l = src.i/255.0; + c = HSL2RGB(h); + + dest.red = static_cast(c.r*255.0); + dest.green = static_cast(c.g*255.0); + dest.blue = static_cast(c.b*255.0); + } + }; + + // ----------------------------- + // dest is a color rgb_alpha_pixel + + template < typename P1 > + struct helper + { + static void assign(P1& dest, const unsigned char& src) + { + dest.red = src; + dest.green = src; + dest.blue = src; + dest.alpha = 255; + } + }; + + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + unsigned char p; + if (src <= 255) + p = static_cast(src); + else + p = 255; + + dest.red = p; + dest.green = p; + dest.blue = p; + dest.alpha = 255; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + dest.alpha = 255; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + COLOUR c; + HSL h; + h.h = src.h; + h.h = h.h/255.0*360; + h.s = src.s/255.0; + h.l = src.i/255.0; + c = HSL2RGB(h); + + dest.red = static_cast(c.r*255.0); + dest.green = static_cast(c.g*255.0); + dest.blue = static_cast(c.b*255.0); + dest.alpha = 255; + } + }; + + // ----------------------------- + // dest is an hsi pixel + + template < typename P1> + struct helper + { + static void assign(P1& dest, const unsigned char& src) + { + dest.h = 0; + dest.s = 0; + dest.i = src; + } + }; + + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + dest.h = 0; + dest.s = 0; + if (src <= 255) + dest.i = static_cast(src); + else + dest.i = 255; + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + rgb_pixel temp; + // convert target hsi pixel to rgb + helper::assign(temp,dest); + + // now assign the rgb_alpha value to our temp rgb pixel + helper::assign(temp,src); + + // now we can just go assign the new rgb value to the + // hsi pixel + helper::assign(dest,temp); + } + }; + + template < typename P1, typename P2 > + struct helper + { + static void assign(P1& dest, const P2& src) + { + COLOUR c1; + HSL c2; + c1.r = src.red/255.0; + c1.g = src.green/255.0; + c1.b = src.blue/255.0; + c2 = RGB2HSL(c1); + + dest.h = static_cast(c2.h/360.0*255.0); + dest.s = static_cast(c2.s*255.0); + dest.i = static_cast(c2.l*255.0); + } + }; + } + + // ----------------------------- + + template < typename P1, typename P2 > + inline void assign_pixel ( + P1& dest, + const P2& src + ) { assign_pixel_helpers::helper::assign(dest,src); } + + template < typename P1> + inline void assign_pixel ( + P1& dest, + const int src + ) + { + unsigned long p; + if (src >= 0) + p = static_cast(src); + else + p = 0; + + assign_pixel(dest, p); + } + + template < typename P1> + inline void assign_pixel ( + P1& dest, + const long src + ) + { + unsigned long p; + if (src >= 0) + p = static_cast(src); + else + p = 0; + + assign_pixel(dest, p); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + inline typename enable_if_c::grayscale>::type assign_pixel_intensity_helper ( + P& dest, + const unsigned long& new_intensity + ) + { + assign_pixel(dest, new_intensity); + } + + template < + typename P + > + inline typename enable_if_c::grayscale == false&& + pixel_traits

::has_alpha>::type assign_pixel_intensity_helper ( + P& dest, + const unsigned long& new_intensity + ) + { + unsigned long alpha = dest.alpha; + hsi_pixel p; + assign_pixel(p,dest); + assign_pixel(p.i, new_intensity); + assign_pixel(dest,p); + dest.alpha = alpha; + } + + template < + typename P + > + inline typename enable_if_c::grayscale == false&& + pixel_traits

::has_alpha == false>::type assign_pixel_intensity_helper ( + P& dest, + const unsigned long& new_intensity + ) + { + hsi_pixel p; + assign_pixel(p,dest); + assign_pixel(p.i, new_intensity); + assign_pixel(dest,p); + } + + template < + typename P + > + inline void assign_pixel_intensity ( + P& dest, + const unsigned long new_intensity + ) + { + assign_pixel_intensity_helper(dest, new_intensity); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + inline typename enable_if_c::grayscale,unsigned long>::type get_pixel_intensity_helper ( + const P& src + ) + { + return static_cast(src); + } + + template < + typename P + > + inline typename enable_if_c::grayscale == false&& + pixel_traits

::has_alpha, unsigned long>::type get_pixel_intensity_helper ( + const P& src + ) + { + P temp = src; + temp.alpha = 255; + hsi_pixel p; + assign_pixel(p,temp); + return static_cast(p.i); + } + + template < + typename P + > + inline typename enable_if_c::grayscale == false&& + pixel_traits

::has_alpha == false, unsigned long>::type get_pixel_intensity_helper ( + const P& src + ) + { + hsi_pixel p; + assign_pixel(p,src); + return static_cast(p.i); + } + + template < + typename P + > + inline unsigned long get_pixel_intensity ( + const P& src + ) + { + return get_pixel_intensity_helper(src); + } + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "pixel.cpp" +#endif + + +#endif // DLIB_PIXEl_ + diff --git a/dlib/platform.h b/dlib/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..2466ea333bc52b638e71056af740b0aded3dc296 --- /dev/null +++ b/dlib/platform.h @@ -0,0 +1,60 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PLATFORm_ +#define DLIB_PLATFORm_ + + +/*! + This file ensures that: + - if (we are compiling under a posix platform) then + - POSIX will be defined + - if (this is also Mac OS X) then + - MACOSX will be defined + - if (this is also HP-UX) then + - HPUX will be defined + - if (we are compiling under an MS Windows platform) then + - WIN32 will be defined +!*/ + + +/* + A good reference for this sort of information is + http://predef.sourceforge.net/ +*/ + +// Define WIN32 if this is MS Windows +#ifndef WIN32 + #if defined( _MSC_VER) || defined(__BORLANDC__) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) + #define WIN32 + #endif +#endif + +#ifndef WIN32 + // since this is the only other platform the library currently supports + // just assume it is POSIX if it isn't WIN32 + #ifndef POSIX + #define POSIX + #endif + + #ifndef HPUX + #if defined(__hpux ) || defined(hpux) || defined (_hpux) + #define HPUX + #endif + #endif + + #ifndef MACOSX + #ifdef __MACOSX__ + #define MACOSX + #endif + #ifdef __APPLE__ + #define MACOSX + #endif + #endif + +#endif + + + + +#endif // DLIB_PLATFORm_ + diff --git a/dlib/queue.h b/dlib/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..cc96e222a6a5e64f18c8bf3e8f598bb73db2173b --- /dev/null +++ b/dlib/queue.h @@ -0,0 +1,84 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_QUEUe_ +#define DLIB_QUEUe_ + +#include "queue/queue_kernel_1.h" +#include "queue/queue_kernel_2.h" +#include "queue/queue_kernel_c.h" + +#include "queue/queue_sort_1.h" + + +#include "memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class queue + { + queue() {} + public: + + + //----------- kernels --------------- + + // kernel_1a + typedef queue_kernel_1 + kernel_1a; + typedef queue_kernel_c + kernel_1a_c; + + + // kernel_2a + typedef queue_kernel_2 + kernel_2a; + typedef queue_kernel_c + kernel_2a_c; + + + // kernel_2b + typedef queue_kernel_2 + kernel_2b; + typedef queue_kernel_c + kernel_2b_c; + + + + + //---------- extensions ------------ + + // sort_1 extend kernel_1a + typedef queue_sort_1 + sort_1a; + typedef queue_sort_1 + sort_1a_c; + + + // sort_1 extend kernel_2a + typedef queue_sort_1 + sort_1b; + typedef queue_sort_1 + sort_1b_c; + + + + // sort_1 extend kernel_2b + typedef queue_sort_1 + sort_1c; + typedef queue_sort_1 + sort_1c_c; + + + + + + }; +} + +#endif // DLIB_QUEUe_ + diff --git a/dlib/queue/queue_kernel_1.h b/dlib/queue/queue_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..521539355a8adbd3ab1ade00f425a4eaf09166fa --- /dev/null +++ b/dlib/queue/queue_kernel_1.h @@ -0,0 +1,555 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_QUEUE_KERNEl_1_ +#define DLIB_QUEUE_KERNEl_1_ + +#include "queue_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class queue_kernel_1 : public enumerable, + public remover + { + + /*! + INITIAL VALUE + queue_size == 0 + current_element == 0 + at_start_ == true + + CONVENTION + queue_size == the number of elements in the queue + at_start() == at_start_ + current_element_valid() == (current_element != 0) + element() == current_element->item + + if (queue_size > 0) + { + in points to the last element to be inserted into the queue + out points to the next element to be dequeued + + each node points to the node inserted after it except for the most + recently inserted node + + current_element == 0 + } + + !*/ + + + struct node + { + node* last; + + T item; + }; + + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + queue_kernel_1 ( + ) : + in(0), + out(0), + queue_size(0), + current_element(0), + at_start_(true) + { + } + + virtual ~queue_kernel_1 ( + ); + + inline void clear( + ); + + void enqueue ( + T& item + ); + + void dequeue ( + T& item + ); + + void cat ( + queue_kernel_1& item + ); + + T& current ( + ); + + const T& current ( + ) const; + + void swap ( + queue_kernel_1& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline T& element ( + ); + + bool move_next ( + ) const; + + private: + + void delete_nodes ( + node* start, + unsigned long length + ); + /*! + requires + - start points to a node in a singly linked list + - start->last points to the next node in the list + - there are at least length nodes in the list begining with start + ensures + - length nodes have been deleted starting with the node pointed + to by start + !*/ + + // data members + + node* in; + node* out; + unsigned long queue_size; + mutable node* current_element; + mutable bool at_start_; + + // restricted functions + queue_kernel_1(queue_kernel_1&); // copy constructor + queue_kernel_1& operator=(queue_kernel_1&); // assignment operator + + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + queue_kernel_1& a, + queue_kernel_1& b + ) { a.swap(b); } + + template < + typename T, + typename mem_manager + > + void deserialize ( + queue_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + item.enqueue(temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type queue_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + queue_kernel_1:: + ~queue_kernel_1 ( + ) + { + delete_nodes(out,queue_size); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + clear ( + ) + { + delete_nodes(out,queue_size); + queue_size = 0; + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + enqueue ( + T& item + ) + { + // make new node + node* temp = new node; + + // swap item into new node + exchange(item,temp->item); + + if (queue_size == 0) + out = temp; + else + in->last = temp; + + // make in point to the new node + in = temp; + + ++queue_size; + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + dequeue ( + T& item + ) + { + // swap out into item + exchange(item,out->item); + + --queue_size; + + if (queue_size == 0) + { + delete out; + } + else + { + node* temp = out; + + // move out pointer to the next element in the queue + out = out->last; + + // delete old node + delete temp; + } + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + cat ( + queue_kernel_1& item + ) + { + if (item.queue_size > 0) + { + if (queue_size > 0) + { + in->last = item.out; + } + else + { + out = item.out; + } + + + in = item.in; + queue_size += item.queue_size; + item.queue_size = 0; + } + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& queue_kernel_1:: + current ( + ) + { + return out->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& queue_kernel_1:: + current ( + ) const + { + return out->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + swap ( + queue_kernel_1& item + ) + { + node* in_temp = in; + node* out_temp = out; + unsigned long queue_size_temp = queue_size; + node* current_element_temp = current_element; + bool at_start_temp = at_start_; + + in = item.in; + out = item.out; + queue_size = item.queue_size; + current_element = item.current_element; + at_start_ = item.at_start_; + + item.in = in_temp; + item.out = out_temp; + item.queue_size = queue_size_temp; + item.current_element = current_element_temp; + item.at_start_ = at_start_temp; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool queue_kernel_1:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long queue_kernel_1:: + size ( + ) const + { + return queue_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + reset ( + ) const + { + at_start_ = true; + current_element = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool queue_kernel_1:: + current_element_valid ( + ) const + { + return (current_element != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& queue_kernel_1:: + element ( + ) const + { + return current_element->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& queue_kernel_1:: + element ( + ) + { + return current_element->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool queue_kernel_1:: + move_next ( + ) const + { + if (at_start_) + { + at_start_ = false; + // if the queue is empty then there is nothing to do + if (queue_size == 0) + { + return false; + } + else + { + current_element = out; + return true; + } + } + else + { + // if we are at the last element then the enumeration has finished + if (current_element == in || current_element == 0) + { + current_element = 0; + return false; + } + else + { + current_element = current_element->last; + return true; + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // remover function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + remove_any ( + T& item + ) + { + dequeue(item); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void queue_kernel_1:: + delete_nodes ( + node* start, + unsigned long length + ) + { + node* temp; + while (length) + { + temp = start->last; + delete start; + start = temp; + --length; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_QUEUE_KERNEl_1_ + diff --git a/dlib/queue/queue_kernel_2.h b/dlib/queue/queue_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..572f5678d1f419faefd744d6be714378e4a3d862 --- /dev/null +++ b/dlib/queue/queue_kernel_2.h @@ -0,0 +1,601 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_QUEUE_KERNEl_2_ +#define DLIB_QUEUE_KERNEl_2_ + +#include "queue_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename T, + unsigned long block_size, + typename mem_manager = memory_manager::kernel_1a + > + class queue_kernel_2 : public enumerable, + public remover + { + + /*! + REQUIREMENTS ON block_size + 0 < block_size < 2000000000 + + INITIAL VALUE + queue_size == 0 + current_element == 0 + at_start_ == true + + CONVENTION + queue_size == the number of elements in the queue + at_start() == at_start_ + current_element_valid() == (current_element != 0) + if (current_element_valid()) then + element() == current_element->item[current_element_pos] + + if (queue_size > 0) + { + in->item[in_pos] == the spot where we will put the next item added + into the queue + out->item[out_pos] == current() + + when enqueuing elements inside each node item[0] is filled first, then + item[1], then item[2], etc... + + + each node points to the node inserted after it except for the most + recently inserted node. + } + + !*/ + + + struct node + { + node* next; + + T item[block_size]; + }; + + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + queue_kernel_2 ( + ) : + in(0), + out(0), + queue_size(0), + current_element(0), + at_start_(true) + { + } + + virtual ~queue_kernel_2 ( + ); + + inline void clear( + ); + + void enqueue ( + T& item + ); + + void dequeue ( + T& item + ); + + void cat ( + queue_kernel_2& item + ); + + T& current ( + ); + + const T& current ( + ) const; + + void swap ( + queue_kernel_2& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline T& element ( + ); + + bool move_next ( + ) const; + + private: + + void delete_nodes ( + node* start, + node* end + ); + /*! + requires + - start points to a node in a singly linked list + - start->next points to the next node in the list + - by following the next pointers you eventually hit the node pointed + to by end + ensures + - calls delete on the start node, the end node, and all nodes in between + !*/ + + // data members + + typename mem_manager::template rebind::other pool; + + node* in; + node* out; + unsigned long queue_size; + unsigned long in_pos; + unsigned long out_pos; + + + mutable node* current_element; + mutable unsigned long current_element_pos; + mutable bool at_start_; + + // restricted functions + queue_kernel_2(queue_kernel_2&); // copy constructor + queue_kernel_2& operator=(queue_kernel_2&); // assignment operator + + }; + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + inline void swap ( + queue_kernel_2& a, + queue_kernel_2& b + ) { a.swap(b); } + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void deserialize ( + queue_kernel_2& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + item.enqueue(temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type queue_kernel_2"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + queue_kernel_2:: + ~queue_kernel_2 ( + ) + { + COMPILE_TIME_ASSERT(0 < block_size && block_size < (unsigned long)(2000000000)); + + if (queue_size > 0) + delete_nodes(out,in); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + clear ( + ) + { + if (queue_size > 0) + { + delete_nodes(out,in); + queue_size = 0; + } + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + enqueue ( + T& item + ) + { + if (queue_size == 0) + { + out = in = pool.allocate(); + in_pos = 0; + out_pos = 0; + } + else if (in_pos >= block_size) + { + in->next = pool.allocate(); + in_pos = 0; + in = in->next; + } + + exchange(item,in->item[in_pos]); + ++in_pos; + + ++queue_size; + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + dequeue ( + T& item + ) + { + // swap out into item + exchange(item,out->item[out_pos]); + + ++out_pos; + --queue_size; + + // if this was the last element in this node then remove this node + if (out_pos == block_size) + { + out_pos = 0; + node* temp = out; + out = out->next; + pool.deallocate(temp); + } + else if (queue_size == 0) + { + pool.deallocate(out); + } + + // put the enumerator at the start + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + cat ( + queue_kernel_2& item + ) + { + if (queue_size > 0) + { + T temp; + assign_zero_if_built_in_scalar_type(temp); + while (item.size() > 0) + { + item.dequeue(temp); + enqueue(temp); + } + } + else + { + in = item.in; + out = item.out; + out_pos = item.out_pos; + in_pos = item.in_pos; + + queue_size = item.queue_size; + item.queue_size = 0; + + // put the enumerator at the start + reset(); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + T& queue_kernel_2:: + current ( + ) + { + return out->item[out_pos]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + const T& queue_kernel_2:: + current ( + ) const + { + return out->item[out_pos]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + swap ( + queue_kernel_2& item + ) + { + exchange(in,item.in); + exchange(out,item.out); + exchange(queue_size,item.queue_size); + exchange(in_pos,item.in_pos); + exchange(out_pos,item.out_pos); + exchange(current_element,item.current_element); + exchange(current_element_pos,item.current_element_pos); + exchange(at_start_,item.at_start_); + pool.swap(item.pool); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + unsigned long queue_kernel_2:: + size ( + ) const + { + return queue_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + bool queue_kernel_2:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + reset ( + ) const + { + at_start_ = true; + current_element = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + bool queue_kernel_2:: + current_element_valid ( + ) const + { + return (current_element != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + const T& queue_kernel_2:: + element ( + ) const + { + return current_element->item[current_element_pos]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + T& queue_kernel_2:: + element ( + ) + { + return current_element->item[current_element_pos]; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + bool queue_kernel_2:: + move_next ( + ) const + { + if (at_start_) + { + at_start_ = false; + // if the queue is empty then there is nothing to do + if (queue_size == 0) + { + return false; + } + else + { + current_element = out; + current_element_pos = out_pos; + return true; + } + } + else if (current_element == 0) + { + return false; + } + else + { + ++current_element_pos; + // if we are at the last element then the enumeration has finished + if (current_element == in && current_element_pos == in_pos ) + { + current_element = 0; + return false; + } + else if (current_element_pos == block_size) + { + current_element_pos = 0; + current_element = current_element->next; + } + + return true; + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // remover function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + remove_any ( + T& item + ) + { + dequeue(item); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + unsigned long block_size, + typename mem_manager + > + void queue_kernel_2:: + delete_nodes ( + node* start, + node* end + ) + { + node* temp; + while (start != end) + { + temp = start; + start = start->next; + pool.deallocate(temp); + } + pool.deallocate(start); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_QUEUE_KERNEl_2_ + diff --git a/dlib/queue/queue_kernel_abstract.h b/dlib/queue/queue_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..f21ab4ee79c2a167bd4c0eebef74ab11212a51f8 --- /dev/null +++ b/dlib/queue/queue_kernel_abstract.h @@ -0,0 +1,193 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_QUEUE_KERNEl_ABSTRACT_ +#ifdef DLIB_QUEUE_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class queue : public enumerable, + public remover + { + + /*! + REQUIREMENTS ON T + T must be swappable by a global swap() + T must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap() and current() functions do not invalidate pointers or + references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements in the queue in the + same order they would be removed by repeated calls to dequeue(). + (e.g. current() would be the first element enumerated) + + WHAT THIS OBJECT REPRESENTS + This is a first in first out queue containing items of type T + + e.g. if the queue is {b,c,d,e} and then 'a' is enqueued + the queue becomes {a,b,c,d,e} and then calling dequeue takes e out + making the queue {a,b,c,d} + !*/ + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + queue ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + virtual ~queue ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void enqueue ( + T& item + ); + /*! + ensures + - item is now at the left end of #*this + - #item has an initial value for its type + - #size() == size() + 1 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + if enqueue() throws then it has no effect + !*/ + + void dequeue ( + T& item + ); + /*! + requires + - size() != 0 + ensures + - #size() == size() - 1 + - the far right element of *this has been removed and swapped + into #item + - #at_start() == true + !*/ + + void cat ( + queue& item + ); + /*! + ensures + - item has been concatenated onto the left end of *this. + i.e. item.current() is attached onto the left end of *this and + the left most element in item will also be the left most item + in #*this + - #size() == size() + item.size() + - #item has its initial value + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + if cat() throws then the state of #item and *this is undefined + until clear() is successfully called on them. + !*/ + + T& current ( + ); + /*! + requires + - size() != 0 + ensures + - returns a const reference to the next element to be dequeued. + i.e. the right most element. + !*/ + + const T& current ( + ) const; + /*! + requires + - size() != 0 + ensures + - returns a non-const reference to the next element to be dequeued. + i.e. the right most element. + !*/ + + void swap ( + queue& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + queue(queue&); // copy constructor + queue& operator=(queue&); // assignment operator + + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + queue& a, + queue& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename mem_manager + > + void deserialize ( + queue& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_QUEUE_KERNEl_ABSTRACT_ + diff --git a/dlib/queue/queue_kernel_c.h b/dlib/queue/queue_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..fc67dc460b94960d829eede6adec6380f2cba2f2 --- /dev/null +++ b/dlib/queue/queue_kernel_c.h @@ -0,0 +1,187 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_QUEUE_KERNEl_C_ +#define DLIB_QUEUE_KERNEl_C_ + +#include "queue_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + + template < + typename queue_base // is an implementation of queue_kernel_abstract.h + > + class queue_kernel_c : public queue_base + { + typedef typename queue_base::type T; + + public: + + void dequeue ( + T& item + ); + + T& current ( + ); + + const T& current ( + ) const; + + const T& element ( + ) const; + + T& element ( + ); + + void remove_any ( + T& item + ); + + }; + + template < + typename queue_base + > + inline void swap ( + queue_kernel_c& a, + queue_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + void queue_kernel_c:: + dequeue ( + T& item + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(this->size() != 0, + "\tvoid queue::dequeue" + << "\n\tsize of queue should not be zero" + << "\n\tthis: " << this + ); + + // call the real function + queue_base::dequeue(item); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + const typename queue_base::type& queue_kernel_c:: + current ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->size() != 0, + "\tconst T& queue::current" + << "\n\tsize of queue should not be zero" + << "\n\tthis: " << this + ); + + // call the real function + return queue_base::current(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + typename queue_base::type& queue_kernel_c:: + current ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->size() != 0, + "\tT& queue::current" + << "\n\tsize of queue should not be zero" + << "\n\tthis: " << this + ); + + // call the real function + return queue_base::current(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + const typename queue_base::type& queue_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& queue::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return queue_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + typename queue_base::type& queue_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tT& queue::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return queue_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + void queue_kernel_c:: + remove_any ( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (this->size() > 0), + "\tvoid queue::remove_any" + << "\n\tsize() must be greater than zero if something is going to be removed" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + queue_base::remove_any(item); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_QUEUE_KERNEl_C_ + diff --git a/dlib/queue/queue_sort_1.h b/dlib/queue/queue_sort_1.h new file mode 100644 index 0000000000000000000000000000000000000000..f1f009f30de32e5878a4fc27d62eac8007217431 --- /dev/null +++ b/dlib/queue/queue_sort_1.h @@ -0,0 +1,162 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_QUEUE_SORt_1_ +#define DLIB_QUEUE_SORt_1_ + +#include "queue_sort_abstract.h" +#include "../algs.h" +#include +#include "../sort.h" + +namespace dlib +{ + + template < + typename queue_base + > + class queue_sort_1 : public queue_base + { + typedef typename queue_base::type T; + + public: + + /*! + This implementation uses the QuickSort algorithm and + when the quicksort depth goes too high it uses the dlib::qsort_array() + function on the data. + !*/ + + void sort ( + ); + + template + void sort ( + const compare_type& compare + ) + { + if (this->size() > 1) + { + sort_this_queue(*this,0,compare); + } + } + + private: + + template + void sort_this_queue ( + queue_base& queue, + long depth, + const compare_type& compare + ) + /*! + ensures + each element in the queue is < the element behind it according + to compare + !*/ + { + if (queue.size() <= 1) + { + // already sorted + } + else if (queue.size() <= 29) + { + T vect[29]; + const unsigned long size = queue.size(); + for (unsigned long i = 0; i < size; ++i) + { + queue.dequeue(vect[i]); + } + isort_array(vect,0,size-1,compare); + for (unsigned long i = 0; i < size; ++i) + { + queue.enqueue(vect[i]); + } + } + else if (depth > 50) + { + std::vector vect(queue.size()); + for (unsigned long i = 0; i < vect.size(); ++i) + { + queue.dequeue(vect[i]); + } + hsort_array(vect,0,vect.size()-1,compare); + for (unsigned long i = 0; i < vect.size(); ++i) + { + queue.enqueue(vect[i]); + } + } + else + { + queue_base left, right; + T partition_element; + T temp; + + queue.dequeue(partition_element); + + // partition queue into left and right + while (queue.size() > 0) + { + queue.dequeue(temp); + if (compare(temp , partition_element)) + { + left.enqueue(temp); + } + else + { + right.enqueue(temp); + } + } + + + long ratio; + if (left.size() > right.size()) + ratio = left.size()/(right.size()+1); // add 1 so we can't divide by zero + else + ratio = right.size()/(left.size()+1); + + sort_this_queue(left,ratio+depth,compare); + sort_this_queue(right,ratio+depth,compare); + + // combine the two queues + left.swap(queue); + queue.enqueue(partition_element); + queue.cat(right); + } + } + + + }; + + template < + typename queue_base + > + inline void swap ( + queue_sort_1& a, + queue_sort_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename queue_base + > + void queue_sort_1:: + sort ( + ) + { + if (this->size() > 1) + { + sort_this_queue(*this,0,std::less()); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_QUEUE_SORt_1_ + diff --git a/dlib/queue/queue_sort_abstract.h b/dlib/queue/queue_sort_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..75a18cc3622421595b03a1c165f65b82e63c04f7 --- /dev/null +++ b/dlib/queue/queue_sort_abstract.h @@ -0,0 +1,74 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_QUEUE_SORt_ABSTRACT_ +#ifdef DLIB_QUEUE_SORt_ABSTRACT_ + + +#include "queue_kernel_abstract.h" + +namespace dlib +{ + + template < + typename queue_base + > + class queue_sort : public queue_base + { + + /*! + REQUIREMENTS ON QUEUE_BASE + queue_base is instantiated with type T and + is an implementation of queue/queue_kernel_abstract.h + + POINTERS AND REFERENCES TO INTERNAL DATA + sort() may invalidate pointers and references to internal data. + + WHAT THIS EXTENSION DOES FOR QUEUE + This gives a queue the ability to sort its contents by calling sort(). + !*/ + + + public: + + void sort ( + ); + /*! + ensures + - for all elements in #*this the ith element is <= the i+1 element + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + data may be lost if sort() throws + !*/ + + template + void sort ( + const compare_type& compare + ); + /*! + ensures + - for all elements in #*this the ith element is <= the i+1 element + - uses compare(a,b) as the < operator. So if compare(a,b) == true + then a comes before b in the resulting ordering. + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + data may be lost if sort() throws + !*/ + }; + + template < + template queue_base + > + inline void swap ( + queue_sort& a, + queue_sort& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_QUEUE_SORt_ABSTRACT_ + diff --git a/dlib/rand.h b/dlib/rand.h new file mode 100644 index 0000000000000000000000000000000000000000..64800b4d821f37162b59c807391a241b50029cf0 --- /dev/null +++ b/dlib/rand.h @@ -0,0 +1,40 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RANd_ +#define DLIB_RANd_ + +#include "rand/rand_kernel_1.h" +#include "rand/rand_float_1.h" + +#include "algs.h" + + + +namespace dlib +{ + + + class rand + { + rand() {} + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef rand_kernel_1 + kernel_1a; + + //---------- extensions ------------ + + // float_1 extend kernel_1a + typedef rand_float_1 + float_1a; + + }; + +} + +#endif // DLIB_RANd_ + diff --git a/dlib/rand/mersenne_twister.h b/dlib/rand/mersenne_twister.h new file mode 100644 index 0000000000000000000000000000000000000000..4ad484165ab384cdc8b0f06170ec9ea161831b46 --- /dev/null +++ b/dlib/rand/mersenne_twister.h @@ -0,0 +1,191 @@ +/* boost random/mersenne_twister.hpp header file + * + * Copyright Jens Maurer 2000-2001 + * 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) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id: mersenne_twister.hpp,v 1.20 2005/07/21 22:04:31 jmaurer Exp $ + * + * Revision history + * 2001-02-18 moved to individual header files +*/ + +#ifndef DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP +#define DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP + +#include +#include // std::copy +#include +#include "../uintn.h" + +namespace dlib +{ + namespace random_helpers + { + + // ------------------------------------------------------------------------------------ + + // http://www.math.keio.ac.jp/matumoto/emt.html + template< + class UIntType, + int w, + int n, + int m, + int r, + UIntType a, + int u, + int s, + UIntType b, + int t, + UIntType c, + int l, + UIntType val + > + class mersenne_twister + { + public: + typedef UIntType result_type; + const static int word_size = w; + const static int state_size = n; + const static int shift_size = m; + const static int mask_bits = r; + const static UIntType parameter_a = a; + const static int output_u = u; + const static int output_s = s; + const static UIntType output_b = b; + const static int output_t = t; + const static UIntType output_c = c; + const static int output_l = l; + + const static bool has_fixed_range = false; + + mersenne_twister() { seed(); } + + explicit mersenne_twister(UIntType value) { seed(value); } + + void seed () { seed(UIntType(5489)); } + + // compiler-generated copy ctor and assignment operator are fine + + void seed(UIntType value) + { + // New seeding algorithm from + // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html + // In the previous versions, MSBs of the seed affected only MSBs of the + // state x[]. + const UIntType mask = ~0u; + x[0] = value & mask; + for (i = 1; i < n; i++) { + // See Knuth "The Art of Computer Programming" Vol. 2, 3rd ed., page 106 + x[i] = (1812433253UL * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask; + } + } + + result_type min() const { return 0; } + result_type max() const + { + // avoid "left shift count >= with of type" warning + result_type res = 0; + for(int i = 0; i < w; ++i) + res |= (1u << i); + return res; + } + + result_type operator()(); + + private: + + void twist(int block); + + // state representation: next output is o(x(i)) + // x[0] ... x[k] x[k+1] ... x[n-1] x[n] ... x[2*n-1] represents + // x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) x(i-k-n) ... x[i(i-k-1)] + // The goal is to always have x(i-n) ... x(i-1) available for + // operator== and save/restore. + + UIntType x[2*n]; + int i; + }; + + // ------------------------------------------------------------------------------------ + + template< + class UIntType, int w, int n, int m, int r, UIntType a, int u, + int s, UIntType b, int t, UIntType c, int l, UIntType val + > + void mersenne_twister::twist( + int block + ) + { + const UIntType upper_mask = (~0u) << r; + const UIntType lower_mask = ~upper_mask; + + if(block == 0) { + for(int j = n; j < 2*n; j++) { + UIntType y = (x[j-n] & upper_mask) | (x[j-(n-1)] & lower_mask); + x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0); + } + } else if (block == 1) { + // split loop to avoid costly modulo operations + { // extra scope for MSVC brokenness w.r.t. for scope + for(int j = 0; j < n-m; j++) { + UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask); + x[j] = x[j+n+m] ^ (y >> 1) ^ (y&1 ? a : 0); + } + } + + for(int j = n-m; j < n-1; j++) { + UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask); + x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0); + } + // last iteration + UIntType y = (x[2*n-1] & upper_mask) | (x[0] & lower_mask); + x[n-1] = x[m-1] ^ (y >> 1) ^ (y&1 ? a : 0); + i = 0; + } + } + + // ------------------------------------------------------------------------------------ + + template< + class UIntType, int w, int n, int m, int r, UIntType a, int u, + int s, UIntType b, int t, UIntType c, int l, UIntType val + > + inline typename mersenne_twister::result_type + mersenne_twister::operator()( + ) + { + if(i == n) + twist(0); + else if(i >= 2*n) + twist(1); + // Step 4 + UIntType z = x[i]; + ++i; + z ^= (z >> u); + z ^= ((z << s) & b); + z ^= ((z << t) & c); + z ^= (z >> l); + return z; + } + + // ------------------------------------------------------------------------------------ + + } // namespace random + + + typedef random_helpers::mersenne_twister mt11213b; + + // validation by experiment from mt19937.c + typedef random_helpers::mersenne_twister mt19937; + +} // namespace dlib + + +#endif // DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP + diff --git a/dlib/rand/rand_float_1.h b/dlib/rand/rand_float_1.h new file mode 100644 index 0000000000000000000000000000000000000000..f9117c0d4099adbd925d09869ca4353b8d768618 --- /dev/null +++ b/dlib/rand/rand_float_1.h @@ -0,0 +1,98 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RAND_FLOAt_1_ +#define DLIB_RAND_FLOAt_1_ + +#include "rand_float_abstract.h" +#include "../algs.h" +#include +#include "../uintn.h" + +namespace dlib +{ + + template < + typename rand_base + > + class rand_float_1 : public rand_base + { + double max_val; + public: + rand_float_1 () + { + max_val = 0xFFFFFF; + max_val *= 0x1000000; + max_val += 0xFFFFFF; + max_val += 0.01; + } + + + double get_random_double ( + ) + { + uint32 temp; + + temp = rand_base::get_random_32bit_number(); + temp &= 0xFFFFFF; + + double val = static_cast(temp); + + val *= 0x1000000; + + temp = rand_base::get_random_32bit_number(); + temp &= 0xFFFFFF; + + val += temp; + + val /= max_val; + + if (val < 1.0) + { + return val; + } + else + { + // return a value slightly less than 1.0 + return 1.0 - std::numeric_limits::epsilon(); + } + } + + float get_random_float ( + ) + { + uint32 temp; + + temp = rand_base::get_random_32bit_number(); + temp &= 0xFFFFFF; + + const float scale = 1.0/0x1000000; + + const float val = static_cast(temp)*scale; + if (val < 1.0f) + { + return val; + } + else + { + // return a value slightly less than 1.0 + return 1.0f - std::numeric_limits::epsilon(); + } + } + + }; + + template < + typename rand_base + > + inline void swap ( + rand_float_1& a, + rand_float_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RAND_FLOAt_1_ + + diff --git a/dlib/rand/rand_float_abstract.h b/dlib/rand/rand_float_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b745e80cf56f59d7da5479751adf58709a794c51 --- /dev/null +++ b/dlib/rand/rand_float_abstract.h @@ -0,0 +1,64 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RAND_FLOAt_ABSTRACT_ +#ifdef DLIB_RAND_FLOAt_ABSTRACT_ + + +#include "rand_kernel_abstract.h" + +namespace dlib +{ + + template < + typename rand_base + > + class rand_float : public rand_base + { + + /*! + REQUIREMENTS ON RAND_BASE + RAND_BASE is instantiated with type T and + is an implementation of rand/rand_kernel_abstract.h + + WHAT THIS EXTENSION DOES FOR RAND + This gives rand the ability to generate random float values. + !*/ + + + public: + + float get_random_float ( + ); + /*! + ensures + - returns a random float number N where: 0.0 <= N < 1.0. + throws + - std::bad_alloc + !*/ + + double get_random_double ( + ); + /*! + ensures + - returns a random double number N where: 0.0 <= N < 1.0. + throws + - std::bad_alloc + !*/ + }; + + template < + template rand_base + > + inline void swap ( + rand_float& a, + rand_float& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_RAND_FLOAt_ABSTRACT_ + + diff --git a/dlib/rand/rand_kernel_1.h b/dlib/rand/rand_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..3dc1c0802e1211676ae62032daeec5c85dc343fd --- /dev/null +++ b/dlib/rand/rand_kernel_1.h @@ -0,0 +1,122 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RAND_KERNEl_1_ +#define DLIB_RAND_KERNEl_1_ + +#include +#include "../algs.h" +#include "rand_kernel_abstract.h" +#include "mersenne_twister.h" + +namespace dlib +{ + + + class rand_kernel_1 + { + + /*! + INITIAL VALUE + - seed == "" + + CONVENTION + - the random numbers come from the boost mersenne_twister code + - get_seed() == seed + !*/ + + public: + + rand_kernel_1( + ) + { + // prime the generator a bit + for (int i = 0; i < 10000; ++i) + mt(); + } + + virtual ~rand_kernel_1( + ) + {} + + void clear( + ) + { + mt.seed(); + seed.clear(); + + // prime the generator a bit + for (int i = 0; i < 10000; ++i) + mt(); + } + + const std::string& get_seed ( + ) + { + return seed; + } + + void set_seed ( + const std::string& value + ) + { + seed = value; + uint32 s = 0; + for (std::string::size_type i = 0; i < seed.size(); ++i) + { + s = (s*37) + static_cast(seed[i]); + } + mt.seed(s); + // prime the generator a bit + for (int i = 0; i < 10000; ++i) + mt(); + } + + unsigned char get_random_8bit_number ( + ) + { + return static_cast(mt()); + } + + uint16 get_random_16bit_number ( + ) + { + return static_cast(mt()); + } + + inline uint32 get_random_32bit_number ( + ) + { + return mt(); + } + + void swap ( + rand_kernel_1& item + ) + { + exchange(mt,item.mt); + exchange(seed, item.seed); + } + + + private: + mt19937 mt; + + std::string seed; + + // restricted functions + rand_kernel_1(rand_kernel_1&); // copy constructor + rand_kernel_1& operator=(rand_kernel_1&); // assignment operator + + }; + + + inline void swap ( + rand_kernel_1& a, + rand_kernel_1& b + ) { a.swap(b); } + +} + +#endif // DLIB_RAND_KERNEl_1_ + + diff --git a/dlib/rand/rand_kernel_abstract.h b/dlib/rand/rand_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..8e52ba4d07f78689108b450ccb9bc01ad416d674 --- /dev/null +++ b/dlib/rand/rand_kernel_abstract.h @@ -0,0 +1,127 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RAND_KERNEl_ABSTRACT_ +#ifdef DLIB_RAND_KERNEl_ABSTRACT_ + +#include +#include "../uintn.h" + +namespace dlib +{ + + + class rand + { + + /*! + INITIAL VALUE + get_seed() == "" + + + WHAT THIS OBJECT REPRESENTS + this object represents a pseudorandom number generator. + + note that different implementations do not necessairly return the + same sequence of random numbers given the same seed. + !*/ + + public: + + + rand( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~rand( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + const std::string& get_seed ( + ); + /*! + ensures + - returns the string currently being used as the random seed. + !*/ + + void set_seed ( + const std::string& value + ); + /*! + ensures + - #get_seed() == value + !*/ + + unsigned char get_random_8bit_number ( + ); + /*! + ensures + - returns a pseudorandom number in the range 0 to 255 + throws + - std::bad_alloc + !*/ + + uint16 get_random_16bit_number ( + ); + /*! + ensures + - returns a pseudorandom number in the range 0 to 2^16-1 + throws + - std::bad_alloc + !*/ + + uint32 get_random_32bit_number ( + ); + /*! + ensures + - returns a pseudorandom number in the range 0 to 2^32-1 + throws + - std::bad_alloc + !*/ + + void swap ( + rand& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + rand(rand&); // copy constructor + rand& operator=(rand&); // assignment operator + + }; + + inline void swap ( + rand& a, + rand& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_RAND_KERNEl_ABSTRACT_ + diff --git a/dlib/reference_counter.h b/dlib/reference_counter.h new file mode 100644 index 0000000000000000000000000000000000000000..5efc9fadeb5e9f8e626d30814cd8208ed6ddb888 --- /dev/null +++ b/dlib/reference_counter.h @@ -0,0 +1,31 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_REFERENCE_COUNTEr_ +#define DLIB_REFERENCE_COUNTEr_ + +#include "reference_counter/reference_counter_kernel_1.h" +#include "algs.h" + +namespace dlib +{ + + template < + typename T, + typename copy = copy_functor + > + class reference_counter + { + reference_counter() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef reference_counter_kernel_1 + kernel_1a; + + }; +} + +#endif // DLIB_REFERENCE_COUNTEr_ + diff --git a/dlib/reference_counter/reference_counter_kernel_1.h b/dlib/reference_counter/reference_counter_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..093151cc196ea6ce56287f55b2d5f12c469e8820 --- /dev/null +++ b/dlib/reference_counter/reference_counter_kernel_1.h @@ -0,0 +1,298 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_REFERENCE_COUNTER_KERNEl_1_ +#define DLIB_REFERENCE_COUNTER_KERNEl_1_ + +#include "reference_counter_kernel_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + template < + typename T, + typename copy = copy_functor + > + class reference_counter_kernel_1 + { + + /*! + INITIAL VALUE + *data = item of type T with its initial value + *count = 1 + + CONVENTION + *data = pointer to item of type T + *count = number of references to *data + + if clear() threw an exception then count = 0 and data is not a + valid pointer + !*/ + + public: + + typedef T type; + + + reference_counter_kernel_1 ( + ); + + inline reference_counter_kernel_1 ( + const reference_counter_kernel_1& item + ); + + virtual ~reference_counter_kernel_1 ( + ); + + void clear ( + ); + + T& modify ( + ); + + inline const T& access ( + ) const; + + inline reference_counter_kernel_1& operator= ( + const reference_counter_kernel_1& rhs + ); + + inline void swap ( + reference_counter_kernel_1& item + ); + + + private: + + T* data; + unsigned long* count; + mutable copy copy_item; + }; + + template < + typename T, + typename copy + > + inline void swap ( + reference_counter_kernel_1& a, + reference_counter_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + reference_counter_kernel_1:: + reference_counter_kernel_1 ( + ) + { + data = new T; + try { count = new unsigned long; } + catch (...) { delete data; throw; } + + *count = 1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + reference_counter_kernel_1:: + reference_counter_kernel_1 ( + const reference_counter_kernel_1& item + ) : + data(item.data), + count(item.count) + { + ++(*count); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + reference_counter_kernel_1:: + ~reference_counter_kernel_1 ( + ) + { + if (*count > 1) + { + // if there are other references to this data + --(*count); + } + else + { + // if there are no other references to this data + delete count; + delete data; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + void reference_counter_kernel_1:: + clear ( + ) + { + // if an exception was thrown last time clear() was called then do this + if (count == 0) + { + data = new T; + try { count = new unsigned long; } + catch (...) { delete data; throw; } + + *count = 1; + } + // if there are other references to the data then do this + else if (*count > 1) + { + --(*count); + + try { data = new T; } + catch (...) { count = 0; throw; } + + try { count = new unsigned long; } + catch (...) { delete data; count = 0; throw; } + + *count = 1; + + } + else + { + // if there are no other references to this data + *count = 1; + delete data; + try { data = new T; } catch (...) { delete count; count = 0; throw; } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + T& reference_counter_kernel_1:: + modify ( + ) + { + // if this is not the only reference then make a new copy + if ( *count > 1 ) + { + T& old_data = *data; + unsigned long& old_count = *count; + + + // get memory for the new copy + try { data = new T; } + catch (...) { data = &old_data; throw; } + + try { count = new unsigned long; } + catch (...) {delete data; data = &old_data; count = &old_count; throw;} + + // decrement the number of references to old_data + --(old_count); + + *count = 1; + + // make a copy of the old data + try { copy_item(old_data,*data); } + catch (...) + { delete data; delete count; data = &old_data; count = &old_count; } + + } + + return *data; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + const T& reference_counter_kernel_1:: + access ( + ) const + { + return *data; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + reference_counter_kernel_1& reference_counter_kernel_1:: + operator= ( + const reference_counter_kernel_1& rhs + ) + { + if (this == &rhs) + return *this; + + // delete the current data if this is the last reference to it + if (*count > 1) + { + // if there are other references to this data + --(*count); + } + else + { + // if there are no other references to this data + delete count; + delete data; + } + + // copy the pointers + count = (rhs.count); + data = (rhs.data); + ++(*count); + + return *this; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename copy + > + void reference_counter_kernel_1:: + swap ( + reference_counter_kernel_1& item + ) + { + T* data_temp = data; + unsigned long* count_temp = count; + + data = item.data; + count = item.count; + + item.data = data_temp; + item.count = count_temp; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_REFERENCE_COUNTER_KERNEl_1_ + diff --git a/dlib/reference_counter/reference_counter_kernel_abstract.h b/dlib/reference_counter/reference_counter_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b5c7a4af89d877416c805e4abb9a9d004c5beb21 --- /dev/null +++ b/dlib/reference_counter/reference_counter_kernel_abstract.h @@ -0,0 +1,138 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_ +#ifdef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_ + +#include "../algs.h" + +namespace dlib +{ + + template < + typename T, + typename copy = copy_functor + > + class reference_counter + { + + /*! + REQUIREMENTS ON T + T must have a default constructor + + REQUIREMENTS ON copy + it should be a function object that copies an object of type T. and + it must have a default constructor and + operator() should be overloaded as + void operator()(const T& source, T& destination); + copy may throw any exception + + POINTERS AND REFERENCES TO INTERNAL DATA + swap() and access() functions do not invalidate pointers or + references to internal data. + All other functions have no such guarantee + + + INITIAL VALUE + reference_counter contains one object of type T and + this object of type T has its initial value + + WHAT THIS OBJECT REPRESENTS + This object represents a container for an object of type T and + provides reference counting capabilities for the object it contains + + !*/ + + public: + + typedef T type; + + reference_counter ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + reference_counter ( + const reference_counter& item + ); + /*! + ensures + - #access() == item.access() + !*/ + + virtual ~reference_counter ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear ( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + T& modify ( + ); + /*! + ensures + - returns a non-const reference to the item contained in *this + - the item is ok to modify. i.e. there are no other references to it + throws + - std::bad_alloc or any exception thrown by T's constructor + modify() may throw this exception if there are other references + to the item and there is not enough memory to copy it. If modify() + throws then it has no effect. + !*/ + + const T& access ( + ) const; + /*! + ensures + - returns a const reference to the item contained in *this + - there may be other references to to the item + !*/ + + reference_counter& operator= ( + const reference_counter& rhs + ); + /*! + ensures + - #access() == rhs.access() + !*/ + + void swap ( + reference_counter& item + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + template < + typename T, + typename copy + > + inline void swap ( + reference_counter& a, + reference_counter& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_ + diff --git a/dlib/sequence.h b/dlib/sequence.h new file mode 100644 index 0000000000000000000000000000000000000000..2afff023e236d0b100232bfd4be464d620198233 --- /dev/null +++ b/dlib/sequence.h @@ -0,0 +1,83 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCe_ +#define DLIB_SEQUENCe_ + +#include "sequence/sequence_kernel_1.h" +#include "sequence/sequence_kernel_2.h" +#include "sequence/sequence_kernel_c.h" + +#include "sequence/sequence_compare_1.h" +#include "sequence/sequence_sort_1.h" +#include "sequence/sequence_sort_2.h" +#include "memory_manager.h" + + + + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class sequence + { + + sequence() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef sequence_kernel_1 + kernel_1a; + typedef sequence_kernel_c + kernel_1a_c; + + // kernel_2a + typedef sequence_kernel_2 + kernel_2a; + typedef sequence_kernel_c + kernel_2a_c; + + + //---------- extensions ------------ + + // compare_1 extend kernel_1a + typedef sequence_compare_1 + compare_1a; + typedef sequence_compare_1 + compare_1a_c; + + // compare_1 extend kernel_2a + typedef sequence_compare_1 + compare_1b; + typedef sequence_compare_1 + compare_1b_c; + + + + // sort_1 extend kernel_2a + typedef sequence_sort_1 + sort_1a; + typedef sequence_sort_1 + sort_1a_c; + + // sort_2 extend kernel_1a + typedef sequence_sort_2 + sort_2a; + typedef sequence_sort_2 + sort_2a_c; + + + + + + + }; +} + +#endif // DLIB_SEQUENCe_ + diff --git a/dlib/sequence/sequence_compare_1.h b/dlib/sequence/sequence_compare_1.h new file mode 100644 index 0000000000000000000000000000000000000000..82bb417bd0fb43306e207dc08af95ec1a40a3432 --- /dev/null +++ b/dlib/sequence/sequence_compare_1.h @@ -0,0 +1,102 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCE_COMPARe_1_ +#define DLIB_SEQUENCE_COMPARe_1_ + +#include "sequence_compare_abstract.h" + +#include "../algs.h" + + +namespace dlib +{ + + template < + typename seq_base + > + class sequence_compare_1 : public seq_base + { + typedef typename seq_base::type T; + + public: + + bool operator< ( + const sequence_compare_1& rhs + ) const; + + bool operator== ( + const sequence_compare_1& rhs + ) const; + + }; + + + template < + typename seq_base + > + inline void swap ( + sequence_compare_1& a, + sequence_compare_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + bool sequence_compare_1:: + operator< ( + const sequence_compare_1& rhs + ) const + { + unsigned int length; + if (this->size() < rhs.size()) + length = this->size(); + else + length = rhs.size(); + + for (unsigned long i = 0; i < length; ++i) + { + if ((*this)[i] < rhs[i]) + return true; + else if ( !((*this)[i] == rhs[i]) ) + return false; + } + // they are equal so far + if (this->size() < rhs.size()) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + bool sequence_compare_1:: + operator== ( + const sequence_compare_1& rhs + ) const + { + if (this->size() != rhs.size()) + return false; + + for (unsigned long i = 0; i < this->size(); ++i) + { + if (!((*this)[i] == rhs[i])) + return false; + } + return true; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SEQUENCE_COMPARe_1_ + diff --git a/dlib/sequence/sequence_compare_abstract.h b/dlib/sequence/sequence_compare_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..0a0446ab48c42b4ef407521030d692050fbd037f --- /dev/null +++ b/dlib/sequence/sequence_compare_abstract.h @@ -0,0 +1,75 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SEQUENCE_COMPARe_ABSTRACT_ +#ifdef DLIB_SEQUENCE_COMPARe_ABSTRACT_ + +#include "sequence_kernel_abstract.h" + +#include "../algs.h" + + +namespace dlib +{ + + template < + typename seq_base + > + class sequence_compare : public seq_base + { + + /*! + REQUIREMENTS ON T + T must implement operator< for its type and + T must implement operator== for its type + + REQUIREMENTS ON SEQUENCE_BASE + must be an implementation of sequence/sequence_kernel_abstract.h + + + POINTERS AND REFERENCES TO INTERNAL DATA + operator== and operator< do not invalidate pointers or references to + data members + + WHAT THIS EXTENSION DOES FOR sequence + This gives a sequence the ability to compare itself to other + sequences using the < and == operators. + !*/ + + public: + + bool operator< ( + const sequence_compare& rhs + ) const; + /*! + ensures + - returns true if there exists an integer j such that 0 <= j < size() + and for all integers i such that 0 <= i < j where it is true that + (*this)[i] <= rhs[i] and (*this)[j] < rhs[j] + - returns false if there is no j that will satisfy the above conditions + !*/ + + bool operator== ( + const sequence_compare& rhs + ) const; + /*! + ensures + - returns true if for all i: (*this)[i] == rhs[i] else returns false + !*/ + + }; + + template < + typename seq_base + > + inline void swap ( + sequence_compare& a, + sequence_compare& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_SEQUENCE_COMPARe_ABSTRACT_ + diff --git a/dlib/sequence/sequence_kernel_1.h b/dlib/sequence/sequence_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..4eb8b1ac7cffb3ad4f4795a9b313783f6c840663 --- /dev/null +++ b/dlib/sequence/sequence_kernel_1.h @@ -0,0 +1,1341 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCE_KERNEl_1_ +#define DLIB_SEQUENCE_KERNEl_1_ + +#include "sequence_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class sequence_kernel_1 : public enumerable, + public remover + { + + /*! + INITIAL VALUE + - tree_root == 0 + - tree_size == 0 + - at_start_ == true + - current_element == 0 + - stack == array of 50 node pointers + - stack_pos == 0 + + CONVENTION + + - if (tree_size > 0) + - tree_root == pointer to the root node of the binary search tree + - else + - tree_root == 0 + + + + - stack[stack_pos-1] == pop() + + - current_element_valid() == (current_element != 0) + + - at_start_ == at_start() + - if (current_element != 0 && current_element != tree_root) then + - stack[stack_pos-1] == the parent of the node pointed to by current_element + + - if (current_element_valid()) then + - element() == current_element->item + + + + - tree_size == size() + - (*this)[i] == return_reference(i) + + + - for all nodes: + - left_size == the number of elements in the left subtree. + - left points to the left subtree or 0 if there is no left subtree. + - right points to the right subtree or 0 if there is no right subtree. + + - all elements in a left subtree have a position in the sequence < that + of the root of the current tree. + + - all elements in a right subtree have a position in the + sequence > that of the root of the current tree. + + - item is the sequence element for that node. + - balance: + - balance == 0 if both subtrees have the same height + - balance == -1 if the left subtree has a height that is + greater than the height of the right subtree by 1 + - balance == 1 if the right subtree has a height that is + greater than the height of the left subtree by 1 + - for all subtrees: + - the height of the left and right subtrees differ by at most one + + !*/ + + + class node + { + public: + node* left; + node* right; + unsigned long left_size; + T item; + signed char balance; + }; + + + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + sequence_kernel_1 ( + ) : + tree_root(0), + tree_size(0), + stack(ppool.allocate_array(50)), + current_element(0), + at_start_(true), + stack_pos(0) + {} + + virtual ~sequence_kernel_1 ( + ); + + inline void clear ( + ); + + void add ( + unsigned long pos, + T& item + ); + + void remove ( + unsigned long pos, + T& item + ); + + void cat ( + sequence_kernel_1& item + ); + + const T& operator[] ( + unsigned long pos + ) const; + + T& operator[] ( + unsigned long pos + ); + + inline void swap ( + sequence_kernel_1& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + const T& element ( + ) const; + + T& element ( + ); + + bool move_next ( + ) const; + + + private: + + void delete_nodes ( + node* t + ); + /*! + requires + - t == a pointer to a valid node + ensures + - deletes t and all its sub nodes. + !*/ + + inline void rotate_left ( + node*& t + ); + /*! + requires + - t->balance == 2 + - t->right->balance == 0 or 1 + ensures + - #t is still a binary search tree + - #t->balance is between 1 and -1 + - #t now has a height smaller by 1 if #t->balance == 0 + !*/ + + inline void rotate_right ( + node*& t + ); + /*! + requires + - t->balance == -2 + - t->left->balance == 0 or -1 + ensures + - #t is still a binary search tree + - #t->balance is between 1 and -1 + - #t now has a height smaller by 1 if #t->balance == 0 + + !*/ + + inline void double_rotate_right ( + node*& t + ); + /*! + requires + - #t->balance == -2 + - #t->left->balance == 1 + ensures + - #t is still a binary search tree + - #t now has a balance of 0 + - #t now has a height smaller by 1 + !*/ + + inline void double_rotate_left ( + node*& t + ); + /*! + requires + - #t->balance == 2 + - #t->right->balance == -1 + ensures + - #t is still a binary search tree + - #t now has a balance of 0 and + - #t now has a height smaller by 1 + !*/ + + bool remove_least_element_in_tree ( + node*& t, + T& item + ); + /*! + requires + - t != 0 (i.e. there must be something in the tree to remove) + ensures + - the least node in t has been removed + - the least node element in t has been put into #item + - #t is still a binary search tree + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + bool add_to_tree ( + node*& t, + unsigned long pos, + T& item + ); + /*! + requires + - pos <= the number of items in the tree + ensures + - item has been added to #t + - #return_reference(pos) == item + - the convention is still satisfied + - #item has an initial value for its type + - returns false if the height of the tree has not changed + - returns true if the height of the tree has grown by one + !*/ + + bool remove_from_tree ( + node*& t, + unsigned long pos, + T& item + ); + /*! + requires + - there is an item in the tree associated with pos + ensures + - the element in the tree associated with pos has been removed + and put into #item + - the convention is still satisfied + - returns false if the height of the tree has not changed + - returns true if the height of the tree has shrunk by one + !*/ + + const T& return_reference ( + const node* t, + unsigned long pos + ) const; + /*! + requires + - there is an item in the tree associated with pos + ensures + - returns a const reference to the item in the tree associated with pos + !*/ + + T& return_reference ( + node* t, + unsigned long pos + ); + /*! + requires + - there is an item in the tree associated with pos + ensures + - returns a non-const reference to the item in the tree associated + with pos + !*/ + + inline bool keep_node_balanced ( + node*& t + ); + /*! + requires + - t != 0 + ensures + - if (t->balance is < 1 or > 1) then + - keep_node_balanced() will ensure that t->balance == 0, -1, or 1 + - returns true if it made the tree one height shorter + - returns false if it didn't change the height + !*/ + + void push ( + node* n + ) const { stack[stack_pos] = n; ++stack_pos; } + /*! + ensures + - pushes n onto the stack + !*/ + + + node* pop ( + ) const { --stack_pos; return stack[stack_pos]; } + /*! + ensures + - pops the top of the stack and returns it + !*/ + + // data members + typename mem_manager::template rebind::other pool; + typename mem_manager::template rebind::other ppool; + + node* tree_root; + unsigned long tree_size; + + mutable node** stack; + mutable node* current_element; + mutable bool at_start_; + mutable unsigned char stack_pos; + + // restricted functions + sequence_kernel_1(sequence_kernel_1&); // copy constructor + sequence_kernel_1& operator=(sequence_kernel_1&); // assignment operator + + }; + + template < + typename T, + typename mem_manager + > + inline void swap ( + sequence_kernel_1& a, + sequence_kernel_1& b + ) { a.swap(b); } + + template < + typename T, + typename mem_manager + > + void deserialize ( + sequence_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + item.add(i,temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type sequence_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + sequence_kernel_1:: + ~sequence_kernel_1 ( + ) + { + ppool.deallocate_array(stack); + if (tree_size > 0) + { + delete_nodes(tree_root); + } + } + +// ---------------------------------------------------------------------------------------- + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + swap ( + sequence_kernel_1& item + ) + { + exchange(stack,item.stack); + exchange(stack_pos,item.stack_pos); + + pool.swap(item.pool); + ppool.swap(item.ppool); + + node* tree_root_temp = item.tree_root; + unsigned long tree_size_temp = item.tree_size; + node* current_element_temp = item.current_element; + bool at_start_temp = item.at_start_; + + item.tree_root = tree_root; + item.tree_size = tree_size; + item.current_element = current_element; + item.at_start_ = at_start_; + + tree_root = tree_root_temp; + tree_size = tree_size_temp; + current_element = current_element_temp; + at_start_ = at_start_temp; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long sequence_kernel_1:: + size ( + ) const + { + return tree_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& sequence_kernel_1:: + operator[] ( + unsigned long pos + ) const + { + return return_reference(tree_root,pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& sequence_kernel_1:: + operator[] ( + unsigned long pos + ) + { + return return_reference(tree_root,pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + add ( + unsigned long pos, + T& item + ) + { + add_to_tree(tree_root,pos,item); + ++tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + remove ( + unsigned long pos, + T& item + ) + { + remove_from_tree(tree_root,pos,item); + --tree_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + cat ( + sequence_kernel_1& item + ) + { + for (unsigned long i = 0; i < item.tree_size; ++i) + { + add_to_tree( + tree_root, + tree_size, + return_reference(item.tree_root,i) + ); + + ++tree_size; + } + + item.clear(); + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + clear ( + ) + { + if (tree_size > 0) + { + delete_nodes(tree_root); + tree_root = 0; + tree_size = 0; + } + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + reset ( + ) const + { + at_start_ = true; + current_element = 0; + stack_pos = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + current_element_valid ( + ) const + { + return (current_element != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& sequence_kernel_1:: + element ( + ) const + { + return current_element->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& sequence_kernel_1:: + element ( + ) + { + return current_element->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + move_next ( + ) const + { + // if we haven't started iterating yet + if (at_start_) + { + at_start_ = false; + if (tree_size == 0) + { + return false; + } + else + { + // find the first element in the tree + current_element = tree_root; + node* temp = current_element->left; + while (temp != 0) + { + push(current_element); + current_element = temp; + temp = current_element->left; + } + return true; + } + } + else + { + if (current_element == 0) + { + return false; + } + else + { + node* temp; + bool went_up; // true if we went up the tree from a child node to parent + bool from_left = false; // true if we went up and were coming from a left child node + // find the next element in the tree + if (current_element->right != 0) + { + // go right and down + temp = current_element; + push(current_element); + current_element = temp->right; + went_up = false; + } + else + { + // go up to the parent if we can + if (current_element == tree_root) + { + // in this case we have iterated over all the element of the tree + current_element = 0; + return false; + } + went_up = true; + node* parent = pop(); + + + from_left = (parent->left == current_element); + // go up to parent + current_element = parent; + } + + + while (true) + { + if (went_up) + { + if (from_left) + { + // in this case we have found the next node + break; + } + else + { + if (current_element == tree_root) + { + // in this case we have iterated over all the elements + // in the tree + current_element = 0; + return false; + } + // we should go up + node* parent = pop(); + from_left = (parent->left == current_element); + current_element = parent; + } + } + else + { + // we just went down to a child node + if (current_element->left != 0) + { + // go left + went_up = false; + temp = current_element; + push(current_element); + current_element = temp->left; + } + else + { + // if there is no left child then we have found the next node + break; + } + } + } + + return true; + } + } + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // remover function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + remove_any ( + T& item + ) + { + remove(0,item); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + rotate_left ( + node*& t + ) + { + + // set the new balance numbers + if (t->right->balance == 1) + { + t->balance = 0; + t->right->balance = 0; + } + else + { + t->balance = 1; + t->right->balance = -1; + } + + // perform the rotation + node* temp = t->right; + t->right = temp->left; + temp->left = t; + t = temp; + + + // set left_size to its correct value + t->left_size += t->left->left_size + 1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + rotate_right ( + node*& t + ) + { + // set the new balance numbers + if (t->left->balance == -1) + { + t->balance = 0; + t->left->balance = 0; + } + else + { + t->balance = -1; + t->left->balance = 1; + } + + // preform the rotation + node* temp = t->left; + t->left = temp->right; + temp->right = t; + t = temp; + + + // set left_size to its correct value + t->right->left_size -= t->left_size + 1; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + double_rotate_right ( + node*& t + ) + { + + node* temp = t; + t = t->left->right; + + temp->left->right = t->left; + t->left = temp->left; + + temp->left = t->right; + t->right = temp; + + if (t->balance < 0) + { + t->left->balance = 0; + t->right->balance = 1; + } + else if (t->balance > 0) + { + t->left->balance = -1; + t->right->balance = 0; + } + else + { + t->left->balance = 0; + t->right->balance = 0; + } + t->balance = 0; + + + // set left_size to its correct value + t->left_size += t->left->left_size + 1; + t->right->left_size -= t->left_size + 1; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + double_rotate_left ( + node*& t + ) + { + node* temp = t; + t = t->right->left; + + temp->right->left = t->right; + t->right = temp->right; + + temp->right = t->left; + t->left = temp; + + if (t->balance < 0) + { + t->left->balance = 0; + t->right->balance = 1; + } + else if (t->balance > 0) + { + t->left->balance = -1; + t->right->balance = 0; + } + else + { + t->left->balance = 0; + t->right->balance = 0; + } + + t->balance = 0; + + // set left_size to its correct value + t->right->left_size -= t->left_size + 1; + t->left_size += t->left->left_size + 1; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + remove_least_element_in_tree ( + node*& t, + T& item + ) + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if the left tree is an empty tree + if ( tree.left == 0) + { + // swap nodes element into item + exchange(tree.item,item); + + // plug hole left by removing this node + t = tree.right; + + // delete the node that was just removed + tree.right = 0; + delete_nodes(&tree); + + // return that the height of this part of the tree has decreased + return true; + } + else + { + // subtract one from the left size + --tree.left_size; + + // keep going left + + // if remove made the tree one height shorter + if ( remove_least_element_in_tree(tree.left,item) ) + { + // if this caused the current tree to strink then report that + if ( tree.balance == -1) + { + ++tree.balance; + return true; + } + else + { + ++tree.balance; + return keep_node_balanced(t); + } + } + + return false; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + add_to_tree ( + node*& t, + unsigned long pos, + T& item + ) + { + // if found place to add + if (t == 0) + { + // create a node to add new item into + t = pool.allocate(); + + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + + // set left and right pointers to 0 to indicate that there are no + // left or right subtrees + tree.left = 0; + tree.right = 0; + tree.balance = 0; + tree.left_size = 0; + + // put item into t + exchange(item,tree.item); + + // indicate that the height of this tree has increased + return true; + } + else // keep looking for a place to add the new item + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + signed char old_balance = tree.balance; + + // add the new item to whatever subtree it should go into + if ( pos < tree.left_size + 1 ) + { + tree.balance -= add_to_tree(tree.left,pos,item); + ++tree.left_size; + } + else + tree.balance += add_to_tree(tree.right,pos - tree.left_size - 1,item); + + + // if the tree was balanced to start with + if (old_balance == 0) + { + // if its not balanced anymore then it grew in height + if (tree.balance != 0) + return true; + else + return false; + } + else + { + // if the tree is now balanced then it didn't grow + if (tree.balance == 0) + { + return false; + } + else + { + // if the tree needs to be balanced + if (tree.balance != old_balance) + { + return !keep_node_balanced(t); + } + // if there has been no change in the heights + else + { + return false; + } + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + remove_from_tree ( + node*& t, + unsigned long pos, + T& item + ) + { + + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if item is on the left + if (pos < tree.left_size) + { + // adjust the left size + --tree.left_size; + + // if the left side of the tree has the greatest height + if (tree.balance == -1) + { + tree.balance += remove_from_tree(tree.left,pos,item); + return !tree.balance; + } + else + { + tree.balance += remove_from_tree(tree.left,pos,item); + return keep_node_balanced(t); + } + + } + // if item is found + else if (pos == tree.left_size) + { + // if there is no left node + if (tree.left == 0) + { + // swap nodes element into item + exchange(tree.item,item); + + // plug hole left by removing this node and free memory + t = tree.right; // plug hole with right subtree + + // delete old node + tree.right = 0; + delete_nodes(&tree); + + // indicate that the height has changed + return true; + } + // if there is no right node + else if (tree.right == 0) + { + // swap nodes element into item + exchange(tree.item,item); + + // plug hole left by removing this node and free memory + t = tree.left; // plug hole with left subtree + + // delete old node + tree.left = 0; + delete_nodes(&tree); + + // indicate that the height of this tree has changed + return true; + } + // if there are both a left and right sub node + else + { + // get an element that can replace the one being removed and do this + // if it made the right subtree shrink by one + if (remove_least_element_in_tree(tree.right,item)) + { + // adjust the tree height + --tree.balance; + + // put the element into item copy and also plug the + // hole with the smallest element from the right. + exchange(item,tree.item); + + // if the height of the current tree has dropped by one + if (tree.balance == 0) + { + return true; + } + else + { + return keep_node_balanced(t); + } + } + // else this remove did not effect the height of this tree + else + { + // put the element into item copy and also plug the + // hole with the smallest element from the right. + exchange(item,tree.item); + + return false; + } + + } + } + // if item is on the right + else + { + + // if the right side of the tree has the greatest height + if (tree.balance == 1) + { + tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item); + return !tree.balance; + } + else + { + tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item); + return keep_node_balanced(t); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& sequence_kernel_1:: + return_reference ( + node* t, + unsigned long pos + ) + { + while (true) + { + // if we have found the node + if (pos == t->left_size) + return t->item; + + if (pos < t->left_size) + { + // go left + t = t->left; + } + else + { + // go right + pos -= t->left_size+1; + t = t->right; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& sequence_kernel_1:: + return_reference ( + const node* t, + unsigned long pos + ) const + { + while (true) + { + // if we have found the node + if (pos == t->left_size) + return t->item; + + if (pos < t->left_size) + { + // go left + t = t->left; + } + else + { + // go right + pos -= t->left_size+1; + t = t->right; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_1:: + keep_node_balanced ( + node*& t + ) + { + // make a reference to the current node so we don't have to dereference + // a pointer a bunch of times + node& tree = *t; + + // if tree does not need to be balanced then return false + if (tree.balance == 0) + return false; + + + // if tree needs to be rotated left + if (tree.balance == 2) + { + if (tree.right->balance >= 0) + rotate_left(t); + else + double_rotate_left(t); + } + // else if the tree needs to be rotated right + else if (tree.balance == -2) + { + if (tree.left->balance <= 0) + rotate_right(t); + else + double_rotate_right(t); + } + + + if (t->balance == 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_1:: + delete_nodes ( + node* t + ) + { + if (t->left) + delete_nodes(t->left); + if (t->right) + delete_nodes(t->right); + pool.deallocate(t); + } + +// ---------------------------------------------------------------------------------------- +} + +#endif // DLIB_SEQUENCE_KERNEl_1_ + diff --git a/dlib/sequence/sequence_kernel_2.h b/dlib/sequence/sequence_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..e7dcc01d732ebb196556100ed7065eacc368551d --- /dev/null +++ b/dlib/sequence/sequence_kernel_2.h @@ -0,0 +1,683 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCE_KERNEl_2_ +#define DLIB_SEQUENCE_KERNEl_2_ + +#include "sequence_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class sequence_kernel_2 : public enumerable, + public remover + { + /*! + INITIAL VALUE + sequence_size == 0 + at_start_ == true + current_enumeration_node == 0 + + CONVENTION + sequence_size == the number of elements in the sequence + + at_start_ == at_start() + (current_enumeration_node!=0) == current_element_valid() + if (current_enumeration_node!=0) then + current_enumeration_node->item == element() + current_enumeration_pos == the position of the node pointed to by + current_enumeration_node + + if ( sequence_size > 0 ) + { + current_node == pointer to a node in the linked list and + current_node->right->right->... eventually == current_node and + current_node->left->left->... eventually == current_node and + current_pos == the position in the sequence of + current_node->item + } + + !*/ + + struct node { + T item; + node* right; + node* left; + }; + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + sequence_kernel_2 ( + ) : + sequence_size(0), + at_start_(true), + current_enumeration_node(0) + {} + + virtual ~sequence_kernel_2 ( + ); + + inline void clear ( + ); + + void add ( + unsigned long pos, + T& item + ); + + void remove ( + unsigned long pos, + T& item + ); + + void cat ( + sequence_kernel_2& item + ); + + const T& operator[] ( + unsigned long pos + ) const; + + T& operator[] ( + unsigned long pos + ); + + void swap ( + sequence_kernel_2& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + const T& element ( + ) const; + + T& element ( + ); + + bool move_next ( + ) const; + + private: + + void delete_nodes ( + node* current_node, + unsigned long sequence_size + ); + /*! + requires + CONVENTION IS CORRECT + ensures + all memory associated with the ring of nodes has been freed + !*/ + + void move_to_pos ( + node*& current_node, + unsigned long& current_pos, + unsigned long pos, + unsigned long size + ) const; + /*! + requires + everything in the CONVENTION is correct and + there is a node corresponding to pos in the CONVENTION and + 0 <= pos < size + ensures + current_pos == pos and + current_node->item is the item in the sequence associated with + position pos + !*/ + + // data members + unsigned long sequence_size; + mutable node* current_node; + mutable unsigned long current_pos; + mutable bool at_start_; + mutable node* current_enumeration_node; + mutable unsigned long current_enumeration_pos; + + // restricted functions + sequence_kernel_2(sequence_kernel_2&); // copy constructor + sequence_kernel_2& operator=(sequence_kernel_2&); // assignment operator + + }; + + + template < + typename T, + typename mem_manager + > + inline void swap ( + sequence_kernel_2& a, + sequence_kernel_2& b + ) { a.swap(b); } + + template < + typename T, + typename mem_manager + > + void deserialize ( + sequence_kernel_2& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + item.add(i,temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type sequence_kernel_2"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + sequence_kernel_2:: + ~sequence_kernel_2 ( + ) + { + delete_nodes(current_node,sequence_size); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + clear ( + ) + { + if (sequence_size != 0) + { + delete_nodes(current_node,sequence_size); + sequence_size = 0; + } + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + add ( + unsigned long pos, + T& item + ) + { + // make new node and swap item into it + node* new_node = new node; + exchange(item,new_node->item); + + if (sequence_size > 0) + { + if (pos == sequence_size) + { + move_to_pos(current_node,current_pos,pos-1,sequence_size); + + node& n_node = *new_node; + node& c_node = *current_node; + + // make new node point to the nodes to its left and right + n_node.right = c_node.right; + n_node.left = current_node; + + // make the left node point back to new_node + c_node.right->left = new_node; + + // make the right node point back to new_node + c_node.right = new_node; + current_pos = pos; + + } + else + { + move_to_pos(current_node,current_pos,pos,sequence_size); + + node& n_node = *new_node; + node& c_node = *current_node; + + // make new node point to the nodes to its left and right + n_node.right = current_node; + n_node.left = c_node.left; + + // make the left node point back to new_node + c_node.left->right = new_node; + + // make the right node point back to new_node + c_node.left = new_node; + } + + } + else + { + current_pos = 0; + new_node->left = new_node; + new_node->right = new_node; + } + + // make the new node the current node + current_node = new_node; + + ++sequence_size; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + remove ( + unsigned long pos, + T& item + ) + { + move_to_pos(current_node,current_pos,pos,sequence_size); + node& c_node = *current_node; + exchange(c_node.item,item); + + node* temp = current_node; + + // close up gap left by remove + c_node.left->right = c_node.right; + c_node.right->left = c_node.left; + + current_node = c_node.right; + + --sequence_size; + + delete temp; + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& sequence_kernel_2:: + operator[] ( + unsigned long pos + ) const + { + move_to_pos(current_node,current_pos,pos,sequence_size); + return current_node->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + cat ( + sequence_kernel_2& item + ) + { + if (item.sequence_size > 0) + { + if (sequence_size > 0) + { + // move both sequences to a convenient location + move_to_pos(current_node,current_pos,0,sequence_size); + item.move_to_pos ( + item.current_node, + item.current_pos, + item.sequence_size-1, + item.sequence_size + ); + + // make copies of poitners + node& item_right = *item.current_node->right; + node& left = *current_node->left; + + + item.current_node->right = current_node; + current_node->left = item.current_node; + + left.right = &item_right; + item_right.left = &left; + + // set sizes + sequence_size += item.sequence_size; + item.sequence_size = 0; + } + else + { + // *this is empty so just swap + item.swap(*this); + } + } + item.clear(); + // reset the enumerator + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& sequence_kernel_2:: + operator[] ( + unsigned long pos + ) + { + move_to_pos(current_node,current_pos,pos,sequence_size); + return current_node->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long sequence_kernel_2:: + size ( + ) const + { + return sequence_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + swap ( + sequence_kernel_2& item + ) + { + unsigned long sequence_size_temp = item.sequence_size; + node* current_node_temp = item.current_node; + unsigned long current_pos_temp = item.current_pos; + bool at_start_temp = item.at_start_; + node* current_enumeration_node_temp = item.current_enumeration_node; + unsigned long current_enumeration_pos_temp = item.current_enumeration_pos; + + item.sequence_size = sequence_size; + item.current_node = current_node; + item.current_pos = current_pos; + item.at_start_ = at_start_; + item.current_enumeration_node = current_enumeration_node; + item.current_enumeration_pos = current_enumeration_pos; + + sequence_size = sequence_size_temp; + current_node = current_node_temp; + current_pos = current_pos_temp; + at_start_ = at_start_temp; + current_enumeration_node = current_enumeration_node_temp; + current_enumeration_pos = current_enumeration_pos_temp; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_2:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + reset ( + ) const + { + at_start_ = true; + current_enumeration_node = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_2:: + current_element_valid ( + ) const + { + return (current_enumeration_node!=0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& sequence_kernel_2:: + element ( + ) const + { + return current_enumeration_node->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& sequence_kernel_2:: + element ( + ) + { + return current_enumeration_node->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool sequence_kernel_2:: + move_next ( + ) const + { + if (at_start_ && sequence_size>0) + { + move_to_pos(current_node,current_pos,0,sequence_size); + current_enumeration_node = current_node; + current_enumeration_pos = 0; + } + else if (current_enumeration_node!=0) + { + ++current_enumeration_pos; + if (current_enumeration_posright; + } + else + { + // we have reached the end of the sequence + current_enumeration_node = 0; + } + } + + at_start_ = false; + return (current_enumeration_node!=0); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // remover function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + remove_any ( + T& item + ) + { + remove(0,item); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + delete_nodes ( + node* current_node, + unsigned long sequence_size + ) + { + node* temp; + while (sequence_size) + { + temp = current_node->right; + delete current_node; + current_node = temp; + --sequence_size; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void sequence_kernel_2:: + move_to_pos ( + node*& current_node, + unsigned long& current_pos, + unsigned long pos, + unsigned long size + ) const + { + if ( current_pos > pos) + { + // number of hops in each direction needed to reach pos + unsigned long right = size + pos - current_pos; + unsigned long left = current_pos - pos; + current_pos = pos; + + if (left < right) + { + // move left to position pos + for (; left > 0; --left) + current_node = current_node->left; + } + else + { + // move left to position pos + for (; right > 0; --right) + current_node = current_node->right; + } + } + else if (current_pos != pos) + { + // number of hops in each direction needed to reach pos + unsigned long right = pos - current_pos; + unsigned long left = size - pos + current_pos; + current_pos = pos; + + if (left < right) + { + // move left to position pos + for (; left > 0; --left) + current_node = current_node->left; + } + else + { + // move left to position pos + for (; right > 0; --right) + current_node = current_node->right; + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SEQUENCE_KERNEl_2_ + diff --git a/dlib/sequence/sequence_kernel_abstract.h b/dlib/sequence/sequence_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..4bee603d11f375e3b271491c7a89de481bfbfb7b --- /dev/null +++ b/dlib/sequence/sequence_kernel_abstract.h @@ -0,0 +1,196 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SEQUENCE_KERNEl_ABSTRACT_ +#ifdef DLIB_SEQUENCE_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" + +namespace dlib +{ + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class sequence : public enumerable, + public remover + { + + /*! + REQUIREMENTS ON T + T must be swappable by a global swap() and + T must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap() and operator[] functions do not invalidate pointers or + references to internal data. + All other functions have no such guarantees. + + ENUMERATION ORDER + The enumerator will iterate over the elements in the sequence from + the 0th element to the (size()-1)th element. + + INITIAL VALUE + size() == 0 + + WHAT THIS OBJECT REPRESENTS + sequence contains items of type T + + This object represents an ordered sequence of items, each item is + associated with an integer value. + The items are numbered from 0 to size()-1 + !*/ + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + sequence ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + virtual ~sequence ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear ( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void add ( + unsigned long pos, + T& item + ); + /*! + requires + - pos <= size() + ensures + - #size() == size() + 1 + - #item has an initial value for its type + - #operator[](pos) == item + i.e. item has been inserted into *this between the elements which + were previously at position pos-1 and pos + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + if add() throws then it has no effect + !*/ + + void remove ( + unsigned long pos, + T& item + ); + /*! + requires + - pos < size() + ensures + - #size() == size() - 1 + - the element at the position pos in *this has been removed and + swapped into #item + - #at_start() == true + !*/ + + void cat ( + sequence& item + ); + /*! + requires + - &item != this (i.e. you can't concatenate a sequence onto itself) + ensures + - item has been concatenated onto the end of *this + i.e. item[0] becomes (#*this)[size()], item[1] + becomes (#*this)[size()+1], etc... + - #size() == size() + item.size() + - #item has its initial value + - #at_start() == true + !*/ + + const T& operator[] ( + unsigned long pos + ) const; + /*! + requires + - pos < size() + ensures + - returns a const reference to the element at position pos + !*/ + + T& operator[] ( + unsigned long pos + ); + /*! + requires + - pos < size() + ensures + - returns a non-const reference to the element at position pos + !*/ + + void swap ( + sequence& item + ); + /*! + ensures + - swaps *this and item + !*/ + + + private: + + // restricted functions + sequence(sequence&); // copy constructor + sequence& operator=(sequence&); // assignment operator + + }; + + + template < + typename T, + typename mem_manager + > + inline void swap ( + sequence& a, + sequence& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename mem_manager + > + void deserialize ( + sequence& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_SEQUENCE_KERNEl_ABSTRACT_ + diff --git a/dlib/sequence/sequence_kernel_c.h b/dlib/sequence/sequence_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..3db99fd3c04a4791450c2533980441d3f28685d4 --- /dev/null +++ b/dlib/sequence/sequence_kernel_c.h @@ -0,0 +1,253 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCE_KERNEl_C_ +#define DLIB_SEQUENCE_KERNEl_C_ + +#include "sequence_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename seq_base + > + class sequence_kernel_c : public seq_base + { + typedef typename seq_base::type T; + public: + + + void add ( + unsigned long pos, + T& item + ); + + void remove ( + unsigned long pos, + T& item + ); + + const T& operator[] ( + unsigned long pos + ) const; + + T& operator[] ( + unsigned long pos + ); + + void cat ( + sequence_kernel_c& item + ); + + const T& element ( + ) const; + + T& element ( + ); + + void remove_any ( + T& item + ); + + }; + + + template < + typename seq_base + > + inline void swap ( + sequence_kernel_c& a, + sequence_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_kernel_c:: + add( + unsigned long pos, + T& item + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( pos <= this->size() ), + "\tvoid sequence::add" + << "\n\tpos must be >= 0 and <= size()" + << "\n\tpos: " << pos + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + seq_base::add(pos,item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_kernel_c:: + cat ( + sequence_kernel_c& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(&item != this, + "\tvoid sequence::cat" + << "\n\tyou can't concatenate a sequence onto itself" + << "\n\t&item: " << &item + << "\n\tthis: " << this + ); + + // call the real function + seq_base::cat(item); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_kernel_c:: + remove ( + unsigned long pos, + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(( pos < this->size() ), + "\tvoid sequence::remove" + << "\n\tpos must be >= 0 and < size()" + << "\n\tpos: " << pos + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + seq_base::remove(pos,item); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + const typename seq_base::type& sequence_kernel_c:: + operator[] ( + unsigned long pos + ) const + { + + // make sure requires clause is not broken + DLIB_CASSERT(( pos < this->size() ), + "\tconst T& sequence::operator[]" + << "\n\tpos must be >= 0 and < size()" + << "\n\tpos: " << pos + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return seq_base::operator[](pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + typename seq_base::type& sequence_kernel_c:: + operator[] ( + unsigned long pos + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(( pos < this->size() ), + "\tT& sequence::operator[]" + << "\n\tpos must be >= 0 and < size()" + << "\n\tpos: " << pos + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + return seq_base::operator[](pos); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + const typename seq_base::type& sequence_kernel_c:: + element ( + ) const + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& sequence::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return seq_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + typename seq_base::type& sequence_kernel_c:: + element ( + ) + { + DLIB_CASSERT(this->current_element_valid() == true, + "\tT& sequence::element()" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + return seq_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_kernel_c:: + remove_any ( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (this->size() > 0), + "\tvoid sequence::remove_any" + << "\n\tsize() must be greater than zero if something is going to be removed" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + seq_base::remove_any(item); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SEQUENCE_KERNEl_C_ + diff --git a/dlib/sequence/sequence_sort_1.h b/dlib/sequence/sequence_sort_1.h new file mode 100644 index 0000000000000000000000000000000000000000..f81e78ce37f009ba4ddca428c99f74c2273d9312 --- /dev/null +++ b/dlib/sequence/sequence_sort_1.h @@ -0,0 +1,182 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCE_SORt_1_ +#define DLIB_SEQUENCE_SORt_1_ + +#include "sequence_sort_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + template < + typename seq_base + > + class sequence_sort_1 : public seq_base + { + typedef typename seq_base::type T; + + public: + + /*! + this is a median of three version of the QuickSort algorithm and + it sorts sequences of less than 30 elements with a selection sort + !*/ + + void sort ( + ); + + private: + + void sort_this_sequence ( + seq_base& sequence + ); + /*! + ensures + - each element in the sequence is < the element behind it + !*/ + + void selection_sort ( + seq_base& sequence + ); + /*! + ensures + - sequence is sorted with a selection_sort + !*/ + + + }; + + + template < + typename seq_base + > + inline void swap ( + sequence_sort_1& a, + sequence_sort_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_sort_1:: + sort ( + ) + { + if (this->size() > 1) + { + sort_this_sequence(*this); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_sort_1:: + sort_this_sequence ( + seq_base& sequence + ) + { + if (sequence.size() < 30) + { + selection_sort(sequence); + } + else + { + seq_base left, right; + T partition_element; + + sequence.remove(0,partition_element); + + dlib::median ( + partition_element, + sequence[sequence.size()-1], + sequence[(sequence.size()-1)/2] + ); + + // partition sequence into left and right + T temp; + while (sequence.size() > 0) + { + sequence.remove(0,temp); + if (temp < partition_element) + { + left.add(0,temp); + } + else + { + right.add(0,temp); + } + } + + sort_this_sequence(left); + sort_this_sequence(right); + + // combine left and right into sequence + left.swap(sequence); + sequence.add(sequence.size(),partition_element); + sequence.cat(right); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_sort_1:: + selection_sort ( + seq_base& sequence + ) + { + if (sequence.size() > 2) + { + T temp[29]; + unsigned long ssize = sequence.size(); + + for (unsigned long i = 0; i < ssize; ++i) + sequence.remove(0,temp[i]); + + unsigned long smallest; + for (unsigned long i = 0; i < ssize - 1; ++i) + { + // find smallest element and swap into i + smallest = i; + for (unsigned long j = i+1; j < ssize; ++j) + { + if (temp[j] < temp[smallest]) + smallest = j; + } + exchange(temp[smallest],temp[i]); + } + + for (unsigned long i = 0; i < ssize; ++i) + sequence.add(i,temp[i]); + } + else if (sequence.size() == 2) + { + if (sequence[1] < sequence[0]) + { + exchange(sequence[0],sequence[1]); + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SEQUENCE_SORt_1_ + diff --git a/dlib/sequence/sequence_sort_2.h b/dlib/sequence/sequence_sort_2.h new file mode 100644 index 0000000000000000000000000000000000000000..88f270b3f8ebce2a07d3092ec131f0b45110b3cb --- /dev/null +++ b/dlib/sequence/sequence_sort_2.h @@ -0,0 +1,65 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEQUENCE_SORt_2_ +#define DLIB_SEQUENCE_SORt_2_ + +#include "sequence_sort_abstract.h" +#include "../algs.h" +#include "../sort.h" + +namespace dlib +{ + + template < + typename seq_base + > + class sequence_sort_2 : public seq_base + { + typedef typename seq_base::type T; + + public: + + /*! + this is a version of the QuickSort algorithm + this uses the dlib::qsort_array function + !*/ + + void sort ( + ); + + + }; + + template < + typename seq_base + > + inline void swap ( + sequence_sort_2& a, + sequence_sort_2& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename seq_base + > + void sequence_sort_2:: + sort ( + ) + { + if (this->size() > 1) + { + dlib::qsort_array(*this,0,this->size()-1); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SEQUENCE_SORt_2_ + diff --git a/dlib/sequence/sequence_sort_abstract.h b/dlib/sequence/sequence_sort_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..65a5f916f29b864fd2b39ad4272275bda7469efa --- /dev/null +++ b/dlib/sequence/sequence_sort_abstract.h @@ -0,0 +1,65 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SEQUENCE_SORt_ABSTRACT_ +#ifdef DLIB_SEQUENCE_SORt_ABSTRACT_ + +#include "sequence_kernel_abstract.h" + +namespace dlib +{ + + template < + typename seq_base + > + class sequence_sort : public seq_base + { + + /*! + REQUIREMENTS ON T + T must implement operator< for its type + + REQUIREMENTS ON seq_base + must be an implementation of sequence/sequence_kernel_abstract.h + + + + POINTERS AND REFERENCES TO INTERNAL DATA + sort() may invalidate pointers and references to data members. + + WHAT THIS EXTENSION DOES FOR sequence + this gives a sequence the ability to sort its contents by calling sort() + !*/ + + + public: + + void sort ( + ); + /*! + ensures + - for all elements in #*this the ith element is <= the i+1 element + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + data may be lost if sort() throws + !*/ + + + }; + + + template < + typename seq_base + > + inline void swap ( + sequence_sort& a, + sequence_sort& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_SEQUENCE_SORt_ABSTRACT_ + diff --git a/dlib/serialize.h b/dlib/serialize.h new file mode 100644 index 0000000000000000000000000000000000000000..2d7218dbd44fe0a2ffe3e64ce8918ca996e8ca89 --- /dev/null +++ b/dlib/serialize.h @@ -0,0 +1,916 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SERIALIZe_ +#define DLIB_SERIALIZe_ + +/*! + There are two global functions in the dlib namespace that provide + serialization and deserialization support. Their signatures and specifications + are as follows: + + void serialize ( + const serializable_type& item, + std::ostream& out + ); + /!* + ensures + - writes the state of item to the output stream out + - if (serializable_type implements the enumerable interface) then + - item.at_start() == true + throws + - serialization_error + This exception is thrown if there is some problem which prevents + us from successfully writing item to the output stream. + - any other exception + *!/ + + void deserialize ( + serializable_type& item, + std::istream& in + ); + /!* + ensures + - #item == a deserialized copy of the serializable_type that was + in the input stream in. + - if (serializable_type implements the enumerable interface) then + - item.at_start() == true + throws + - serialization_error + This exception is thrown if there is some problem which prevents + us from successfully deserializing item from the input stream. + If this exception is thrown then item will have an initial value + for its type. + - any other exception + *!/ + + + This file provides serialization support to the following object types: + - The C++ base types (NOT including pointer types) + - std::string + - std::wstring + - std::vector + - std::map + - std::complex + - dlib::uint64 + - enumerable where T is a serializable type + - map_pair where D and R are both serializable types. + - C style arrays of serializable types + + This file provides deserialization support to the following object types: + - The C++ base types (NOT including pointer types) + - std::string + - std::wstring + - std::vector + - std::map + - std::complex + - dlib::uint64 + - C style arrays of serializable types + + Support for deserialization of objects which implement the enumerable or + map_pair interfaces is the responsibility of those objects. + + Note that you can deserialize an integer value to any integral type (except for a + char type) if its value will fit into the target integer type. I.e. the types + short, int, long, unsigned short, unsigned int, unsigned long, and dlib::uint64 + can all receive serialized data from each other so long as the actual serizlied + value fits within the receiving integral type's range. + + Also note that for any container to be serializable the type of object it contains + must be serializable. + + FILE STREAMS + If you are serializing to and from file streams it is important to + remember to set the file streams to binary mode using the std::ios::binary + flag. + + + INTEGRAL SERIALIZATION FORMAT + All C++ integral types (except the char types) are serialized to the following + format: + The first byte is a control byte. It tells you if the serialized number is + positive or negative and also tells you how many of the following bytes are + part of the number. The absolute value of the number is stored in little + endian byte order and follows the control byte. + + The control byte: + The high order bit of the control byte is a flag that tells you if the + encoded number is negative or not. It is set to 1 when the number is + negative and 0 otherwise. + The 4 low order bits of the control byte represent an unsigned number + and tells you how many of the following bytes are part of the encoded + number. + + +!*/ + + +#include "algs.h" +#include "assert.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "uintn.h" +#include "interfaces/enumerable.h" +#include "interfaces/map_pair.h" +#include "enable_if.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class serialization_error : public error + { + public: + serialization_error(const std::string& e):error(e) {} + }; + +// ---------------------------------------------------------------------------------------- + + namespace ser_helper + { + + template < + typename T + > + typename enable_if_c::is_signed,bool>::type pack_int ( + T item, + std::ostream& out + ) + /*! + requires + - T is a signed integral type + ensures + - if (no problems occur serializing item) then + - writes item to out + - returns false + - else + - returns true + !*/ + { + COMPILE_TIME_ASSERT(sizeof(T) <= 8); + unsigned char buf[8]; + unsigned char size = 0; + unsigned char neg; + if (item < 0) + { + neg = 0x80; + item *= -1; + } + else + { + neg = 0; + } + + for (unsigned char i = 0; i < sizeof(T); ++i) + { + buf[i] = static_cast(item&0xFF); + item >>= 8; + if (item == 0) { size = i+1; break; } + } + if (size == 0) + size = sizeof(T); + size |= neg; + + out.write(reinterpret_cast(&size),1); + size &= 0x7F; // strip off the neg flag + out.write(reinterpret_cast(buf),size); + + // check if there was an error + if (!out) + return true; + else + return false; + } + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + typename enable_if_c::is_signed,bool>::type unpack_int ( + T& item, + std::istream& in + ) + /*! + requires + - T is a signed integral type + ensures + - if (there are no problems deserializing item) then + - returns false + - #item == the value stored in in + - else + - returns true + + !*/ + { + COMPILE_TIME_ASSERT(sizeof(T) <= 8); + + + unsigned char buf[8]; + unsigned char size; + bool is_negative; + + item = 0; + in.read(reinterpret_cast(&size),1); + // check if an error occurred + if (!in) + return true; + if (size&0x80) + is_negative = true; + else + is_negative = false; + size &= 0x0F; + + // check if the serialized object is too big + if (size > sizeof(T)) + return true; + + in.read(reinterpret_cast(&buf),size); + + // check if there was an error reading from in. + if (!in) + return true; + + for (unsigned char i = size-1; true; --i) + { + item <<= 8; + item |= buf[i]; + if (i == 0) + break; + } + + if (is_negative) + item *= -1; + + + return false; + } + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + typename disable_if_c::is_signed,bool>::type pack_int ( + T item, + std::ostream& out + ) + /*! + requires + - T is an unsigned integral type + ensures + - if (no problems occur serializing item) then + - writes item to out + - returns false + - else + - returns true + !*/ + { + COMPILE_TIME_ASSERT(sizeof(T) <= 8); + unsigned char buf[8]; + unsigned char size = 0; + + for (unsigned char i = 0; i < sizeof(T); ++i) + { + buf[i] = static_cast(item&0xFF); + item >>= 8; + if (item == 0) { size = i+1; break; } + } + if (size == 0) + size = sizeof(T); + + out.write(reinterpret_cast(&size),1); + out.write(reinterpret_cast(buf),size); + + // check if there was an error + if (!out) + return true; + else + return false; + } + + // ------------------------------------------------------------------------------------ + + template < + typename T + > + typename disable_if_c::is_signed,bool>::type unpack_int ( + T& item, + std::istream& in + ) + /*! + requires + - T is an unsigned integral type + ensures + - if (there are no problems deserializing item) then + - returns false + - #item == the value stored in in + - else + - returns true + + !*/ + { + COMPILE_TIME_ASSERT(sizeof(T) <= 8); + + unsigned char buf[8]; + unsigned char size; + + item = 0; + in.read(reinterpret_cast(&size),1); + // mask out the 3 reserved bits + size &= 0x8F; + // check if an error occurred + if (!in || size > sizeof(T)) + return true; + + + in.read(reinterpret_cast(&buf),size); + + // check if the serialized object is too big to fit into something of type T. + // or if there was an error reading from in. + if (!in) + return true; + + for (unsigned char i = size-1; true; --i) + { + item <<= 8; + item |= buf[i]; + if (i == 0) + break; + } + + return false; + } + + } + +// ---------------------------------------------------------------------------------------- + + #define USE_DEFAULT_INT_SERIALIZATION_FOR(T) \ + inline void serialize (const T& item, std::ostream& out) \ + { if (ser_helper::pack_int(item,out)) throw serialization_error("Error serializing object of type " + std::string(#T)); } \ + inline void deserialize (T& item, std::istream& in) \ + { if (ser_helper::unpack_int(item,in)) throw serialization_error("Error deserializing object of type " + std::string(#T)); } + + #define USE_DEFAULT_BYTE_SERIALIZATION_FOR(T) \ + inline void serialize (const T& item,std::ostream& out) \ + { out.write(reinterpret_cast(&item),1); if (!out) throw serialization_error("Error serializing object of type " + std::string(#T)); } \ + inline void deserialize (T& item, std::istream& in) \ + { in.read(reinterpret_cast(&item),1); if (!in) throw serialization_error("Error deserializing object of type " + std::string(#T)); } + +// ---------------------------------------------------------------------------------------- + + USE_DEFAULT_INT_SERIALIZATION_FOR(short) + USE_DEFAULT_INT_SERIALIZATION_FOR(int) + USE_DEFAULT_INT_SERIALIZATION_FOR(long) + USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned short) + USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned int) + USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned long) + USE_DEFAULT_INT_SERIALIZATION_FOR(uint64) + + USE_DEFAULT_BYTE_SERIALIZATION_FOR(char) + USE_DEFAULT_BYTE_SERIALIZATION_FOR(signed char) + USE_DEFAULT_BYTE_SERIALIZATION_FOR(unsigned char) + + // Don't define serialization for wchar_t when using a version of visual studio + // older than 8.0 (visual studio 2005) since before then they improperly set + // wchar_t to be a typedef rather than its own type as required by the C++ + // standard. +#if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED + USE_DEFAULT_INT_SERIALIZATION_FOR(wchar_t) +#endif + +// ---------------------------------------------------------------------------------------- + + template + inline bool serialize_floating_point ( + const T& item, + std::ostream& out + ) + { + std::ios::fmtflags oldflags = out.flags(); + out.flags(); + std::streamsize ss = out.precision(35); + if (item == std::numeric_limits::infinity()) + out << "inf "; + else if (item == -std::numeric_limits::infinity()) + out << "ninf "; + else if (item < std::numeric_limits::infinity()) + out << item << ' '; + else + out << "NaN "; + out.flags(oldflags); + out.precision(ss); + return (!out); + } + + template + inline bool deserialize_floating_point ( + T& item, + std::istream& in + ) + { + std::ios::fmtflags oldflags = in.flags(); + in.flags(); + std::streamsize ss = in.precision(35); + if (in.peek() == 'i') + { + item = std::numeric_limits::infinity(); + in.get(); + in.get(); + in.get(); + } + else if (in.peek() == 'n') + { + item = -std::numeric_limits::infinity(); + in.get(); + in.get(); + in.get(); + in.get(); + } + else if (in.peek() == 'N') + { + item = std::numeric_limits::quiet_NaN(); + in.get(); + in.get(); + in.get(); + } + else + { + in >> item; + } + in.flags(oldflags); + in.precision(ss); + return (in.get() != ' '); + } + + inline void serialize ( const float& item, std::ostream& out) + { + if (serialize_floating_point(item,out)) + throw serialization_error("Error serializing object of type float"); + } + + inline void deserialize (float& item, std::istream& in) + { + if (deserialize_floating_point(item,in)) + throw serialization_error("Error deserializing object of type float"); + } + + inline void serialize ( const double& item, std::ostream& out) + { + if (serialize_floating_point(item,out)) + throw serialization_error("Error serializing object of type double"); + } + + inline void deserialize (double& item, std::istream& in) + { + if (deserialize_floating_point(item,in)) + throw serialization_error("Error deserializing object of type double"); + } + + inline void serialize ( const long double& item, std::ostream& out) + { + if (serialize_floating_point(item,out)) + throw serialization_error("Error serializing object of type long double"); + } + + inline void deserialize ( long double& item, std::istream& in) + { + if (deserialize_floating_point(item,in)) + throw serialization_error("Error deserializing object of type long double"); + } + +// ---------------------------------------------------------------------------------------- +// prototypes + + template + void serialize ( + const std::map& item, + std::ostream& out + ); + + template + void deserialize ( + std::map& item, + std::istream& in + ); + + template + void serialize ( + const std::vector& item, + std::ostream& out + ); + + template + void deserialize ( + std::vector& item, + std::istream& in + ); + + inline void serialize ( + const std::string& item, + std::ostream& out + ); + + inline void deserialize ( + std::string& item, + std::istream& in + ); + + template < + typename T + > + inline void serialize ( + const enumerable& item, + std::ostream& out + ); + + template < + typename domain, + typename range + > + inline void serialize ( + const map_pair& item, + std::ostream& out + ); + + template < + typename T, + size_t length + > + inline void serialize ( + const T (&array)[length], + std::ostream& out + ); + + template < + typename T, + size_t length + > + inline void deserialize ( + T (&array)[length], + std::istream& in + ); + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + bool item, + std::ostream& out + ) + { + if (item) + out << '1'; + else + out << '0'; + + if (!out) + throw serialization_error("Error serializing object of type bool"); + } + + inline void deserialize ( + bool& item, + std::istream& in + ) + { + int ch = in.get(); + if (ch != EOF) + { + if (ch == '1') + item = true; + else if (ch == '0') + item = false; + else + throw serialization_error("Error deserializing object of type bool"); + } + else + { + throw serialization_error("Error deserializing object of type bool"); + } + } + +// ---------------------------------------------------------------------------------------- + + template + void serialize ( + const std::map& item, + std::ostream& out + ) + { + try + { + const unsigned long size = static_cast(item.size()); + + serialize(size,out); + typename std::map::const_iterator i; + for (i = item.begin(); i != item.end(); ++i) + { + serialize(i->first,out); + serialize(i->second,out); + } + + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while serializing object of type std::map"); } + } + + template + void deserialize ( + std::map& item, + std::istream& in + ) + { + try + { + item.clear(); + + unsigned long size; + deserialize(size,in); + domain d; + range r; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(d,in); + deserialize(r,in); + item[d] = r; + } + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while deserializing object of type std::map"); } + } + +// ---------------------------------------------------------------------------------------- + + template + void serialize ( + const std::vector& item, + std::ostream& out + ) + { + try + { + const unsigned long size = static_cast(item.size()); + + serialize(size,out); + for (unsigned long i = 0; i < item.size(); ++i) + serialize(item[i],out); + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while serializing object of type std::vector"); } + } + + template + void deserialize ( + std::vector& item, + std::istream& in + ) + { + try + { + unsigned long size; + deserialize(size,in); + item.resize(size); + for (unsigned long i = 0; i < size; ++i) + deserialize(item[i],in); + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while deserializing object of type std::vector"); } + } + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const std::string& item, + std::ostream& out + ) + { + const unsigned long size = static_cast(item.size()); + try{ serialize(size,out); } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while serializing object of type std::string"); } + + out.write(item.c_str(),size); + if (!out) throw serialization_error("Error serializing object of type std::string"); + } + + inline void deserialize ( + std::string& item, + std::istream& in + ) + { + char* buf = 0; + try + { + unsigned long size; + try { deserialize(size,in); } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while deserializing object of type std::string"); } + + buf = new char[size+1]; + buf[size] = 0; + in.read(buf,size); + item.assign(buf); + if (!in) throw serialization_error("Error deserializing object of type std::string"); + delete [] buf; + } + catch (...) + { + if (buf) + delete [] buf; + item.erase(); + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const std::wstring& item, + std::ostream& out + ) + { + const unsigned long size = static_cast(item.size()); + try{ serialize(size,out); } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while serializing object of type std::wstring"); } + + for (unsigned long i = 0; i < item.size(); ++i) + serialize(item[i], out); + if (!out) throw serialization_error("Error serializing object of type std::wstring"); + } + + inline void deserialize ( + std::wstring& item, + std::istream& in + ) + { + unsigned long size; + try { deserialize(size,in); } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while deserializing object of type std::wstring"); } + + item.resize(size); + for (unsigned long i = 0; i < item.size(); ++i) + deserialize(item[i],in); + + if (!in) throw serialization_error("Error deserializing object of type std::wstring"); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + inline void serialize ( + const enumerable& item, + std::ostream& out + ) + { + try + { + item.reset(); + serialize(item.size(),out); + while (item.move_next()) + serialize(item.element(),out); + item.reset(); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type enumerable"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range + > + inline void serialize ( + const map_pair& item, + std::ostream& out + ) + { + try + { + serialize(item.key(),out); + serialize(item.value(),out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type map_pair"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + size_t length + > + inline void serialize ( + const T (&array)[length], + std::ostream& out + ) + { + try + { + serialize(length,out); + for (size_t i = 0; i < length; ++i) + serialize(array[i],out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing a C style array"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + size_t length + > + inline void deserialize ( + T (&array)[length], + std::istream& in + ) + { + size_t size; + try + { + deserialize(size,in); + if (size == length) + { + for (size_t i = 0; i < length; ++i) + deserialize(array[i],in); + } + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing a C style array"); + } + + if (size != length) + throw serialization_error("Error deserializing a C style array, lengths do not match"); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + inline void serialize ( + const std::complex& item, + std::ostream& out + ) + { + try + { + serialize(item.real(),out); + serialize(item.imag(),out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing an object of type std::complex"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + inline void deserialize ( + std::complex& item, + std::istream& in + ) + { + try + { + T real, imag; + deserialize(real,in); + deserialize(imag,in); + item = std::complex(real,imag); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing an object of type std::complex"); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SERIALIZe_ + diff --git a/dlib/server.h b/dlib/server.h new file mode 100644 index 0000000000000000000000000000000000000000..dd61b1a3d104cb8c0cbb4bb45810f8ed0a6f61aa --- /dev/null +++ b/dlib/server.h @@ -0,0 +1,65 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SERVEr_ +#define DLIB_SERVEr_ + +#include "server/server_kernel_1.h" +#include "server/server_kernel_c.h" +#include "server/server_iostream_1.h" +#include "server/server_http_1.h" + +#include "set.h" +#include "algs.h" +#include "sockstreambuf.h" +#include "map.h" +#include "queue.h" +#include + + + +namespace dlib +{ + + class server + { + server() {} + + + typedef set::kernel_1a set_of_cons_1a; + + typedef sockstreambuf::kernel_1a ssbuf1a; + typedef sockstreambuf::kernel_2a ssbuf2a; + + typedef map::kernel_1a_c map_ss_type; + typedef queue::kernel_1a_c queue_type; + + typedef map::kernel_2a>::kernel_1b id_map; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef server_kernel_1 + kernel_1a; + typedef server_kernel_c + kernel_1a_c; + + // iostream_1a + typedef server_iostream_1 + iostream_1a; + typedef server_iostream_1 + iostream_1a_c; + + // http_1a + typedef server_http_1 + http_1a; + typedef server_http_1 + http_1a_c; + + }; + +} + +#endif // DLIB_SERVEr_ + diff --git a/dlib/server/server_http_1.h b/dlib/server/server_http_1.h new file mode 100644 index 0000000000000000000000000000000000000000..53d44448cd417dfda28a42188dcfcf86332f6503 --- /dev/null +++ b/dlib/server/server_http_1.h @@ -0,0 +1,356 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SERVER_HTTp_1_ +#define DLIB_SERVER_HTTp_1_ + + +#include "server_iostream_abstract.h" +#include "server_http_abstract.h" +#include +#include +#include +#include "../logger.h" + +namespace dlib +{ + + template < + typename server_base, + typename map_ss_type, + typename queue_string_type + > + class server_http_1 : public server_base + { + + /*! + CONVENTION + this extension doesn't add any new state to this object. + !*/ + + + public: + typedef map_ss_type map_type; + typedef queue_string_type queue_type; + + private: + + virtual void on_request ( + const std::string& path, + std::string& result, + const map_type& queries, + const map_type& cookies, + queue_type& new_cookies, + const map_type& incoming_headers, + map_type& response_headers, + const std::string& foreign_ip, + const std::string& local_ip, + unsigned short foreign_port, + unsigned short local_port + ) = 0; + + unsigned char to_hex ( + unsigned char ch + ) const + { + if (ch <= '9' && ch >= '0') + ch -= '0'; + else if (ch <= 'f' && ch >= 'a') + ch -= 'a' - 10; + else if (ch <= 'F' && ch >= 'A') + ch -= 'A' - 10; + else + ch = 0; + return ch; + } + + const std::string decode_query_string ( + const std::string& str + ) const + { + using namespace std; + string result; + string::size_type i; + for (i = 0; i < str.size(); ++i) + { + if (str[i] == '+') + { + result += ' '; + } + else if (str[i] == '%' && str.size() > i+2) + { + const unsigned char ch1 = to_hex(str[i+1]); + const unsigned char ch2 = to_hex(str[i+2]); + const unsigned char ch = (ch1 << 4) | ch2; + result += ch; + i += 2; + } + else + { + result += str[i]; + } + } + return result; + } + + void on_connect ( + std::istream& in, + std::ostream& out, + const std::string& foreign_ip, + const std::string& local_ip, + unsigned short foreign_port, + unsigned short local_port, + uint64 + ) + { + bool my_fault = true; + try + { + enum req_type {get, post} rtype; + + using namespace std; + map_type cookies; + string word; + string path; + in >> word; + if (word == "GET" || word == "get") + { + rtype = get; + } + else if ( word == "POST" || word == "post") + { + rtype = post; + } + else + { + // this isn't a GET or POST request so just drop the connection + return; + } + + // get the path + in >> path; + + // now loop over all the incoming_headers + string line; + getline(in,line); + unsigned long content_length = 0; + string content_type; + map_type incoming_headers; + string first_part_of_header; + string::size_type position_of_double_point; + while (line.size() > 2) + { + position_of_double_point = line.find_first_of(':'); + if ( position_of_double_point != string::npos ) + { + first_part_of_header = line.substr(0, position_of_double_point); + if ( incoming_headers.is_in_domain(first_part_of_header) ) + { + incoming_headers[ first_part_of_header ] += " " + line.substr(position_of_double_point+1); + } + else + { + string second_part_of_header(line.substr(position_of_double_point+1)); + incoming_headers.add( first_part_of_header, second_part_of_header ); + } + + // look for Content-Type: + if (line.size() > 14 && + line[0] == 'C' && + line[1] == 'o' && + line[2] == 'n' && + line[3] == 't' && + line[4] == 'e' && + line[5] == 'n' && + line[6] == 't' && + line[7] == '-' && + (line[8] == 'T' || line[8] == 't') && + line[9] == 'y' && + line[10] == 'p' && + line[11] == 'e' && + line[12] == ':' + ) + { + content_type = line.substr(14); + if (content_type[content_type.size()-1] == '\r') + content_type.erase(content_type.size()-1); + } + // look for Content-Length: + else if (line.size() > 16 && + line[0] == 'C' && + line[1] == 'o' && + line[2] == 'n' && + line[3] == 't' && + line[4] == 'e' && + line[5] == 'n' && + line[6] == 't' && + line[7] == '-' && + (line[8] == 'L' || line[8] == 'l') && + line[9] == 'e' && + line[10] == 'n' && + line[11] == 'g' && + line[12] == 't' && + line[13] == 'h' && + line[14] == ':' + ) + { + istringstream sin(line.substr(16)); + sin >> content_length; + if (!sin) + content_length = 0; + } + // look for any cookies + else if (line.size() > 6 && + line[0] == 'C' && + line[1] == 'o' && + line[2] == 'o' && + line[3] == 'k' && + line[4] == 'i' && + line[5] == 'e' && + line[6] == ':' + ) + { + string::size_type pos = 6; + string key, value; + bool seen_key_start = false; + bool seen_equal_sign = false; + while (pos + 1 < line.size()) + { + ++pos; + // ignore whitespace between cookies + if (!seen_key_start && line[pos] == ' ') + continue; + + seen_key_start = true; + if (!seen_equal_sign) + { + if (line[pos] == '=') + { + seen_equal_sign = true; + } + else + { + key += line[pos]; + } + } + else + { + if (line[pos] == ';') + { + if (cookies.is_in_domain(key) == false) + cookies.add(key,value); + seen_equal_sign = false; + seen_key_start = false; + } + else + { + value += line[pos]; + } + } + } + if (key.size() > 0 && cookies.is_in_domain(key) == false) + cookies.add(key,value); + } + } // no ':' in it! + getline(in,line); + } // while (line.size() > 2 ) + + // If there is data being posted back to us as a query string then + // just stick it onto the end of the path so the following code can + // then just pick it out like we do for GET requests. + if (rtype == post && content_type == "application/x-www-form-urlencoded" + && content_length > 0) + { + line.resize(content_length); + in.read(&line[0],content_length); + path += "?" + line; + } + + string result; + map_type queries; + string::size_type pos = path.find_first_of("?"); + if (pos != string::npos) + { + word = path.substr(pos+1); + path = path.substr(0,pos); + for (pos = 0; pos < word.size(); ++pos) + { + if (word[pos] == '&') + word[pos] = ' '; + } + + istringstream sin(word); + sin >> word; + while (sin) + { + pos = word.find_first_of("="); + if (pos != string::npos) + { + string key = decode_query_string(word.substr(0,pos)); + string value = decode_query_string(word.substr(pos+1)); + if (queries.is_in_domain(key) == false) + queries.add(key,value); + } + sin >> word; + } + } + + + my_fault = false; + queue_type new_cookies; + map_type response_headers; + // if there wasn't a problem with the input stream at some point + // then lets trigger this request callback. + if (in) + on_request(path,result,queries,cookies,new_cookies,incoming_headers, response_headers, foreign_ip,local_ip,foreign_port,local_port); + my_fault = true; + + out << "HTTP/1.0 200 OK\r\n"; + // only send this header if the user hasn't told us to send another kind + if (response_headers.is_in_domain("Content-Type") == false && + response_headers.is_in_domain("content-type") == false) + { + out << "Content-Type: text/html\r\n"; + } + out << "Content-Length: " << result.size() << "\r\n"; + + // Set any new headers + response_headers.reset(); + while (response_headers.move_next()) + out << response_headers.element().key() << ':' << response_headers.element().value() << "\r\n"; + + // set any cookies + new_cookies.reset(); + while (new_cookies.move_next()) + { + out << "Set-Cookie: " << new_cookies.element() << "\r\n"; + } + out << "\r\n" << result; + } + catch (std::bad_alloc&) + { + dlog << LERROR << "We ran out of memory in server_http::on_connect()"; + // If this is an escaped exception from on_request then let it fly! + // Seriously though, this way it is obvious to the user that something bad happened + // since they probably won't have the dlib logger enabled. + if (!my_fault) + throw; + } + + } + + const static logger dlog; + }; + + template < + typename server_base, + typename map_ss_type, + typename queue_string_type + > + const logger server_http_1::dlog("dlib.server"); +} + +#endif // DLIB_SERVER_HTTp_1_ + + + + diff --git a/dlib/server/server_http_abstract.h b/dlib/server/server_http_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..6ec3edb558c1ec54505fb790d217e00ddf84040e --- /dev/null +++ b/dlib/server/server_http_abstract.h @@ -0,0 +1,118 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SERVER_HTTp_ABSTRACT_ +#ifdef DLIB_SERVER_HTTp_ABSTRACT_ + + +#include "server_iostream_abstract.h" +#include +#include +#include + +namespace dlib +{ + + template < + typename server_base, + typename map_ss_type, + typename queue_string_type + > + class server_http : public server_base + { + + /*! + REQUIREMENTS ON server_base + is an implementation of server/server_iostream_abstract.h + + REQUIREMENTS ON map_ss_type + is an implementation of map/map_kernel_abstract.h with + domain set to std::string and range set to std::string + + REQUIREMENTS ON queue_string_type + is an implementation of queue/queue_kernel_abstract.h with + T set to std::string + + WHAT THIS EXTENSION DOES FOR SERVER IOSTREAM + This extension turns the server object into a simple HTTP server. + It only handles HTTP GET and POST requests and each incoming request triggers the + on_request() callback. + + COOKIE STRINGS + The strings returned in the new_cookies queue should be of the following form: + cookie_name=cookie contents; expires=Fri, 31-Dec-2010 23:59:59 GMT; path=/; domain=.example.net + + You don't have to supply all the extra cookie arguments. So if you just want to + set a cookie that will expire when the client's browser is closed you can + use a string such as "cookie_name=cookie contents" + + HTTP HEADERS + The HTTP headers in the incoming_headers and response_headers are the name/value pairs + of HTTP headers. For example, the HTTP header "Content-Type: text/html" would be + encoded such that response_headers["Content-Type"] == "text/html". + + Also note that if you wish to change the content type of your response to the + client you may do so by setting the "Content-Type" header to whatever you like. + However, setting this field manually is not necessary as it will default to + "text/html" if you don't explicitly set it to something. + !*/ + + public: + typedef map_ss_type map_type; + typedef queue_string_type queue_type; + + private: + + void on_request ( + const std::string& path, + std::string& result, + const map_type& queries, + const map_type& cookies, + queue_type& new_cookies, + const map_type& incoming_headers, + map_type& response_headers, + const std::string& foreign_ip, + const std::string& local_ip, + unsigned short foreign_port, + unsigned short local_port + ) = 0; + /*! + requires + - on_request() is called when there is an HTTP GET or POST request to be serviced + - path == the path being requested by this request + - queries == a map that contains all the key/value pairs in the query string + of this request. The key and value strings of the query string will + have been decoded back into their original form before being sent to this + function (i.e. '+' decoded back to ' ' and "%hh" into its corresponding + ascii value) + - cookies == The set of cookies that came from the client along with this + request. + - foreign_ip == the foreign ip address for this request + - foreign_port == the foreign port number for this request + - local_ip == the IP of the local interface this request is coming in on + - local_port == the local port number this request is coming in on + - on_request() is run in its own thread + - is_running() == true + - the number of current on_request() functions running < get_max_connection() + - new_cookies.size() == 0 + - response_headers.size() == 0 + - incoming_headers == a map that contains all the incoming HTTP headers + from the client web browser. + ensures + - #result == the HTML page to be displayed as the response to this request. + - this function will not call clear() + - #new_cookies == a set of new cookies to pass back to the client along + with the result of this request. + - #response_headers == a set of additional headers you wish to appear in the + HTTP response to this request. (This may be empty) + throws + - does not throw any exceptions + !*/ + + }; + +} + +#endif // DLIB_SERVER_HTTp_ABSTRACT_ + + + diff --git a/dlib/server/server_iostream_1.h b/dlib/server/server_iostream_1.h new file mode 100644 index 0000000000000000000000000000000000000000..422034d9c98c44e3b3e05fa48a3479ffa8ce893f --- /dev/null +++ b/dlib/server/server_iostream_1.h @@ -0,0 +1,164 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SERVER_IOSTREAm_1_ +#define DLIB_SERVER_IOSTREAm_1_ + +#include +#include "server_iostream_abstract.h" +#include "../logger.h" +#include "../uintn.h" + + +namespace dlib +{ + + template < + typename server_base, + typename ssbuf, + typename id_map + > + class server_iostream_1 : public server_base + { + + /*! + REQUIREMENTS ON ssbuf + - must be an implementation of dlib/sockstreambuf/sockstreambuf_kernel_abstract.h + + REQUIREMENTS ON id_map + - must be an implementation of dlib/map/map_kernel_abstract.h and domain must + be set to uint64 and range must be set to connection* + + INITIAL VALUE + - next_id == 0 + - con_map.size() == 0 + + CONVENTION + - next_id == the id of the next connection + - for all current connections + - con_map[id] == the connection object with the given id + - m == the mutex that protects the members of this object + !*/ + + public: + server_iostream_1( + ) : + next_id(0) + {} + + ~server_iostream_1( + ) + { + server_base::clear(); + } + + protected: + + void shutdown_connection ( + uint64 id + ) + { + auto_mutex M(m); + if (con_map.is_in_domain(id)) + { + con_map[id]->shutdown(); + } + } + + private: + + virtual void on_connect ( + std::istream& in, + std::ostream& out, + const std::string& foreign_ip, + const std::string& local_ip, + unsigned short foreign_port, + unsigned short local_port, + uint64 connection_id + )=0; + + void on_connect ( + connection& con + ) + { + bool my_fault = true; + uint64 this_con_id; + try + { + ssbuf buf(&con); + std::istream in(&buf); + std::ostream out(&buf); + in.tie(&out); + + // add this connection to the con_map + { + auto_mutex M(m); + this_con_id = next_id; + connection* this_con = &con; + con_map.add(this_con_id,this_con); + this_con_id = next_id; + ++next_id; + } + + my_fault = false; + on_connect( + in, + out, + con.get_foreign_ip(), + con.get_local_ip(), + con.get_foreign_port(), + con.get_local_port(), + this_con_id + ); + + // remove this connection from the con_map + { + auto_mutex M(m); + connection* this_con; + uint64 junk; + con_map.remove(this_con_id,junk,this_con); + } + + } + catch (std::bad_alloc&) + { + // make sure we remove this connection from the con_map + { + auto_mutex M(m); + if (con_map.is_in_domain(this_con_id)) + { + connection* this_con; + uint64 junk; + con_map.remove(this_con_id,junk,this_con); + } + } + + dlog << LERROR << "We ran out of memory in server_iostream::on_connect()"; + // if this is an escaped exception from on_connect then let it fly! + // Seriously though, this way it is obvious to the user that something bad happened + // since they probably won't have the dlib logger enabled. + if (!my_fault) + throw; + } + } + + uint64 next_id; + id_map con_map; + const static logger dlog; + mutex m; + + + }; + + template < + typename server_base, + typename ssbuf, + typename id_map + > + const logger server_iostream_1::dlog("dlib.server"); + +} + +#endif // DLIB_SERVER_IOSTREAm_1_ + + + diff --git a/dlib/server/server_iostream_abstract.h b/dlib/server/server_iostream_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..311efcc4faa5a6ebb2334de076affc86fc91f579 --- /dev/null +++ b/dlib/server/server_iostream_abstract.h @@ -0,0 +1,90 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SERVER_IOSTREAm_ABSTRACT_ +#ifdef DLIB_SERVER_IOSTREAm_ABSTRACT_ + + +#include "server_kernel_abstract.h" +#include +#include +#include "../uintn.h" + +namespace dlib +{ + + template < + typename server_base + > + class server_iostream : public server_base + { + + /*! + REQUIREMENTS ON server_base + is an implementation of server/server_kernel_abstract.h + + WHAT THIS EXTENSION DOES FOR SERVER + This extension redefines the on_connect() function so that + instead of giving you a connection object you get an istream + and ostream object. + + THREAD SAFETY + Note that in on_connect() the input stream in is tied to the output stream + out. This means that when you read from in it will modify out and thus + it is not safe to touch in and out concurrently from different threads + unless you untie them (which you do by saying in.tie(0);) + !*/ + + protected: + + void shutdown_connection ( + uint64 id + ); + /*! + ensures + - if (there is a connection currently being serviced with the given id) then + - the specified connection is shutdown. (i.e. connection::shutdown() is + called on it so the iostreams operating on it will return EOF) + !*/ + + private: + + virtual void on_connect ( + std::istream& in, + std::ostream& out, + const std::string& foreign_ip, + const std::string& local_ip, + unsigned short foreign_port, + unsigned short local_port, + uint64 connection_id + )=0; + /*! + requires + - on_connect() is called when there is a new TCP connection that needs + to be serviced. + - in == the input stream that reads data from the new connection + - out == the output stream that writes data to the new connection + - in.tie() == &out (i.e. when you read from in it automatically calls out.flush()) + - foreign_ip == the foreign ip address for this connection + - foreign_port == the foreign port number for this connection + - local_ip == the IP of the local interface this connection is using + - local_port == the local port number for this connection + - on_connect() is run in its own thread + - is_running() == true + - the number of current connections < get_max_connection() + - connection_id == an integer that uniquely identifies this connection. + It can be used by shutdown_connection() to terminate this connection. + ensures + - when the iostreams hit EOF on_connect() will terminate. + (because this is how clear() signals you the server is shutting down) + - this function will not call clear() + throws + - does not throw any exceptions + !*/ + + }; + +} + +#endif // DLIB_SERVER_IOSTREAm_ABSTRACT_ + + diff --git a/dlib/server/server_kernel_1.h b/dlib/server/server_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..81e8d5d8b70545dc6f5fb05fa894a326e6970fc6 --- /dev/null +++ b/dlib/server/server_kernel_1.h @@ -0,0 +1,699 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SERVER_KERNEL_1_ +#define DLIB_SERVER_KERNEL_1_ + +#include "server_kernel_abstract.h" + +// non-templatable dependencies +#include "../threads.h" +#include "../sockets.h" +#include +#include "../algs.h" +#include "../logger.h" + + +namespace dlib +{ + + + template < + typename set_of_connections + > + class server_kernel_1 + { + + /*! + REQUIREMENTS ON set_of_connections + implements set/set_kernel_abstract.h or hash_set/hash_set_kernel_abstract.h + and is a set/hash_set of dlib::connection* + + + INITIAL VALUE + listening_port == 0 + listening_ip == "" + running == false + shutting_down == false + cons.size() == 0 + listening_port_mutex == a mutex + listening_ip_mutex == a mutex + running_mutex == a mutex + running_signaler == a signaler associated with running_mutex + shutting_down_mutex == a mutex + cons_mutex == a mutex + thread_count == 0 + thread_count_mutex == a mutex + thread_count_signaler == a signaler associated with thread_count_mutex + thread_count_zero == a signaler associated with thread_count_mutex + max_connections == 0 + max_connections_mutex == a mutex for max_connections + + CONVENTION + listening_port == get_listening_port() + listening_ip == get_listening_ip() + running == is_running() + shutting_down == true while clear() is running. this + bool is used to tell the thread blocked on + accept that it should terminate + cons == a set containing all open connections + listening_port_mutex == a mutex for listening_port + listening_ip_mutex == a mutex for listening_ip + running_mutex == a mutex for running + running_signaler == a signaler for running and + is associated with running_mutex. it is + used to signal when running is false + shutting_down_mutex == a mutex for shutting_down + cons_mutex == a mutex for cons + thread_count == the number of threads currently running + thread_count_mutex == a mutex for thread_count + thread_count_signaler == a signaler for thread_count and + is associated with thread_count_mutex. it + is used to signal when thread_count is + decremented + thread_count_zero == a signaler for thread_count and + is associated with thread_count_mutex. it + is used to signal when thread_count becomes + zero + max_connections == get_max_connections() + max_connections_mutex == a mutex for max_connections + !*/ + + + + // this structure is used to pass parameters to new threads + struct param + { + param ( + server_kernel_1& server_, + connection& new_connection_ + ) : + server(server_), + new_connection(new_connection_) + {} + + server_kernel_1& server; + connection& new_connection; + }; + + + + public: + + server_kernel_1( + ); + + virtual ~server_kernel_1( + ); + + void clear( + ); + + void start ( + ); + + bool is_running ( + ) const; + + const std::string get_listening_ip ( + ) const; + + int get_listening_port ( + ) const; + + void set_listening_port ( + int port + ); + + void set_listening_ip ( + const std::string& ip + ); + + void set_max_connections ( + int max + ); + + int get_max_connections ( + ) const; + + + private: + + virtual void on_connect ( + connection& new_connection + )=0; + + virtual void on_listening_port_assigned ( + ) {} + + const static logger sdlog; + + static void service_connection( + void* item + ); + /*! + requires + item is a pointer to a param struct + ensures + services the new connection + will take care of closing the connection and + adding the connection to cons when it first starts and + remove the connection from cons and signal that it has + done so when it ends + !*/ + + // data members + int listening_port; + std::string listening_ip; + bool running; + bool shutting_down; + set_of_connections cons; + mutex listening_port_mutex; + mutex listening_ip_mutex; + mutex running_mutex; + signaler running_signaler; + mutex shutting_down_mutex; + mutex cons_mutex; + int thread_count; + mutex thread_count_mutex; + signaler thread_count_signaler; + int max_connections; + mutex max_connections_mutex; + signaler thread_count_zero; + + + // restricted functions + server_kernel_1(server_kernel_1&); + server_kernel_1& operator= ( + server_kernel_1& + ); + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + server_kernel_1:: + server_kernel_1 ( + ) : + listening_port(0), + running(false), + shutting_down(false), + running_signaler(running_mutex), + thread_count(0), + thread_count_signaler(thread_count_mutex), + max_connections(0), + thread_count_zero(thread_count_mutex) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + server_kernel_1:: + ~server_kernel_1 ( + ) + { + clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + int server_kernel_1:: + get_max_connections ( + ) const + { + max_connections_mutex.lock(); + int temp = max_connections; + max_connections_mutex.unlock(); + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + set_max_connections ( + int max + ) + { + max_connections_mutex.lock(); + max_connections = max; + max_connections_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + clear ( + ) + { + // signal that we are shutting down + shutting_down_mutex.lock(); + shutting_down = true; + shutting_down_mutex.unlock(); + + + + max_connections_mutex.lock(); + listening_port_mutex.lock(); + listening_ip_mutex.lock(); + listening_ip = ""; + listening_port = 0; + max_connections = 0; + listening_port_mutex.unlock(); + listening_ip_mutex.unlock(); + max_connections_mutex.unlock(); + + + // tell all the connections to shut down + cons_mutex.lock(); + connection* temp; + while (cons.size() > 0) + { + cons.remove_any(temp); + temp->shutdown(); + } + cons_mutex.unlock(); + + + // wait for all the connections to shut down + thread_count_mutex.lock(); + while (thread_count > 0) + { + thread_count_zero.wait(); + } + thread_count_mutex.unlock(); + + + + + // wait for the listener to close + running_mutex.lock(); + while (running == true) + { + running_signaler.wait(); + } + running_mutex.unlock(); + + + + // signal that the shutdown is complete + shutting_down_mutex.lock(); + shutting_down = false; + shutting_down_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + start ( + ) + { + + listener* sock; + int status = create_listener(sock,listening_port,listening_ip); + + // if there was an error then clear this object + if (status < 0) + { + max_connections_mutex.lock(); + listening_port_mutex.lock(); + listening_ip_mutex.lock(); + listening_ip = ""; + listening_port = 0; + max_connections = 0; + listening_port_mutex.unlock(); + listening_ip_mutex.unlock(); + max_connections_mutex.unlock(); + } + + + + // throw an exception for the error + if (status == PORTINUSE) + { + throw dlib::socket_error( + EPORT_IN_USE, + "error occurred in server_kernel_1::start()\nport already in use" + ); + } + else if (status == OTHER_ERROR) + { + throw dlib::socket_error( + EOTHER, + "error occurred in server_kernel_1::start()\nunable to crate listener" + ); + } + + running_mutex.lock(); + running = true; + running_mutex.unlock(); + + // determine the listening port + bool port_assigned = false; + listening_port_mutex.lock(); + if (listening_port == 0) + { + port_assigned = true; + listening_port = sock->get_listening_port(); + } + listening_port_mutex.unlock(); + if (port_assigned) + on_listening_port_assigned(); + + + + + connection* client; + bool exit = false; + while ( true ) + { + + + // accept the next connection + status = sock->accept(client,1000); + + + // if there was an error then quit the loop + if (status == OTHER_ERROR) + { + break; + } + + shutting_down_mutex.lock(); + // if we are shutting down then signal that we should quit the loop + exit = shutting_down; + shutting_down_mutex.unlock(); + + + // if we should be shutting down + if (exit) + { + // if a connection was opened then close it + if (status == 0) + delete client; + break; + } + + + + // if the accept timed out + if (status == TIMEOUT) + { + continue; + } + + + + + + // add this new connection to cons + cons_mutex.lock(); + connection* client_temp = client; + try{cons.add(client_temp);} + catch(...) + { + delete sock; + delete client; + cons_mutex.unlock(); + + // signal that we are not running start() anymore + running_mutex.lock(); + running = false; + running_signaler.broadcast(); + running_mutex.unlock(); + + + clear(); + throw; + } + cons_mutex.unlock(); + + + // make a param structure + param* temp; + try{ + temp = new param ( + *this, + *client + ); + } catch (...) + { + delete sock; + delete client; + running_mutex.lock(); + running = false; + running_signaler.broadcast(); + running_mutex.unlock(); + clear(); + throw; + } + + + // if create_new_thread failed + if (!create_new_thread(service_connection,temp)) + { + delete temp; + // close the listening socket + delete sock; + + // close the new connection and remove it from cons + cons_mutex.lock(); + connection* ctemp; + if (cons.is_member(client)) + { + cons.remove(client,ctemp); + } + delete client; + cons_mutex.unlock(); + + + // signal that the listener has closed + running_mutex.lock(); + running = false; + running_signaler.broadcast(); + running_mutex.unlock(); + + // make sure the object is cleared + clear(); + + // throw the exception + throw dlib::thread_error( + ECREATE_THREAD, + "error occurred in server_kernel_1::start()\nunable to start thread" + ); + } + // if we made the new thread then update thread_count + else + { + // increment the thread count + thread_count_mutex.lock(); + ++thread_count; + if (thread_count == 0) + thread_count_zero.broadcast(); + thread_count_mutex.unlock(); + } + + + + + // check if we have hit the maximum allowed number of connections + max_connections_mutex.lock(); + // if max_connections is zero or the loop is ending then skip this + if (max_connections != 0) + { + // wait for thread_count to be less than max_connections + thread_count_mutex.lock(); + while (thread_count >= max_connections) + { + max_connections_mutex.unlock(); + thread_count_signaler.wait(); + max_connections_mutex.lock(); + + // if we are shutting down the quit the loop + shutting_down_mutex.lock(); + exit = shutting_down; + shutting_down_mutex.unlock(); + if (exit) + break; + } + thread_count_mutex.unlock(); + } + max_connections_mutex.unlock(); + + if (exit) + { + break; + } + } //while ( true ) + + + // close the socket + delete sock; + + // signal that the listener has closed + running_mutex.lock(); + running = false; + running_signaler.broadcast(); + running_mutex.unlock(); + + // if there was an error with accept then throw an exception + if (status == OTHER_ERROR) + { + // make sure the object is cleared + clear(); + + // throw the exception + throw dlib::socket_error( + EOTHER, + "error occurred in server_kernel_1::start()\nlistening socket returned error" + ); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + bool server_kernel_1:: + is_running ( + ) const + { + running_mutex.lock(); + bool temp = running; + running_mutex.unlock(); + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + const std::string server_kernel_1:: + get_listening_ip ( + ) const + { + listening_ip_mutex.lock(); + std::string ip(listening_ip); + listening_ip_mutex.unlock(); + return ip; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + int server_kernel_1:: + get_listening_port ( + ) const + { + listening_port_mutex.lock(); + int port = listening_port; + listening_port_mutex.unlock(); + return port; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + set_listening_port ( + int port + ) + { + listening_port_mutex.lock(); + listening_port = port; + listening_port_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + set_listening_ip ( + const std::string& ip + ) + { + listening_ip_mutex.lock(); + listening_ip = ip; + listening_ip_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // static member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename soc + > + const logger server_kernel_1::sdlog("dlib.server"); + + template < + typename soc + > + void server_kernel_1:: + service_connection( + void* item + ) + { + param& p = *reinterpret_cast(item); + + + p.server.on_connect(p.new_connection); + + + // remove this connection from cons and close it + p.server.cons_mutex.lock(); + connection* temp; + if (p.server.cons.is_member(&p.new_connection)) + p.server.cons.remove(&p.new_connection,temp); + try{ close_gracefully(&p.new_connection); } + catch (...) { sdlog << LERROR << "close_gracefully() threw"; } + p.server.cons_mutex.unlock(); + + // decrement the thread count and signal if it is now zero + p.server.thread_count_mutex.lock(); + --p.server.thread_count; + p.server.thread_count_signaler.broadcast(); + if (p.server.thread_count == 0) + p.server.thread_count_zero.broadcast(); + p.server.thread_count_mutex.unlock(); + + delete &p; + + + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SERVER_KERNEL_1_ + diff --git a/dlib/server/server_kernel_abstract.h b/dlib/server/server_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..e23ed428afbbddcf0b7a26babebbdf81c3f1cc29 --- /dev/null +++ b/dlib/server/server_kernel_abstract.h @@ -0,0 +1,264 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SERVER_KERNEL_ABSTRACT_ +#ifdef DLIB_SERVER_KERNEL_ABSTRACT_ + +// non-templatable dependencies +#include "../threads/threads_kernel_abstract.h" +#include "../sockets/sockets_kernel_abstract.h" +#include + + +namespace dlib +{ + + + class server + { + + /*! + INITIAL VALUE + get_listening_ip() == "" + get_listening_port() == 0 + is_running() == false + get_max_connections() == 0 + + + CALLBACK FUNCTIONS + on_connect(): + To use this object inherit from it and define the pure virtual function + on_connect. Inside this function is where you will handle each new + connection. Note that the connection object passed to on_connect() should + NOT be closed, just let the function end and it will be gracefully closed + for you. Also note that each call to on_connect() is run in its own + thread. Also note that on_connect() should NOT throw any exceptions, + all exceptions must be dealt with inside on_connect() and cannot be + allowed to leave. + + on_listening_port_assigned(): + This function is called to let the client know that the operating + system has assigned a port number to the listening port. This + happens if a port number of zero was given. Note that this + function does not need to be defined. If you don't care then + don't define it and it will do nothing. Note also that this function + is NOT called in its own thread. Thus, making it block might hang the + server. + + WHAT THIS OBJECT REPRESENTS + This object represents a server that listens on a port and spawns new + threads to handle each new connection. + + Note that the clear() function does not return until all calls to + on_connect() have finished and the start() function has been shutdown. + Also note that when clear() is called all open connection objects + will be shutdown(). + + A note about get_max_connections(). When the maximum number of + connections has been reached accept() will simply not be called + until the number of open connections drops below get_max_connections() + + THREAD SAFETY + All member functions are thread-safe. + !*/ + + public: + + server( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~server( + ); + /*! + requires + - is not called from any of server's callbacks + ensures + - all resources associated with *this have been released + !*/ + + void clear( + ); + /*! + requires + - is not called from any of server's callbacks + ensures + - #*this has its initial value + - all open connection objects passed to on_connect() are shutdown() + - blocks until all calls to on_connect() have finished + - blocks until the start() function has released all its resources + throws + - std::bad_alloc + if this exception is thrown then the server object is unusable + until clear() is called and succeeds + !*/ + + void start ( + ); + /*! + requires + - is_running() == false + ensures + - starts listening on the port and ip specified by get_listening_ip() + and #get_listening_port() for new connections. + - if (get_listening_port() == 0) then + - a port to listen on will be automatically selected + - #get_listening_port() == the selected port being used + - if (get_listening_ip() == "" ) then + - all local IPs will be listened on + - blocks until clear() is called or an error occurs + throws + - dlib::socket_error + start() will throw this exception if there is some problem binding + ports and/or starting the server or if there is a problem + accepting new connections while it's running. + If this happens then + - All open connection objects passed to on_connect() are shutdown() + and the exception will not be thrown until all on_connect() calls + have terminated. + - The server will be cleared and returned to its initial value. + - dlib::thread_error + start() will throw this exception if there is a problem + creating new threads. Or it may throw this exception if there + is a problem creating threading objects. + If this happens then + - All open connection objects passed to on_connect() are shutdown() + and the exception will not be thrown until all on_connect() calls + have terminated. + - The server will be cleared and returned to its initial value. + - std::bad_alloc + start() may throw this exception and if it does then the object + will be unusable until clear() is called and succeeds + !*/ + + bool is_running ( + ) const; + /*! + ensures + - returns true if start() is running + - returns false if start() is not running or has released all + its resources and is about to terminate + throws + - std::bad_alloc + !*/ + + int get_max_connections ( + ) const; + /*! + ensures + - returns the maximum number of connections the server will accept + at a time + - returns 0 if the server will accept any number of connections + throws + - std::bad_alloc + !*/ + + + const std::string get_listening_ip ( + ) const; + /*! + ensures + - returns the local ip to listen for new connections on + - returns "" if ALL local ips are to be listened on + throws + - std::bad_alloc + !*/ + + int get_listening_port ( + ) const; + /*! + ensures + - returns the local port number to listen for new connections on + - returns 0 if the local port number has not yet been set + throws + - std::bad_alloc + !*/ + + void set_listening_port ( + int port + ); + /*! + requires + - port >= 0 + - is_running() == false + ensures + - #get_listening_port() == port + throws + - std::bad_alloc + !*/ + + void set_listening_ip ( + const std::string& ip + ); + /*! + requires + - ip is of the form #.#.#.# (dotted quad notation) or ip == "" + - is_running() == false + ensures + - #get_listening_ip() == ip + throws + - std::bad_alloc + !*/ + + void set_max_connections ( + int max + ); + /*! + requires + - max >= 0 + ensures + - #get_max_connections() == max + throws + - std::bad_alloc + !*/ + + + + private: + + virtual void on_connect ( + connection& new_connection + )=0; + /*! + requires + - on_connect() is run in its own thread + - is_running() == true + - the number of current connections < get_max_connection() + - new_connection == the new connection to the server which is + to be serviced by this call to on_connect() + ensures + - when new_connection is shutdown() on_connect() will terminate + - this function will not call clear() + throws + - does not throw any exceptions + !*/ + + // do nothing by default + virtual void on_listening_port_assigned ( + ) {} + /*! + requires + - is called if a listening port of zero was specified and + an actual port number has just been assigned to the server + ensures + - this function will not block + - this function will not call clear() + throws + - does not throw any exceptions + !*/ + + + // restricted functions + server(server&); // copy constructor + server& operator=(server&); // assignment operator + }; + +} + +#endif // DLIB_SERVER_KERNEL_ABSTRACT_ + diff --git a/dlib/server/server_kernel_c.h b/dlib/server/server_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..1d8a433dcd81428e243360e44e27930beeab438e --- /dev/null +++ b/dlib/server/server_kernel_c.h @@ -0,0 +1,193 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SERVER_KERNEl_C_ +#define DLIB_SERVER_KERNEl_C_ + +#include "server_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include +#include + +namespace dlib +{ + + + template < + typename server_base + > + class server_kernel_c : public server_base + { + + public: + + void start ( + ); + + + void set_listening_port ( + int port + ); + + void set_listening_ip ( + const std::string& ip + ); + + void set_max_connections ( + int max + ); + + private: + bool is_dotted_quad ( + std::string ip + ) const; + /*! + ensures + returns true if ip is a valid dotted quad ip address else + returns false + !*/ + + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename server_base + > + void server_kernel_c:: + start ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( + this->is_running() == false, + "\tvoid server::start" + << "\n\tis_running() == " << this->is_running() + << "\n\tthis: " << this + ); + + // call the real function + server_base::start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename server_base + > + void server_kernel_c:: + set_max_connections ( + int max + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( + max >= 0 , + "\tvoid server::set_max_connections" + << "\n\tmax == " << max + << "\n\tthis: " << this + ); + + // call the real function + server_base::set_max_connections(max); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename server_base + > + void server_kernel_c:: + set_listening_port ( + int port + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( + ( port >= 0 && + this->is_running() == false ), + "\tvoid server::set_listening_port" + << "\n\tport == " << port + << "\n\tis_running() == " << this->is_running() + << "\n\tthis: " << this + ); + + // call the real function + server_base::set_listening_port(port); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename server_base + > + void server_kernel_c:: + set_listening_ip ( + const std::string& ip + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( + ( ( is_dotted_quad(ip) || ip == "" ) && + this->is_running() == false ), + "\tvoid server::set_listening_ip" + << "\n\tip == " << ip + << "\n\tis_running() == " << this->is_running() + << "\n\tthis: " << this + ); + + // call the real function + server_base::set_listening_ip(ip); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename server_base + > + bool server_kernel_c:: + is_dotted_quad ( + std::string ip + ) const + { + + int num; + char dot; + std::istringstream sin(ip); + + for (int i = 0; i < 3; ++i) + { + sin >> num; if (!sin) return false; + if (num < 0 || num > 255) + return false; + + sin >> dot; if (!sin) return false; + if (dot != '.') + return false; + } + + sin >> num; if (!sin) return false; + if (num < 0 || num > 255) + return false; + + if (sin.get() != EOF) + return false; + + return true; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SERVER_KERNEl_C_ + diff --git a/dlib/set.h b/dlib/set.h new file mode 100644 index 0000000000000000000000000000000000000000..7c606342bfcc5f9ac2547ec2f2ccbf64029d6736 --- /dev/null +++ b/dlib/set.h @@ -0,0 +1,74 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SEt_ +#define DLIB_SEt_ + +#include "set/set_kernel_1.h" +#include "set/set_kernel_c.h" + + + +#include "binary_search_tree.h" + +#include "set/set_compare_1.h" + +#include "memory_manager.h" +#include + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class set + { + set() {} + + + + + + typedef typename binary_search_tree::kernel_1a + binary_search_tree_1; + + typedef typename binary_search_tree::kernel_2a + binary_search_tree_2; + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef set_kernel_1 + kernel_1a; + typedef set_kernel_c + kernel_1a_c; + + // kernel_1b + typedef set_kernel_1 + kernel_1b; + typedef set_kernel_c + kernel_1b_c; + + + //---------- extensions ------------ + + // compare extensions + typedef set_compare_1 + compare_1a; + typedef set_compare_1 + compare_1a_c; + + typedef set_compare_1 + compare_1b; + typedef set_compare_1 + compare_1b_c; + + }; +} + +#endif // DLIB_SEt_ + diff --git a/dlib/set/set_compare_1.h b/dlib/set/set_compare_1.h new file mode 100644 index 0000000000000000000000000000000000000000..0d84987d72828b719e071b45c185ad6060d7fa6f --- /dev/null +++ b/dlib/set/set_compare_1.h @@ -0,0 +1,122 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SET_COMPARe_1_ +#define DLIB_SET_COMPARe_1_ + +#include "set_compare_abstract.h" + +#include "../algs.h" + + + +namespace dlib +{ + + template < + typename set_base + > + class set_compare_1 : public set_base + { + + public: + + bool operator< ( + const set_compare_1& rhs + ) const; + + bool operator== ( + const set_compare_1& rhs + ) const; + + }; + + + template < + typename set_base + > + inline void swap ( + set_compare_1& a, + set_compare_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + bool set_compare_1:: + operator< ( + const set_compare_1& rhs + ) const + { + bool result = false; + if (set_base::size() < rhs.size()) + result = true; + + if (set_base::size() == rhs.size()) + { + rhs.reset(); + set_base::reset(); + while (rhs.move_next()) + { + set_base::move_next(); + if (set_base::element() < rhs.element()) + { + result = true; + break; + } + else if (rhs.element() < set_base::element()) + { + break; + } + } + } + + set_base::reset(); + rhs.reset(); + + return result; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + bool set_compare_1:: + operator== ( + const set_compare_1& rhs + ) const + { + bool result = true; + if (set_base::size() != rhs.size()) + result = false; + + + rhs.reset(); + set_base::reset(); + while (rhs.move_next() && set_base::move_next()) + { + if (!(rhs.element() == set_base::element())) + { + result = false; + break; + } + } + + set_base::reset(); + rhs.reset(); + + return result; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SET_COMPARe_1_ + diff --git a/dlib/set/set_compare_abstract.h b/dlib/set/set_compare_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..a7bbc8480d4329b81920c89b7249c9e14b4a5a84 --- /dev/null +++ b/dlib/set/set_compare_abstract.h @@ -0,0 +1,93 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SET_COMPARe_ABSTRACT_ +#ifdef DLIB_SET_COMPARe_ABSTRACT_ + +#include "set_kernel_abstract.h" + +#include "../algs.h" + + +namespace dlib +{ + + template < + typename set_base + > + class set_compare : public set_base + { + + /*! + REQUIREMENTS ON set_base + must be an implementation of set/set_kernel_abstract.h + + POINTERS AND REFERENCES TO INTERNAL DATA + operator== and operator< invalidate pointers or references to + data members. + + WHAT THIS EXTENSION DOES FOR set + This gives a set the ability to compare itself to other + sets using the < and == operators. + + The < operator is conceptually weird for sets. It is useful + though because it allows you to make sets of sets since + sets require that their containing type implement operator<. + + Also note that it is the case that for any two sets a and b + if (a rhs.size()) then + - returns false + - else + - returns true if there exists an integer j such that 0 <= j < size() + and for all integers i such that 0 <= i < j where it is true that + (*this)[i] == rhs[i] and (*this)[j] < rhs[j] + - returns false if there is no j that will satisfy the above conditions. + !*/ + + bool operator== ( + const set_compare& rhs + ) const; + /*! + ensures + - #at_start() == true + - returns true if *this and rhs contain the same elements. + returns false otherwise. + !*/ + }; + + + template < + typename set_base + > + inline void swap ( + set_compare& a, + set_compare& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_SET_COMPARe_ABSTRACT_ + diff --git a/dlib/set/set_kernel_1.h b/dlib/set/set_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..b06a183f6f4e434842f6ff1f97252f727ab1d87e --- /dev/null +++ b/dlib/set/set_kernel_1.h @@ -0,0 +1,373 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SET_KERNEl_1_ +#define DLIB_SET_KERNEl_1_ + +#include "set_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename bst_base, + typename mem_manager = memory_manager::kernel_1a + > + class set_kernel_1 : public enumerable, + public asc_remover + { + + /*! + REQUIREMENTS ON bst_base + bst_base is instantiated with and + implements binray_search_tree/binary_search_tree_kernel_abstract.h + + INITIAL VALUE + bst has its initial value + + CONVENTION + bst.size() == the number of elements in the set and + the elements in the set are stored in bst + !*/ + + + public: + + typedef T type; + typedef typename bst_base::compare_type compare_type; + typedef mem_manager mem_manager_type; + + set_kernel_1( + ) + { + } + + virtual ~set_kernel_1( + ) + {} + + inline void clear( + ); + + inline void add ( + T& item + ); + + inline bool is_member ( + const T& item + ) const; + + inline void remove ( + const T& item, + T& item_copy + ); + + inline void destroy ( + const T& item + ); + + inline void swap ( + set_kernel_1& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + inline bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + + inline const T& element ( + ); + + inline bool move_next ( + ) const; + + + private: + + bst_base bst; + char junk; + + // restricted functions + set_kernel_1(set_kernel_1&); + set_kernel_1& operator=(set_kernel_1&); + + }; + + template < + typename T, + typename bst_base, + typename mem_manager + > + inline void swap ( + set_kernel_1& a, + set_kernel_1& b + ) { a.swap(b); } + + template < + typename T, + typename bst_base, + typename mem_manager + > + void deserialize ( + set_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + item.add(temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type set_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + clear ( + ) + { + bst.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + add ( + T& item + ) + { + bst.add(item,junk); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + bool set_kernel_1:: + is_member( + const T& item + ) const + { + return (bst[item] != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + remove_any ( + T& item + ) + { + bst.remove_any(item,junk); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + remove( + const T& item, + T& item_copy + ) + { + bst.remove(item,item_copy,junk); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + destroy( + const T& item + ) + { + bst.destroy(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + unsigned long set_kernel_1:: + size ( + ) const + { + return bst.size(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + swap ( + set_kernel_1& item + ) + { + bst.swap(item.bst); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + bool set_kernel_1:: + at_start ( + ) const + { + return bst.at_start(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + void set_kernel_1:: + reset ( + ) const + { + bst.reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + bool set_kernel_1:: + current_element_valid ( + ) const + { + return bst.current_element_valid(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + const T& set_kernel_1:: + element ( + ) const + { + return bst.element().key(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + const T& set_kernel_1:: + element ( + ) + { + return bst.element().key(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename bst_base, + typename mem_manager + > + bool set_kernel_1:: + move_next ( + ) const + { + return bst.move_next(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SET_KERNEl_1_ + diff --git a/dlib/set/set_kernel_abstract.h b/dlib/set/set_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..8ec0bb12ce79b19476f3b39e5d3b5ed60e764249 --- /dev/null +++ b/dlib/set/set_kernel_abstract.h @@ -0,0 +1,192 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SET_KERNEl_ABSTRACT_ +#ifdef DLIB_SET_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" +#include + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a, + typename compare = std::less + > + class set : public enumerable, + public asc_remover + { + + /*! + REQUIREMENTS ON T + T must be comparable by compare where compare is a functor compatible with std::less and + T must be swappable by a global swap() and + T must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap() and is_member() functions do not invalidate pointers + or references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements in the set in + ascending order according to the compare functor. + (i.e. the elements are enumerated in sorted order) + + WHAT THIS OBJECT REPRESENTS + set contains items of type T + + This object represents an unaddressed collection of items. + Every element in a set is unique. + + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + public: + + typedef T type; + typedef compare compare_type; + typedef mem_manager mem_manager_type; + + set( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + virtual ~set( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void add ( + T& item + ); + /*! + requires + - is_member(item) == false + ensures + - #is_member(item) == true + - #item has an initial value for its type + - #size() == size() + 1 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + if add() throws then it has no effect + !*/ + + bool is_member ( + const T& item + ) const; + /*! + ensures + - returns whether or not there is an element in *this equivalent to + item + !*/ + + void remove ( + const T& item, + T& item_copy + ); + /*! + requires + - is_member(item) == true + - &item != &item_copy (i.e. item and item_copy cannot be the same + variable) + ensures + - #is_member(item) == false + - the element in *this equivalent to item has been removed and + swapped into #item_copy + - #size() == size() - 1 + - #at_start() == true + !*/ + + void destroy ( + const T& item + ); + /*! + requires + - is_member(item) == true + ensures + - #is_member(item) == false + - #size() == size() - 1 + - #at_start() == true + !*/ + + void swap ( + set& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + set(set&); // copy constructor + set& operator=(set&); // assignment operator + + }; + + template < + typename T, + typename mem_manager, + typename compare + > + inline void swap ( + set& a, + set& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename mem_manager, + typename compare + > + void deserialize ( + set& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_SET_KERNEl_ABSTRACT_ + diff --git a/dlib/set/set_kernel_c.h b/dlib/set/set_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..8075c15367ecb6d3dac0c3dc8f125d4038412230 --- /dev/null +++ b/dlib/set/set_kernel_c.h @@ -0,0 +1,194 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SET_KERNEl_C_ +#define DLIB_SET_KERNEl_C_ + +#include "set_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename set_base + > + class set_kernel_c : public set_base + { + typedef typename set_base::type T; + public: + + void add ( + T& item + ); + + void remove_any ( + T& item + ); + + void remove ( + const T& item, + T& item_copy + ); + + void destroy ( + const T& item + ); + + const T& element ( + ); + + const T& element ( + ) const; + }; + + + template < + typename set_base + > + inline void swap ( + set_kernel_c& a, + set_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + void set_kernel_c:: + add( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( !is_member(item), + "\tvoid set::add" + << "\n\titem being added must not already be in the set" + << "\n\tthis: " << this + ); + + // call the real function + set_base::add(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + void set_kernel_c:: + remove ( + const T& item, + T& item_copy + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_member(item) && + (reinterpret_cast(&item) != reinterpret_cast(&item_copy)), + "\tvoid set::remove" + << "\n\titem should be in the set if it's going to be removed" + << "\n\tthis: " << this + << "\n\t&item: " << &item + << "\n\t&item_copy: " << &item_copy + << "\n\tis_member(item): " << (is_member(item)?"true":"false") + ); + + // call the real function + set_base::remove(item,item_copy); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + void set_kernel_c:: + destroy ( + const T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( is_member(item), + "\tvoid set::destroy" + << "\n\titem should be in the set if it's going to be removed" + << "\n\tthis: " << this + << "\n\t&item: " << &item + ); + + // call the real function + set_base::destroy(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + void set_kernel_c:: + remove_any ( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->size() != 0, + "\tvoid set::remove_any" + << "\n\tsize must be greater than zero if an item is to be removed" + << "\n\tthis: " << this + ); + + // call the real function + set_base::remove_any(item); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + const typename set_base::type& set_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& set::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return set_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + const typename set_base::type& set_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& set::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return set_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + +} + +#endif // DLIB_SET_KERNEl_C_ + diff --git a/dlib/set_utils.h b/dlib/set_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..a60c21a19c4be66d5351a6544d0a6431cc14dd50 --- /dev/null +++ b/dlib/set_utils.h @@ -0,0 +1,11 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SET_UTILs_H_ +#define DLIB_SET_UTILs_H_ + +#include "set_utils/set_utils.h" + +#endif // DLIB_SET_UTILs_H_ + + + diff --git a/dlib/set_utils/set_utils.h b/dlib/set_utils/set_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..0a86132c16d498457f96174a735fa54545d3f8db --- /dev/null +++ b/dlib/set_utils/set_utils.h @@ -0,0 +1,267 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SET_UTILs_ +#define DLIB_SET_UTILs_ + +#include "../algs.h" +#include "set_utils_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace set_utils_helpers + { + template + inline bool is_same_object ( + const T& a, + const U& b + ) + { + if (is_same_type::value == false) + return false; + if ((void*)&a == (void*)&b) + return true; + else + return false; + } + } + + template < + typename T, + typename U + > + unsigned long set_intersection_size ( + const T& a, + const U& b + ) + { + using namespace set_utils_helpers; + if (is_same_object(a,b)) + return a.size(); + + unsigned long num = 0; + + if (a.size() < b.size()) + { + a.reset(); + while (a.move_next()) + { + if (b.is_member(a.element())) + ++num; + } + } + else + { + b.reset(); + while (b.move_next()) + { + if (a.is_member(b.element())) + ++num; + } + } + + return num; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U, + typename V + > + void set_union ( + const T& a, + const U& b, + V& u + ) + { + typedef typename T::type type; + using namespace set_utils_helpers; + if (is_same_object(a,u) || is_same_object(b,u)) + { + V local_u; + type temp; + a.reset(); + while (a.move_next()) + { + temp = a.element(); + local_u.add(temp); + } + + b.reset(); + while (b.move_next()) + { + if (a.is_member(b.element()) == false) + { + temp = b.element(); + local_u.add(temp); + } + } + + local_u.swap(u); + } + else + { + u.clear(); + + type temp; + a.reset(); + while (a.move_next()) + { + temp = a.element(); + u.add(temp); + } + + b.reset(); + while (b.move_next()) + { + if (a.is_member(b.element()) == false) + { + temp = b.element(); + u.add(temp); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U, + typename V + > + void set_intersection ( + const T& a, + const U& b, + V& i + ) + { + typedef typename T::type type; + using namespace set_utils_helpers; + if (is_same_object(a,i) || is_same_object(b,i)) + { + V local_i; + + type temp; + + if (a.size() < b.size()) + { + a.reset(); + while (a.move_next()) + { + if (b.is_member(a.element())) + { + temp = a.element(); + local_i.add(temp); + } + } + } + else + { + b.reset(); + while (b.move_next()) + { + if (a.is_member(b.element())) + { + temp = b.element(); + local_i.add(temp); + } + } + } + + local_i.swap(i); + } + else + { + i.clear(); + type temp; + + if (a.size() < b.size()) + { + a.reset(); + while (a.move_next()) + { + if (b.is_member(a.element())) + { + temp = a.element(); + i.add(temp); + } + } + } + else + { + b.reset(); + while (b.move_next()) + { + if (a.is_member(b.element())) + { + temp = b.element(); + i.add(temp); + } + } + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U, + typename V + > + void set_difference ( + const T& a, + const U& b, + V& d + ) + { + typedef typename T::type type; + using namespace set_utils_helpers; + if (is_same_object(a,d) || is_same_object(b,d)) + { + V local_d; + + type temp; + + a.reset(); + while (a.move_next()) + { + if (b.is_member(a.element()) == false) + { + temp = a.element(); + local_d.add(temp); + } + } + + local_d.swap(d); + } + else + { + d.clear(); + type temp; + + a.reset(); + while (a.move_next()) + { + if (b.is_member(a.element()) == false) + { + temp = a.element(); + d.add(temp); + } + } + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SET_UTILs_ + + + diff --git a/dlib/set_utils/set_utils_abstract.h b/dlib/set_utils/set_utils_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..785c5be5e4e3c3e18547989596305c90e04f41cd --- /dev/null +++ b/dlib/set_utils/set_utils_abstract.h @@ -0,0 +1,98 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SET_UTILs_ABSTRACT_ +#ifdef DLIB_SET_UTILs_ABSTRACT_ + +#include "../set.h" +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U + > + unsigned long set_intersection_size ( + const T& a, + const U& b + ); + /*! + requires + - T and U must both be implementations of set/set_kernel_abstract.h + ensures + - returns the number of elements that are in both set a and b + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U, + typename V + > + void set_union ( + const T& a, + const U& b, + V& u + ); + /*! + requires + - T, U, and V must all be implementations of set/set_kernel_abstract.h + - the types of objects contained in these sets must be copyable + ensures + - #u == the union of a and b. That is, u contains all elements + of a and all the elements of b. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U, + typename V + > + void set_intersection ( + const T& a, + const U& b, + V& i + ); + /*! + requires + - T, U, and V must all be implementations of set/set_kernel_abstract.h + - the types of objects contained in these sets must be copyable + ensures + - #i == the intersection of a and b. That is, i contains all elements + of a that are also in b. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U, + typename V + > + void set_difference ( + const T& a, + const U& b, + V& d + ); + /*! + requires + - T, U, and V must all be implementations of set/set_kernel_abstract.h + - the types of objects contained in these sets must be copyable + ensures + - #d == the difference of a and b. That is, d contains all elements + of a that are NOT in b. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SET_UTILs_ABSTRACT_ + + diff --git a/dlib/sliding_buffer.h b/dlib/sliding_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..241d61cdeb6ef7b90ba0f2f44f825a440e239009 --- /dev/null +++ b/dlib/sliding_buffer.h @@ -0,0 +1,37 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SLIDING_BUFFEr_ +#define DLIB_SLIDING_BUFFEr_ + + +#include "sliding_buffer/sliding_buffer_kernel_1.h" +#include "sliding_buffer/sliding_buffer_kernel_c.h" + + + +namespace dlib +{ + + template < + typename T + > + class sliding_buffer + { + + sliding_buffer() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef sliding_buffer_kernel_1 + kernel_1a; + typedef sliding_buffer_kernel_c + kernel_1a_c; + + + }; +} + +#endif // DLIB_SLIDING_BUFFEr_ + diff --git a/dlib/sliding_buffer/sliding_buffer_kernel_1.h b/dlib/sliding_buffer/sliding_buffer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..126fb8e640a16f2b1a10f19ec494623b13316f41 --- /dev/null +++ b/dlib/sliding_buffer/sliding_buffer_kernel_1.h @@ -0,0 +1,227 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SLIDING_BUFFER_KERNEl_1_ +#define DLIB_SLIDING_BUFFER_KERNEl_1_ + +#include "sliding_buffer_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../serialize.h" + +namespace dlib +{ + + template < + typename T + > + class sliding_buffer_kernel_1 : public enumerable + { + /*! + INITIAL VALUE + - buffer_size == 0 + - buffer == 0 + - buffer_start == 0 + - current == 0 + - at_start_ == true + + CONVENTION + - buffer_size == size() + + - element() == (*this)[current] + - current_element_valid() == (current < buffer_size) && at_start_ == false + - at_start() == at_start_ + + - if (buffer_size != 0) then + - buffer[(buffer_start+i)&(mask)] == operator[](i) + - mask == buffer_size-1 + - else + - buffer == 0 + - buffer_size == 0 + !*/ + + public: + + typedef T type; + + sliding_buffer_kernel_1 ( + ) : + buffer_start(0), + buffer_size(0), + buffer(0), + current(0), + at_start_(true) + {} + + virtual ~sliding_buffer_kernel_1 ( + ) { if (buffer) delete [] buffer; } + + void clear( + ) + { + buffer_size = 0; + if (buffer) delete [] buffer; + buffer = 0; + at_start_ = true; + current = 0; + } + + void set_size ( + unsigned long exp_size + ) + { + at_start_ = true; + if (buffer) delete [] buffer; + buffer_size = 1; + while (exp_size != 0) + { + --exp_size; + buffer_size <<= 1; + } + mask = buffer_size-1; + try { buffer = new T[buffer_size]; } + catch (...) { buffer = 0; buffer_size = 0; throw; } + } + + unsigned long size ( + ) const { return buffer_size; } + + void rotate_left ( + unsigned long amount + ) { buffer_start = ((buffer_start-amount)&mask); at_start_ = true; } + + void rotate_right ( + unsigned long amount + ) { buffer_start = ((buffer_start+amount)&mask); at_start_ = true;} + + const T& operator[] ( + unsigned long index + ) const { return buffer[(buffer_start+index)&mask]; } + + T& operator[] ( + unsigned long index + ) { return buffer[(buffer_start+index)&mask]; } + + unsigned long get_element_id( + unsigned long index + ) const { return ((buffer_start+index)&mask); } + + unsigned long get_element_index ( + unsigned long element_id + ) const { return ((element_id-buffer_start)&mask);} + + void swap ( + sliding_buffer_kernel_1& item + ) + { + exchange(buffer_start,item.buffer_start); + exchange(buffer_size,item.buffer_size); + exchange(buffer,item.buffer); + exchange(mask,item.mask); + exchange(current,item.current); + exchange(at_start_,item.at_start_); + } + + + bool at_start ( + ) const { return at_start_; } + + void reset ( + ) const { at_start_ = true; } + + bool current_element_valid ( + ) const { return (current < buffer_size) && (at_start_ == false); } + + const T& element ( + ) const { return (*this)[current]; } + + T& element ( + ) { return (*this)[current]; } + + bool move_next ( + ) const + { + if (at_start_ == false) + { + if (current+1 < buffer_size) + { + ++current; + return true; + } + else + { + current = buffer_size; + return false; + } + } + else + { + at_start_ = false; + current = 0; + return (buffer_size != 0); + } + } + + + private: + + // data members + unsigned long buffer_start; + unsigned long buffer_size; + T* buffer; + unsigned long mask; + + + mutable unsigned long current; + mutable bool at_start_; + + // restricted functions + sliding_buffer_kernel_1(sliding_buffer_kernel_1&); // copy constructor + sliding_buffer_kernel_1& operator=(sliding_buffer_kernel_1&); // assignment operator + + }; + + template < + typename T + > + inline void swap ( + sliding_buffer_kernel_1& a, + sliding_buffer_kernel_1& b + ) { a.swap(b); } + + template < + typename T + > + void deserialize ( + sliding_buffer_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + if (size > 0) + { + int count = 0; + while (size != 1) + { + size /= 2; + ++count; + } + item.set_size(count); + + for (unsigned long i = 0; i < item.size(); ++i) + deserialize(item[i],in); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type sliding_buffer_kernel_1"); + } + } +} + +#endif // DLIB_SLIDING_BUFFER_KERNEl_1_ + diff --git a/dlib/sliding_buffer/sliding_buffer_kernel_abstract.h b/dlib/sliding_buffer/sliding_buffer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b1390b371c2d6594e2e49c8a389b0725a7845490 --- /dev/null +++ b/dlib/sliding_buffer/sliding_buffer_kernel_abstract.h @@ -0,0 +1,202 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SLIDING_BUFFER_KERNEl_ABSTRACT_ +#ifdef DLIB_SLIDING_BUFFER_KERNEl_ABSTRACT_ + +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../serialize.h" + +namespace dlib +{ + + template < + typename T + > + class sliding_buffer : public enumerable + { + /*! + REQUIREMENTS ON T + T must have a default constructor + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements of the sliding_buffer in the + order (*this)[0], (*this)[1], (*this)[2], ... + + WHAT THIS OBJECT REPRESENTS + This object represents an array of T objects. The main + feature of this object is its ability to rotate its contents + left or right. An example will make it clear. + + suppose we have the following buffer (assuming T is a char): + "some data!" <-- the data in the buffer + 9876543210 <-- the index numbers associated with each character + + applying rotate_left(2) to this buffer would give us + "me data!so" + 9876543210 + + if instead of calling rotate_left we call rotate_right(3) instead we would have + "ta!some da" + 9876543210 + !*/ + + public: + + typedef T type; + + sliding_buffer ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor. + !*/ + + virtual ~sliding_buffer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor. + if this exception is thrown then #*this is unusable + until clear() is called and succeeds + !*/ + + void set_size ( + unsigned long exp_size + ); + /*! + requires + - 0 < expsize < 32 + ensures + - #size() == 2^expsize + - the value of all elements in the buffer are undefined + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor. + if this exception is thrown then #size() == 0 + !*/ + + void rotate_left ( + unsigned long amount + ); + /*! + ensures + - for all i where 0 <= i < size(): + (#*this)[i] == (*this)[(i-amount)&(size()-1)] + i.e. rotates the contents of *this left by amount spaces + - #at_start() == true + !*/ + + void rotate_right ( + unsigned long amount + ); + /*! + ensures + - for all i where 0 <= i < size(): + (#*this)[i] == (*this)[(i+amount)&(size()-1)] + i.e. rotates the contents of *this right by amount spaces + - #at_start() == true + !*/ + + unsigned long get_element_id ( + unsigned long index + ) const; + /*! + requires + - index < size() + ensures + - returns an element id number that uniquely references the element at + the given index. (you can use this id to locate the new position of + an element after the buffer has been rotated) + - returned value is < size() + !*/ + + unsigned long get_element_index ( + unsigned long element_id + ) const; + /*! + require + - element_id < size() + ensures + - returns the index of the element with the given element_id. + ( (*this)[get_element_index(element_id)] will always refer to the same element + no matter where it has been rotated to) + - returned value is < size() + !*/ + + const T& operator[] ( + unsigned long index + ) const; + /*! + requires + - index < size() + ensures + - returns a const reference to the element in *this at position index + !*/ + + T& operator[] ( + unsigned long index + ); + /*! + requires + - index < size() + ensures + - returns a reference to the element in *this at position index + !*/ + + void swap ( + sliding_buffer& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + sliding_buffer(sliding_buffer&); // copy constructor + sliding_buffer& operator=(sliding_buffer&); // assignment operator + + }; + + template < + typename T + > + void swap ( + sliding_buffer& a, + sliding_buffer& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T + > + void deserialize ( + sliding_buffer& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_SLIDING_BUFFER_KERNEl_ABSTRACT_ + diff --git a/dlib/sliding_buffer/sliding_buffer_kernel_c.h b/dlib/sliding_buffer/sliding_buffer_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..7dacb91fdf0c403d3d2df71021407cfc58c16b14 --- /dev/null +++ b/dlib/sliding_buffer/sliding_buffer_kernel_c.h @@ -0,0 +1,222 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SLIDING_BUFFER_KERNEl_C_ +#define DLIB_SLIDING_BUFFER_KERNEl_C_ + +#include "sliding_buffer_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include + +namespace dlib +{ + + template < + typename sb_base + > + class sliding_buffer_kernel_c : public sb_base + { + typedef typename sb_base::type T; + + public: + void set_size ( + unsigned long exp_size + ); + + const T& operator[] ( + unsigned long index + ) const; + + T& operator[] ( + unsigned long index + ); + + unsigned long get_element_id ( + unsigned long index + ) const; + + unsigned long get_element_index ( + unsigned long element_id + ) const; + + const T& element ( + ) const; + + T& element ( + ); + + + }; + + template < + typename sb_base + > + inline void swap ( + sliding_buffer_kernel_c& a, + sliding_buffer_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + void sliding_buffer_kernel_c:: + set_size ( + unsigned long exp_size + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( 0 < exp_size && exp_size < 32, + "\tvoid sliding_buffer::set_size(unsigned long)" + << "\n\texp_size must be some number between 1 and 31" + << "\n\tthis: " << this + << "\n\texp_size: " << exp_size + ); + + // call the real function + sb_base::set_size(exp_size); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + unsigned long sliding_buffer_kernel_c:: + get_element_id ( + unsigned long index + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( index < this->size(), + "\tunsigned long sliding_buffer::get_element_id(unsigned long) const" + << "\n\tindex must be in the range 0 to size()-1" + << "\n\tthis: " << this + << "\n\tsize(): " << this->size() + << "\n\tindex: " << index + ); + + // call the real function + return sb_base::get_element_id(index); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + unsigned long sliding_buffer_kernel_c:: + get_element_index ( + unsigned long element_id + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( element_id < this->size(), + "\tunsigned long sliding_buffer::get_element_index(unsigned long) const" + << "\n\tid must be in the range 0 to size()-1" + << "\n\tthis: " << this + << "\n\tsize(): " << this->size() + << "\n\tid: " << element_id + ); + + // call the real function + return sb_base::get_element_index(element_id); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + const typename sb_base::type& sliding_buffer_kernel_c:: + operator[] ( + unsigned long index + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( index < this->size(), + "\tconst T& sliding_buffer::operator[](unsigned long) const" + << "\n\tindex must be in the range 0 to size()-1" + << "\n\tthis: " << this + << "\n\tsize(): " << this->size() + << "\n\tindex: " << index + ); + + // call the real function + return sb_base::operator[](index); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + typename sb_base::type& sliding_buffer_kernel_c:: + operator[] ( + unsigned long index + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( index < this->size(), + "\tT& sliding_buffer::operator[](unsigned long)" + << "\n\tindex must be in the range 0 to size()-1" + << "\n\tthis: " << this + << "\n\tsize(): " << this->size() + << "\n\tindex: " << index + ); + + // call the real function + return sb_base::operator[](index); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + const typename sb_base::type& sliding_buffer_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& sliding_buffer::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return sb_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename sb_base + > + typename sb_base::type& sliding_buffer_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tT& sliding_buffer::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return sb_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SLIDING_BUFFER_KERNEl_C_ + diff --git a/dlib/smart_pointers.h b/dlib/smart_pointers.h new file mode 100644 index 0000000000000000000000000000000000000000..8b0de4112b399b7fbdbb6339f838ee955fd52f2d --- /dev/null +++ b/dlib/smart_pointers.h @@ -0,0 +1,12 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SMART_POINTERs_H_ +#define DLIB_SMART_POINTERs_H_ + +#include "smart_pointers/scoped_ptr.h" +#include "smart_pointers/shared_ptr.h" +#include "smart_pointers/weak_ptr.h" + +#endif // DLIB_SMART_POINTERs_H_ + + diff --git a/dlib/smart_pointers/scoped_ptr.h b/dlib/smart_pointers/scoped_ptr.h new file mode 100644 index 0000000000000000000000000000000000000000..833f07f207aed562949b1cff52061fcd1e3fc62c --- /dev/null +++ b/dlib/smart_pointers/scoped_ptr.h @@ -0,0 +1,99 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SCOPED_PTr_ +#define DLIB_SCOPED_PTr_ + +#include +#include "../noncopyable.h" +#include "../algs.h" +#include "scoped_ptr_abstract.h" + +namespace dlib +{ + + template + class scoped_ptr : noncopyable + { + /*! + CONVENTION + - get() == ptr + !*/ + + public: + typedef T element_type; + + explicit scoped_ptr ( + T* p = 0 + ) : ptr(p) { } + + ~scoped_ptr() { if (ptr) delete ptr; } + + void reset ( + T* p = 0 + ) + { + if (ptr) + delete ptr; + ptr = p; + } + + T& operator*() const + { + DLIB_ASSERT(get() != 0, + "\tscoped_ptr::operator*()" + << "\n\tget() can't be null if you are going to dereference it" + << "\n\tthis: " << this + ); + + return *ptr; + } + + T* operator->() const + { + DLIB_ASSERT(get() != 0, + "\tscoped_ptr::operator*()" + << "\n\tget() can't be null" + << "\n\tthis: " << this + ); + + return ptr; + } + + T* get() const + { + return ptr; + } + + operator bool() const + { + return (ptr != 0); + } + + void swap( + scoped_ptr& b + ) + { + std::swap(ptr,b.ptr); + } + + private: + + T* ptr; + }; + + template < + typename T + > + void swap( + scoped_ptr& a, + scoped_ptr& b + ) + { + a.swap(b); + } + +} + +#endif // DLIB_SCOPED_PTr_ + + diff --git a/dlib/smart_pointers/scoped_ptr_abstract.h b/dlib/smart_pointers/scoped_ptr_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..806a8a7019195f9f5aa0b5e90a4b9b4105ea02e0 --- /dev/null +++ b/dlib/smart_pointers/scoped_ptr_abstract.h @@ -0,0 +1,115 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SCOPED_PTr_ABSTRACT_ +#ifdef DLIB_SCOPED_PTr_ABSTRACT_ + +#include "../noncopyable.h" + +namespace dlib +{ + + template < + typename T + > + class scoped_ptr : noncopyable + { + /*! + INITIAL VALUE + defined by constructor + + WHAT THIS OBJECT REPRESENTS + This is a implementation of the scoped_ptr class found in the Boost C++ + library. It is a simple smart pointer class which guarantees that the + pointer contained within it will always be deleted. + + The class does not permit copying and so does not do any kind of + reference counting. Thus it is very simply and quite fast. + !*/ + + public: + typedef T element_type; + + explicit scoped_ptr ( + T* p = 0 + ); + /*! + ensures + - #get() == p + !*/ + + ~scoped_ptr( + ); + /*! + ensures + - if (get() != 0) then + - calls delete get() + !*/ + + void reset ( + T* p = 0 + ); + /*! + ensures + - if (get() != 0) then + - calls delete get() + - #get() == p + (i.e. makes this object contain a pointer to p instead of whatever it + used to contain) + !*/ + + T& operator*( + ) const; + /*! + requires + - get() != 0 + ensures + - returns a reference to *get() + !*/ + + T* operator->( + ) const; + /*! + requires + - get() != 0 + ensures + - returns the pointer contained in this object + !*/ + + T* get( + ) const; + /*! + ensures + - returns the pointer contained in this object + !*/ + + operator bool( + ) const; + /*! + ensures + - returns get() != 0 + !*/ + + void swap( + scoped_ptr& b + ); + /*! + ensures + - swaps *this and item + !*/ + }; + + template < + typename T + > + void swap( + scoped_ptr& a, + scoped_ptr& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ +} + +#endif // DLIB_SCOPED_PTr_ABSTRACT_ + + diff --git a/dlib/smart_pointers/shared_ptr.h b/dlib/smart_pointers/shared_ptr.h new file mode 100644 index 0000000000000000000000000000000000000000..7efe29207c6aca5e97f42c12656e41ba578f196c --- /dev/null +++ b/dlib/smart_pointers/shared_ptr.h @@ -0,0 +1,519 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SHARED_PTr_ +#define DLIB_SHARED_PTr_ + +#include +#include +#include +#include // for the exceptions +#include "../algs.h" +#include "shared_ptr_abstract.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class bad_weak_ptr: public std::exception {}; + +// ---------------------------------------------------------------------------------------- + + template class weak_ptr; + +// ---------------------------------------------------------------------------------------- + + struct shared_ptr_deleter + { + virtual void del(const void* p) = 0; + virtual ~shared_ptr_deleter() {} + + virtual void* get_deleter_void(const std::type_info& t) const = 0; + /*! + ensures + - if (the deleter in this object has typeid() == t) then + - returns a pointer to the deleter + - else + - return 0 + !*/ + }; + + struct shared_ptr_node; + struct weak_ptr_node + { + weak_ptr_node ( + shared_ptr_node* sn + ) : + ref_count(1), + shared_node(sn) + { + DLIB_ASSERT(sn != 0,""); + } + + long ref_count; + shared_ptr_node* shared_node; + }; + + struct shared_ptr_node + { + shared_ptr_node( + ) : + ref_count(1), + del(0), + weak_node(0) + {} + + long ref_count; + shared_ptr_deleter* del; + weak_ptr_node* weak_node; + }; + + struct shared_ptr_static_cast {}; + struct shared_ptr_const_cast {}; + struct shared_ptr_dynamic_cast {}; + +// ---------------------------------------------------------------------------------------- + + template + class shared_ptr + { + /*! + CONVENTION + - get() == data + - unique() == (shared_node != 0) && (shared_node->ref_count == 1) + - if (shared_node != 0) then + - use_count() == shared_node->ref_count + - get() == a valid pointer + - if (we are supposed to use the deleter) then + - shared_node->del == the deleter to use + - else + - shared_node->del == 0 + - else + - use_count() == 0 + - get() == 0 + + + - if (there are any weak_ptrs that reference this->data) then + - shared_node->weak_node->ref_count == the number of referencing weak_ptrs + - else + - shared_node->weak_node == 0 + !*/ + + template + struct deleter_template : public shared_ptr_deleter + { + deleter_template(const D& d_) : d(d_) {} + void del(const void* p) { d((T*)p); } + D d; + + void* get_deleter_void(const std::type_info& t) const + { + if (typeid(D) == t) + return (void*)&d; + else + return 0; + } + }; + + public: + + typedef T element_type; + + shared_ptr( + ) : data(0), shared_node(0) {} + + template + explicit shared_ptr( + Y* p + ) : data(p) + { + DLIB_ASSERT(p != 0, + "\tshared_ptr::shared_ptr(p)" + << "\n\tp can't be null" + << "\n\tthis: " << this + ); + try + { + shared_node = new shared_ptr_node; + } + catch (...) + { + delete p; + throw; + } + } + + template + shared_ptr( + Y* p, + const D& d + ) : + data(p) + { + DLIB_ASSERT(p != 0, + "\tshared_ptr::shared_ptr(p,d)" + << "\n\tp can't be null" + << "\n\tthis: " << this + ); + try + { + shared_node = 0; + shared_node = new shared_ptr_node; + shared_node->del = new deleter_template(d); + } + catch (...) + { + if (shared_node) delete shared_node; + d(p); + throw; + } + } + + ~shared_ptr() + { + if ( shared_node != 0) + { + if (shared_node->ref_count == 1) + { + // delete the data in the appropriate way + if (shared_node->del) + { + shared_node->del->del(data); + delete shared_node->del; + } + else + { + delete data; + } + + // notify any weak_ptrs that the data has now expired + if (shared_node->weak_node) + shared_node->weak_node->shared_node = 0; + + // finally delete the shared_node + delete shared_node; + } + else + { + shared_node->ref_count -= 1; + } + } + } + + shared_ptr( + const shared_ptr& r + ) + { + data = r.data; + shared_node = r.shared_node; + if (shared_node) + shared_node->ref_count += 1; + } + + template + shared_ptr( + const shared_ptr& r, + const shared_ptr_static_cast& + ) + { + data = static_cast(r.data); + if (data != 0) + { + shared_node = r.shared_node; + shared_node->ref_count += 1; + } + else + { + shared_node = 0; + } + } + + template + shared_ptr( + const shared_ptr& r, + const shared_ptr_const_cast& + ) + { + data = const_cast(r.data); + if (data != 0) + { + shared_node = r.shared_node; + shared_node->ref_count += 1; + } + else + { + shared_node = 0; + } + } + + template + shared_ptr( + const shared_ptr& r, + const shared_ptr_dynamic_cast& + ) + { + data = dynamic_cast(r.data); + if (data != 0) + { + shared_node = r.shared_node; + shared_node->ref_count += 1; + } + else + { + shared_node = 0; + } + } + + template + shared_ptr( + const shared_ptr& r + ) + { + data = r.data; + shared_node = r.shared_node; + if (shared_node) + shared_node->ref_count += 1; + } + + + template + explicit shared_ptr( + const weak_ptr& r + ) + { + if (r.expired()) + throw bad_weak_ptr(); + + data = r.data; + shared_node = r.weak_node->shared_node; + shared_node->ref_count += 1; + } + + template + explicit shared_ptr( + std::auto_ptr& r + ) + { + DLIB_ASSERT(r.get() != 0, + "\tshared_ptr::shared_ptr(auto_ptr r)" + << "\n\tr.get() can't be null" + << "\n\tthis: " << this + ); + shared_node = new shared_ptr_node; + data = r.release(); + } + + shared_ptr& operator= ( + const shared_ptr& r + ) + { + shared_ptr(r).swap(*this); + return *this; + } + + template + shared_ptr& operator= ( + const shared_ptr& r + ) + { + shared_ptr(r).swap(*this); + return *this; + } + + template + shared_ptr& operator= ( + std::auto_ptr& r + ) + { + DLIB_ASSERT(r.get() != 0, + "\tshared_ptr::operator=(auto_ptr r)" + << "\n\tr.get() can't be null" + << "\n\tthis: " << this + ); + + reset(); + shared_node = new shared_ptr_node; + data = r.release(); + return *this; + } + + void reset() + { + shared_ptr().swap(*this); + } + + template + void reset(Y* p) + { + DLIB_ASSERT(p != 0, + "\tshared_ptr::reset(p)" + << "\n\tp can't be null" + << "\n\tthis: " << this + ); + + shared_ptr(p).swap(*this); + } + + template + void reset( + Y* p, + const D& d + ) + { + DLIB_ASSERT(p != 0, + "\tshared_ptr::reset(p,d)" + << "\n\tp can't be null" + << "\n\tthis: " << this + ); + + shared_ptr(p,d).swap(*this); + } + + T& operator*( + ) const + { + DLIB_ASSERT(get() != 0, + "\tshared_ptr::operator*()" + << "\n\tget() can't be null if you are going to dereference it" + << "\n\tthis: " << this + ); + + return *data; + } + + T* operator->( + ) const + { + DLIB_ASSERT(get() != 0, + "\tshared_ptr::operator->()" + << "\n\tget() can't be null" + << "\n\tthis: " << this + ); + + return data; + } + + T* get() const { return data; } + + bool unique() const + { + return use_count() == 1; + } + + long use_count() const + { + if (shared_node != 0) + return shared_node->ref_count; + else + return 0; + } + + operator bool( + ) const { return get() != 0; } + + void swap(shared_ptr& b) + { + std::swap(data, b.data); + std::swap(shared_node, b.shared_node); + } + + template + D* _get_deleter( + ) const + { + if (shared_node && shared_node->del) + return static_cast(shared_node->del->get_deleter_void(typeid(D))); + else + return 0; + } + + template + bool _private_less ( + const shared_ptr& rhs + ) const + { + return shared_node < rhs.shared_node; + } + + private: + + template friend class shared_ptr; + template friend class weak_ptr; + + T* data; + shared_ptr_node* shared_node; + }; + +// ---------------------------------------------------------------------------------------- + + template + bool operator== ( + const shared_ptr& a, + const shared_ptr& b + ) { return a.get() == b.get(); } + + template + bool operator!= ( + const shared_ptr& a, + const shared_ptr& b + ) { return a.get() != b.get(); } + + template + bool operator< ( + const shared_ptr& a, + const shared_ptr& b + ) + { + return a._private_less(b); + } + + template + void swap( + shared_ptr& a, + shared_ptr& b + ) { a.swap(b); } + + template + shared_ptr static_pointer_cast( + const shared_ptr& r + ) + { + return shared_ptr(r, shared_ptr_static_cast()); + } + + template + shared_ptr const_pointer_cast( + shared_ptr const & r + ) + { + return shared_ptr(r, shared_ptr_const_cast()); + } + + template + shared_ptr dynamic_pointer_cast( + const shared_ptr& r + ) + { + return shared_ptr(r, shared_ptr_dynamic_cast()); + } + + template + std::basic_ostream & operator<< (std::basic_ostream & os, shared_ptr const & p) + { + os << p.get(); + return os; + } + + template + D* get_deleter(const shared_ptr& p) + { + return p.template _get_deleter(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SHARED_PTr_ + diff --git a/dlib/smart_pointers/shared_ptr_abstract.h b/dlib/smart_pointers/shared_ptr_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..9ad684f4fc06f0c25a1b972d62a4684020cba65e --- /dev/null +++ b/dlib/smart_pointers/shared_ptr_abstract.h @@ -0,0 +1,403 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SHARED_PTr_ABSTRACT_ +#ifdef DLIB_SHARED_PTr_ABSTRACT_ + +#include "weak_ptr_abstract.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class bad_weak_ptr: public std::exception {} + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class shared_ptr + { + /*! + INITIAL VALUE + defined by constructors + + WHAT THIS OBJECT REPRESENTS + This object represents a reference counted smart pointer. Each shared_ptr + contains a pointer to some object and when the last shared_ptr that points + to the object is destructed or reset() then the object is guaranteed to be + deleted. + + This is an implementation of the std::tr1::shared_ptr template from the + document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++ + Library Extensions. The only deviation from that document is that this + shared_ptr is declared inside the dlib namespace rather than std::tr1. + + THREAD SAFETY + This object is not thread safe. Especially so since it is + reference counted. So you should take care to not have two shared_ptr + objects in different threads that point to the same object. + !*/ + + public: + + typedef T element_type; + + shared_ptr( + ); + /*! + ensures + - #get() == 0 + - #use_count() == 0 + !*/ + + template + explicit shared_ptr( + Y* p + ); + /*! + requires + - p is convertible to a T* type pointer + - p can be deleted by calling "delete p;" and doing so will not throw exceptions + - p != 0 + ensures + - #get() == p + - #use_count() == 1 + - #*this object owns the pointer p + throws + - std::bad_alloc + if this exception is thrown then "delete p;" is called + !*/ + + template + shared_ptr( + Y* p, + const D& d + ); + /*! + requires + - p is convertible to a T* type pointer + - D is copy constructable (and the copy constructor of D doesn't throw) + - p can be deleted by calling "d(p);" and doing so will not throw exceptions + - p != 0 + ensures + - #get() == p + - #use_count() == 1 + - #*this object owns the pointer p + throws + - std::bad_alloc + if this exception is thrown then "d(p);" is called + !*/ + + shared_ptr( + const shared_ptr& r + ); + /*! + ensures + - #get() == #r.get() + - #use_count() == #r.use_count() + - If r is empty, constructs an empty shared_ptr object; otherwise, constructs + a shared_ptr object that shares ownership with r. + !*/ + + template + shared_ptr( + const shared_ptr& r + ); + /*! + requires + - Y* is convertible to T* + ensures + - #get() == #r.get() + - #use_count() == #r.use_count() + - If r is empty, constructs an empty shared_ptr object; otherwise, constructs + a shared_ptr object that shares ownership with r. + !*/ + + template + explicit shared_ptr( + const weak_ptr& r + ); + /*! + requires + - Y* is convertible to T* + ensures + - #get() == #r.get() + - #use_count() == #r.use_count() + - If r is empty, constructs an empty shared_ptr object; otherwise, constructs + a shared_ptr object that shares ownership with r. + throws + - bad_weak_ptr + this exception is thrown if r.expired() == true + !*/ + + template + explicit shared_ptr( + std::auto_ptr& r + ); + /*! + requires + - p.get() != 0 + - p.release() is convertible to a T* type pointer + - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions + ensures + - #get() == p.release() + - #use_count() == 1 + - #r.get() == 0 + - #*this object owns the pointer p.release() + throws + - std::bad_alloc + !*/ + + ~shared_ptr( + ); + /*! + ensures + - if (use_count() > 1) + - this object destroys itself but otherwise has no effect (i.e. + the pointer get() is still valid and shared between the remaining + shared_ptr objects) + - else if (use_count() == 1) + - deletes the pointer get() by calling delete (or using the deleter passed + to the constructor if one was passed in) + - else + - in this case get() == 0 so there is nothing to do so nothing occurs + !*/ + + shared_ptr& operator= ( + const shared_ptr& r + ); + /*! + ensures + - equivalent to shared_ptr(r).swap(*this). + - returns #*this + !*/ + + template + shared_ptr& operator= ( + const shared_ptr& r + ); + /*! + requires + - Y* is convertible to T* + ensures + - equivalent to shared_ptr(r).swap(*this). + - returns #*this + !*/ + + template + shared_ptr& operator= ( + std::auto_ptr& r + ); + /*! + requires + - p.get() != 0 + - p.release() is convertible to a T* type pointer + - p.release() can be deleted by calling "delete p.release();" and doing so will not throw exceptions + ensures + - equivalent to shared_ptr(r).swap(*this). + - returns #*this + !*/ + + void reset( + ); + /*! + ensures + - equivalent to shared_ptr().swap(*this) + !*/ + + template + void reset( + Y* p + ); + /*! + requires + - p is convertible to a T* type pointer + - p can be deleted by calling "delete p;" and doing so will not throw exceptions + - p != 0 + ensures + - equivalent to shared_ptr(p).swap(*this) + !*/ + + template + void reset( + Y* p, + const D& d + ); + /*! + requires + - p is convertible to a T* type pointer + - D is copy constructable (and the copy constructor of D doesn't throw) + - p can be deleted by calling "d(p);" and doing so will not throw exceptions + - p != 0 + ensures + - equivalent to shared_ptr(p,d).swap(*this) + !*/ + + T* get( + ) const; + /*! + ensures + - returns the stored pointer + !*/ + + T& operator*( + ) const; + /*! + requires + - get() != 0 + ensures + - returns a reference to *get() + !*/ + + T* operator->( + ) const; + /*! + requires + - get() != 0 + ensures + - returns get() + !*/ + + bool unique( + ) const; + /*! + ensures + - returns (use_count() == 1) + !*/ + + long use_count( + ) const; + /*! + ensures + - The number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this + is empty. + !*/ + + operator bool( + ) const; + /*! + ensures + - returns (get() != 0) + !*/ + + void swap( + shared_ptr& b + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + + template + bool operator== ( + const shared_ptr& a, + const shared_ptr& b + ); + /*! + ensures + - returns a.get() == b.get() + !*/ + + template + bool operator!= ( + const shared_ptr& a, + const shared_ptr& b + ) { return a.get() != b.get(); } + /*! + ensures + - returns a.get() != b.get() + !*/ + + template + bool operator< ( + const shared_ptr& a, + const shared_ptr& b + ); + /*! + ensures + - Defines an operator< on shared_ptr types appropriate for use in the associative + containers. + !*/ + + template + void swap( + shared_ptr& a, + shared_ptr& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template + shared_ptr static_pointer_cast( + const shared_ptr& r + ); + /*! + - if (r.get() == 0) then + - returns shared_ptr() + - else + - returns a shared_ptr object that stores static_cast(r.get()) and shares + ownership with r. + !*/ + + template + shared_ptr const_pointer_cast( + const shared_ptr& r + ); + /*! + - if (r.get() == 0) then + - returns shared_ptr() + - else + - returns a shared_ptr object that stores const_cast(r.get()) and shares + ownership with r. + !*/ + + template + shared_ptr dynamic_pointer_cast( + const shared_ptr& r + ); + /*! + ensures + - if (dynamic_cast(r.get()) returns a nonzero value) then + - returns a shared_ptr object that stores a copy of + dynamic_cast(r.get()) and shares ownership with r + - else + - returns an empty shared_ptr object. + !*/ + + template + std::basic_ostream & operator<< ( + std::basic_ostream & os, + const shared_ptr& p + ); + /*! + ensures + - performs os << p.get() + - returns os + !*/ + + template + D* get_deleter( + const shared_ptr& p + ); + /*! + ensures + - if (*this owns a deleter d of type cv-unqualified D) then + - returns &d + - else + - returns 0 + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SHARED_PTr_ABSTRACT_ + diff --git a/dlib/smart_pointers/weak_ptr.h b/dlib/smart_pointers/weak_ptr.h new file mode 100644 index 0000000000000000000000000000000000000000..9120bff3e8a57277d650c32fc0fd9a6a20db1b70 --- /dev/null +++ b/dlib/smart_pointers/weak_ptr.h @@ -0,0 +1,225 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_WEAK_PTr_ +#define DLIB_WEAK_PTr_ + +#include +#include +#include "shared_ptr.h" +#include "../algs.h" +#include "weak_ptr_abstract.h" + +namespace dlib { + + template < + typename T + > + class weak_ptr + { + + /*! + CONVENTION + - if (weak_node != 0) then + - data == valid pointer to shared data + - weak_node->ref_count == the number of weak_ptrs that reference this->data + - else + - data == 0 + + - expired() == ((weak_node == 0) || (weak_node->shared_node == 0)) + - if (expired() == false) then + - use_count() == weak_node->shared_node->ref_count + - else + - use_count() == 0 + !*/ + + public: + typedef T element_type; + + weak_ptr( + ) : data(0), weak_node(0) + { + } + + template + weak_ptr( + const shared_ptr& r + ) + { + data = r.data; + if (r.shared_node) + { + if (r.shared_node->weak_node) + { + weak_node = r.shared_node->weak_node; + weak_node->ref_count += 1; + } + else + { + weak_node = new weak_ptr_node(r.shared_node); + r.shared_node->weak_node = weak_node; + } + } + else + { + weak_node = 0; + } + } + + weak_ptr( + const weak_ptr& r + ) + { + data = r.data; + weak_node = r.weak_node; + if (weak_node) + weak_node->ref_count += 1; + } + + template + weak_ptr( + const weak_ptr& r + ) + { + data = r.data; + weak_node = r.weak_node; + if (weak_node) + weak_node->ref_count += 1; + } + + ~weak_ptr( + ) + { + if (weak_node) + { + // make note that this weak_ptr is being destroyed + weak_node->ref_count -= 1; + + // if this is the last weak_ptr then we should clean up our stuff + if (weak_node->ref_count == 0) + { + if (expired() == false) + weak_node->shared_node->weak_node = 0; + delete weak_node; + } + } + } + + weak_ptr& operator= ( + const weak_ptr& r + ) + { + weak_ptr(r).swap(*this); + return *this; + } + + template + weak_ptr& operator= ( + const weak_ptr& r + ) + { + weak_ptr(r).swap(*this); + return *this; + } + + template + weak_ptr& operator=( + const shared_ptr& r + ) + { + weak_ptr(r).swap(*this); + return *this; + } + + long use_count( + ) const + { + if (expired()) + return 0; + else + return weak_node->shared_node->ref_count; + } + + bool expired() const { return weak_node == 0 || weak_node->shared_node == 0; } + + shared_ptr lock( + ) const + { + if (expired()) + return shared_ptr(); + else + return shared_ptr(*this); + } + + void reset( + ) + { + weak_ptr().swap(*this); + } + + void swap( + weak_ptr& b + ) + { + std::swap(data, b.data); + std::swap(weak_node, b.weak_node); + } + + template + bool _private_less ( + const weak_ptr& rhs + ) const + { + if (expired()) + { + if (rhs.expired()) + { + return false; + } + else + { + return true; + } + } + else + { + if (rhs.expired()) + { + return false; + } + else + { + // in this case they have both not expired so lets + // compare the shared_node pointers + return (weak_node->shared_node) < (rhs.weak_node->shared_node); + } + } + } + + private: + + template friend class shared_ptr; + template friend class weak_ptr; + + T* data; + weak_ptr_node* weak_node; + }; + + template + bool operator< ( + const weak_ptr& a, + const weak_ptr& b + ) + { + return a._private_less(b); + } + + template + void swap( + weak_ptr& a, + weak_ptr & b + ) { a.swap(b); } +} + +#endif // DLIB_WEAK_PTr_ + + diff --git a/dlib/smart_pointers/weak_ptr_abstract.h b/dlib/smart_pointers/weak_ptr_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..12cd4ba1812c66402a20397608efb070ac293823 --- /dev/null +++ b/dlib/smart_pointers/weak_ptr_abstract.h @@ -0,0 +1,193 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_WEAK_PTr_ABSTRACT_ +#ifdef DLIB_WEAK_PTr_ABSTRACT_ + +#include "shared_ptr_abstract.h" + +namespace dlib { + + template < + typename T + > + class weak_ptr + { + + /*! + INITIAL VALUE + defined by constructor + + WHAT THIS OBJECT REPRESENTS + The weak_ptr class template stores a weak reference to an object that is + already managed by a shared_ptr. To access the object, a weak_ptr can + be converted to a shared_ptr using the member function lock(). + + This is an implementation of the std::tr1::weak_ptr template from the + document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++ + Library Extensions. The only deviation from that document is that this + shared_ptr is declared inside the dlib namespace rather than std::tr1. + !*/ + + public: + typedef T element_type; + + weak_ptr( + ); + /*! + ensures + - #use_count() == 0 + - creates an empty weak_ptr + !*/ + + template + weak_ptr( + const shared_ptr& r + ); + /*! + requires + - Y* must be convertible to T* + ensures + - if (r is empty) then + - constructs an empty weak_ptr object + - else + - constructs a weak_ptr object that shares ownership with r and + stores a copy of the pointer stored in r. + - #use_count() == #r.use_count() + !*/ + + weak_ptr( + const weak_ptr& r + ); + /*! + ensures + - if (r is empty) then + - constructs an empty weak_ptr object + - else + - constructs a weak_ptr object that shares ownership with r and + stores a copy of the pointer stored in r. + - #use_count() == #r.use_count() + !*/ + + template + weak_ptr( + const weak_ptr& r + ); + /*! + requires + - Y* must be convertible to T* + ensures + - if (r is empty) then + - constructs an empty weak_ptr object + - else + - constructs a weak_ptr object that shares ownership with r and + stores a copy of the pointer stored in r. + - #use_count() == #r.use_count() + !*/ + + ~weak_ptr( + ); + /*! + ensures + - destroys this weak_ptr object but has no effect on the object its + stored pointer points to. + !*/ + + weak_ptr& operator= ( + const weak_ptr& r + ); + /*! + ensures + - equivalent to weak_ptr(r).swap(*this) + !*/ + + template + weak_ptr& operator= ( + const weak_ptr& r + ); + /*! + requires + - Y* must be convertible to T* + ensures + - equivalent to weak_ptr(r).swap(*this) + !*/ + + template + weak_ptr& operator=( + const shared_ptr& r + ); + /*! + requires + - Y* must be convertible to T* + ensures + - equivalent to weak_ptr(r).swap(*this) + !*/ + + long use_count( + ) const; + /*! + ensures + - if (*this is empty) then + - returns 0 + - else + - returns the number of shared_ptr instances that share ownership + with *this + !*/ + + bool expired( + ) const; + /*! + ensures + - returns (use_count() == 0) + !*/ + + shared_ptr lock( + ) const; + /*! + ensures + - if (expired()) then + - returns shared_ptr() + - else + - returns shared_ptr(*this) + !*/ + + void reset( + ); + /*! + ensures + - equivalent to weak_ptr().swap(*this) + !*/ + + void swap( + weak_ptr& b + ); + /*! + ensures + - swaps *this and item + !*/ + + }; + + template + bool operator< ( + const weak_ptr& a, + const weak_ptr& b + ); + /*! + ensures + - Defines an operator< on shared_ptr types appropriate for use in the associative + containers. + !*/ + + template + void swap( + weak_ptr& a, + weak_ptr & b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ +} + +#endif // DLIB_WEAK_PTr_ABSTRACT_ + + diff --git a/dlib/sockets.h b/dlib/sockets.h new file mode 100644 index 0000000000000000000000000000000000000000..6dd6897e6f57b0a0fff1916c805ef6fa70914811 --- /dev/null +++ b/dlib/sockets.h @@ -0,0 +1,20 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETs_ +#define DLIB_SOCKETs_ + +#include "platform.h" + + +#ifdef WIN32 +#include "sockets/windows.h" +#endif + +#ifndef WIN32 +#include "sockets/posix.h" +#endif + +#include "sockets/sockets_extensions.h" + +#endif // DLIB_SOCKETs_ + diff --git a/dlib/sockets/posix.h b/dlib/sockets/posix.h new file mode 100644 index 0000000000000000000000000000000000000000..5fff80cde8b96cd19f034aa9b7c35c06cb5018a4 --- /dev/null +++ b/dlib/sockets/posix.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_KERNEl_1_ +#include "sockets_kernel_2.h" +#endif + diff --git a/dlib/sockets/sockets_extensions.cpp b/dlib/sockets/sockets_extensions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..705a0e20261d8d92c01335fa274d60c265af8ae1 --- /dev/null +++ b/dlib/sockets/sockets_extensions.cpp @@ -0,0 +1,234 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_EXTENSIONs_CPP +#define DLIB_SOCKETS_EXTENSIONs_CPP + +#include +#include +#include "../sockets.h" +#include "../error.h" +#include "sockets_extensions.h" +#include "../timer.h" +#include "../algs.h" +#include "../timeout.h" +#include "../misc_api.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + connection* connect ( + const std::string& host_or_ip, + unsigned short port + ) + { + std::string ip; + connection* con; + if (is_ip_address(host_or_ip)) + { + ip = host_or_ip; + } + else + { + if( hostname_to_ip(host_or_ip,ip)) + throw socket_error(ERESOLVE,"unable to resolve '" + host_or_ip + "' in connect()"); + } + + if(create_connection(con,port,ip)) + throw socket_error("unable to connect to '" + host_or_ip + "'"); + + return con; + } + +// ---------------------------------------------------------------------------------------- + + namespace connect_timeout_helpers + { + mutex connect_mutex; + signaler connect_signaler(connect_mutex); + timestamper ts; + long outstanding_connects = 0; + + struct thread_data + { + std::string host_or_ip; + unsigned short port; + connection* con; + bool connect_ended; + bool error_occurred; + }; + + void thread(void* param) + { + thread_data p = *static_cast(param); + try + { + p.con = connect(p.host_or_ip, p.port); + } + catch (...) + { + p.error_occurred = true; + } + + auto_mutex M(connect_mutex); + // report the results back to the connect() call that spawned this + // thread. + static_cast(param)->con = p.con; + static_cast(param)->error_occurred = p.error_occurred; + connect_signaler.broadcast(); + + // wait for the call to connect() that spawned this thread to terminate + // before we delete the thread_data struct. + while (static_cast(param)->connect_ended == false) + connect_signaler.wait(); + + connect_signaler.broadcast(); + --outstanding_connects; + delete static_cast(param); + } + } + + connection* connect ( + const std::string& host_or_ip, + unsigned short port, + unsigned long timeout + ) + { + using namespace connect_timeout_helpers; + + auto_mutex M(connect_mutex); + + const uint64 end_time = ts.get_timestamp() + timeout*1000; + + + // wait until there are less than 100 outstanding connections + while (outstanding_connects > 100) + { + uint64 cur_time = ts.get_timestamp(); + if (end_time > cur_time) + { + timeout = static_cast((end_time - cur_time)/1000); + } + else + { + throw socket_error("unable to connect to '" + host_or_ip + "' because connect timed out"); + } + + connect_signaler.wait_or_timeout(timeout); + } + + + thread_data* data = new thread_data; + data->host_or_ip = host_or_ip.c_str(); + data->port = port; + data->con = 0; + data->connect_ended = false; + data->error_occurred = false; + + + if (create_new_thread(thread, data) == false) + { + delete data; + throw socket_error("unable to connect to '" + host_or_ip); + } + + ++outstanding_connects; + + // wait until we have a connection object + while (data->con == 0) + { + uint64 cur_time = ts.get_timestamp(); + if (end_time > cur_time && data->error_occurred == false) + { + timeout = static_cast((end_time - cur_time)/1000); + } + else + { + // let the thread know that it should terminate + data->connect_ended = true; + connect_signaler.broadcast(); + if (data->error_occurred) + throw socket_error("unable to connect to '" + host_or_ip); + else + throw socket_error("unable to connect to '" + host_or_ip + "' because connect timed out"); + } + + connect_signaler.wait_or_timeout(timeout); + } + + // let the thread know that it should terminate + data->connect_ended = true; + connect_signaler.broadcast(); + return data->con; + } + +// ---------------------------------------------------------------------------------------- + + bool is_ip_address ( + std::string ip + ) + { + for (std::string::size_type i = 0; i < ip.size(); ++i) + { + if (ip[i] == '.') + ip[i] = ' '; + } + std::istringstream sin(ip); + + bool bad = false; + int num; + for (int i = 0; i < 4; ++i) + { + sin >> num; + if (!sin || num < 0 || num > 255) + { + bad = true; + break; + } + } + + if (sin.get() != EOF) + bad = true; + + return !bad; + } + +// ---------------------------------------------------------------------------------------- + + void close_gracefully ( + connection* con, + unsigned long timeout + ) + { + if(con->shutdown_outgoing()) + { + // there was an error so just close it now and return + delete con; + return; + } + + try + { + timeout::kernel_1a t(*con,&connection::shutdown,timeout); + + char junk[100]; + // wait for the other end to close their side + while (con->read(junk,sizeof(junk)) > 0); + } + catch (...) + { + delete con; + throw; + } + + delete con; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SOCKETS_EXTENSIONs_CPP + + diff --git a/dlib/sockets/sockets_extensions.h b/dlib/sockets/sockets_extensions.h new file mode 100644 index 0000000000000000000000000000000000000000..e52be3dfd5073dc14cca5cc1cb0f79f780633745 --- /dev/null +++ b/dlib/sockets/sockets_extensions.h @@ -0,0 +1,50 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_EXTENSIONs_ +#define DLIB_SOCKETS_EXTENSIONs_ + +#include +#include "../sockets.h" +#include "sockets_extensions_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + connection* connect ( + const std::string& host_or_ip, + unsigned short port + ); + +// ---------------------------------------------------------------------------------------- + + connection* connect ( + const std::string& host_or_ip, + unsigned short port, + unsigned long timeout + ); + +// ---------------------------------------------------------------------------------------- + + bool is_ip_address ( + std::string ip + ); + +// ---------------------------------------------------------------------------------------- + + void close_gracefully ( + connection* con, + unsigned long timeout = 500 + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "sockets_extensions.cpp" +#endif + +#endif // DLIB_SOCKETS_EXTENSIONs_ + diff --git a/dlib/sockets/sockets_extensions_abstract.h b/dlib/sockets/sockets_extensions_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..f8061216e0de2680ea8b6e85e1fdb10002af3169 --- /dev/null +++ b/dlib/sockets/sockets_extensions_abstract.h @@ -0,0 +1,95 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SOCKETS_EXTENSIONs_ABSTRACT_ +#ifdef DLIB_SOCKETS_EXTENSIONs_ABSTRACT_ + +#include +#include "sockets_kernel_abstract.h" +#include "../error.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + connection* connect ( + const std::string& host_or_ip, + unsigned short port + ); + /*! + ensures + - returns a connection object that is connected to the given host at the + given port + throws + - dlib::socket_error + This exception is thrown if there is some problem that prevents us from + creating the connection + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + + connection* connect ( + const std::string& host_or_ip, + unsigned short port, + unsigned long timeout + ); + /*! + ensures + - returns a connection object that is connected to the given host at the + given port. + - blocks for at most timeout milliseconds + throws + - dlib::socket_error + This exception is thrown if there is some problem that prevents us from + creating the connection or if timeout milliseconds elapses before + the connect is successful. + - std::bad_alloc + !*/ + +// ---------------------------------------------------------------------------------------- + + + bool is_ip_address ( + std::string ip + ); + /*! + ensures + - if (ip is a valid ip address) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + void close_gracefully ( + connection* con, + unsigned long timeout = 500 + ); + /*! + requires + - con == a valid pointer to a connection object + ensures + - performs a graceful close of the given connection and if it takes longer than + timeout milliseconds to complete then forces the connection closed. + - Specifically, a graceful close means that the outgoing part of con is + closed (a FIN is sent) and then we wait for the other end to to close their + end of the connection. This way any data still on its way to the other + end of the connection will be received properly. + - this function will block until the graceful close is completed or we timeout. + - calls "delete con;". Thus con is no longer a valid pointer after this function + has finished. + throws + - std::bad_alloc or dlib::thread_error + If either of these exceptions are thrown con will still be closed via + "delete con;" + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SOCKETS_EXTENSIONs_ABSTRACT_ + + diff --git a/dlib/sockets/sockets_kernel_1.cpp b/dlib/sockets/sockets_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6292767f10e5f4cbd7747b2a7ca4a72cea7d079 --- /dev/null +++ b/dlib/sockets/sockets_kernel_1.cpp @@ -0,0 +1,822 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_KERNEL_1_CPp_ +#define DLIB_SOCKETS_KERNEL_1_CPp_ +#include "../platform.h" + +#ifdef WIN32 + +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ +#endif + +#include "../windows_magic.h" + +#include "sockets_kernel_1.h" + +#include +#include + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif + + +// tell visual studio to link to the libraries we need if we are +// in fact using visual studio +#ifdef _MSC_VER +#pragma comment (lib, "ws2_32.lib") +#endif + +#include "../assert.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class SOCKET_container + { + /*! + This object is just a wrapper around the SOCKET type. It exists + so that we can #include the windows.h and Winsock2.h header files + in this cpp file and not at all in the header file. + !*/ + public: + SOCKET_container ( + SOCKET s = INVALID_SOCKET + ) : val(s) {} + + SOCKET val; + operator SOCKET&() { return val; } + + SOCKET_container& operator= ( + const SOCKET& s + ) { val = s; return *this; } + + bool operator== ( + const SOCKET& s + ) const { return s == val; } + }; + +// ---------------------------------------------------------------------------------------- +// stuff to ensure that WSAStartup() is always called before any sockets stuff is needed + + namespace sockets_kernel_1_mutex + { + mutex startup_lock; + } + + class sockets_startupdown + { + public: + sockets_startupdown(); + ~sockets_startupdown() { WSACleanup( ); } + + }; + sockets_startupdown::sockets_startupdown ( + ) + { + WSADATA wsaData; + WSAStartup (MAKEWORD(2,0), &wsaData); + } + + void sockets_startup() + { + // mutex crap to make this function thread-safe + sockets_kernel_1_mutex::startup_lock.lock(); + static sockets_startupdown a; + sockets_kernel_1_mutex::startup_lock.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + // lookup functions + + int + get_local_hostname ( + std::string& hostname + ) + { + // ensure that WSAStartup has been called and WSACleanup will eventually + // be called when program ends + sockets_startup(); + + try + { + + char temp[NI_MAXHOST]; + if (gethostname(temp,NI_MAXHOST) == SOCKET_ERROR ) + { + return OTHER_ERROR; + } + + hostname = temp; + } + catch (...) + { + return OTHER_ERROR; + } + + return 0; + } + +// ----------------- + + int + hostname_to_ip ( + const std::string& hostname, + std::string& ip, + int n + ) + { + // ensure that WSAStartup has been called and WSACleanup will eventually + // be called when program ends + sockets_startup(); + + try + { + + // if no hostname was given then return error + if ( hostname.empty()) + return OTHER_ERROR; + + hostent* address; + address = gethostbyname(hostname.c_str()); + + if (address == 0) + { + return OTHER_ERROR; + } + + // find the nth address + in_addr* addr = reinterpret_cast(address->h_addr_list[0]); + for (int i = 1; i <= n; ++i) + { + addr = reinterpret_cast(address->h_addr_list[i]); + + // if there is no nth address then return error + if (addr == 0) + return OTHER_ERROR; + } + + char* resolved_ip = inet_ntoa(*addr); + + // check if inet_ntoa returned an error + if (resolved_ip == NULL) + { + return OTHER_ERROR; + } + + ip.assign(resolved_ip); + + } + catch(...) + { + return OTHER_ERROR; + } + + return 0; + } + +// ----------------- + + int + ip_to_hostname ( + const std::string& ip, + std::string& hostname + ) + { + // ensure that WSAStartup has been called and WSACleanup will eventually + // be called when program ends + sockets_startup(); + + try + { + + // if no ip was given then return error + if (ip.empty()) + return OTHER_ERROR; + + hostent* address; + unsigned long ipnum = inet_addr(ip.c_str()); + + // if inet_addr coudln't convert ip then return an error + if (ipnum == INADDR_NONE) + { + return OTHER_ERROR; + } + address = gethostbyaddr(reinterpret_cast(&ipnum),4,AF_INET); + + // check if gethostbyaddr returned an error + if (address == 0) + { + return OTHER_ERROR; + } + hostname.assign(address->h_name); + + } + catch (...) + { + return OTHER_ERROR; + } + return 0; + + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // connection object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + connection:: + connection( + SOCKET_container sock, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port, + const std::string& local_ip + ) : + user_data(0), + connection_socket(*(new SOCKET_container())), + connection_foreign_port(foreign_port), + connection_foreign_ip(foreign_ip), + connection_local_port(local_port), + connection_local_ip(local_ip), + sd(false), + sdo(false), + sdr(0) + { + connection_socket = sock; + } + +// ---------------------------------------------------------------------------------------- + + connection:: + ~connection ( + ) + { + if (connection_socket != INVALID_SOCKET) + closesocket(connection_socket); + delete &connection_socket; + } + +// ---------------------------------------------------------------------------------------- + + long connection:: + write ( + const char* buf, + long num + ) + { + const long old_num = num; + long status; + while (num > 0) + { + if ( (status = send(connection_socket,buf,num,0)) == SOCKET_ERROR) + { + if (sdo_called()) + return SHUTDOWN; + else + return OTHER_ERROR; + } + num -= status; + buf += status; + } + return old_num; + } + +// ---------------------------------------------------------------------------------------- + + long connection:: + read ( + char* buf, + long num + ) + { + long status = recv(connection_socket,buf,num,0); + if (status == SOCKET_ERROR) + { + // if this error is the result of a shutdown call then return SHUTDOWN + if (sd_called()) + return SHUTDOWN; + else + return OTHER_ERROR; + } + else if (status == 0 && sd_called()) + { + return SHUTDOWN; + } + return status; + } + +// ---------------------------------------------------------------------------------------- + + int connection:: + shutdown_outgoing ( + ) + { + sd_mutex.lock(); + if (sdo || sd) + { + sd_mutex.unlock(); + return sdr; + } + sdo = true; + sdr = ::shutdown(connection_socket,SD_SEND); + + // convert -1 error code into the OTHER_ERROR error code + if (sdr == -1) + sdr = OTHER_ERROR; + + int temp = sdr; + + sd_mutex.unlock(); + return temp; + } + +// ---------------------------------------------------------------------------------------- + + int connection:: + shutdown ( + ) + { + sd_mutex.lock(); + if (sd) + { + sd_mutex.unlock(); + return sdr; + } + sd = true; + SOCKET stemp = connection_socket; + connection_socket = INVALID_SOCKET; + sdr = closesocket(stemp); + + // convert SOCKET_ERROR error code into the OTHER_ERROR error code + if (sdr == SOCKET_ERROR) + sdr = OTHER_ERROR; + + int temp = sdr; + + sd_mutex.unlock(); + return temp; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // listener object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + listener:: + listener( + SOCKET_container sock, + unsigned short port, + const std::string& ip + ) : + listening_socket(*(new SOCKET_container)), + listening_port(port), + listening_ip(ip), + inaddr_any(listening_ip.empty()) + { + listening_socket = sock; + } + +// ---------------------------------------------------------------------------------------- + + listener:: + ~listener ( + ) + { + closesocket(listening_socket); + delete &listening_socket; + } + +// ---------------------------------------------------------------------------------------- + + int listener:: + accept ( + connection*& new_connection, + unsigned long timeout + ) + { + SOCKET incoming; + sockaddr_in incomingAddr; + int length = sizeof(sockaddr_in); + + // implement timeout with select if timeout is > 0 + if (timeout > 0) + { + fd_set read_set; + // initialize read_set + FD_ZERO(&read_set); + + // add the listening socket to read_set + FD_SET(listening_socket, &read_set); + + // setup a timeval structure + timeval time_to_wait; + time_to_wait.tv_sec = static_cast(timeout/1000); + time_to_wait.tv_usec = static_cast((timeout%1000)*1000); + + + // wait on select + int status = select(0,&read_set,0,0,&time_to_wait); + + // if select timed out + if (status == 0) + return TIMEOUT; + + // if select returned an error + if (status == SOCKET_ERROR) + return OTHER_ERROR; + + } + + + // call accept to get a new connection + incoming=::accept(listening_socket,reinterpret_cast(&incomingAddr),&length); + + // if there was an error return OTHER_ERROR + if ( incoming == INVALID_SOCKET ) + return OTHER_ERROR; + + + // get the port of the foreign host into foreign_port + int foreign_port = ntohs(incomingAddr.sin_port); + + // get the IP of the foreign host into foreign_ip + std::string foreign_ip; + { + char* foreign_ip_temp = inet_ntoa(incomingAddr.sin_addr); + + // check if inet_ntoa() returned an error + if (foreign_ip_temp == NULL) + { + closesocket(incoming); + return OTHER_ERROR; + } + + foreign_ip.assign(foreign_ip_temp); + } + + + // get the local ip + std::string local_ip; + if (inaddr_any == true) + { + sockaddr_in local_info; + length = sizeof(sockaddr_in); + // get the local sockaddr_in structure associated with this new connection + if ( getsockname ( + incoming, + reinterpret_cast(&local_info), + &length + ) == SOCKET_ERROR + ) + { // an error occurred + closesocket(incoming); + return OTHER_ERROR; + } + char* temp = inet_ntoa(local_info.sin_addr); + + // check if inet_ntoa() returned an error + if (temp == NULL) + { + closesocket(incoming); + return OTHER_ERROR; + } + local_ip.assign(temp); + } + else + { + local_ip = listening_ip; + } + + + // set the SO_OOBINLINE option + int flag_value = 1; + if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int)) == SOCKET_ERROR ) + { + closesocket(incoming); + return OTHER_ERROR; + } + + + // make a new connection object for this new connection + try + { + new_connection = new connection ( + incoming, + foreign_port, + foreign_ip, + listening_port, + local_ip + ); + } + catch (...) { closesocket(incoming); return OTHER_ERROR; } + + return 0; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // socket creation functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + int + create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip + ) + { + // ensure that WSAStartup has been called and WSACleanup will eventually + // be called when program ends + sockets_startup(); + + sockaddr_in sa; // local socket structure + ZeroMemory(&sa,sizeof(sockaddr_in)); // initialize sa + + SOCKET sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket + + // if socket() returned an error then return OTHER_ERROR + if (sock == INVALID_SOCKET ) + { + return OTHER_ERROR; + } + + // set the local socket structure + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + if (ip.empty()) + { + // if the listener should listen on any IP + sa.sin_addr.S_un.S_addr = htons(INADDR_ANY); + } + else + { + // if there is a specific ip to listen on + sa.sin_addr.S_un.S_addr = inet_addr(ip.c_str()); + // if inet_addr cound't convert the ip then return an error + if ( sa.sin_addr.S_un.S_addr == INADDR_NONE ) + { + closesocket(sock); + return OTHER_ERROR; + } + } + + // set the SO_REUSEADDR option + int flag_value = 1; + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast(&flag_value),sizeof(int)); + + // bind the new socket to the requested port and ip + if (bind(sock,reinterpret_cast(&sa),sizeof(sockaddr_in))==SOCKET_ERROR) + { // if there was an error + closesocket(sock); + + // if the port is already bound then return PORTINUSE + if (WSAGetLastError() == WSAEADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + + // tell the new socket to listen + if ( listen(sock,SOMAXCONN) == SOCKET_ERROR) + { + // if there was an error return OTHER_ERROR + closesocket(sock); + + // if the port is already bound then return PORTINUSE + if (WSAGetLastError() == WSAEADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + // determine the port used if necessary + if (port == 0) + { + sockaddr_in local_info; + int length = sizeof(sockaddr_in); + if ( getsockname ( + sock, + reinterpret_cast(&local_info), + &length + ) == SOCKET_ERROR + ) + { + closesocket(sock); + return OTHER_ERROR; + } + port = ntohs(local_info.sin_port); + } + + + // initialize a listener object on the heap with the new socket + try { new_listener = new listener(sock,port,ip); } + catch(...) { closesocket(sock); return OTHER_ERROR; } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + + int + create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port, + const std::string& local_ip + ) + { + // ensure that WSAStartup has been called and WSACleanup + // will eventually be called when program ends + sockets_startup(); + + + sockaddr_in local_sa; // local socket structure + sockaddr_in foreign_sa; // foreign socket structure + ZeroMemory(&local_sa,sizeof(sockaddr_in)); // initialize local_sa + ZeroMemory(&foreign_sa,sizeof(sockaddr_in)); // initialize foreign_sa + + int length; + + SOCKET sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket + + // if socket() returned an error then return OTHER_ERROR + if (sock == INVALID_SOCKET ) + { + return OTHER_ERROR; + } + + // set the foreign socket structure + foreign_sa.sin_family = AF_INET; + foreign_sa.sin_port = htons(foreign_port); + foreign_sa.sin_addr.S_un.S_addr = inet_addr(foreign_ip.c_str()); + + // if inet_addr cound't convert the ip then return an error + if ( foreign_sa.sin_addr.S_un.S_addr == INADDR_NONE ) + { + closesocket(sock); + return OTHER_ERROR; + } + + + // set up the local socket structure + local_sa.sin_family = AF_INET; + + // set the local ip + if (local_ip.empty()) + { + // if the listener should listen on any IP + local_sa.sin_addr.S_un.S_addr = htons(INADDR_ANY); + } + else + { + // if there is a specific ip to listen on + local_sa.sin_addr.S_un.S_addr = inet_addr(local_ip.c_str()); + + // if inet_addr couldn't convert the ip then return an error + if (local_sa.sin_addr.S_un.S_addr == INADDR_NONE) + { + closesocket(sock); + return OTHER_ERROR; + } + } + + // set the local port + local_sa.sin_port = htons(local_port); + + + + // bind the new socket to the requested local port and local ip + if ( bind ( + sock, + reinterpret_cast(&local_sa), + sizeof(sockaddr_in) + ) == SOCKET_ERROR + ) + { // if there was an error + closesocket(sock); + + // if the port is already bound then return PORTINUSE + if (WSAGetLastError() == WSAEADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + // connect the socket + if (connect ( + sock, + reinterpret_cast(&foreign_sa), + sizeof(sockaddr_in) + ) == SOCKET_ERROR + ) + { + closesocket(sock); + // if the port is already bound then return PORTINUSE + if (WSAGetLastError() == WSAEADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + + + // determine the local port and IP and store them in used_local_ip + // and used_local_port + int used_local_port; + std::string used_local_ip; + sockaddr_in local_info; + if (local_port == 0) + { + length = sizeof(sockaddr_in); + if (getsockname ( + sock, + reinterpret_cast(&local_info), + &length + ) == SOCKET_ERROR + ) + { + closesocket(sock); + return OTHER_ERROR; + } + used_local_port = ntohs(local_info.sin_port); + } + else + { + used_local_port = local_port; + } + + // determine real local ip + if (local_ip.empty()) + { + // if local_port is not 0 then we must fill the local_info structure + if (local_port != 0) + { + length = sizeof(sockaddr_in); + if ( getsockname ( + sock, + reinterpret_cast(&local_info), + &length + ) == SOCKET_ERROR + ) + { + closesocket(sock); + return OTHER_ERROR; + } + } + char* temp = inet_ntoa(local_info.sin_addr); + + // check if inet_ntoa returned an error + if (temp == NULL) + { + closesocket(sock); + return OTHER_ERROR; + } + used_local_ip.assign(temp); + } + else + { + used_local_ip = local_ip; + } + + // set the SO_OOBINLINE option + int flag_value = 1; + if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int)) == SOCKET_ERROR ) + { + closesocket(sock); + return OTHER_ERROR; + } + + // initialize a connection object on the heap with the new socket + try + { + new_connection = new connection ( + sock, + foreign_port, + foreign_ip, + used_local_port, + used_local_ip + ); + } + catch(...) {closesocket(sock); return OTHER_ERROR; } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // WIN32 + +#endif // DLIB_SOCKETS_KERNEL_1_CPp_ + diff --git a/dlib/sockets/sockets_kernel_1.h b/dlib/sockets/sockets_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..d5cecb187f8e64accb88f4f640bc61a4a3d9a5d3 --- /dev/null +++ b/dlib/sockets/sockets_kernel_1.h @@ -0,0 +1,300 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_KERNEl_1_ +#define DLIB_SOCKETS_KERNEl_1_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#include "sockets_kernel_abstract.h" + +#include "../algs.h" +#include +#include "../threads.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + // forward declarations + class socket_factory; + class listener; + class SOCKET_container; + +// ---------------------------------------------------------------------------------------- + + // lookup functions + + int + get_local_hostname ( + std::string& hostname + ); + +// ----------------- + + int + hostname_to_ip ( + const std::string& hostname, + std::string& ip, + int n = 0 + ); + +// ----------------- + + int + ip_to_hostname ( + const std::string& ip, + std::string& hostname + ); + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // connection object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class connection + { + /*! + INITIAL_VALUE + - sd == false + - sdo == false + - sdr == 0 + + CONVENTION + - connection_socket == the socket handle for this connection. + - connection_foreign_port == the port that foreign host is using for + this connection. + - connection_foreign_ip == a string containing the IP address of the + foreign host. + - connection_local_port == the port that the local host is using for + this connection. + - connection_local_ip == a string containing the IP address of the + local interface being used by this connection. + + - sd == if shutdown() has been called then true else false. + - sdo == if shutdown_outgoing() has been called then true else false. + - sdr == the return value of shutdown() if it has been called. if it + hasn't been called then 0. + + !*/ + + friend class listener; // make listener a friend of connection + // make create_connection a friend of connection + friend int create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port = 0, + const std::string& local_ip = "" + ); + + public: + + ~connection ( + ); + + void* user_data; + + long write ( + const char* buf, + long num + ); + + long read ( + char* buf, + long num + ); + + + unsigned short get_local_port ( + ) const { return connection_local_port; } + + unsigned short get_foreign_port ( + ) const { return connection_foreign_port; } + + const std::string& get_local_ip ( + ) const { return connection_local_ip; } + + const std::string& get_foreign_ip ( + ) const { return connection_foreign_ip; } + + int shutdown_outgoing ( + ); + + int shutdown ( + ); + + private: + + bool sd_called ( + )const + /*! + ensures + - returns true if shutdown() has been called else + returns false + !*/ + { + sd_mutex.lock(); + bool temp = sd; + sd_mutex.unlock(); + return temp; + } + + bool sdo_called ( + )const + /*! + ensures + - returns true if shutdown_outgoing() or shutdown() has been called + else returns false + !*/ + { + sd_mutex.lock(); + bool temp = false; + if (sdo || sd) + temp = true; + sd_mutex.unlock(); + return temp; + } + + + // data members + SOCKET_container& connection_socket; + const unsigned short connection_foreign_port; + const std::string connection_foreign_ip; + const unsigned short connection_local_port; + const std::string connection_local_ip; + + bool sd; // called shutdown + bool sdo; // called shutdown_outgoing + int sdr; // return value for shutdown + mutex sd_mutex; // a lock for the three above vars + + + connection( + SOCKET_container sock, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port, + const std::string& local_ip + ); + /*! + requires + sock is a socket handle and + sock is the handle for the connection between foreign_ip:foreign_port + and local_ip:local_port + ensures + *this is initialized correctly with the above parameters + !*/ + + + // restricted functions + connection(connection&); // copy constructor + connection& operator=(connection&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // listener object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class listener + { + /*! + CONVENTION + if (inaddr_any == false) + { + listening_ip == a string containing the address the listener is + listening on + } + else + { + the listener is listening on all interfaces + } + + listening_port == the port the listener is listening on + listening_socket == the listening socket handle for this object + !*/ + + // make the create_listener a friend of listener + friend int create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip = "" + ); + + public: + + ~listener ( + ); + + int accept ( + connection*& new_connection, + unsigned long timeout = 0 + ); + + unsigned short get_listening_port ( + ) { return listening_port; } + + const std::string& get_listening_ip ( + ) { return listening_ip; } + + private: + + // data members + SOCKET_container& listening_socket; + const unsigned short listening_port; + const std::string listening_ip; + const bool inaddr_any; + + listener( + SOCKET_container sock, + unsigned short port, + const std::string& ip + ); + /*! + requires + sock is a socket handle and + sock is listening on the port and ip(may be "") indicated in the + above parameters + ensures + *this is initialized correctly with the above parameters + !*/ + + + // restricted functions + listener(listener&); // copy constructor + listener& operator=(listener&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + int create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip + ); + + int create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port, + const std::string& local_ip + ); + +// ---------------------------------------------------------------------------------------- + + +} + +#ifdef NO_MAKEFILE +#include "sockets_kernel_1.cpp" +#endif + +#endif // DLIB_SOCKETS_KERNEl_1_ + diff --git a/dlib/sockets/sockets_kernel_2.cpp b/dlib/sockets/sockets_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5a8e661e05f20d6632cd8955097304874f3d352 --- /dev/null +++ b/dlib/sockets/sockets_kernel_2.cpp @@ -0,0 +1,858 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_KERNEL_2_CPp_ +#define DLIB_SOCKETS_KERNEL_2_CPp_ + +#include "../platform.h" + +#ifdef POSIX + + +#include "sockets_kernel_2.h" +#include +#include "../set.h" + + + +namespace dlib +{ +// ---------------------------------------------------------------------------------------- + +#ifdef HPUX + typedef int dsocklen_t; +#else + typedef socklen_t dsocklen_t; +#endif + +// ---------------------------------------------------------------------------------------- +// stuff to ensure that the signal SIGPIPE is ignored before any connections are made +// so that when a connection object is shutdown the program won't end on a broken pipe + + namespace sockets_kernel_2_mutex + { + mutex startup_lock; + } + + + void sockets_startup() + { + // mutex crap to make this function thread safe + sockets_kernel_2_mutex::startup_lock.lock(); + static bool init = false; + if (init == false) + { + init = true; + signal( SIGPIPE, SIG_IGN); + } + sockets_kernel_2_mutex::startup_lock.unlock(); + } + + +// ---------------------------------------------------------------------------------------- + + // lookup functions + + int + get_local_hostname ( + std::string& hostname + ) + { + try + { + char temp[MAXHOSTNAMELEN]; + + if (gethostname(temp,MAXHOSTNAMELEN) == -1) + { + return OTHER_ERROR; + } + // ensure that NUL is at the end of the string + temp[MAXHOSTNAMELEN-1] = '\0'; + + hostname = temp; + } + catch (...) + { + return OTHER_ERROR; + } + + return 0; + } + +// ----------------- + + int + hostname_to_ip ( + const std::string& hostname, + std::string& ip, + int n + ) + { + try + { + set::kernel_1a sos; + + if (hostname.empty()) + return OTHER_ERROR; + + addrinfo* result = 0; + if (getaddrinfo(hostname.c_str(),0,0,&result)) + { + return OTHER_ERROR; + } + addrinfo* result_orig = result; + + // loop over all the addrinfo structures and add them to the set. the reason for doing + // this dumb crap is because different platforms return all kinds of weird garbage. many + // return the same ip multiple times, etc... + while (result != 0) + { + char temp[16]; + inet_ntop ( + AF_INET, + &((reinterpret_cast(result->ai_addr))->sin_addr), + temp,16 + ); + + result = result->ai_next; + + ip.assign(temp); + if (sos.is_member(ip) == false) + sos.add(ip); + } + + freeaddrinfo(result_orig); + + // now return the nth unique ip address + int i = 0; + while (sos.move_next()) + { + if (i == n) + { + ip = sos.element(); + return 0; + } + ++i; + } + + return OTHER_ERROR; + } + catch (...) + { + return OTHER_ERROR; + } + return 0; + } + +// ----------------- + + int + ip_to_hostname ( + const std::string& ip, + std::string& hostname + ) + { + + try + { + + if (ip.empty()) + return OTHER_ERROR; + + sockaddr_in sa; + sa.sin_family = AF_INET; + inet_pton(AF_INET,ip.c_str(),&sa.sin_addr); + + char temp[NI_MAXHOST]; + if ( getnameinfo ( + reinterpret_cast(&sa),sizeof(sockaddr_in), + temp, + NI_MAXHOST, + 0, + 0, + NI_NAMEREQD + ) + ) + { + return OTHER_ERROR; + } + + hostname.assign(temp); + + } + catch (...) + { + return OTHER_ERROR; + } + return 0; + } + +// ---------------------------------------------------------------------------------------- + + connection:: + connection( + int sock, + int foreign_port, + const std::string& foreign_ip, + int local_port, + const std::string& local_ip + ) : + connection_socket(sock), + connection_foreign_port(foreign_port), + connection_foreign_ip(foreign_ip), + connection_local_port(local_port), + connection_local_ip(local_ip), + sd(false), + sdo(false), + sdr(0) + {} + +// ---------------------------------------------------------------------------------------- + + long connection:: + write ( + const char* buf, + long num + ) + { + const long old_num = num; + long status; + while (num > 0) + { + if ( (status = ::send(connection_socket,buf,num,0)) <=0) + { + // if send was interupted by a signal then restart it + if (errno == EINTR) + { + continue; + } + else + { + // check if shutdown or shutdown_outgoing have been called + if (sdo_called()) + return SHUTDOWN; + else + return OTHER_ERROR; + } + } + num -= status; + buf += status; + } + return old_num; + } + +// ---------------------------------------------------------------------------------------- + + long connection:: + read ( + char* buf, + long num + ) + { + long status; + while (true) + { + status = recv(connection_socket,buf,num,0); + if (status == -1) + { + // if recv was interupted then try again + if (errno == EINTR) + continue; + else + { + if (sd_called()) + return SHUTDOWN; + else + return OTHER_ERROR; + } + } + else if (status == 0 && sd_called()) + { + return SHUTDOWN; + } + + return status; + } // while (true) + } + +// ---------------------------------------------------------------------------------------- + + connection:: + ~connection ( + ) + { + while (true) + { + int status = ::close(connection_socket); + if (status == -1 && errno == EINTR) + continue; + break; + } + } + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // listener object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + listener:: + listener( + int sock, + int port, + const std::string& ip + ) : + listening_socket(sock), + listening_port(port), + listening_ip(ip), + inaddr_any(listening_ip.empty()) + {} + +// ---------------------------------------------------------------------------------------- + + listener:: + ~listener ( + ) + { + while (true) + { + int status = ::close(listening_socket); + if (status == -1 && errno == EINTR) + continue; + break; + } + } + +// ---------------------------------------------------------------------------------------- + + int listener:: + accept ( + connection*& new_connection, + int timeout + ) + { + int incoming; + sockaddr_in incomingAddr; + dsocklen_t length = sizeof(sockaddr_in); + + // implement timeout with select if timeout is > 0 + if (timeout > 0) + { + + fd_set read_set; + // initialize read_set + FD_ZERO(&read_set); + + // add the listening socket to read_set + FD_SET(listening_socket, &read_set); + + timeval time_to_wait; + + + // loop on select so if its interupted then we can start it again + while (true) + { + + // setup a timeval structure + time_to_wait.tv_sec = static_cast(timeout/1000); + time_to_wait.tv_usec = static_cast((timeout%1000)*1000); + + // wait on select + int status = select(listening_socket+1,&read_set,0,0,&time_to_wait); + + // if select timed out + if (status == 0) + return TIMEOUT; + + // if select returned an error + if (status == -1) + { + // if select was interupted or the connection was aborted + // then go back to select + if (errno == EINTR || + errno == ECONNABORTED || +#ifdef EPROTO + errno == EPROTO || +#endif + errno == ECONNRESET + ) + { + continue; + } + else + { + return OTHER_ERROR; + } + } + + // accept the new connection + incoming=::accept ( + listening_socket, + reinterpret_cast(&incomingAddr), + &length + ); + + // if there was an error return OTHER_ERROR + if ( incoming == -1 ) + { + // if accept was interupted then go back to accept + if (errno == EINTR || + errno == ECONNABORTED || +#ifdef EPROTO + errno == EPROTO || +#endif + errno == ECONNRESET + ) + { + continue; + } + else + { + return OTHER_ERROR; + } + } + + // if there were no errors then quit loop + break; + + } + + } + // else if there is no time out then just go into accept + else + { + while (true) + { + // call accept to get a new connection + incoming=::accept ( + listening_socket, + reinterpret_cast(&incomingAddr), + &length + ); + + // if there was an error return OTHER_ERROR + if ( incoming == -1 ) + { + // if accept was interupted then go back to accept + if (errno == EINTR || + errno == ECONNABORTED || +#ifdef EPROTO + errno == EPROTO || +#endif + errno == ECONNRESET + ) + { + continue; + } + else + { + return OTHER_ERROR; + } + } + break; + } + + } + + + // get the port of the foreign host into foreign_port + int foreign_port = ntohs(incomingAddr.sin_port); + + // get the IP of the foreign host into foreign_ip + char foreign_ip[16]; + inet_ntop(AF_INET,&incomingAddr.sin_addr,foreign_ip,16); + + + + // get the local ip for this connection into local_ip + char temp_local_ip[16]; + std::string local_ip; + if (inaddr_any == true) + { + sockaddr_in local_info; + length = sizeof(sockaddr_in); + // get the local sockaddr_in structure associated with this new connection + if ( getsockname ( + incoming, + reinterpret_cast(&local_info), + &length + ) == -1 + ) + { // an error occurred + while (true) + { + int status = ::close(incoming); + if (status == -1 && errno == EINTR) + continue; + break; + } + return OTHER_ERROR; + } + local_ip = const_cast ( + inet_ntop(AF_INET,&local_info.sin_addr,temp_local_ip,16) + ); + } + else + { + local_ip = listening_ip; + } + + + + // set the SO_OOBINLINE option + int flag_value = 1; + if (setsockopt(incoming,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int))) + { + while (true) + { + int status = ::close(incoming); + if (status == -1 && errno == EINTR) + continue; + break; + } + return OTHER_ERROR; + } + + + + // make a new connection object for this new connection + try + { + new_connection = new connection ( + incoming, + foreign_port, + foreign_ip, + listening_port, + local_ip + ); + } + catch (...) + { + while (true) + { + int status = ::close(incoming); + if (status == -1 && errno == EINTR) + continue; + break; + } + return OTHER_ERROR; + } + + return 0; + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // socket creation functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + static void + close_socket ( + int sock + ) + /*! + requires + - sock == a socket + ensures + - sock has been closed + !*/ + { + while (true) + { + int status = ::close(sock); + if (status == -1 && errno == EINTR) + continue; + break; + } + } + +// ---------------------------------------------------------------------------------------- + + int + create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip + ) + { + sockets_startup(); + + + sockaddr_in sa; // local socket structure + memset(&sa,'\0',sizeof(sockaddr_in)); // initialize sa + + + int sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket + + // if socket() returned an error then return OTHER_ERROR + if (sock == -1) + { + return OTHER_ERROR; + } + + // set the local socket structure + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + if (ip.empty()) + { + // if the listener should listen on any IP + sa.sin_addr.s_addr = htons(INADDR_ANY); + } + else + { + // if there is a specific ip to listen on + sa.sin_addr.s_addr = inet_addr(ip.c_str()); + + // if inet_addr couldn't convert the ip then return an error + if ( sa.sin_addr.s_addr == ( in_addr_t)(-1)) + { + close_socket(sock); + return OTHER_ERROR; + } + } + + // set the SO_REUSEADDR option + int flag_value = 1; + if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,reinterpret_cast(&flag_value),sizeof(int))) + { + close_socket(sock); + return OTHER_ERROR; + } + + + // bind the new socket to the requested port and ip + if (bind(sock,reinterpret_cast(&sa),sizeof(sockaddr_in)) == -1) + { // if there was an error + close_socket(sock); + + // if the port is already bound then return PORTINUSE + if (errno == EADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + + // tell the new socket to listen + if ( listen(sock,SOMAXCONN) == -1) + { + // if there was an error return OTHER_ERROR + close_socket(sock); + + // if the port is already bound then return PORTINUSE + if (errno == EADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + // determine the used local port if necessary + if (port == 0) + { + sockaddr_in local_info; + dsocklen_t length = sizeof(sockaddr_in); + if ( getsockname( + sock, + reinterpret_cast(&local_info), + &length + ) == -1) + { + close_socket(sock); + return OTHER_ERROR; + } + port = ntohs(local_info.sin_port); + } + + // initialize a listener object on the heap with the new socket + try { new_listener = new listener(sock,port,ip); } + catch(...) { close_socket(sock); return OTHER_ERROR; } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + + int + create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port, + const std::string& local_ip + ) + { + sockets_startup(); + + sockaddr_in local_sa; // local socket structure + sockaddr_in foreign_sa; // foreign socket structure + memset(&local_sa,'\0',sizeof(sockaddr_in)); // initialize local_sa + memset(&foreign_sa,'\0',sizeof(sockaddr_in)); // initialize foreign_sa + + dsocklen_t length; + + int sock = socket (AF_INET, SOCK_STREAM, 0); // get a new socket + + // if socket() returned an error then return OTHER_ERROR + if (sock == -1 ) + { + return OTHER_ERROR; + } + + // set the foreign socket structure + foreign_sa.sin_family = AF_INET; + foreign_sa.sin_port = htons(foreign_port); + foreign_sa.sin_addr.s_addr = inet_addr(foreign_ip.c_str()); + + // if inet_addr couldn't convert the ip then return an error + if ( foreign_sa.sin_addr.s_addr == ( in_addr_t)(-1)) + { + close_socket(sock); + return OTHER_ERROR; + } + + + // set up the local socket structure + local_sa.sin_family = AF_INET; + + // set the local port + local_sa.sin_port = htons(local_port); + + // set the local ip + if (local_ip.empty()) + { + // if the listener should listen on any IP + local_sa.sin_addr.s_addr = htons(INADDR_ANY); + } + else + { + // if there is a specific ip to listen on + local_sa.sin_addr.s_addr = inet_addr(local_ip.c_str()); + + // if inet_addr couldn't convert the ip then return an error + if ( local_sa.sin_addr.s_addr == ( in_addr_t)(-1)) + { + close_socket(sock); + return OTHER_ERROR; + } + } + + + + + + // bind the new socket to the requested local port and local ip + if ( bind(sock,reinterpret_cast(&local_sa),sizeof(sockaddr_in)) == -1) + { // if there was an error + close_socket(sock); + + // if the port is already bound then return PORTINUSE + if (errno == EADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + // connect the socket + if ( connect ( + sock, + reinterpret_cast(&foreign_sa), + sizeof(sockaddr_in) + ) == -1 + ) + { + close_socket(sock); + // if the port is already bound then return PORTINUSE + if (errno == EADDRINUSE) + return PORTINUSE; + else + return OTHER_ERROR; + } + + + // determine the local port and IP and store them in used_local_ip + // and used_local_port + int used_local_port; + char temp_used_local_ip[16]; + std::string used_local_ip; + sockaddr_in local_info; + + // determine the port + if (local_port == 0) + { + length = sizeof(sockaddr_in); + if ( getsockname( + sock, + reinterpret_cast(&local_info), + &length + ) == -1) + { + close_socket(sock); + return OTHER_ERROR; + } + used_local_port = ntohs(local_info.sin_port); + } + else + { + used_local_port = local_port; + } + + // determine the ip + if (local_ip.empty()) + { + // if local_port is not 0 then we must fill the local_info structure + if (local_port != 0) + { + length = sizeof(sockaddr_in); + if ( getsockname ( + sock, + reinterpret_cast(&local_info), + &length + ) == -1 + ) + { + close_socket(sock); + return OTHER_ERROR; + } + } + used_local_ip = inet_ntop(AF_INET,&local_info.sin_addr,temp_used_local_ip,16); + } + else + { + used_local_ip = local_ip; + } + + + // set the SO_OOBINLINE option + int flag_value = 1; + if (setsockopt(sock,SOL_SOCKET,SO_OOBINLINE,reinterpret_cast(&flag_value),sizeof(int))) + { + close_socket(sock); + return OTHER_ERROR; + } + + + // initialize a connection object on the heap with the new socket + try + { + new_connection = new connection ( + sock, + foreign_port, + foreign_ip, + used_local_port, + used_local_ip + ); + } + catch(...) {close_socket(sock); return OTHER_ERROR; } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // POSIX + +#endif // DLIB_SOCKETS_KERNEL_2_CPp_ + diff --git a/dlib/sockets/sockets_kernel_2.h b/dlib/sockets/sockets_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..f9c341f13491b965f39139baf186a0d4107bd522 --- /dev/null +++ b/dlib/sockets/sockets_kernel_2.h @@ -0,0 +1,348 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_KERNEl_2_ +#define DLIB_SOCKETS_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#include "../platform.h" + +#include "sockets_kernel_abstract.h" + +#define _BSD_SOCKLEN_T_ + +#include +#include +#include +#include +#ifndef HPUX +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../threads.h" +#include "../algs.h" + + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + // forward declarations + class socket_factory; + class listener; + +// ---------------------------------------------------------------------------------------- + + // lookup functions + + int + get_local_hostname ( + std::string& hostname + ); + +// ----------------- + + int + hostname_to_ip ( + const std::string& hostname, + std::string& ip, + int n = 0 + ); + +// ----------------- + + int + ip_to_hostname ( + const std::string& ip, + std::string& hostname + ); + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // connection object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class connection + { + /*! + INITIAL_VALUE + sd == false + sdo == false + sdr == 0 + + + CONVENTION + connection_socket == the socket handle for this connection. + connection_foreign_port == the port that foreign host is using for + this connection + connection_foreign_ip == a string containing the IP address of the + foreign host + connection_local_port == the port that the local host is using for + this connection + connection_local_ip == a string containing the IP address of the + local interface being used by this connection + + sd == if shutdown() has been called then true + else false + sdo == if shutdown_outgoing() has been called then true + else false + sdr == the return value of shutdown() if it has been + called. if it hasn't been called then 0 + + + !*/ + + friend class listener; // make listener a friend of connection + // make create_connection a friend of connection + friend int create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port = 0, + const std::string& local_ip = "" + ); + + public: + + ~connection(); + + void* user_data; + + long write ( + const char* buf, + long num + ); + + long read ( + char* buf, + long num + ); + + int get_local_port ( + ) const { return connection_local_port; } + + int get_foreign_port ( + ) const { return connection_foreign_port; } + + const std::string& get_local_ip ( + ) const { return connection_local_ip; } + + const std::string& get_foreign_ip ( + ) const { return connection_foreign_ip; } + + int shutdown_outgoing ( + ) + { + sd_mutex.lock(); + if (sdo || sd) + { + sd_mutex.unlock(); + return sdr; + } + sdo = true; + sdr = ::shutdown(connection_socket,SHUT_WR); + int temp = sdr; + sd_mutex.unlock(); + return temp; + } + + int shutdown ( + ) + { + sd_mutex.lock(); + if (sd) + { + sd_mutex.unlock(); + return sdr; + } + sd = true; + sdr = ::shutdown(connection_socket,SHUT_RDWR); + int temp = sdr; + sd_mutex.unlock(); + return temp; + } + + private: + + + bool sd_called ( + )const + /*! + ensures + - returns true if shutdown() has been called else + - returns false + !*/ + { + sd_mutex.lock(); + bool temp = sd; + sd_mutex.unlock(); + return temp; + } + + bool sdo_called ( + )const + /*! + ensures + - returns true if shutdown_outgoing() or shutdown() has been called + else returns false + !*/ + { + sd_mutex.lock(); + bool temp = false; + if (sdo || sd) + temp = true; + sd_mutex.unlock(); + return temp; + } + + + // data members + int connection_socket; + const int connection_foreign_port; + const std::string connection_foreign_ip; + const int connection_local_port; + const std::string connection_local_ip; + + bool sd; // called shutdown + bool sdo; // called shutdown_outgoing + int sdr; // return value for shutdown + mutex sd_mutex; // a lock for the three above vars + + connection( + int sock, + int foreign_port, + const std::string& foreign_ip, + int local_port, + const std::string& local_ip + ); + /*! + requires + - sock is a socket handle + - sock is the handle for the connection between foreign_ip:foreign_port + and local_ip:local_port + ensures + - *this is initialized correctly with the above parameters + !*/ + + + // restricted functions + connection(); + connection(connection&); // copy constructor + connection& operator=(connection&); // assignement opertor + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // listener object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class listener + { + /*! + CONVENTION + if (inaddr_any == false) + { + listening_ip == a string containing the address the listener is + listening on + } + else + { + the listener is listening on all interfaces + } + + listening_port == the port the listener is listening on + listening_socket == the listening socket handle for this object + !*/ + + // make the create_listener a friend of listener + friend int create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip = "" + ); + + public: + + ~listener(); + + int accept ( + connection*& new_connection, + int timeout = 0 + ); + + int get_listening_port ( + ) const { return listening_port; } + + const std::string& get_listening_ip ( + ) const { return listening_ip; } + + private: + + // data members + int listening_socket; + const int listening_port; + const std::string listening_ip; + const bool inaddr_any; + + listener( + int sock, + int port, + const std::string& ip + ); + /*! + requires + - sock is a socket handle + - sock is listening on the port and ip(may be "") indicated in the above + parameters + ensures + - *this is initialized correctly with the above parameters + !*/ + + + // restricted functions + listener(); + listener(listener&); // copy constructor + listener& operator=(listener&); // assignement opertor + }; + +// ---------------------------------------------------------------------------------------- + + int create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip + ); + + int create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port, + const std::string& local_ip + ); + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "sockets_kernel_2.cpp" +#endif + +#endif // DLIB_SOCKETS_KERNEl_2_ + diff --git a/dlib/sockets/sockets_kernel_abstract.h b/dlib/sockets/sockets_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..9937310c0df6013795fde729f72ed65bcc93a6c2 --- /dev/null +++ b/dlib/sockets/sockets_kernel_abstract.h @@ -0,0 +1,403 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SOCKETS_KERNEl_ABSTRACT_ +#ifdef DLIB_SOCKETS_KERNEl_ABSTRACT_ + +#include +#include "../threads.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + GENERAL COMMENTS: + Nothing in here will throw exceptions + + Timeouts: + All timeout values are measured in milliseconds but you are not + guaranteed to have that level of resolution. The actual resolution + is implementation defined. + + GENERAL WARNING + Don't call any of these functions or make any of these objects + before main() has been entered. + !*/ + +// ---------------------------------------------------------------------------------------- + + // LOOKUP FUNCTIONS + + // all lookup functions are thread-safe + + int get_local_hostname ( + std::string& hostname + ); + /*! + ensures + - if (#get_local_hostname() == 0) then + - #hostname == a string containing the hostname of the local computer + + - returns 0 upon success + - returns OTHER_ERROR upon failure and in this case #hostname's value + is undefined + !*/ + +// ----------------- + + int hostname_to_ip ( + const std::string& hostname, + std::string& ip, + int n = 0 + ); + /*! + requires + - n >= 0 + ensures + - if (#hostname_to_ip() == 0) then + - #ip == string containing the nth ip address associated with the hostname + + - returns 0 upon success + - returns OTHER_ERROR upon failure + !*/ + +// ----------------- + + int ip_to_hostname ( + const std::string& ip, + std::string& hostname + ); + /*! + ensures + - if (#ip_to_hostname() == 0) then + - #hostname == string containing the hostname associated with ip + + - returns 0 upon success + - returns OTHER_ERROR upon failure + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // + // socket creation functions + // + // The following functions are guaranteed to be thread-safe + // +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + int create_listener ( + listener*& new_listener, + unsigned short port, + const std::string& ip = "" + ); + /*! + requires + - 0 <= port <= 65535 + ensures + - if (#create_listener() == 0) then + - #new_listener == a pointer to a listener object that is listening on + the specified port and ip for an incoming connection + - if (ip == "") then + - the new listener will be listening on all interfaces + - if (port == 0) then + - the kernel will assign a free port to listen on + + + - returns 0 if create_listener was successful + - returns PORTINUSE if the specified local port was already in use + - returns OTHER_ERROR if some other error occurred + !*/ + + int create_connection ( + connection*& new_connection, + unsigned short foreign_port, + const std::string& foreign_ip, + unsigned short local_port = 0, + const std::string& local_ip = "" + ); + /*! + requires + - 0 < foreign_port <= 65535 + - 0 <= local_port <= 65535 + ensures + - if (#create_connection() == 0) then + - #new_connection == a pointer to a connection object that is connected + to foreign_ip on port foreign_port and is using the local interface + local_ip and local port local_port + - #new_connection->user_data == 0 + - if (local_ip == "") then + - the operating system will chose this for you + - if (local_port == 0) then + - the operating system will chose this for you + + - returns 0 if create_connection was successful + - returns PORTINUSE if the specified local port was already in use + - returns OTHER_ERROR if some other error occurred + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // connection object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class connection + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a TCP connection. + + Instances of this class can only be created by using the + create_connection function or listener class defined below. + + NOTE: + A connection object must ALWAYS be closed (delete the pointer to the + connection) or it will cause a resource leak. + + Note also that all errors indicated by a return code of OTHER_ERROR + are fatal so if one occurs the connection should just be closed. + + CLOSING A CONNECTION + Note that if ~connection() or shutdown() is called before the remote client + has received all sent data it is possible that the data will be lost. To + avoid this you should call the close_gracefully() function to close your + connections (unless you actually do want to immediately dispose of a + connection and don't care about the data). + (example: close_gracefully(con); // close con gracefully but force it closed + // if it takes more than 500 milliseconds.) + + THREAD SAFETY + - It is always safe to call shutdown() or shutdown_outgoing(). + - you may NOT call any function more than once at a time (except the + shutdown functions). + - do not call read() more than once at a time + - do not call write() more than once at a time + - You can safely call shutdown or shutdown_outgoing in conjunction with + the read/write functions. + This is helpful if you want to unblock another thread that is + blocking on a read/write operation. Shutting down the connection + will cause the read/write functions to return a value of SHUTDOWN. + + OUT-OF-BAND DATA: + All out-of-band data will be put inline into the normal data stream. + This means that you can read any out-of-band data via calls to read(). + (i.e. the SO_OOBINLINE socket option will be set) + !*/ + + public: + + ~connection ( + ); + /*! + requires + - no other threads are using this connection object + ensures + - closes the connection (this is an abrupt non-graceful close) + - frees the resources used by this object + !*/ + + void* user_data; + /*! + This pointer is provided so that the client programmer may easily assocaite + some data with a connection object. You can really do whatever you want + with it. Initially user_data is 0. + !*/ + + long write ( + const char* buf, + long num + ); + /*! + requires + - num > 0 + - buf points to an array of at least num bytes + ensures + - will block until ONE of the following occurrs: + - num bytes from buf have been written to the connection + - an error has occurred + - the outgoing channel of the connection has been shutdown locally + + - returns num if write succeeded + - returns OTHER_ERROR if there was an error (this could be due to a + connection close) + - returns SHUTDOWN if the outgoing channel of the connection has been + shutdown locally + !*/ + + long read ( + char* buf, + long num + ); + /*! + requires + - num > 0 + - buf points to an array of at least num bytes + ensures + - read() will not read more than num bytes of data into #buf + - read blocks until ONE of the following happens: + - there is some data available and it has been written into #buf + - the remote end of the connection is closed + - an error has occurred + - the connection has been shutdown locally + + - returns the number of bytes read into #buf if there was any data. + - returns 0 if the connection has ended/terminated and there is no more data. + - returns OTHER_ERROR if there was an error. + - returns SHUTDOWN if the connection has been shutdown locally + !*/ + + unsigned short get_local_port ( + ) const; + /*! + ensures + - returns the local port number for this connection + !*/ + + unsigned short get_foreign_port ( + ) const; + /*! + ensures + - returns the foreign port number for this connection + !*/ + + const std::string& get_local_ip ( + ) const; + /*! + ensures + - returns the IP of the local interface this connection is using + !*/ + + const std::string& get_foreign_ip ( + ) const; + /*! + ensures + - returns the IP of the foreign host for this connection + !*/ + + int shutdown ( + ); + /*! + ensures + - if (#shutdown() == 0 && connection was still open) then + - terminates the connection but does not free the resources for the + connection object + + - any read() or write() calls on this connection will return immediately + with the code SHUTDOWN. + + - returns 0 upon success + - returns OTHER_ERROR if there was an error + !*/ + + int shutdown_outgoing ( + ); + /*! + ensures + - if (#shutdown_outgoing() == 0 && outgoing channel was still open) then + - sends a FIN to indicate that no more data will be sent on this + connection but leaves the receive half of the connection open to + receive more data from the other host + + - any calls to write() will return immediately with the code SHUTDOWN. + + - returns 0 upon success + - returns OTHER_ERROR if there was an error + !*/ + + private: + // restricted functions + connection(); + connection(connection&); // copy constructor + connection& operator=(connection&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // listener object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class listener + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a TCP socket waiting for incoming connections. + Calling accept returns a pointer to any new incoming connections on its + port. + + Instances of this class can only be created by using the + create_listener function defined below. + + NOTE: + A listener object must ALWAYS be closed (delete the pointer to it) or + it will cause a resource leak. + + Note also that all errors indicated by a return code of OTHER_ERROR + are fatal so if one occurs the listener should be closed. + + THREAD SAFETY + None of the functions in this object are guaranteed to be thread-safe. + This means that you must serialize all access to this object. + !*/ + + public: + + ~listener ( + ); + /*! + requires + - no other threads are using this listener object + ensures + - closes the listener + - frees the resources used by this object + !*/ + + int accept ( + connection*& new_connection, + unsigned long timeout = 0 + ); + /*! + requires + - timeout < 2000000 + ensures + - blocks until a new connection is ready or timeout milliseconds have + elapsed. + - #new_connection == a pointer to the new connection object + - #new_connection->user_data == 0 + - if (timeout == 0) then + - the timeout argument is ignored + + - returns 0 if accept() was successful + - returns TIMEOUT if timeout milliseconds have elapsed + - returns OTHER_ERROR if an error has occured + !*/ + + unsigned short get_listening_port ( + ) const; + /*! + ensures + - returns the port number that this object is listening on + !*/ + + const std::string& get_listening_ip ( + ) const; + /*! + ensures + - returns a string containing the IP (e.g. "127.0.0.1") of the + interface this object is listening on + - returns "" if it is accepting connections on all interfaces + !*/ + + private: + // restricted functions + listener(); + listener(listener&); // copy constructor + listener& operator=(listener&); // assignment operator + }; +} + +#endif // DLIB_SOCKETS_KERNEl_ABSTRACT_ + diff --git a/dlib/sockets/windows.h b/dlib/sockets/windows.h new file mode 100644 index 0000000000000000000000000000000000000000..cab8d529ac81f644cc4ccb83a2c8edaf6a30e0d8 --- /dev/null +++ b/dlib/sockets/windows.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKETS_KERNEl_2_ +#include "sockets_kernel_1.h" +#endif + diff --git a/dlib/sockstreambuf.h b/dlib/sockstreambuf.h new file mode 100644 index 0000000000000000000000000000000000000000..382ebe416a97196d02eb1ab0d200f7fe892a07c7 --- /dev/null +++ b/dlib/sockstreambuf.h @@ -0,0 +1,36 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef _SOCKSTREAMBUf_ +#define _SOCKSTREAMBUf_ + +#include "sockstreambuf/sockstreambuf_kernel_1.h" +#include "sockstreambuf/sockstreambuf_kernel_2.h" + + +namespace dlib +{ + + + class sockstreambuf + { + sockstreambuf() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef sockstreambuf_kernel_1 + kernel_1a; + + // kernel_2a + typedef sockstreambuf_kernel_2 + kernel_2a; + + + }; +} + +#endif + diff --git a/dlib/sockstreambuf/sockstreambuf_kernel_1.cpp b/dlib/sockstreambuf/sockstreambuf_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d643e88e57ca68502ebfed820fc796c5949d102 --- /dev/null +++ b/dlib/sockstreambuf/sockstreambuf_kernel_1.cpp @@ -0,0 +1,167 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKSTREAMBUF_KERNEL_1_CPp_ +#define DLIB_SOCKSTREAMBUF_KERNEL_1_CPp_ +#include "sockstreambuf_kernel_1.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + // output functions +// ---------------------------------------------------------------------------------------- + + sockstreambuf_kernel_1::int_type sockstreambuf_kernel_1:: + overflow ( + int_type c + ) + { + if (c != EOF) + { + char temp = static_cast(c); + if (con.write(&temp,1) != 1) + { + // if the write was not successful + return EOF; + } + } + return c; + } + +// ---------------------------------------------------------------------------------------- + + std::streamsize sockstreambuf_kernel_1:: + xsputn ( + const char* s, + std::streamsize num + ) + { + if (con.write(s,static_cast(num)) != num) + { + // the write was not successful so return that 0 bytes were written + return 0; + } + return num; + } + +// ---------------------------------------------------------------------------------------- + // input functions +// ---------------------------------------------------------------------------------------- + + sockstreambuf_kernel_1::int_type sockstreambuf_kernel_1:: + underflow( + ) + { + if (lastread_next) + { + return lastread; + } + else if (peek != EOF) + { + return peek; + } + else + { + char temp; + if (con.read(&temp,1) != 1) + { + // some error occurred + return EOF; + } + peek = static_cast(temp); + return peek; + } + } + +// ---------------------------------------------------------------------------------------- + + sockstreambuf_kernel_1::int_type sockstreambuf_kernel_1:: + uflow( + ) + { + if (lastread_next) + { + lastread_next = false; + return lastread; + } + else if (peek != EOF) + { + lastread = peek; + peek = EOF; + return lastread; + } + else + { + char temp; + if (con.read(&temp,1) != 1) + { + // some error occurred + return EOF; + } + lastread = static_cast(temp); + return lastread; + } + } + +// ---------------------------------------------------------------------------------------- + + sockstreambuf_kernel_1::int_type sockstreambuf_kernel_1:: + pbackfail( + int_type c + ) + { + // if they are trying to push back a character that they didn't read last + // that is an error + if (c != EOF && c != lastread) + return EOF; + + // if they are trying to push back a second character then thats an error + if (lastread_next) + return EOF; + + lastread_next = true; + return 1; + } + +// ---------------------------------------------------------------------------------------- + + std::streamsize sockstreambuf_kernel_1:: + xsgetn ( + char_type* s, + std::streamsize n + ) + { + std::streamsize temp = n; + if (lastread_next && n > 0) + { + *s = lastread; + lastread_next = false; + ++s; + --n; + } + if (peek != EOF && n > 0) + { + *s = peek; + peek = EOF; + ++s; + --n; + } + + while (n>0) + { + int status = con.read(s,static_cast(n)); + if (status < 1) + break; + n -= status; + s += status; + } + + return temp-n; + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_SOCKSTREAMBUF_KERNEL_1_CPp_ + diff --git a/dlib/sockstreambuf/sockstreambuf_kernel_1.h b/dlib/sockstreambuf/sockstreambuf_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..2926103d28fcdaf59dd9d22be2a6e3240c556f70 --- /dev/null +++ b/dlib/sockstreambuf/sockstreambuf_kernel_1.h @@ -0,0 +1,98 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKSTREAMBUF_KERNEl_1_ +#define DLIB_SOCKSTREAMBUF_KERNEl_1_ + +#include +#include +#include "../sockets.h" +#include "sockstreambuf_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class sockstreambuf_kernel_1 : public std::streambuf + { + /*! + INITIAL VALUE + con == a connection + lastread_next == false + peek == EOF + + CONVENTION + if (peek != EOF) then + peek == the last character read from the connection object and + is used to store the char in the event the user peeks by + calling sgetc() + if (lastread != EOF) then + lastread == the last character read and consumed by the user + + if (lastread_next) then + the next character to be returned to the user is lastread because + the user put it back into the buffer + + !*/ + + public: + sockstreambuf_kernel_1 ( + connection* con_ + ) : + con(*con_), + peek(EOF), + lastread_next(false) + {} + + connection* get_connection ( + ) { return &con; } + + + protected: + + // output functions + int_type overflow ( + int_type c + ); + + std::streamsize xsputn ( + const char* s, + std::streamsize num + ); + + // input functions + int_type underflow( + ); + + int_type uflow( + ); + + int_type pbackfail( + int_type c + ); + + std::streamsize xsgetn ( + char_type* s, + std::streamsize n + ); + + private: + + // member data + connection& con; + int_type peek; + int_type lastread; + bool lastread_next; + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "sockstreambuf_kernel_1.cpp" +#endif + +#endif // DLIB_SOCKSTREAMBUF_KERNEl_1_ + diff --git a/dlib/sockstreambuf/sockstreambuf_kernel_2.cpp b/dlib/sockstreambuf/sockstreambuf_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb137c7523b828bbc18f6e8464f9803599442a64 --- /dev/null +++ b/dlib/sockstreambuf/sockstreambuf_kernel_2.cpp @@ -0,0 +1,158 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKSTREAMBUF_KERNEL_2_CPp_ +#define DLIB_SOCKSTREAMBUF_KERNEL_2_CPp_ +#include "sockstreambuf_kernel_2.h" + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + // output functions +// ---------------------------------------------------------------------------------------- + + sockstreambuf_kernel_2::int_type sockstreambuf_kernel_2:: + overflow ( + int_type c + ) + { + if (c != EOF) + { + *pptr() = c; + pbump(1); + } + if (flush_out_buffer() == EOF) + { + // an error occurred + return EOF; + } + return c; + } + +// ---------------------------------------------------------------------------------------- + + std::streamsize sockstreambuf_kernel_2:: + xsputn ( + const char* s, + std::streamsize num + ) + { + int space_left = static_cast(epptr()-pptr()); + if (num <= space_left) + { + std::memcpy(pptr(),s,static_cast(num)); + pbump(static_cast(num)); + return num; + } + else + { + std::memcpy(pptr(),s,space_left); + s += space_left; + pbump(space_left); + int num_left = static_cast(num) - space_left; + + if (flush_out_buffer() == EOF) + { + // the write was not successful so return that 0 bytes were written + return 0; + } + + if (num_left < out_buffer_size) + { + std::memcpy(pptr(),s,num_left); + pbump(num_left); + return num; + } + else + { + if (con.write(s,num_left) != num_left) + { + // the write was not successful so return that 0 bytes were written + return 0; + } + return num; + } + } + } + +// ---------------------------------------------------------------------------------------- + // input functions +// ---------------------------------------------------------------------------------------- + + sockstreambuf_kernel_2::int_type sockstreambuf_kernel_2:: + underflow( + ) + { + if (gptr() < egptr()) + { + return static_cast(*gptr()); + } + + int num_put_back = static_cast(gptr() - eback()); + if (num_put_back > max_putback) + { + num_put_back = max_putback; + } + + // copy the putback characters into the putback end of the in_buffer + std::memmove(in_buffer+(max_putback-num_put_back), gptr()-num_put_back, num_put_back); + + int num = con.read(in_buffer+max_putback, in_buffer_size-max_putback); + if (num <= 0) + { + // an error occurred or the connection is over which is EOF + return EOF; + } + + // reset in_buffer pointers + setg (in_buffer+(max_putback-num_put_back), + in_buffer+max_putback, + in_buffer+max_putback+num); + + return static_cast(*gptr()); + } + +// ---------------------------------------------------------------------------------------- + + std::streamsize sockstreambuf_kernel_2:: + xsgetn ( + char_type* s, + std::streamsize n + ) + { + std::streamsize temp = n; + while (n > 0) + { + int num = static_cast(egptr() - gptr()); + if (num >= n) + { + // copy data from our buffer + std::memcpy(s, gptr(), static_cast(n)); + gbump(static_cast(n)); + return temp; + } + + // read more data into our buffer + if (num == 0) + { + if (underflow() == EOF) + break; + continue; + } + + // copy all the data from our buffer + std::memcpy(s, gptr(), num); + n -= num; + gbump(num); + s += num; + } + return temp-n; + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_SOCKSTREAMBUF_KERNEL_2_CPp_ + diff --git a/dlib/sockstreambuf/sockstreambuf_kernel_2.h b/dlib/sockstreambuf/sockstreambuf_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..06a8a0d9c1e135e2381b4e7d87990f675734a5d9 --- /dev/null +++ b/dlib/sockstreambuf/sockstreambuf_kernel_2.h @@ -0,0 +1,132 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SOCKSTREAMBUF_KERNEl_2_ +#define DLIB_SOCKSTREAMBUF_KERNEl_2_ + +#include +#include +#include "../sockets.h" +#include "sockstreambuf_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class sockstreambuf_kernel_2 : public std::streambuf + { + /*! + INITIAL VALUE + - con == a connection + - in_buffer == an array of in_buffer_size bytes + - out_buffer == an array of out_buffer_size bytes + + CONVENTION + - in_buffer == the input buffer used by this streambuf + - out_buffer == the output buffer used by this streambuf + - max_putback == the maximum number of chars to have in the put back buffer. + !*/ + + public: + sockstreambuf_kernel_2 ( + connection* con_ + ) : + con(*con_), + out_buffer(0), + in_buffer(0) + { + try + { + out_buffer = new char[out_buffer_size]; + in_buffer = new char[in_buffer_size]; + } + catch (...) + { + if (out_buffer) delete [] out_buffer; + throw; + } + setp(out_buffer, out_buffer + (out_buffer_size-1)); + setg(in_buffer+max_putback, + in_buffer+max_putback, + in_buffer+max_putback); + } + + virtual ~sockstreambuf_kernel_2 ( + ) + { + sync(); + delete [] out_buffer; + delete [] in_buffer; + } + + connection* get_connection ( + ) { return &con; } + + + protected: + + int flush_out_buffer ( + ) + { + int num = static_cast(pptr()-pbase()); + if (con.write(out_buffer,num) != num) + { + // the write was not successful so return EOF + return EOF; + } + pbump(-num); + return num; + } + + // output functions + int_type overflow ( + int_type c + ); + + int sync ( + ) + { + if (flush_out_buffer() == EOF) + { + // an error occurred + return -1; + } + return 0; + } + + std::streamsize xsputn ( + const char* s, + std::streamsize num + ); + + // input functions + int_type underflow( + ); + + std::streamsize xsgetn ( + char_type* s, + std::streamsize n + ); + + private: + + // member data + connection& con; + static const int max_putback = 4; + static const int out_buffer_size = 10000; + static const int in_buffer_size = 10000; + char* out_buffer; + char* in_buffer; + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "sockstreambuf_kernel_2.cpp" +#endif + +#endif // DLIB_SOCKSTREAMBUF_KERNEl_2_ + diff --git a/dlib/sockstreambuf/sockstreambuf_kernel_abstract.h b/dlib/sockstreambuf/sockstreambuf_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..dd6a483f1cb5b15d7e2838ece47b66b0e01d804c --- /dev/null +++ b/dlib/sockstreambuf/sockstreambuf_kernel_abstract.h @@ -0,0 +1,86 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SOCKSTREAMBUF_KERNEl_ABSTRACT_ +#ifdef DLIB_SOCKSTREAMBUF_KERNEl_ABSTRACT_ + +#include +#include +#include "../sockets/sockets_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class sockstreambuf : public std::streambuf + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a stream buffer capable of writing to and + reading from TCP connections. + + NOTE: + For a sockstreambuf EOF is when the connection has closed or otherwise + returned some kind of error. + + Also note that any data written to the streambuf may be buffered + internally. So if you need to ensure that data is actually sent then you + should flush the stream. + + A read operation is guaranteed to block until the number of bytes + requested has arrived on the connection. It will never keep blocking + once enough data has arrived. + + THREADING + generally speaking, this object has the same kind of threading + restrictions as a connection object. those being: + - do not try to write to a sockstreambuf from more than one thread + - do not try to read from a sockstreambuf from more than one thread + - you may call shutdown() on the connection object and this will + cause any reading or writing calls to end. To the sockstreambuf it + will appear the same as hitting EOF. (note that EOF for a sockstreambuf + means that the connection has closed) + - it is safe to read from and write to the sockstreambuf at the same time + - it is not safe to try to putback a char and read from the stream from + different threads + !*/ + public: + sockstreambuf ( + connection* con + ); + /*! + requires + - con == a valid connection object + ensures + - *this will read from and write to con + throws + - std::bad_alloc + !*/ + + ~sockstreambuf ( + ); + /*! + requires + - get_connection() object has not been deleted + ensures + - sockstream buffer is destructed but the connection object will + NOT be closed. + - Any buffered data is flushed to the connection. + !*/ + + connection* get_connection ( + ); + /*! + ensures + - returns a pointer to the connection object which this buffer + reads from and writes to + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SOCKSTREAMBUF_KERNEl_ABSTRACT_ + diff --git a/dlib/sort.h b/dlib/sort.h new file mode 100644 index 0000000000000000000000000000000000000000..c73f280f083b9a241b328e4b6bdaf5c846cb1280 --- /dev/null +++ b/dlib/sort.h @@ -0,0 +1,490 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SORt_ +#define DLIB_SORt_ + +#include "algs.h" +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + inline void qsort_array ( + T& array, + unsigned long left, + unsigned long right, + const compare& comp + ); + /*! + requires + - T implements operator[] + - the items in array must be comparable by comp where comp is a function + object with the same syntax as std::less<> + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + - left <= right + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - sorts using a quick sort algorithm + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void hsort_array ( + T& array, + unsigned long left, + unsigned long right, + const compare& comp + ); + /*! + requires + - T implements operator[] + - the items in array must be comparable by comp where comp is a function + object with the same syntax as std::less<> + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + - left <= right + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - sorts using a heapsort algorithm + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void isort_array ( + T& array, + unsigned long left, + unsigned long right, + const compare& comp + ); + /*! + requires + - T implements operator[] + - the items in array must be comparable by comp where comp is a function + object with the same syntax as std::less<> + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + - left <= right + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - sorts using an insertion sort algorithm + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + inline void qsort_array ( + T& array, + unsigned long left, + unsigned long right + ); + /*! + requires + - T implements operator[] + - the items in array must be comparable by std::less + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + - left <= right + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - sorts using a quick sort algorithm + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void hsort_array ( + T& array, + unsigned long left, + unsigned long right + ); + /*! + requires + - T implements operator[] + - the items in array must be comparable by std::less + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + - left <= right + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - sorts using a heapsort algorithm + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void isort_array ( + T& array, + unsigned long left, + unsigned long right + ); + /*! + requires + - T implements operator[] + - the items in array must be comparable by std::less + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + - left <= right + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - sorts using an insertion sort algorithm + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// IMPLEMENTATION DETAILS +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace sort_helpers + { + template + inline const std::less comp (const T&) + { + return std::less(); + } + + template < + typename T, + typename Y, + typename compare + > + inline unsigned long qsort_partition ( + T& array, + Y& pivot, + const unsigned long left, + const unsigned long right, + const compare& comp + ) + /*! + requires + - &pivot == &array[right] + - T implements operator[] + - the items in array must be comparable by comp + - left and right are within the bounts of the array + - left < right + ensures + - returns a number called partition_element such that: + - left <= partition_element <= right + - all elements in #array < #array[partition_element] have + indices >= left and < partition_element + - all elements in #array > #array[partition_element] have + indices > partition_element and <= right + !*/ + { + DLIB_ASSERT (&pivot == &array[right] && left < right, + "\tunsigned long qsort_partition()" + << "\n\t&pivot: " << &pivot + << "\n\t&array[right]: " << &array[right] + << "\n\tleft: " << left + << "\n\tright: " << right ); + + exchange(array[(right-left)/2 +left],pivot); + + unsigned long i = left; + for (unsigned long j = left; j < right; ++j) + { + if (comp(array[j] , pivot)) + { + swap(array[i],array[j]); + ++i; + } + } + exchange(array[i],pivot); + + return i; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void qsort_array_main ( + T& array, + const unsigned long left, + const unsigned long right, + unsigned long depth_check, + const compare& comp + ) + /*! + requires + - T implements operator[] + - the items in array must be comparable by comp + - the items in array must be swappable by a global swap() + - left and right are within the bounds of array + i.e. array[left] and array[right] are valid elements + ensures + - for all elements in #array between and including left and right the + ith element is < the i+1 element + - will only recurse about as deep as log(depth_check) calls + - sorts using a quick sort algorithm + !*/ + { + if ( left < right) + { + if (right-left < 30 || depth_check == 0) + { + hsort_array(array,left,right,comp); + } + else + { + // The idea here is to only let quick sort go about log(N) + // calls deep before it kicks into something else. + depth_check >>= 1; + depth_check += (depth_check>>4); + + unsigned long partition_element = + qsort_partition(array,array[right],left,right,comp); + + if (partition_element > 0) + qsort_array_main(array,left,partition_element-1,depth_check,comp); + qsort_array_main(array,partition_element+1,right,depth_check,comp); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void heapify ( + T& array, + const unsigned long start, + const unsigned long end, + unsigned long i, + const compare& comp + ) + /*! + requires + - T implements operator[] + - the items in array must be comparable by comp + - the items in array must be swappable by a global swap() + - start, end, and i are within the bounds of array + i.e. array[start], array[end], and array[i] are valid elements + - start <= i <= end + - array[i/2] is a max heap + - array[i/2+1] is a max heap + - start and end specify the range of the array we are working with. + ensures + - array[i] is now a max heap + !*/ + { + DLIB_ASSERT (start <= i && i <= end, + "\tvoid heapify()" + << "\n\tstart: " << start + << "\n\tend: " << end + << "\n\ti: " << i ); + + bool keep_going = true; + unsigned long left; + unsigned long right; + unsigned long largest; + while (keep_going) + { + keep_going = false; + left = (i<<1)+1-start; + right = left+1; + + if (left <= end && comp(array[i] , array[left])) + largest = left; + else + largest = i; + + if (right <= end && comp(array[largest] , array[right])) + largest = right; + + if (largest != i) + { + exchange(array[i],array[largest]); + i = largest; + keep_going = true; + } + } + } + +// ---------------------------------------------------------------------------------------- + } +// ---------------------------------------------------------------------------------------- + + + template < + typename T + > + inline void qsort_array ( + T& array, + unsigned long left, + unsigned long right + ) + { + using namespace sort_helpers; + qsort_array(array,left,right,comp(array[left])); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void hsort_array ( + T& array, + unsigned long left, + unsigned long right + ) + { + using namespace sort_helpers; + hsort_array(array,left,right,comp(array[left])); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void isort_array ( + T& array, + unsigned long left, + unsigned long right + ) + { + using namespace sort_helpers; + isort_array(array,left,right,comp(array[left])); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void isort_array ( + T& array, + const unsigned long left, + const unsigned long right, + const compare& comp + ) + { + DLIB_ASSERT (left <= right, + "\tvoid isort_array()" + << "\n\tleft: " << left + << "\n\tright: " << right ); + using namespace sort_helpers; + + unsigned long pos; + for (unsigned long i = left+1; i <= right; ++i) + { + // everything from left to i-1 is sorted. + pos = i; + for (unsigned long j = i-1; comp(array[pos] , array[j]); --j) + { + exchange(array[pos],array[j]); + pos = j; + + if (j == left) + break; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void qsort_array ( + T& array, + const unsigned long left, + const unsigned long right, + const compare& comp + ) + { + DLIB_ASSERT (left <= right, + "\tvoid qsort_array()" + << "\n\tleft: " << left + << "\n\tright: " << right ); + + sort_helpers::qsort_array_main(array,left,right,right-left,comp); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void hsort_array ( + T& array, + const unsigned long left, + const unsigned long right, + const compare& comp + ) + { + DLIB_ASSERT (left <= right, + "\tvoid hsort_array()" + << "\n\tleft: " << left + << "\n\tright: " << right ); + + if (right-left < 30) + { + isort_array(array,left,right,comp); + return; + } + + // turn array into a max heap + for (unsigned long i = left+((right-left)>>1);; --i) + { + sort_helpers::heapify(array,left,right,i,comp); + if (i == left) + break; + } + + // now sort the array + for (unsigned long i = right; i > left;) + { + exchange(array[i],array[left]); + sort_helpers::heapify(array,left,--i,left,comp); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SORt_ + diff --git a/dlib/sstream b/dlib/sstream new file mode 100644 index 0000000000000000000000000000000000000000..eb0e59e4176001d73c2070b3dd7cb2a6f9677eef --- /dev/null +++ b/dlib/sstream @@ -0,0 +1 @@ +#include "dlib_include_path_tutorial.txt" diff --git a/dlib/stack.h b/dlib/stack.h new file mode 100644 index 0000000000000000000000000000000000000000..a60a395f0a5b7e235a1bdf0b6b755a458804ee32 --- /dev/null +++ b/dlib/stack.h @@ -0,0 +1,34 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STACk_ +#define DLIB_STACk_ + +#include "stack/stack_kernel_1.h" +#include "stack/stack_kernel_c.h" +#include "memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class stack + { + stack() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef stack_kernel_1 + kernel_1a; + typedef stack_kernel_c + kernel_1a_c; + + }; +} + +#endif // DLIB_STACk_ + diff --git a/dlib/stack/stack_kernel_1.h b/dlib/stack/stack_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..e9630275b4eb5ed47dbc9a0bf333b3e33530c60a --- /dev/null +++ b/dlib/stack/stack_kernel_1.h @@ -0,0 +1,505 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STACK_KERNEl_1_ +#define DLIB_STACK_KERNEl_1_ + +#include "stack_kernel_abstract.h" +#include "../algs.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class stack_kernel_1 : public enumerable, + public remover + { + + /*! + INITIAL VALUE + stack_size == 0 + top == 0 + current_element == 0 + _at_start == true + + + CONVENTION + at_start() == _at_start + current_element_valid() == (current_element != 0) + if (current_element != 0) then + element() == current_element->item + + stack_size == the number of elements in the stack. + Each node points to the next node to be poped off the stack. + The last node in the list has its next pointer is set to 0. + + if (size == 0) + { + top == 0 + } + else + { + top == pointer to the last element added to the stack + } + !*/ + + struct node + { + node* next; + T item; + }; + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + stack_kernel_1( + ): + top(0), + stack_size(0), + current_element(0), + _at_start(true) + {} + + virtual ~stack_kernel_1( + ); + + inline void clear( + ); + + inline void push( + T& item + ); + + void pop( + T& item + ); + + T& current( + ); + + const T& current( + ) const; + + inline void swap ( + stack_kernel_1& item + ); + + // functions from the remover interface + inline void remove_any ( + T& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline T& element ( + ); + + bool move_next ( + ) const; + + private: + + void delete_elements_in_stack( + node*& top + ); + /*! + requires + - top points to the top of the stack + ensures + - all memory has been freed + - #top = 0 + !*/ + + + // data members + typename mem_manager::template rebind::other pool; + node* top; + unsigned long stack_size; + mutable node* current_element; + mutable bool _at_start; + + + // restricted functions + stack_kernel_1(stack_kernel_1&); // copy constructor + stack_kernel_1& operator=(stack_kernel_1&); // assignment operator + + }; + + + template < + typename T, + typename mem_manager + > + inline void swap ( + stack_kernel_1& a, + stack_kernel_1& b + ) { a.swap(b); } + + template < + typename T, + typename mem_manager + > + void deserialize ( + stack_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + T temp = T(); + stack_kernel_1 temp_stack; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(temp,in); + temp_stack.push(temp); + } + while (temp_stack.size() > 0) + { + temp_stack.pop(temp); + item.push(temp); + } + } + catch (serialization_error e) + { + item.clear(); + throw serialization_error(e.info + "\n while deserializing object of type stack_kernel_1"); + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + stack_kernel_1:: + ~stack_kernel_1( + ) + { + delete_elements_in_stack(top); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + clear( + ) + { + if (stack_size != 0) + { + delete_elements_in_stack(top); + stack_size = 0; + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& stack_kernel_1:: + current( + ) + { + return top->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& stack_kernel_1:: + current( + ) const + { + return top->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + swap( + stack_kernel_1& item + ) + { + pool.swap(item.pool); + + // declare temp variables + node* top_temp; + unsigned long stack_size_temp; + + // swap stack_size variables + stack_size_temp = item.stack_size; + item.stack_size = stack_size; + stack_size = stack_size_temp; + + // swap top pointers + top_temp = item.top; + item.top = top; + top = top_temp; + + exchange(current_element,item.current_element); + exchange(_at_start,item._at_start); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + push( + T& item + ) + { + // allocate memory for new node + node* new_node = pool.allocate(); + + // swap item into new_node + exchange(new_node->item,item); + + // put new_node into stack + new_node->next = top; + top = new_node; + ++stack_size; + + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + pop( + T& item + ) + { + node* old_node = top; + top = top->next; + + // swap the item from the stack into item + exchange(old_node->item,item); + + // free the memory + pool.deallocate(old_node); + --stack_size; + + reset(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + delete_elements_in_stack( + node*& top + ) + { + node* temp; + while (top != 0) + { + temp = top->next; + pool.deallocate(top); + top = temp; + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + unsigned long stack_kernel_1:: + size ( + ) const + { + return stack_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool stack_kernel_1:: + at_start ( + ) const + { + return _at_start; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + reset ( + ) const + { + _at_start = true; + current_element = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool stack_kernel_1:: + current_element_valid ( + ) const + { + return current_element != 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + const T& stack_kernel_1:: + element ( + ) const + { + return current_element->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + T& stack_kernel_1:: + element ( + ) + { + return current_element->item; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + bool stack_kernel_1:: + move_next ( + ) const + { + if (!_at_start) + { + if (current_element) + { + current_element = current_element->next; + if (current_element) + return true; + else + return false; + } + else + { + return false; + } + } + else + { + _at_start = false; + if (stack_size) + { + current_element = top; + return true; + } + else + { + return false; + } + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // remover function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename mem_manager + > + void stack_kernel_1:: + remove_any ( + T& item + ) + { + pop(item); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STACK_KERNEl_1_ + diff --git a/dlib/stack/stack_kernel_abstract.h b/dlib/stack/stack_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..49d144ffce677c7dcc7f4d3dd6b64957bbf9d6e9 --- /dev/null +++ b/dlib/stack/stack_kernel_abstract.h @@ -0,0 +1,177 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_STACK_KERNEl_ABSTRACT_ +#ifdef DLIB_STACK_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include "../memory_manager/memory_manager_kernel_abstract.h" + +namespace dlib +{ + + template < + typename T, + typename mem_manager = memory_manager::kernel_1a + > + class stack : public enumerable, + public remover + { + + /*! + REQUIREMENTS ON T + T must be swappable by a global swap() and + T must have a default constructor + + REQUIREMENTS ON mem_manager + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + mem_manager::type can be set to anything. + + POINTERS AND REFERENCES TO INTERNAL DATA + swap() and current() functions do not invalidate pointers + or references to internal data. + All other functions have no such guarantee. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements in the stack in the + same order they would be removed in by repeated calls to pop(). + (e.g. current() would be the first element enumerated) + + WHAT THIS OBJECT REPRESENTS + This is a last in first out stack containing items of type T. + + e.g. if the stack is {b,c,d,e} then a is put in + the stack becomes {a,b,c,d,e} and then pop takes a back out + returning the stack to {b,c,d,e} + !*/ + + public: + + typedef T type; + typedef mem_manager mem_manager_type; + + stack ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor + !*/ + + virtual ~stack ( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void push ( + T& item + ); + /*! + ensures + - item has been swapped onto the top of the stack + - #current() == item + - #item has an initial value for its type + - #size() == size() + 1 + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor + if push() throws then it has no effect + !*/ + + void pop ( + T& item + ); + /*! + requires + - size() != 0 + ensures + - #size() == size() - 1 + - #item == current() + i.e. the top element of *this has been removed and swapped + into #item + - #at_start() == true + !*/ + + T& current ( + ); + /*! + requires + - size() != 0 + ensures + - returns a const reference to the element at the top of *this + !*/ + + const T& current ( + ) const; + /*! + requires + - size() != 0 + ensures + - returns a non-const reference to the element at the top of *this + !*/ + + void swap ( + stack& item + ); + /*! + ensures + - swaps *this and item + !*/ + + + private: + + // restricted functions + stack(stack&); // copy constructor + stack& operator=(stack&); // assignment operator + + }; + + + template < + typename T, + typename mem_manager + > + inline void swap ( + stack& a, + stack& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename mem_manager + > + void deserialize ( + stack& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_STACK_KERNEl_ABSTRACT_ + diff --git a/dlib/stack/stack_kernel_c.h b/dlib/stack/stack_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..582d72e118d66b8d616b1799cbe5e4b1b34908c7 --- /dev/null +++ b/dlib/stack/stack_kernel_c.h @@ -0,0 +1,189 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STACK_KERNEl_C_ +#define DLIB_STACK_KERNEl_C_ + +#include "stack_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename stack_base + > + class stack_kernel_c : public stack_base + { + typedef typename stack_base::type T; + public: + void pop( + T& item + ); + + T& current( + ); + + const T& current( + ) const; + + const T& element( + ) const; + + T& element( + ); + + void remove_any ( + T& item + ); + + }; + + + template < + typename stack_base + > + inline void swap ( + stack_kernel_c& a, + stack_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename stack_base + > + void stack_kernel_c:: + pop( + T& item + ) + { + + // make sure requires clause is not broken + DLIB_CASSERT(this->size() != 0, + "\tvoid stack::pop" + << "\n\tsize of stack should not be zero" + << "\n\tthis: " << this + ); + + // call the real function + stack_base::pop(item); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack_base + > + const typename stack_base::type& stack_kernel_c:: + current( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->size() != 0, + "\tconst T& stack::current" + << "\n\tsize of stack should not be zero" + << "\n\tthis: " << this + ); + + // call the real function + return stack_base::current(); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack_base + > + typename stack_base::type& stack_kernel_c:: + current( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->size() != 0, + "\tT& stack::current" + << "\n\tsize of stack should not be zero" + << "\n\tthis: " << this + ); + + // call the real function + return stack_base::current(); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack_base + > + typename stack_base::type& stack_kernel_c:: + element( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid(), + "\tT& stack::element" + << "\n\tThe current element must be valid if you are to access it." + << "\n\tthis: " << this + ); + + // call the real function + return stack_base::element(); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack_base + > + const typename stack_base::type& stack_kernel_c:: + element( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid(), + "\tconst T& stack::element" + << "\n\tThe current element must be valid if you are to access it." + << "\n\tthis: " << this + ); + + // call the real function + return stack_base::element(); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename stack_base + > + void stack_kernel_c:: + remove_any ( + T& item + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( (this->size() > 0), + "\tvoid stack::remove_any" + << "\n\tsize() must be greater than zero if something is going to be removed" + << "\n\tsize(): " << this->size() + << "\n\tthis: " << this + ); + + // call the real function + stack_base::remove_any(item); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STACK_KERNEl_C_ + diff --git a/dlib/static_map.h b/dlib/static_map.h new file mode 100644 index 0000000000000000000000000000000000000000..4eb15441f4bd2ab43f92af57370d7d26f95479ad --- /dev/null +++ b/dlib/static_map.h @@ -0,0 +1,43 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_MAp_ +#define DLIB_STATIC_MAp_ + +#include "static_map/static_map_kernel_1.h" +#include "static_map/static_map_kernel_c.h" + +#include + + +namespace dlib +{ + + template < + typename domain, + typename range, + typename compare = std::less + > + class static_map + { + static_map() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef static_map_kernel_1 + kernel_1a; + typedef static_map_kernel_c + kernel_1a_c; + + + + + + }; +} + +#endif // DLIB_STATIC_MAp_ + diff --git a/dlib/static_map/static_map_kernel_1.h b/dlib/static_map/static_map_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..584c4a13d1c329e34f339473d65efde33f247b03 --- /dev/null +++ b/dlib/static_map/static_map_kernel_1.h @@ -0,0 +1,756 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_MAP_KERNEl_1_ +#define DLIB_STATIC_MAP_KERNEl_1_ + +#include "static_map_kernel_abstract.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../algs.h" +#include "../serialize.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename compare = std::less + > + class static_map_kernel_1 : public enumerable > + { + + /*! + INITIAL VALUE + - map_size == 0 + - d == 0 + - r == 0 + - mp.d = 0; + - at_start_ == true + + + CONVENTION + - size() == map_size + - if (size() > 0) then + - d == pointer to an array containing all the domain elements + - r == pointer to an array containing all the range elements + - for every i: operator[](d[i]) == r[i] + - d is sorted according to operator< + - else + - d == 0 + - r == 0 + + - current_element_valid() == (mp.d != 0) + - at_start() == (at_start_) + - if (current_element_valid()) then + - element() == mp + !*/ + + class mpair : public map_pair + { + public: + const domain* d; + range* r; + + const domain& key( + ) const { return *d; } + + const range& value( + ) const { return *r; } + + range& value( + ) { return *r; } + }; + + + // I would define this outside the class but Borland 5.5 has some problems + // with non-inline templated friend functions. + friend void deserialize ( + static_map_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + item.map_size = size; + item.d = new domain[size]; + item.r = new range[size]; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(item.d[i],in); + deserialize(item.r[i],in); + } + } + catch (serialization_error& e) + { + item.map_size = 0; + if (item.d) + { + delete [] item.d; + item.d = 0; + } + if (item.r) + { + delete [] item.r; + item.r = 0; + } + + throw serialization_error(e.info + "\n while deserializing object of type static_map_kernel_1"); + } + catch (...) + { + item.map_size = 0; + if (item.d) + { + delete [] item.d; + item.d = 0; + } + if (item.r) + { + delete [] item.r; + item.r = 0; + } + + throw; + } + } + + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + + static_map_kernel_1( + ); + + virtual ~static_map_kernel_1( + ); + + void clear ( + ); + + void load ( + pair_remover& source + ); + + void load ( + asc_pair_remover& source + ); + + inline const range* operator[] ( + const domain& d + ) const; + + inline range* operator[] ( + const domain& d + ); + + inline void swap ( + static_map_kernel_1& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + inline bool current_element_valid ( + ) const; + + inline const map_pair& element ( + ) const; + + inline map_pair& element ( + ); + + inline bool move_next ( + ) const; + + + private: + + bool binary_search ( + const domain& item, + unsigned long& pos + ) const; + /*! + ensures + - if (there is an item in d equivalent to item) then + - returns true + - d[#pos] is equivalent item + - else + - returns false + !*/ + + void sort_arrays ( + unsigned long left, + unsigned long right + ); + /*! + requires + - left and right are within the bounts of the array + ensures + - everything in the convention is still true and d[left] though + d[right] is sorted according to operator< + !*/ + + void qsort_partition ( + unsigned long& partition_element, + const unsigned long left, + const unsigned long right + ); + /*! + requires + - left < right + - left and right are within the bounts of the array + ensures + - the convention is still true + - left <= #partition_element <= right + - all elements in #d < #d[#partition_element] have + indices >= left and < #partition_element + - all elements in #d >= #d[#partition_element] have + indices >= #partition_element and <= right + !*/ + + unsigned long median ( + unsigned long one, + unsigned long two, + unsigned long three + ); + /*! + requires + - one, two, and three are valid indexes into d + ensures + - returns the median of d[one], d[two], and d[three] + !*/ + + + + + // data members + unsigned long map_size; + domain* d; + range* r; + mutable mpair mp; + mutable bool at_start_; + compare comp; + + // restricted functions + static_map_kernel_1(static_map_kernel_1&); // copy constructor + static_map_kernel_1& operator=(static_map_kernel_1&); // assignment operator + }; + + template < + typename domain, + typename range, + typename compare + > + inline void swap ( + static_map_kernel_1& a, + static_map_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + static_map_kernel_1:: + static_map_kernel_1( + ) : + map_size(0), + d(0), + r(0), + at_start_(true) + { + mp.d = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + static_map_kernel_1:: + ~static_map_kernel_1( + ) + { + if (map_size > 0) + { + delete [] d; + delete [] r; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + clear ( + ) + { + if (map_size > 0) + { + map_size = 0; + delete [] d; + delete [] r; + d = 0; + r = 0; + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + load ( + pair_remover& source + ) + { + if (source.size() > 0) + { + domain* old_d = d; + d = new domain[source.size()]; + try { r = new range[source.size()]; } + catch (...) { delete [] d; d = old_d; throw; } + + map_size = source.size(); + + for (unsigned long i = 0; source.size() > 0; ++i) + source.remove_any(d[i],r[i]); + + sort_arrays(0,map_size-1); + } + else + { + clear(); + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + load ( + asc_pair_remover& source + ) + { + if (source.size() > 0) + { + domain* old_d = d; + d = new domain[source.size()]; + try { r = new range[source.size()]; } + catch (...) { delete [] d; d = old_d; throw; } + + map_size = source.size(); + + for (unsigned long i = 0; source.size() > 0; ++i) + source.remove_any(d[i],r[i]); + } + else + { + clear(); + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + const range* static_map_kernel_1:: + operator[] ( + const domain& d_item + ) const + { + unsigned long pos; + if (binary_search(d_item,pos)) + return r+pos; + else + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + range* static_map_kernel_1:: + operator[] ( + const domain& d_item + ) + { + unsigned long pos; + if (binary_search(d_item,pos)) + return r+pos; + else + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + unsigned long static_map_kernel_1:: + size ( + ) const + { + return map_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + swap ( + static_map_kernel_1& item + ) + { + exchange(map_size,item.map_size); + exchange(d,item.d); + exchange(r,item.r); + exchange(mp,item.mp); + exchange(at_start_,item.at_start_); + exchange(comp,item.comp); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + bool static_map_kernel_1:: + at_start ( + ) const + { + return (at_start_); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + reset ( + ) const + { + mp.d = 0; + at_start_ = true; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + bool static_map_kernel_1:: + current_element_valid ( + ) const + { + return (mp.d != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + const map_pair& static_map_kernel_1:: + element ( + ) const + { + return mp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + map_pair& static_map_kernel_1:: + element ( + ) + { + return mp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + bool static_map_kernel_1:: + move_next ( + ) const + { + // if at_start() && size() > 0 + if (at_start_ && map_size > 0) + { + at_start_ = false; + mp.r = r; + mp.d = d; + return true; + } + // else if current_element_valid() + else if (mp.d != 0) + { + ++mp.d; + ++mp.r; + if (static_cast(mp.d - d) < map_size) + { + return true; + } + else + { + mp.d = 0; + return false; + } + } + else + { + at_start_ = false; + return false; + } + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + bool static_map_kernel_1:: + binary_search ( + const domain& item, + unsigned long& pos + ) const + { + unsigned long high = map_size; + unsigned long low = 0; + unsigned long p = map_size; + unsigned long idx; + while (p > 0) + { + p = (high-low)>>1; + idx = p+low; + if (comp(item , d[idx])) + { + high = idx; + } + else if (comp(d[idx] , item)) + { + low = idx; + } + else + { + pos = idx; + return true; + } + } + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + sort_arrays ( + unsigned long left, + unsigned long right + ) + { + if ( left < right) + { + unsigned long partition_element; + qsort_partition(partition_element,left,right); + + if (partition_element > 0) + sort_arrays(left,partition_element-1); + sort_arrays(partition_element+1,right); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + void static_map_kernel_1:: + qsort_partition ( + unsigned long& partition_element, + const unsigned long left, + const unsigned long right + ) + { + partition_element = right; + + unsigned long med = median(partition_element,left,((right-left)>>1) +left); + exchange(d[partition_element],d[med]); + exchange(r[partition_element],r[med]); + + unsigned long right_scan = right-1; + unsigned long left_scan = left; + + while (true) + { + // find an element to the left of partition_element that needs to be moved + while ( comp( d[left_scan] , d[partition_element]) ) + { + ++left_scan; + } + + // find an element to the right of partition_element that needs to be moved + while ( + !(comp (d[right_scan] , d[partition_element])) && + (right_scan > left_scan) + ) + { + --right_scan; + } + if (left_scan >= right_scan) + break; + + exchange(d[left_scan],d[right_scan]); + exchange(r[left_scan],r[right_scan]); + + } + exchange(d[left_scan],d[partition_element]); + exchange(r[left_scan],r[partition_element]); + partition_element = left_scan; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename domain, + typename range, + typename compare + > + unsigned long static_map_kernel_1:: + median ( + unsigned long one, + unsigned long two, + unsigned long three + ) + { + if ( comp( d[one] , d[two]) ) + { + // one < two + if ( comp( d[two] , d[three]) ) + { + // one < two < three : two + return two; + } + else + { + // one < two >= three + if (comp( d[one] , d[three])) + { + // three + return three; + } + } + + } + else + { + // one >= two + if ( comp(d[three] , d[one] )) + { + // three <= one >= two + if ( comp(d[three] , d[two]) ) + { + // two + return two; + } + else + { + // three + return three; + } + } + } + return one; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STATIC_MAP_KERNEl_1_ + diff --git a/dlib/static_map/static_map_kernel_abstract.h b/dlib/static_map/static_map_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..a9274965f51bd3c0009dae066e86644f177520e7 --- /dev/null +++ b/dlib/static_map/static_map_kernel_abstract.h @@ -0,0 +1,178 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_STATIC_MAP_KERNEl_ABSTRACT_ +#ifdef DLIB_STATIC_MAP_KERNEl_ABSTRACT_ + +#include "../interfaces/map_pair.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include + +namespace dlib +{ + + template < + typename domain, + typename range, + typename compare = std::less + > + class static_map : public enumerable > + { + + /*! + REQUIREMENTS ON domain + domain must be comparable by compare where compare is a functor compatible with std::less and + domain is swappable by a global swap() and + domain must have a default constructor + + REQUIREMENTS ON range + range is swappable by a global swap() and + range must have a default constructor + + POINTERS AND REFERENCES TO INTERNAL DATA + Only the destructor and load_from() will invalidate pointers or + references to internal data. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the domain (and each associated + range element) elements in ascending order according to the compare functor. + (i.e. the elements are enumerated in sorted order) + + WHAT THIS OBJECT REPRESENTS + static_map contains items of type domain and range + + This object is similar an array. It maps items of type domain on to + items of type range. + + NOTE + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + public: + + typedef domain domain_type; + typedef range range_type; + typedef compare compare_type; + + static_map ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + !*/ + + virtual ~static_map( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + If this exception is thrown then #*this is unusable + until clear() is called and succeeds. + !*/ + + void load ( + pair_remover& source + ); + /*! + ensures + - #size() == source.size() + - #source.size() == 0 + - all the pairs in source are removed and placed into #*this + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by domain's or range's + constructor. + If this exception is thrown then the call to load() will have + no effect on #*this. + !*/ + + const range* operator[] ( + const domain& d + ) const; + /*! + ensures + - if (there is an element in the domain equivalent to d) then + - returns a pointer to an element in the range of *this that + is associated with an element in the domain of *this + equivalent to d. + - else + - returns 0 + !*/ + + range* operator[] ( + const domain& d + ); + /*! + ensures + - if (there is an element in the domain equivalent to d) then + - returns a pointer to an element in the range of *this that + is associated with an element in the domain of *this + equivalent to d. + - else + - returns 0 + !*/ + + void swap ( + static_map& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + static_map(static_map&); // copy constructor + static_map& operator=(static_map&); // assignment operator + }; + + template < + typename domain, + typename range, + typename compare + > + inline void swap ( + static_map& a, + static_map& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename domain, + typename range, + typename compare + > + void deserialize ( + static_map& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ +} + +#endif // DLIB_STATIC_MAP_KERNEl_ABSTRACT_ + diff --git a/dlib/static_map/static_map_kernel_c.h b/dlib/static_map/static_map_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..c446c01d9b5f9d937ddb34bafb49d3df50160b7f --- /dev/null +++ b/dlib/static_map/static_map_kernel_c.h @@ -0,0 +1,89 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_MAP_KERNEl_C_ +#define DLIB_STATIC_MAP_KERNEl_C_ + +#include "static_map_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include "../interfaces/map_pair.h" +#include "../interfaces/remover.h" + +namespace dlib +{ + + template < + typename map_base + > + class static_map_kernel_c : public map_base + { + typedef typename map_base::domain_type domain; + typedef typename map_base::range_type range; + + public: + const map_pair& element ( + ) const; + + map_pair& element ( + ); + + }; + + template < + typename map_base + > + inline void swap ( + static_map_kernel_c& a, + static_map_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + const map_pair& static_map_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst map_pair& static_map::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return map_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map_base + > + map_pair& static_map_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tmap_pair& static_map::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return map_base::element(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STATIC_MAP_KERNEl_C_ + diff --git a/dlib/static_set.h b/dlib/static_set.h new file mode 100644 index 0000000000000000000000000000000000000000..ecdbb6100e550324ea6d5326fffa96b3190a6eac --- /dev/null +++ b/dlib/static_set.h @@ -0,0 +1,49 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_SEt_ +#define DLIB_STATIC_SEt_ + +#include "static_set/static_set_kernel_1.h" +#include "static_set/static_set_kernel_c.h" +#include "static_set/static_set_compare_1.h" + +#include + +namespace dlib +{ + + template < + typename T, + typename compare = std::less + > + class static_set + { + static_set() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef static_set_kernel_1 + kernel_1a; + typedef static_set_kernel_c + kernel_1a_c; + + + //----------- extensions ------------- + + typedef static_set_compare_1 + compare_1a; + typedef static_set_compare_1 + compare_1a_c; + + + + + }; +} + +#endif // DLIB_STATIC_SEt_ + diff --git a/dlib/static_set/static_set_compare_1.h b/dlib/static_set/static_set_compare_1.h new file mode 100644 index 0000000000000000000000000000000000000000..0d5976c7ea7be0d6a49a4fa1958241191a295ee3 --- /dev/null +++ b/dlib/static_set/static_set_compare_1.h @@ -0,0 +1,122 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_SET_COMPARe_1_ +#define DLIB_STATIC_SET_COMPARe_1_ + +#include "static_set_compare_abstract.h" + +#include "../algs.h" + + + +namespace dlib +{ + + template < + typename static_set_base + > + class static_set_compare_1 : public static_set_base + { + + public: + + bool operator< ( + const static_set_compare_1& rhs + ) const; + + bool operator== ( + const static_set_compare_1& rhs + ) const; + + }; + + + template < + typename static_set_base + > + inline void swap ( + static_set_compare_1& a, + static_set_compare_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename static_set_base + > + bool static_set_compare_1:: + operator< ( + const static_set_compare_1& rhs + ) const + { + bool result = false; + if (static_set_base::size() < rhs.size()) + result = true; + + if (static_set_base::size() == rhs.size()) + { + rhs.reset(); + static_set_base::reset(); + while (rhs.move_next()) + { + static_set_base::move_next(); + if (static_set_base::element() < rhs.element()) + { + result = true; + break; + } + else if (rhs.element() < static_set_base::element()) + { + break; + } + } + } + + static_set_base::reset(); + rhs.reset(); + + return result; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename static_set_base + > + bool static_set_compare_1:: + operator== ( + const static_set_compare_1& rhs + ) const + { + bool result = true; + if (static_set_base::size() != rhs.size()) + result = false; + + + rhs.reset(); + static_set_base::reset(); + while (rhs.move_next() && static_set_base::move_next()) + { + if (!(rhs.element() == static_set_base::element())) + { + result = false; + break; + } + } + + static_set_base::reset(); + rhs.reset(); + + return result; + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STATIC_SET_COMPARe_1_ + diff --git a/dlib/static_set/static_set_compare_abstract.h b/dlib/static_set/static_set_compare_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..179fd15bfaff4f727ce89aa86d1ae144e03917ab --- /dev/null +++ b/dlib/static_set/static_set_compare_abstract.h @@ -0,0 +1,93 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_STATIC_SET_COMPARe_ABSTRACT_ +#ifdef DLIB_STATIC_SET_COMPARe_ABSTRACT_ + +#include "static_set_kernel_abstract.h" + +#include "../algs.h" + + +namespace dlib +{ + + template < + typename static_set_base + > + class static_set_compare : public static_set_base + { + + /*! + REQUIREMENTS ON static_set_base + must an implementation of static_set/static_set_kernel_abstract.h + + POINTERS AND REFERENCES TO INTERNAL DATA + operator== and operator< invalidate pointers or references to + data members. + + WHAT THIS EXTENSION DOES FOR static_set + This gives a static_set the ability to compare itself to other + static_sets using the < and == operators. + + The < operator is conceptually weird for sets. It is useful + though because it allows you to make sets of sets since + sets require that their containing type implement operator<. + + Also note that it is the case that for any two sets a and b + if (a rhs.size()) then + - returns false + - else + - returns true if there exists an integer j such that 0 <= j < size() + and for all integers i such that 0 <= i < j where it is true that + (*this)[i] == rhs[i] and (*this)[j] < rhs[j] + - returns false if there is no j that will satisfy the above conditions. + !*/ + + bool operator== ( + const static_set_compare& rhs + ) const; + /*! + ensures + - #at_start() == true + - returns true if *this and rhs contain the same elements. + returns false otherwise. + !*/ + }; + + + template < + typename static_set_base + > + inline void swap ( + static_set_compare& a, + static_set_compare& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_STATIC_SET_COMPARe_ABSTRACT_ + diff --git a/dlib/static_set/static_set_kernel_1.h b/dlib/static_set/static_set_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..d60a9422416434d6a4841be86eafb550fc90752d --- /dev/null +++ b/dlib/static_set/static_set_kernel_1.h @@ -0,0 +1,446 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_SET_KERNEl_1_ +#define DLIB_STATIC_SET_KERNEl_1_ + +#include "static_set_kernel_abstract.h" +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../algs.h" +#include "../sort.h" +#include "../serialize.h" +#include + +namespace dlib +{ + + template < + typename T, + typename compare = std::less + > + class static_set_kernel_1 : public enumerable + { + + /*! + INITIAL VALUE + - set_size == 0 + - d == 0 + - at_start_ == true + - cur == 0 + + CONVENTION + - size() == set_size + - if (set_size > 0) then + - d == pointer to an array containing all the elements of the set + - d is sorted according to operator< + - else + - d == 0 + + - current_element_valid() == (cur != 0) + - at_start() == (at_start_) + - if (current_element_valid()) then + - element() == *cur + !*/ + + // I would define this outside the class but Borland 5.5 has some problems + // with non-inline templated friend functions. + friend void deserialize ( + static_set_kernel_1& item, + std::istream& in + ) + { + try + { + item.clear(); + unsigned long size; + deserialize(size,in); + item.set_size = size; + item.d = new T[size]; + for (unsigned long i = 0; i < size; ++i) + { + deserialize(item.d[i],in); + } + } + catch (serialization_error e) + { + item.set_size = 0; + if (item.d) + { + delete [] item.d; + item.d = 0; + } + + throw serialization_error(e.info + "\n while deserializing object of type static_set_kernel_1"); + } + catch (...) + { + item.set_size = 0; + if (item.d) + { + delete [] item.d; + item.d = 0; + } + + throw; + } + } + + public: + + typedef T type; + typedef compare compare_type; + + static_set_kernel_1( + ); + + virtual ~static_set_kernel_1( + ); + + void clear ( + ); + + void load ( + remover& source + ); + + void load ( + asc_remover& source + ); + + bool is_member ( + const T& item + ) const; + + inline void swap ( + static_set_kernel_1& item + ); + + // functions from the enumerable interface + inline unsigned long size ( + ) const; + + inline bool at_start ( + ) const; + + inline void reset ( + ) const; + + inline bool current_element_valid ( + ) const; + + inline const T& element ( + ) const; + + inline const T& element ( + ); + + inline bool move_next ( + ) const; + + + private: + + + // data members + unsigned long set_size; + T* d; + mutable T* cur; + mutable bool at_start_; + + // restricted functions + static_set_kernel_1(static_set_kernel_1&); // copy constructor + static_set_kernel_1& operator=(static_set_kernel_1&); // assignment operator + }; + + template < + typename T, + typename compare + > + inline void swap ( + static_set_kernel_1& a, + static_set_kernel_1& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + static_set_kernel_1:: + static_set_kernel_1( + ) : + set_size(0), + d(0), + cur(0), + at_start_(true) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + static_set_kernel_1:: + ~static_set_kernel_1( + ) + { + if (set_size > 0) + delete [] d; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void static_set_kernel_1:: + clear( + ) + { + if (set_size > 0) + { + set_size = 0; + delete [] d; + d = 0; + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void static_set_kernel_1:: + load ( + remover& source + ) + { + if (source.size() > 0) + { + d = new T[source.size()]; + + set_size = source.size(); + + for (unsigned long i = 0; source.size() > 0; ++i) + source.remove_any(d[i]); + + compare comp; + qsort_array(d,0,set_size-1,comp); + } + else + { + clear(); + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void static_set_kernel_1:: + load ( + asc_remover& source + ) + { + if (source.size() > 0) + { + d = new T[source.size()]; + + set_size = source.size(); + + for (unsigned long i = 0; source.size() > 0; ++i) + source.remove_any(d[i]); + } + else + { + clear(); + } + reset(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + bool static_set_kernel_1:: + is_member ( + const T& item + ) const + { + unsigned long high = set_size; + unsigned long low = 0; + unsigned long p = set_size; + unsigned long idx; + while (p > 0) + { + p = (high-low)>>1; + idx = p+low; + if (item < d[idx]) + high = idx; + else if (d[idx] < item) + low = idx; + else + return true; + } + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + unsigned long static_set_kernel_1:: + size ( + ) const + { + return set_size; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void static_set_kernel_1:: + swap ( + static_set_kernel_1& item + ) + { + exchange(set_size,item.set_size); + exchange(d,item.d); + exchange(cur,item.cur); + exchange(at_start_,item.at_start_); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // enumerable function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + bool static_set_kernel_1:: + at_start ( + ) const + { + return at_start_; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + void static_set_kernel_1:: + reset ( + ) const + { + at_start_ = true; + cur = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + bool static_set_kernel_1:: + current_element_valid ( + ) const + { + return (cur != 0); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + const T& static_set_kernel_1:: + element ( + ) const + { + return *cur; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + const T& static_set_kernel_1:: + element ( + ) + { + return *cur; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename compare + > + bool static_set_kernel_1:: + move_next ( + ) const + { + // if at_start() && size() > 0 + if (at_start_ && set_size > 0) + { + at_start_ = false; + cur = d; + return true; + } + // else if current_element_valid() + else if (cur != 0) + { + ++cur; + if (static_cast(cur - d) < set_size) + { + return true; + } + else + { + cur = 0; + return false; + } + } + else + { + at_start_ = false; + return false; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STATIC_SET_KERNEl_1_ + diff --git a/dlib/static_set/static_set_kernel_abstract.h b/dlib/static_set/static_set_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..1fa8e11a3386b4f28204d661c540aba6bc7cb6a0 --- /dev/null +++ b/dlib/static_set/static_set_kernel_abstract.h @@ -0,0 +1,151 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_STATIC_SET_KERNEl_ABSTRACT_ +#ifdef DLIB_STATIC_SET_KERNEl_ABSTRACT_ + +#include "../interfaces/enumerable.h" +#include "../interfaces/remover.h" +#include "../serialize.h" +#include + +namespace dlib +{ + + template < + typename T, + typename compare = std::less + > + class static_set : public enumerable + { + + /*! + REQUIREMENTS ON T + T must be comparable by compare where compare is a functor compatible with std::less and + T is swappable by a global swap() and + T must have a default constructor + + POINTERS AND REFERENCES TO INTERNAL DATA + Only the destructor will invalidate pointers or references + to internal data. + + INITIAL VALUE + size() == 0 + + ENUMERATION ORDER + The enumerator will iterate over the elements in the set in + ascending order according to the compare functor. + (i.e. the elements are enumerated in sorted order) + + WHAT THIS OBJECT REPRESENTS + static_set contains items of type T + + This object represents an unaddressed collection of items. + + NOTE + definition of equivalent: + a is equivalent to b if + a < b == false and + b < a == false + !*/ + + public: + + typedef T type; + typedef compare compare_type; + + static_set ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc or any exception thrown by T's constructor. + !*/ + + virtual ~static_set( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then #*this is unusable + until clear() is called and succeeds. + !*/ + + void load ( + remover& source + ); + /*! + ensures + - #size() == source.size() + - #source.size() == 0 + - all the elements in source are removed and placed into #*this + - #at_start() == true + throws + - std::bad_alloc or any exception thrown by T's constructor. + If this exception is thrown then the call to load() will have + no effect on #*this. + !*/ + + bool is_member ( + const T& item + ) const; + /*! + ensures + - if (there is an item in *this equivalent to item) then + - returns true + - else + - returns false + !*/ + + void swap ( + static_set& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + static_set(static_set&); // copy constructor + static_set& operator=(static_set&); // assignment operator + }; + + template < + typename T, + typename compare + > + inline void swap ( + static_set& a, + static_set& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + template < + typename T, + typename compare + > + void deserialize ( + static_set& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +} + +#endif // DLIB_STATIC_SET_KERNEl_ABSTRACT_ + diff --git a/dlib/static_set/static_set_kernel_c.h b/dlib/static_set/static_set_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..1de2132a9e95594c96c6d773e13cd9f7752d5293 --- /dev/null +++ b/dlib/static_set/static_set_kernel_c.h @@ -0,0 +1,88 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STATIC_SET_KERNEl_C_ +#define DLIB_STATIC_SET_KERNEl_C_ + +#include "static_set_kernel_abstract.h" +#include "../algs.h" +#include "../assert.h" +#include "../interfaces/remover.h" + +namespace dlib +{ + + template < + typename set_base + > + class static_set_kernel_c : public set_base + { + typedef typename set_base::type T; + public: + + const T& element ( + ); + + const T& element ( + ) const; + }; + + + template < + typename set_base + > + inline void swap ( + static_set_kernel_c& a, + static_set_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + const typename set_base::type& static_set_kernel_c:: + element ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& static_set::element() const" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return set_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_base + > + const typename set_base::type& static_set_kernel_c:: + element ( + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(this->current_element_valid() == true, + "\tconst T& static_set::element" + << "\n\tyou can't access the current element if it doesn't exist" + << "\n\tthis: " << this + ); + + // call the real function + return set_base::element(); + } + +// ---------------------------------------------------------------------------------------- + + +} + +#endif // DLIB_STATIC_SET_KERNEl_C_ + diff --git a/dlib/std_allocator.h b/dlib/std_allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..f5985b3128072514b96758f8dac97fed21660c04 --- /dev/null +++ b/dlib/std_allocator.h @@ -0,0 +1,186 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STD_ALLOc_H_ +#define DLIB_STD_ALLOc_H_ + +#include +#include +#include "enable_if.h" +#include "algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename M + > + class std_allocator + { + /*! + REQUIREMENTS ON M + must be an implementation of memory_manager/memory_manager_kernel_abstract.h or + must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or + must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + M::type can be set to anything. + + WHAT THIS OBJECT REPRESENTS + This object is an implementation of an allocator that conforms to the C++ standard + requirements for allocator objects. The M template argument is one of the dlib + memory manager objects and this allocator implementation will do all of its memory allocations + using whatever dlib memory manager you supply. + + Thus, using this allocator object you can use any of the dlib memory manager objects with + the contains in the STL or with any other object that requires a C++ allocator object. + !*/ + + public: + //type definitions + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + + //rebind std_allocator to type U + template + struct rebind { + typedef std_allocator other; + }; + + //return address of values + pointer address (reference value) const { return &value; } + + const_pointer address (const_reference value) const { return &value; } + + /*constructors and destructor + *-nothing to do because the std_allocator has no state + */ + std_allocator() throw() { } + + std_allocator(const std_allocator&) throw() { } + + template + std_allocator (const std_allocator&) throw() { } + + ~std_allocator() throw() { } + + //return maximum number of elements that can be allocated + size_type max_size () const throw() + { + //for numeric_limits see Section 4.3, page 59 + return std::numeric_limits::max() / sizeof(T); + } + + //allocate but don't initialize num elements of type T + pointer allocate ( + size_type num, + typename std_allocator::const_pointer hint = 0 + ) + { + return (pointer) pool.allocate_array(num*sizeof(T)); + } + + //initialize elements of allocated storage p with value value + void construct (pointer p, const T& value) + { + //initialize memory with placement new + new((void*)p)T(value); + } + + + //destroy elements of initialized storage p + void destroy (pointer p) + { + // destroy objects by calling their destructor + p->~T(); + } + + //deallocate storage p of deleted elements + void deallocate (pointer p, size_type num) + { + pool.deallocate_array((char*)p); + } + + void swap ( + std_allocator& item + ) + { + pool.swap(item.pool); + } + + private: + typename M::template rebind::other pool; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename M + > + class std_allocator + { + public: + //type definitions + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + + //rebind std_allocator to type U + template + struct rebind { + typedef std_allocator other; + }; + + }; + +// ---------------------------------------------------------------------------------------- + + template + struct std_alloc_compare + { const static bool are_interchangeable = false; }; + + template + struct std_alloc_compare >::type> + { const static bool are_interchangeable = true; }; + + template + struct std_alloc_compare::type> + { const static bool are_interchangeable = true; }; + + //return that all specializations of this std_allocator are interchangeable if they use memory_manager_global + // instances with the same mm_global_type + template + bool operator== ( + const std_allocator&, + const std_allocator& + ) throw() + { return std_alloc_compare::are_interchangeable; } + + template + bool operator!= ( + const std_allocator&, + const std_allocator& + ) throw() + { return !std_alloc_compare::are_interchangeable; } + +// ---------------------------------------------------------------------------------------- + + template + void swap ( + std_allocator& a, + std_allocator& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STD_ALLOc_H_ + diff --git a/dlib/stl_checked.h b/dlib/stl_checked.h new file mode 100644 index 0000000000000000000000000000000000000000..c1880027b6253b54826253f4c410afa0ee5590d7 --- /dev/null +++ b/dlib/stl_checked.h @@ -0,0 +1,10 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STL_CHECKEd_HEADER +#define DLIB_STL_CHECKEd_HEADER + +#include "stl_checked/std_vector_c.h" + +#endif // DLIB_STL_CHECKEd_HEADER + + diff --git a/dlib/stl_checked/std_vector_c.h b/dlib/stl_checked/std_vector_c.h new file mode 100644 index 0000000000000000000000000000000000000000..c16428e237f04a994e8fe8c1424d8f67ff9cde06 --- /dev/null +++ b/dlib/stl_checked/std_vector_c.h @@ -0,0 +1,346 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STD_VECTOr_C_H_ +#define DLIB_STD_VECTOr_C_H_ + +#include +#include +#include "../assert.h" +#include "std_vector_c_abstract.h" +#include "../serialize.h" + +namespace dlib +{ + + template < + typename T, + typename Allocator = std::allocator + > + class std_vector_c + { + typedef typename std::vector base_type; + base_type impl; + public: + // types: + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + typedef typename base_type::iterator iterator; // See 23.1 + typedef typename base_type::const_iterator const_iterator; // See 23.1 + typedef typename base_type::size_type size_type; // See 23.1 + typedef typename base_type::difference_type difference_type;// See 23.1 + typedef T value_type; + typedef Allocator allocator_type; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + + // 23.2.4.1 construct/copy/destroy: + explicit std_vector_c(const Allocator& alloc= Allocator()) : impl(alloc) {} + + explicit std_vector_c(size_type n, const T& value = T(), + const Allocator& alloc= Allocator()) : impl(n, value, alloc) {} + + template + std_vector_c(InputIterator first, InputIterator last, + const Allocator& alloc= Allocator()) : impl(first,last,alloc) {} + + std_vector_c(const std_vector_c& x) : impl(x.impl) {} + + + std_vector_c& operator=(const std_vector_c& x) + { + impl = x.impl; + return *this; + } + + template + void assign(InputIterator first, InputIterator last) { impl.assign(first,last); } + void assign(size_type n, const T& u) { impl.assign(n,u); } + allocator_type get_allocator() const { return impl.get_allocator(); } + // iterators: + iterator begin() { return impl.begin(); } + const_iterator begin() const { return impl.begin(); } + iterator end() { return impl.end(); } + const_iterator end() const { return impl.end(); } + reverse_iterator rbegin() { return impl.rbegin(); } + const_reverse_iterator rbegin() const { return impl.rbegin(); } + reverse_iterator rend() { return impl.rend(); } + const_reverse_iterator rend() const { return impl.rend(); } + // 23.2.4.2 capacity: + size_type size() const { return impl.size(); } + size_type max_size() const { return impl.max_size(); } + void resize(size_type sz, T c = T()) { impl.resize(sz,c); } + size_type capacity() const { return impl.capacity(); } + bool empty() const { return impl.empty(); } + void reserve(size_type n) { impl.reserve(n); } + + // element access: + const_reference at(size_type n) const { return impl.at(n); } + reference at(size_type n) { return impl.at(n); } + + + // 23.2.4.3 modifiers: + void push_back(const T& x) { impl.push_back(x); } + void swap(std_vector_c& x) { impl.swap(x.impl); } + void clear() { impl.clear(); } + + + // ------------------------------------------------------ + // Things that have preconditions that should be checked. + // ------------------------------------------------------ + + reference operator[]( + size_type n + ) + { + DLIB_CASSERT(n < size(), + "\treference std_vector_c::operator[](n)" + << "\n\tYou have supplied an invalid index" + << "\n\tthis: " << this + << "\n\tn: " << n + << "\n\tsize(): " << size() + ); + return impl[n]; + } + + // ------------------------------------------------------ + + const_reference operator[]( + size_type n + ) const + { + DLIB_CASSERT(n < size(), + "\tconst_reference std_vector_c::operator[](n)" + << "\n\tYou have supplied an invalid index" + << "\n\tthis: " << this + << "\n\tn: " << n + << "\n\tsize(): " << size() + ); + return impl[n]; + } + + // ------------------------------------------------------ + + reference front( + ) + { + DLIB_CASSERT(size() > 0, + "\treference std_vector_c::front()" + << "\n\tYou can't call front() on an empty vector" + << "\n\tthis: " << this + ); + return impl.front(); + } + + // ------------------------------------------------------ + + const_reference front( + ) const + { + DLIB_CASSERT(size() > 0, + "\tconst_reference std_vector_c::front()" + << "\n\tYou can't call front() on an empty vector" + << "\n\tthis: " << this + ); + return impl.front(); + } + + // ------------------------------------------------------ + + reference back( + ) + { + DLIB_CASSERT(size() > 0, + "\treference std_vector_c::back()" + << "\n\tYou can't call back() on an empty vector" + << "\n\tthis: " << this + ); + return impl.back(); + } + + // ------------------------------------------------------ + + const_reference back( + ) const + { + DLIB_CASSERT(size() > 0, + "\tconst_reference std_vector_c::back()" + << "\n\tYou can't call back() on an empty vector" + << "\n\tthis: " << this + ); + return impl.back(); + } + + // ------------------------------------------------------ + + void pop_back( + ) + { + DLIB_CASSERT(size() > 0, + "\tconst_reference std_vector_c::pop_back()" + << "\n\tYou can't call pop_back() on an empty vector" + << "\n\tthis: " << this + ); + impl.pop_back(); + } + + // ------------------------------------------------------ + + iterator insert( + iterator position, + const T& x + ) + { + DLIB_CASSERT( begin() <= position && position <= end(), + "\titerator std_vector_c::insert(position,x)" + << "\n\tYou have called insert() with an invalid position" + << "\n\tthis: " << this + ); + return impl.insert(position, x); + } + + // ------------------------------------------------------ + + void insert( + iterator position, + size_type n, + const T& x + ) + { + DLIB_CASSERT( begin() <= position && position <= end(), + "\tvoid std_vector_c::insert(position,n,x)" + << "\n\tYou have called insert() with an invalid position" + << "\n\tthis: " << this + ); + impl.insert(position, n, x); + } + + // ------------------------------------------------------ + + template + void insert( + iterator position, + InputIterator first, + InputIterator last + ) + { + DLIB_CASSERT( begin() <= position && position <= end(), + "\tvoid std_vector_c::insert(position,first,last)" + << "\n\tYou have called insert() with an invalid position" + << "\n\tthis: " << this + ); + impl.insert(position, first, last); + } + + // ------------------------------------------------------ + + iterator erase( + iterator position + ) + { + DLIB_CASSERT( begin() <= position && position < end(), + "\titerator std_vector_c::erase(position)" + << "\n\tYou have called erase() with an invalid position" + << "\n\tthis: " << this + ); + return impl.erase(position); + } + + // ------------------------------------------------------ + + iterator erase( + iterator first, + iterator last + ) + { + DLIB_CASSERT( begin() <= first && first <= last && last <= end(), + "\titerator std_vector_c::erase(first,last)" + << "\n\tYou have called erase() with an invalid range of iterators" + << "\n\tthis: " << this + ); + return impl.erase(first,last); + } + + // ------------------------------------------------------ + + + }; + +// ---------------------------------------------------------------------------------------- + + template + bool operator==(const std_vector_c& x, const std_vector_c& y) + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } + + template + bool operator< (const std_vector_c& x, const std_vector_c& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + template + bool operator!=(const std_vector_c& x, const std_vector_c& y) + { return !(x == y); } + + template + bool operator> (const std_vector_c& x, const std_vector_c& y) + { return y < x; } + + template + bool operator>=(const std_vector_c& x, const std_vector_c& y) + { return !(x < y); } + + template + bool operator<=(const std_vector_c& x, const std_vector_c& y) + { return !(y < x); } + + // specialized algorithms: + template + void swap(std_vector_c& x, std_vector_c& y) { x.swap(y); } + +// ---------------------------------------------------------------------------------------- + + template + void serialize ( + const std_vector_c& item, + std::ostream& out + ) + { + try + { + const unsigned long size = static_cast(item.size()); + + serialize(size,out); + for (unsigned long i = 0; i < item.size(); ++i) + serialize(item[i],out); + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while serializing object of type std_vector_c"); } + } + +// ---------------------------------------------------------------------------------------- + + template + void deserialize ( + std_vector_c& item, + std::istream& in + ) + { + try + { + unsigned long size; + deserialize(size,in); + item.resize(size); + for (unsigned long i = 0; i < size; ++i) + deserialize(item[i],in); + } + catch (serialization_error& e) + { throw serialization_error(e.info + "\n while deserializing object of type std_vector_c"); } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STD_VECTOr_C_H_ + diff --git a/dlib/stl_checked/std_vector_c_abstract.h b/dlib/stl_checked/std_vector_c_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..7a2e23977617574d2ff27da388096b6ab8bd0e76 --- /dev/null +++ b/dlib/stl_checked/std_vector_c_abstract.h @@ -0,0 +1,507 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_STD_VECTOr_C_ABSTRACT_H_ +#ifdef DLIB_STD_VECTOr_C_ABSTRACT_H_ + +#include +#include +#include "../assert.h" + +namespace dlib +{ + + template < + typename T, + typename Allocator = std::allocator + > + class std_vector_c + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is a simple wrapper around the std::vector object. It + provides an identical interface but also checks the preconditions of + each member function. That is, if you violate a requires + clause the dlib::fatal_error exception is thrown. + !*/ + + typedef typename std::vector base_type; + public: + typedef typename Allocator::reference reference; + typedef typename Allocator::const_reference const_reference; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef T value_type; + typedef Allocator allocator_type; + typedef typename Allocator::pointer pointer; + typedef typename Allocator::const_pointer const_pointer; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + + explicit std_vector_c( + const Allocator& alloc = Allocator() + ); + /*! + ensures + - #get_allocator() == alloc + - #size() == 0 + !*/ + + explicit std_vector_c ( + size_type n, + const T& value = T(), + const Allocator& alloc = Allocator() + ); + /*! + ensures + - #size() == n + - #get_allocator() == alloc + - for all valid i: + - (*this)[i] == value + !*/ + + template + std_vector_c ( + InputIterator first, + InputIterator last, + const Allocator& alloc = Allocator() + ); + /*! + ensures + - #size() == std::distance(first,last) + - #get_allocator() == alloc + - std::equal(first, last, begin()) == true + !*/ + + std_vector_c( + const std_vector_c& x + ); + /*! + ensures + - #*this == x + !*/ + + + std_vector_c& operator= ( + const std_vector_c& x + ); + /*! + ensures + - #*this == x + - returns #*this + !*/ + + template + void assign( + InputIterator first, + InputIterator last + ); + /*! + ensures + - #size() == std::distance(first,last) + - std::equal(first, last, begin()) == true + !*/ + + void assign( + size_type n, + const T& value + ); + /*! + ensures + - #size() == n + - for all valid i: + - (*this)[i] == value + !*/ + + allocator_type get_allocator( + ) const; + /*! + ensures + - returns the allocator used by this vector + !*/ + + iterator begin( + ); + /*! + ensures + - if (size() > 0) then + - returns an iterator referring to the first element in + this container. + - else + - returns end() + !*/ + + const_iterator begin( + ) const; + /*! + ensures + - if (size() > 0) then + - returns a const_iterator referring to the first element in + this container. + - else + - returns end() + !*/ + + iterator end( + ); + /*! + ensures + - returns an iterator that represents one past the end of + this container + !*/ + + const_iterator end( + ) const; + /*! + ensures + - returns an iterator that represents one past the end of + this container + !*/ + + reverse_iterator rbegin( + ); + /*! + ensures + - returns std::reverse_iterator(end()) + !*/ + + const_reverse_iterator rbegin( + ) const; + /*! + ensures + - returns std::reverse_iterator(end()) + !*/ + + reverse_iterator rend( + ); + /*! + ensures + - returns std::reverse_iterator(begin()) + !*/ + + const_reverse_iterator rend( + ) const; + /*! + ensures + - returns std::reverse_iterator(begin()) + !*/ + + size_type size( + ) const; + /*! + ensures + - returns end()-begin() + (i.e. returns the number of elements in this container) + !*/ + + size_type max_size( + ) const; + /*! + ensures + - returns the maximum number of elements this vector can contain + !*/ + + void resize( + size_type sz, + T c = T() + ); + /*! + ensures + - #size() == sz + - any element with index between 0 and sz - 1 which was in the + vector before the call to resize() retains its value and index. + All other elements have a value given by c. + !*/ + + size_type capacity( + ) const; + /*! + ensures + - returns the total number of elements that the vector can hold without + requiring reallocation. + !*/ + + bool empty( + ) const; + /*! + ensures + - if (size() == 0) then + - returns true + - else + - returns false + !*/ + + void reserve( + size_type n + ); + /*! + ensures + - #capacity() >= n + !*/ + + const_reference at( + size_type n + ) const; + /*! + ensures + - if (n < size()) then + - returns a const reference to (*this)[n] + - else + - throws std::out_of_range + !*/ + + reference at( + size_type n + ); + /*! + ensures + - if (n < size()) then + - returns a reference to (*this)[n] + - else + - throws std::out_of_range + !*/ + + void push_back( + const T& x + ); + /*! + ensures + - #size() == size() + 1 + - #back() == x + !*/ + + void swap( + std_vector_c& x + ); + /*! + ensures + - swaps the state of *this and x + !*/ + + void clear( + ); + /*! + ensures + - size() == 0 + !*/ + + reference operator[]( + size_type n + ); + /*! + requires + - n < size() + ensures + - returns a reference to the nth element of this container + !*/ + + const_reference operator[]( + size_type n + ) const; + /*! + requires + - n < size() + ensures + - returns a const reference to the nth element of this container + !*/ + + reference front( + ); + /*! + requires + - size() > 0 + ensures + - returns a reference to (*this)[0] + !*/ + + const_reference front( + ) const; + /*! + requires + - size() > 0 + ensures + - returns a const reference to (*this)[0] + !*/ + + reference back( + ); + /*! + requires + - size() > 0 + ensures + - returns a reference to (*this)[size()-1] + !*/ + + const_reference back( + ) const; + /*! + requires + - size() > 0 + ensures + - returns a const reference to (*this)[size()-1] + !*/ + + void pop_back( + ); + /*! + requires + - size() > 0 + ensures + - #size() == size() - 1 + - removes the last element in the vector but leaves the others + unmodified. + !*/ + + iterator insert( + iterator position, + const T& x + ); + /*! + requires + - begin() <= position && position < end() + (i.e. position references an element in this vector object) + ensures + - #size() == size() + 1 + - inserts a copy of x into *this before the given position + - returns an iterator that points to the copy of x inserted + into *this + !*/ + + void insert( + iterator position, + size_type n, + const T& x + ); + /*! + requires + - begin() <= position && position < end() + (i.e. position references an element in this vector object) + ensures + - #size() == size() + n + - inserts n copies of x into *this before the given position + !*/ + + template + void insert( + iterator position, + InputIterator first, + InputIterator last + ); + /*! + requires + - begin() <= position && position < end() + (i.e. position references an element in this vector object) + - first and last are not iterators into *this + ensures + - #size() == size() + std::distance(last,first) + - inserts copies of the range of elements [first,last) into *this + before the given position + !*/ + + iterator erase( + iterator position + ); + /*! + requires + - begin() <= position && position < end() + (i.e. position references an element in this vector object) + ensures + - #size() == size() - 1 + - removes the element in this vector referenced by position but + leaves all other elements in this vector unmodified. + - if (position < end()-1) then + - returns an iterator referencing the element immediately + following *position prior to the erase. + - else + - returns end() + !*/ + + iterator erase( + iterator first, + iterator last + ); + /*! + requires + - begin() <= first && first <= last && last <= end() + (i.e. the range [first,last) must be inside this container ) + ensures + - #size() == size() - (last-first) + - removes the elements in this vector referenced by the + iterator range [first,last) but leaves all other elements + in this vector unmodified. + - if (last < end()-1) then + - returns an iterator referencing the element immediately + following *last prior to the erase. + - else + - returns end() + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +// provide global comparison operators that work for the std_vector_c object. + + template + bool operator==(const std_vector_c& x, const std_vector_c& y) + { return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin()); } + + template + bool operator< (const std_vector_c& x, const std_vector_c& y) + { return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + template + bool operator!=(const std_vector_c& x, const std_vector_c& y) + { return !(x == y); } + + template + bool operator> (const std_vector_c& x, const std_vector_c& y) + { return y < x; } + + template + bool operator>=(const std_vector_c& x, const std_vector_c& y) + { return !(x < y); } + + template + bool operator<=(const std_vector_c& x, const std_vector_c& y) + { return !(y < x); } + +// ---------------------------------------------------------------------------------------- + + template + void swap(std_vector_c& x, std_vector_c& y) { x.swap(y); } + /*! + provides a global swap function + !*/ + +// ---------------------------------------------------------------------------------------- + + template + void serialize ( + const std_vector_c& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + +// ---------------------------------------------------------------------------------------- + + template + void deserialize ( + std_vector_c& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STD_VECTOr_C_ABSTRACT_H_ + + diff --git a/dlib/string.h b/dlib/string.h new file mode 100644 index 0000000000000000000000000000000000000000..31cd582011dbecf9745697436e4a40c8a2b53a83 --- /dev/null +++ b/dlib/string.h @@ -0,0 +1,9 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STRINg_TOP_ +#define DLIB_STRINg_TOP_ + +#include "string/string.h" + +#endif // DLIB_STRINg_TOP_ + diff --git a/dlib/string/string.h b/dlib/string/string.h new file mode 100644 index 0000000000000000000000000000000000000000..16ad6ef95bb05fba400d4f2ea6fb4c1418eef462 --- /dev/null +++ b/dlib/string/string.h @@ -0,0 +1,624 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_STRINg_ +#define DLIB_STRINg_ + +#include +#include +#include "../algs.h" +#include "../error.h" +#include "../assert.h" +#include "string_abstract.h" +#include "../uintn.h" +#include +#include +#include "../enable_if.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename traits, + typename alloc + > + const std::basic_string tolower ( + const std::basic_string& str + ) + { + std::basic_string temp; + + temp.resize(str.size()); + + for (typename std::basic_string::size_type i = 0; i < str.size(); ++i) + temp[i] = (char)std::tolower(str[i]); + + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename traits, + typename alloc + > + const std::basic_string toupper ( + const std::basic_string& str + ) + { + std::basic_string temp; + + temp.resize(str.size()); + + for (typename std::basic_string::size_type i = 0; i < str.size(); ++i) + temp[i] = (char)std::toupper(str[i]); + + return temp; + } + +// ---------------------------------------------------------------------------------------- + + class cast_to_string_error : public error + { + public: + cast_to_string_error():error(ECAST_TO_STRING) {} + }; + + template < + typename T + > + const std::string cast_to_string ( + const T& item + ) + { + std::ostringstream sout; + sout << item; + if (!sout) + throw cast_to_string_error(); + return sout.str(); + } + + // don't declare this if we are using mingw because it apparently doesn't + // support iostreams with wchar_t? +#ifndef __MINGW32__ + template < + typename T + > + const std::wstring cast_to_wstring ( + const T& item + ) + { + std::basic_ostringstream sout; + sout << item; + if (!sout) + throw cast_to_string_error(); + return sout.str(); + } +#endif + +// ---------------------------------------------------------------------------------------- + + class string_cast_error : public error + { + public: + string_cast_error(const std::string& str): + error(ESTRING_CAST,"string cast error: invalid string = '" + str + "'") {} + }; + + template < + typename T + > + struct string_cast_helper + { + template < typename charT, typename traits, typename alloc > + static const T cast ( + const std::basic_string& str + ) + { + using namespace std; + basic_istringstream sin(str); + T temp; + sin >> temp; + if (!sin) throw string_cast_error(narrow(str)); + if (sin.get() != char_traits::eof()) throw string_cast_error(narrow(str)); + return temp; + } + }; + + template + struct string_cast_helper > + { + template < typename charT, typename traits, typename alloc > + static const std::basic_string cast ( + const std::basic_string& str + ) + { + std::basic_string temp; + temp.resize(str.size()); + for (unsigned long i = 0; i < str.size(); ++i) + temp[i] = zero_extend_cast(str[i]); + return temp; + } + }; + + template <> + struct string_cast_helper + { + template < typename charT, typename traits, typename alloc > + static const bool cast ( + const std::basic_string& str + ) + { + using namespace std; + if (str.size() == 1 && str[0] == '1') + return true; + if (str.size() == 1 && str[0] == '0') + return false; + if (tolower(narrow(str)) == "true") + return true; + if (tolower(narrow(str)) == "false") + return false; + + throw string_cast_error(narrow(str)); + } + }; + +#define DLIB_STRING_CAST_INTEGRAL(type) \ + template <> \ + struct string_cast_helper \ + { \ + template < typename charT, typename traits, typename alloc> \ + static const type cast ( \ + const std::basic_string& str \ + ) \ + { \ + using namespace std; \ + basic_istringstream sin(str); \ + type temp; \ + if (str.size() > 2 && str[0] == _dT(charT,'0') && str[1] == _dT(charT,'x')) \ + sin >> hex >> temp; \ + else \ + sin >> temp; \ + if (!sin) throw string_cast_error(narrow(str)); \ + if (sin.get() != char_traits::eof()) throw string_cast_error(narrow(str)); \ + return temp; \ + } \ + }; + + DLIB_STRING_CAST_INTEGRAL(unsigned short) + DLIB_STRING_CAST_INTEGRAL(short) + DLIB_STRING_CAST_INTEGRAL(unsigned int) + DLIB_STRING_CAST_INTEGRAL(int) + DLIB_STRING_CAST_INTEGRAL(unsigned long) + DLIB_STRING_CAST_INTEGRAL(long) + DLIB_STRING_CAST_INTEGRAL(uint64) + + template < + typename T, + typename charT, + typename traits, + typename alloc + > + inline const T string_cast ( + const std::basic_string& str + ) + { + COMPILE_TIME_ASSERT(is_pointer_type::value == false); + return string_cast_helper::cast(str); + } + + template + inline const T string_cast (const char* str){ return string_cast(std::string(str)); } + template + inline const T string_cast (const wchar_t* str){ return string_cast(std::wstring(str)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + inline const typename disable_if,std::string>::type narrow ( + const std::basic_string& str + ) + { + std::string temp; + temp.reserve(str.size()); + std::string::size_type i; + std::basic_ostringstream sout; + for (i = 0; i < str.size(); ++i) + { + temp += sout.narrow(str[i],' '); + } + return temp; + } + + template < + typename charT, + typename traits, + typename alloc + > + inline const typename enable_if,std::string>::type narrow ( + const std::basic_string& str + ) + { + return str; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string wrap_string ( + const std::basic_string& str, + const unsigned long first_pad, + const unsigned long rest_pad, + const unsigned long max_per_line = 79 + ) + { + DLIB_ASSERT ( first_pad < max_per_line && rest_pad < max_per_line && + rest_pad >= first_pad, + "\tconst std::basic_string wrap_string()" + << "\n\tfirst_pad: " << first_pad + << "\n\trest_pad: " << rest_pad + << "\n\tmax_per_line: " << max_per_line ); + + using namespace std; + + basic_ostringstream sout; + basic_istringstream sin(str); + + for (unsigned long i = 0; i < rest_pad; ++i) + sout << _dT(charT," "); + const basic_string pad(sout.str()); + sout.str(_dT(charT,"")); + + for (unsigned long i = 0; i < first_pad; ++i) + sout << _dT(charT," "); + + + typename basic_string::size_type remaining = max_per_line - rest_pad; + + basic_string temp; + + sin >> temp; + while (sin) + { + if (temp.size() > remaining) + { + if (temp.size() + rest_pad >= max_per_line) + { + string::size_type i = 0; + for (; i < temp.size(); ++i) + { + sout << temp[i]; + --remaining; + if (remaining == 0) + { + sout << _dT(charT,"\n") << pad; + remaining = max_per_line - rest_pad; + } + } + } + else + { + sout << _dT(charT,"\n") << pad << temp; + remaining = max_per_line - rest_pad - temp.size(); + } + } + else if (temp.size() == remaining) + { + sout << temp; + remaining = 0; + } + else + { + sout << temp; + remaining -= temp.size(); + } + + sin >> temp; + if (remaining == 0 && sin) + { + sout << _dT(charT,"\n") << pad; + remaining = max_per_line - rest_pad; + } + else + { + sout << _dT(charT," "); + --remaining; + } + } + + return sout.str(); + } + + template < + typename charT + > + const std::basic_string wrap_string ( + const charT* str, + const unsigned long first_pad, + const unsigned long rest_pad, + const unsigned long max_per_line = 79 + ) { return wrap_string(std::basic_string(str),first_pad,rest_pad,max_per_line); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string ltrim ( + const std::basic_string& str, + const std::basic_string& trim_chars + ) + { + typedef std::basic_string string; + typename string::size_type pos = str.find_first_not_of(trim_chars); + if (pos != string::npos) + return str.substr(pos); + else + return std::basic_string(); + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string ltrim ( + const std::basic_string& str, + const charT* trim_chars = _dT(charT," \t\r\n") + ) { return ltrim(str,std::basic_string(trim_chars)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rtrim ( + const std::basic_string& str, + const std::basic_string& trim_chars + ) + { + typedef std::basic_string string; + + typename string::size_type pos = str.find_last_not_of(trim_chars); + if (pos != string::npos) + return str.substr(0,pos+1); + else + return std::basic_string(); + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rtrim ( + const std::basic_string& str, + const charT* trim_chars = _dT(charT," \t\r\n") + ) { return rtrim(str,std::basic_string(trim_chars)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string trim ( + const std::basic_string& str, + const std::basic_string& trim_chars + ) + { + typedef std::basic_string string; + typename string::size_type lpos = str.find_first_not_of(trim_chars); + if (lpos != string::npos) + { + typename string::size_type rpos = str.find_last_not_of(trim_chars); + return str.substr(lpos,rpos-lpos+1); + } + else + { + return std::basic_string(); + } + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string trim ( + const std::basic_string& str, + const charT* trim_chars = _dT(charT," \t\r\n") + ) { return trim(str,std::basic_string(trim_chars)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rpad ( + const std::basic_string& str, + long pad_length, + const std::basic_string& pad_string + ) + { + typedef std::basic_string string; + // if str is too big then just return str + if (pad_length <= static_cast(str.size())) + return str; + + // make the string we will padd onto the string + string P; + while (P.size() < pad_length - str.size()) + P += pad_string; + P = P.substr(0,pad_length - str.size()); + + // return the padded string + return str + P; + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rpad ( + const std::basic_string& str, + long pad_length, + const charT* pad_string = _dT(charT," ") + ) { return rpad(str,pad_length,std::basic_string(pad_string)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string lpad ( + const std::basic_string& str, + long pad_length, + const std::basic_string& pad_string + ) + { + typedef std::basic_string string; + // if str is too big then just return str + if (pad_length <= static_cast(str.size())) + return str; + + // make the string we will padd onto the string + string P; + while (P.size() < pad_length - str.size()) + P += pad_string; + P = P.substr(0,pad_length - str.size()); + + // return the padded string + return P + str; + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string lpad ( + const std::basic_string& str, + long pad_length, + const charT* pad_string = _dT(charT," ") + ) { return lpad(str,pad_length,std::basic_string(pad_string)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string pad ( + const std::basic_string& str, + long pad_length, + const std::basic_string& pad_string + ) + { + const long str_size = static_cast(str.size()); + return rpad(lpad(str,(pad_length-str_size)/2 + str_size,pad_string), + pad_length, + pad_string); + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string pad ( + const std::basic_string& str, + long pad_length, + const charT* pad_string = _dT(charT," ") + ) { return pad(str,pad_length,std::basic_string(pad_string)); } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string left_substr ( + const std::basic_string& str, + const std::basic_string& delim + ) + { + return str.substr(0,str.find_first_of(delim)); + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string left_substr ( + const std::basic_string& str, + const charT* delim = _dT(charT," \n\r\t") + ) + { + return str.substr(0,str.find_first_of(delim)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string right_substr ( + const std::basic_string& str, + const std::basic_string& delim + ) + { + typename std::basic_string::size_type delim_pos = str.find_last_of(delim); + if (delim_pos != std::basic_string::npos) + return str.substr(delim_pos+1); + else + return _dT(charT,""); + } + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string right_substr ( + const std::basic_string& str, + const charT* delim = _dT(charT," \n\r\t") + ) + { + typename std::basic_string::size_type delim_pos = str.find_last_of(delim); + if (delim_pos != std::basic_string::npos) + return str.substr(delim_pos+1); + else + return _dT(charT,""); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STRINg_ + diff --git a/dlib/string/string_abstract.h b/dlib/string/string_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..a40d54db25e29956abb0fd517eae339a243589bc --- /dev/null +++ b/dlib/string/string_abstract.h @@ -0,0 +1,437 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_STRINg_ABSTRACT_ +#ifdef DLIB_STRINg_ABSTRACT_ + +#include +#include +#include "../error.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class string_cast_error : public error + { + public: + string_cast_error():error(ECAST_TO_STRING) {} + }; + + template < + typename T, + typename charT, + typename traits, + typename alloc + > + const T string_cast ( + const std::basic_string& str + ); + /*! + requires + - T is not a pointer type + ensures + - returns str converted to T + throws + - string_cast_error + This exception is thrown if string_cast() is unable to convert + str into a T. Also, string_cast_error::info == str + !*/ + +// ---------------------------------------------------------------------------------------- + + class cast_to_string_error : public error + { + public: + cast_to_string_error():error(ECAST_TO_STRING) {} + }; + + template < + typename T + > + const std::string cast_to_string ( + const T& item + ); + /*! + requires + - T is not a pointer type + ensures + - returns item converted to std::string + throws + - cast_to_string_error + This exception is thrown if cast_to_string() is unable to convert + item into a std::string. + !*/ + + template < + typename T + > + const std::wstring cast_to_wstring ( + const T& item + ); + /*! + requires + - T is not a pointer type + ensures + - returns item converted to std::wstring + throws + - cast_to_string_error + This exception is thrown if cast_to_string() is unable to convert + item into a std::string. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::string narrow ( + const std::basic_string& str + ); + /*! + ensures + - returns str as a std::string by converting every character in it to a char. + Note that any characters that do not have a mapping to type char will be + converted to a space. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string wrap_string ( + const std::basic_string& str, + const unsigned long first_pad, + const unsigned long rest_pad, + const unsigned long max_per_line = 79 + ); + /*! + requires + - first_pad < max_per_line + - rest_pad < max_per_line + - rest_pad >= first_pad + ensures + - returns a copy of str S such that: + - S is broken up into lines separated by the \n character. + - The first line starts with first_pad space characters. + - The second and all subsequent lines start with rest_pad space characters. + - The first line is no longer than max_per_line - (rest_pad-first_pad) characters. + - The second and all subsequent lines are no longer than max_per_line characters. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename traits + typename alloc + > + const std::basic_string tolower ( + const std::basic_string& str + ); + /*! + ensures + - returns a copy of str S such that: + - #S.size() == str.size() + - #S[i] == std::tolower(str[i]) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename traits, + typename alloc + > + const std::basic_string toupper ( + const std::basic_string& str + ); + /*! + ensures + - returns a copy of str S such that: + - #S.size() == str.size() + - #S[i] == std::toupper(str[i]) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string ltrim ( + const std::basic_string& str, + const std::basic_string& trim_chars + ); + /*! + ensures + - returns a copy of str with any leading trim_chars + from the left side of the string removed. + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string ltrim ( + const std::basic_string& str, + const charT* trim_chars = _dT(charT," \t\r\n") + ); + /*! + ensures + - returns ltrim(str, std::basic_string(trim_chars)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rtrim ( + const std::basic_string& str, + const std::basic_string& trim_chars + ); + /*! + ensures + - returns a copy of str with any trailing trim_chars + from the right side of the string removed. + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rtrim ( + const std::basic_string& str, + const charT* trim_chars = _dT(charT," \t\r\n") + ); + /*! + ensures + - returns rtrim(str, std::basic_string(trim_chars)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string trim ( + const std::basic_string& str, + const std::basic_string& trim_chars + ); + /*! + ensures + - returns a copy of str with any leading or trailing trim_chars + from the ends of the string removed. + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string trim ( + const std::basic_string& str, + const charT* trim_chars = _dT(charT," \t\r\n") + ); + /*! + ensures + - returns trim(str, std::basic_string(trim_chars)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rpad ( + const std::basic_string& str, + long pad_length, + const std::basic_string& pad_string + ); + /*! + ensures + - if (pad_length <= str.size()) then + - returns str + - else + - let P be a string defined as follows: + - P.size() == pad_length - str.size() + - P == (pad_string + pad_string + ... + pad_string).substr(0,pad_length - str.size()) + (i.e. P == a string with the above specified size that contains just + repitions of the pad_string) + - returns the string str + P + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string rpad ( + const std::basic_string& str, + long pad_length, + const charT* pad_string = _dT(charT," ") + ); + /*! + ensures + - returns rpad(str, pad_length, std::basic_string(pad_string)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string lpad ( + const std::basic_string& str, + long pad_length, + const std::basic_string& pad_string + ); + /*! + ensures + - if (pad_length <= str.size()) then + - returns str + - else + - let P be a string defined as follows: + - P.size() == pad_length - str.size() + - P == (pad_string + pad_string + ... + pad_string).substr(0,pad_length - str.size()) + (i.e. P == a string with the above specified size that contains just + repitions of the pad_string) + - returns the string P + str + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string lpad ( + const std::basic_string& str, + long pad_length, + const charT* pad_string = _dT(charT," ") + ); + /*! + ensures + - returns lpad(str, pad_length, std::basic_string(pad_string)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string pad ( + const std::basic_string& str, + long pad_length, + const std::basic_string& pad_string + ); + /*! + ensures + - let str_size == static_cast(str.size()) + - returns rpad( lpad(str, (pad_length-str_size)/2 + str_size, pad_string), + pad_length, + pad_string); + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string pad ( + const std::basic_string& str, + long pad_length, + const charT* pad_string = _dT(charT," ") + ); + /*! + ensures + - returns pad(str, pad_length, std::basic_string(pad_string)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string left_substr ( + const std::basic_string& str, + const std::basic_string& delim + ); + /*! + ensures + - let delim_pos = str.find_first_of(delim) + - returns str.substr(0,delim_pos) + !*/ + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string left_substr ( + const std::basic_string& str, + const charT* delim = _dT(charT," \n\r\t") + ); + /*! + ensures + - returns left_substr(str, std::basic_string(delim)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT, + typename traits, + typename alloc + > + const std::basic_string right_substr ( + const std::basic_string& str, + const std::basic_string& delim + ); + /*! + ensures + - let delim_pos = str.find_last_of(delim) + - if (delim_pos == std::string::npos) then + - returns "" + - else + - returns str.substr(delim_pos+1) + !*/ + + template < + typename charT, + typename traits + typename alloc + > + const std::basic_string right_substr ( + const std::basic_string& str, + const charT* delim = _dT(charT," \n\r\t") + ); + /*! + ensures + - returns right_substr(str, std::basic_string(delim)) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_STRINg_ABSTRACT_ + diff --git a/dlib/svm.h b/dlib/svm.h new file mode 100644 index 0000000000000000000000000000000000000000..0601cbb2e4aeaa71cad31f8cb610164ac224c109 --- /dev/null +++ b/dlib/svm.h @@ -0,0 +1,10 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SVm_HEADER +#define DLIB_SVM_HEADER + +#include "svm/svm.h" + +#endif // DLIB_SVm_HEADER + + diff --git a/dlib/svm/svm.h b/dlib/svm/svm.h new file mode 100644 index 0000000000000000000000000000000000000000..fb65c5a201791406ca7e266af9818b5ce6d98c47 --- /dev/null +++ b/dlib/svm/svm.h @@ -0,0 +1,1560 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SVm_ +#define DLIB_SVm_ + +#include "svm_abstract.h" +#include +#include +#include +#include "../matrix.h" +#include "../algs.h" +#include "../serialize.h" +#include "../rand.h" +#include "dlib/std_allocator.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename T::type maximum_nu ( + const T& y + ) + { + typedef typename T::type scalar_type; + // make sure requires clause is not broken + DLIB_ASSERT(y.nr() > 1 && y.nc() == 1, + "\ttypedef T::type maximum_nu(y)" + << "\n\ty should be a column vector with more than one entry" + << "\n\ty.nr(): " << y.nr() + << "\n\ty.nc(): " << y.nc() + ); + + long pos_count = 0; + long neg_count = 0; + for (long r = 0; r < y.nr(); ++r) + { + if (y(r) == 1.0) + { + ++pos_count; + } + else if (y(r) == -1.0) + { + ++neg_count; + } + else + { + // make sure requires clause is not broken + DLIB_ASSERT(y(r) == -1.0 || y(r) == 1.0, + "\ttypedef T::type maximum_nu(y)" + << "\n\ty should contain only 1 and 0 entries" + << "\n\tr: " << r + << "\n\ty(r): " << y(r) + ); + } + } + return static_cast(2.0*(scalar_type)std::min(pos_count,neg_count)/(scalar_type)y.nr()); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + class kernel_matrix_cache + { + typedef typename K::scalar_type scalar_type; + typedef typename K::sample_type sample_type; + typedef typename K::mem_manager_type mem_manager_type; + + const matrix& x; + const matrix& y; + K kernel_function; + + mutable matrix cache; + mutable matrix diag_cache; + mutable matrix lookup; + mutable matrix rlookup; + mutable long next; + + /*! + INITIAL VALUE + - for all valid x: + - lookup(x) == -1 + - rlookup(x) == -1 + + CONVENTION + - if (lookup(c) != -1) then + - cache(lookup(c),*) == the cached column c of the kernel matrix + - rlookup(lookup(c)) == c + + - if (rlookup(x) != -1) then + - lookup(rlookup(x)) == x + - cache(x,*) == the cached column rlookup(x) of the kernel matrix + + - next == the next row in the cache table to use to cache something + !*/ + + public: + kernel_matrix_cache ( + const matrix& x_, + const matrix& y_, + K kernel_function_, + long max_size_megabytes + ) : x(x_), y(y_), kernel_function(kernel_function_) + { + // figure out how many rows of the kernel matrix we can have + // with the given amount of memory. + long max_size = (max_size_megabytes*1024*1024)/(x.nr()*sizeof(scalar_type)); + // don't let it be 0 + if (max_size == 0) + max_size = 1; + long size = std::min(max_size,x.nr()); + + diag_cache.set_size(x.nr(),1); + cache.set_size(size,x.nr()); + lookup.set_size(x.nr(),1); + rlookup.set_size(size,1); + set_all_elements(lookup,-1); + set_all_elements(rlookup,-1); + next = 0; + + for (long i = 0; i < diag_cache.nr(); ++i) + diag_cache(i) = kernel_function(x(i),x(i)); + } + + inline bool is_cached ( + long r + ) const + { + return (lookup(r) != -1); + } + + inline scalar_type operator () ( + long r, + long c + ) const + { + if (lookup(c) != -1) + { + return cache(lookup(c),r); + } + else if (r == c) + { + return diag_cache(r); + } + else if (lookup(r) != -1) + { + // the kernel is symmetric so this is legit + return cache(lookup(r),c); + } + else + { + // if the lookup table is pointing to cache(next,*) then clear lookup(next) + if (rlookup(next) != -1) + lookup(rlookup(next)) = -1; + + // make the lookup table os that it says c is now cached at the spot indicated by next + lookup(c) = next; + rlookup(next) = c; + + // compute this column in the kernel matrix and store it in the cache + for (long i = 0; i < cache.nc(); ++i) + cache(next,i) = y(c)*y(i)*kernel_function(x(c),x(i)); + + scalar_type val = cache(next,r); + next = (next + 1)%cache.nr(); + return val; + } + } + + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + struct radial_basis_kernel + { + typedef typename T::type scalar_type; + typedef T sample_type; + typedef typename T::mem_manager_type mem_manager_type; + + radial_basis_kernel(const scalar_type g) : gamma(g) {} + radial_basis_kernel() : gamma(0.1) {} + radial_basis_kernel( + const radial_basis_kernel& k + ) : gamma(k.gamma) {} + + + const scalar_type gamma; + + scalar_type operator() ( + const sample_type& a, + const sample_type& b + ) const + { + const scalar_type d = trans(a-b)*(a-b); + return std::exp(-gamma*d); + } + + radial_basis_kernel& operator= ( + const radial_basis_kernel& k + ) + { + const_cast(gamma) = k.gamma; + return *this; + } + }; + + template < + typename T + > + void serialize ( + const radial_basis_kernel& item, + std::ostream& out + ) + { + try + { + serialize(item.gamma, out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type radial_basis_kernel"); + } + } + + template < + typename T + > + void deserialize ( + radial_basis_kernel& item, + std::istream& in + ) + { + typedef typename T::type scalar_type; + try + { + deserialize(const_cast(item.gamma), in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type radial_basis_kernel"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + struct polynomial_kernel + { + typedef typename T::type scalar_type; + typedef T sample_type; + typedef typename T::mem_manager_type mem_manager_type; + + polynomial_kernel(const scalar_type g, const scalar_type c, const scalar_type d) : gamma(g), coef(c), degree(d) {} + polynomial_kernel() : gamma(1), coef(0), degree(1) {} + polynomial_kernel( + const polynomial_kernel& k + ) : gamma(k.gamma), coef(k.coef), degree(k.degree) {} + + typedef T type; + const scalar_type gamma; + const scalar_type coef; + const scalar_type degree; + + scalar_type operator() ( + const sample_type& a, + const sample_type& b + ) const + { + return std::pow(gamma*(trans(a)*b) + coef, degree); + } + + polynomial_kernel& operator= ( + const polynomial_kernel& k + ) + { + const_cast(gamma) = k.gamma; + const_cast(coef) = k.coef; + const_cast(degree) = k.degree; + return *this; + } + }; + + template < + typename T + > + void serialize ( + const polynomial_kernel& item, + std::ostream& out + ) + { + try + { + serialize(item.gamma, out); + serialize(item.coef, out); + serialize(item.degree, out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type polynomial_kernel"); + } + } + + template < + typename T + > + void deserialize ( + polynomial_kernel& item, + std::istream& in + ) + { + typedef typename T::type scalar_type; + try + { + deserialize(const_cast(item.gamma), in); + deserialize(const_cast(item.coef), in); + deserialize(const_cast(item.degree), in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type polynomial_kernel"); + } + } + +// ---------------------------------------------------------------------------------------- + + template + struct linear_kernel + { + typedef typename T::type scalar_type; + typedef T sample_type; + typedef typename T::mem_manager_type mem_manager_type; + + scalar_type operator() ( + const sample_type& a, + const sample_type& b + ) const + { + return trans(a)*b; + } + }; + + template < + typename T + > + void serialize ( + const linear_kernel& item, + std::ostream& out + ){} + + template < + typename T + > + void deserialize ( + linear_kernel& item, + std::istream& in + ){} + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + struct decision_function + { + typedef typename K::scalar_type scalar_type; + typedef typename K::sample_type sample_type; + typedef typename K::mem_manager_type mem_manager_type; + + typedef matrix scalar_vector_type; + typedef matrix sample_vector_type; + + const scalar_vector_type alpha; + const scalar_type b; + const K kernel_function; + const sample_vector_type support_vectors; + + decision_function ( + ) : b(0), kernel_function(K()) {} + + decision_function ( + const decision_function& d + ) : + alpha(d.alpha), + b(d.b), + kernel_function(d.kernel_function), + support_vectors(d.support_vectors) + {} + + decision_function ( + const scalar_vector_type& alpha_, + const scalar_type& b_, + const K& kernel_function_, + const sample_vector_type& support_vectors_ + ) : + alpha(alpha_), + b(b_), + kernel_function(kernel_function_), + support_vectors(support_vectors_) + {} + + decision_function& operator= ( + const decision_function& d + ) + { + if (this != &d) + { + const_cast(alpha) = d.alpha; + const_cast(b) = d.b; + const_cast(kernel_function) = d.kernel_function; + const_cast(support_vectors) = d.support_vectors; + } + return *this; + } + + scalar_type operator() ( + const sample_type& x + ) const + { + scalar_type temp = 0; + for (long i = 0; i < alpha.nr(); ++i) + temp += alpha(i) * kernel_function(x,support_vectors(i)); + + return temp - b; + } + }; + + template < + typename K + > + void serialize ( + const decision_function& item, + std::ostream& out + ) + { + try + { + serialize(item.alpha, out); + serialize(item.b, out); + serialize(item.kernel_function, out); + serialize(item.support_vectors, out); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while serializing object of type decision_function"); + } + } + + template < + typename K + > + void deserialize ( + decision_function& item, + std::istream& in + ) + { + typedef typename K::scalar_type scalar_type; + typedef typename K::sample_type sample_type; + typedef typename K::mem_manager_type mem_manager_type; + + typedef matrix scalar_vector_type; + typedef matrix sample_vector_type; + try + { + deserialize(const_cast(item.alpha), in); + deserialize(const_cast(item.b), in); + deserialize(const_cast(item.kernel_function), in); + deserialize(const_cast(item.support_vectors), in); + } + catch (serialization_error e) + { + throw serialization_error(e.info + "\n while deserializing object of type decision_function"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + struct probabilistic_decision_function + { + typedef typename K::scalar_type scalar_type; + typedef typename K::sample_type sample_type; + typedef typename K::mem_manager_type mem_manager_type; + + const scalar_type a; + const scalar_type b; + const decision_function decision_funct; + + probabilistic_decision_function ( + ) : a(0), b(0), decision_funct(decision_function()) {} + + probabilistic_decision_function ( + const probabilistic_decision_function& d + ) : + a(d.a), + b(d.b), + decision_funct(d.decision_funct) + {} + + probabilistic_decision_function ( + const scalar_type a_, + const scalar_type b_, + const decision_function& decision_funct_ + ) : + a(a_), + b(b_), + decision_funct(decision_funct_) + {} + + probabilistic_decision_function& operator= ( + const probabilistic_decision_function& d + ) + { + if (this != &d) + { + const_cast(a) = d.a; + const_cast(b) = d.b; + const_cast&>(decision_funct) = d.decision_funct; + } + return *this; + } + + scalar_type operator() ( + const sample_type& x + ) const + { + scalar_type f = decision_funct(x); + return 1/(1 + std::exp(a*f + b)); + } + }; + + template < + typename K + > + void serialize ( + const probabilistic_decision_function& item, + std::ostream& out + ) + { + try + { + serialize(item.a, out); + serialize(item.b, out); + serialize(item.decision_funct, out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type probabilistic_decision_function"); + } + } + + template < + typename K + > + void deserialize ( + probabilistic_decision_function& item, + std::istream& in + ) + { + typedef typename K::scalar_type scalar_type; + try + { + deserialize(const_cast(item.a), in); + deserialize(const_cast(item.b), in); + deserialize(const_cast&>(item.decision_funct), in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type probabilistic_decision_function"); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename scalar_type, + typename scalar_vector_type + > + inline void set_initial_alpha ( + const scalar_vector_type& y, + const scalar_type nu, + scalar_vector_type& alpha + ) + { + set_all_elements(alpha,0); + const scalar_type l = y.nr(); + scalar_type temp = nu*l/2; + long num = (long)std::floor(temp); + long num_total = (long)std::ceil(temp); + + int count = 0; + for (int i = 0; i < alpha.nr(); ++i) + { + if (y(i) == 1) + { + if (count < num) + { + ++count; + alpha(i) = 1; + } + else + { + if (temp > num) + { + ++count; + alpha(i) = temp - std::floor(temp); + } + break; + } + } + } + + if (count != num_total) + { + std::ostringstream sout; + sout << "invalid nu of " << nu << ". Must be between 0 and " << (scalar_type)count/y.nr(); + throw error(sout.str()); + } + + count = 0; + for (int i = 0; i < alpha.nr(); ++i) + { + if (y(i) == -1) + { + if (count < num) + { + ++count; + alpha(i) = 1; + } + else + { + if (temp > num) + { + ++count; + alpha(i) = temp - std::floor(temp); + } + break; + } + } + } + + if (count != num_total) + { + std::ostringstream sout; + sout << "invalid nu of " << nu << ". Must be between 0 and " << (scalar_type)count/y.nr(); + throw error(sout.str()); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K, + typename scalar_vector_type, + typename scalar_type + > + inline bool find_working_group ( + const scalar_vector_type& y, + const scalar_vector_type& alpha, + const kernel_matrix_cache& Q, + const scalar_vector_type& df, + const scalar_type tau, + const scalar_type eps, + long& i_out, + long& j_out + ) + { + using namespace std; + long ip = -1; + long jp = -1; + long in = -1; + long jn = -1; + + scalar_type ip_val = -numeric_limits::infinity(); + scalar_type jp_val = numeric_limits::infinity(); + scalar_type in_val = -numeric_limits::infinity(); + scalar_type jn_val = numeric_limits::infinity(); + + // loop over the alphas and find the maximum ip and in indices. + for (long i = 0; i < alpha.nr(); ++i) + { + if (y(i) == 1) + { + if (alpha(i) < 1.0) + { + if (-df(i) > ip_val) + { + ip_val = -df(i); + ip = i; + } + } + } + else + { + if (alpha(i) > 0.0) + { + if (df(i) > in_val) + { + in_val = df(i); + in = i; + } + } + } + } + + scalar_type Mp = numeric_limits::infinity(); + scalar_type Mn = numeric_limits::infinity(); + scalar_type bp = -numeric_limits::infinity(); + scalar_type bn = -numeric_limits::infinity(); + + // now we need to find the minimum jp and jn indices + for (long j = 0; j < alpha.nr(); ++j) + { + if (y(j) == 1) + { + if (alpha(j) > 0.0) + { + scalar_type b = ip_val + df(j); + if (-df(j) < Mp) + Mp = -df(j); + + if (b > 0 && (Q.is_cached(j) || b > bp || jp == -1 )) + { + bp = b; + scalar_type a = Q(ip,ip) + Q(j,j) - 2*Q(j,ip); + if (a <= 0) + a = tau; + scalar_type temp = -b*b/a; + if (temp < jp_val) + { + jp_val = temp; + jp = j; + } + } + } + } + else + { + if (alpha(j) < 1.0) + { + scalar_type b = in_val - df(j); + if (df(j) < Mn) + Mn = df(j); + + if (b > 0 && (Q.is_cached(j) || b > bn || jn == -1 )) + { + bn = b; + scalar_type a = Q(in,in) + Q(j,j) - 2*Q(j,in); + if (a <= 0) + a = tau; + scalar_type temp = -b*b/a; + if (temp < jn_val) + { + jn_val = temp; + jn = j; + } + } + } + } + } + + // if we are at the optimal point then return false so the caller knows + // to stop optimizing + if (std::max(ip_val - Mp, in_val - Mn) < eps) + return false; + + if (jp_val < jn_val) + { + i_out = ip; + j_out = jp; + } + else + { + i_out = in; + j_out = jn; + } + + if (j_out >= 0 && i_out >= 0) + return true; + else + return false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename scalar_vector_type, + typename scalar_type + > + void calculate_rho_and_b( + const scalar_vector_type& y, + const scalar_vector_type& alpha, + const scalar_vector_type& df, + scalar_type& rho, + scalar_type& b + ) + { + using namespace std; + long num_p_free = 0; + long num_n_free = 0; + scalar_type sum_p_free = 0; + scalar_type sum_n_free = 0; + + scalar_type upper_bound_p = -numeric_limits::infinity(); + scalar_type upper_bound_n = -numeric_limits::infinity(); + scalar_type lower_bound_p = numeric_limits::infinity(); + scalar_type lower_bound_n = numeric_limits::infinity(); + + for(long i = 0; i < alpha.nr(); ++i) + { + if(y(i) == 1) + { + if(alpha(i) == 1) + { + if (df(i) > upper_bound_p) + upper_bound_p = df(i); + } + else if(alpha(i) == 0) + { + if (df(i) < lower_bound_p) + lower_bound_p = df(i); + } + else + { + ++num_p_free; + sum_p_free += df(i); + } + } + else + { + if(alpha(i) == 1) + { + if (df(i) > upper_bound_n) + upper_bound_n = df(i); + } + else if(alpha(i) == 0) + { + if (df(i) < lower_bound_n) + lower_bound_n = df(i); + } + else + { + ++num_n_free; + sum_n_free += df(i); + } + } + } + + scalar_type r1,r2; + if(num_p_free > 0) + r1 = sum_p_free/num_p_free; + else + r1 = (upper_bound_p+lower_bound_p)/2; + + if(num_n_free > 0) + r2 = sum_n_free/num_n_free; + else + r2 = (upper_bound_n+lower_bound_n)/2; + + rho = (r1+r2)/2; + b = (r1-r2)/2/rho; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K, + typename scalar_vector_type, + typename scalar_type + > + inline void optimize_working_pair ( + const scalar_vector_type& y, + scalar_vector_type& alpha, + const kernel_matrix_cache& Q, + const scalar_vector_type& df, + const scalar_type tau, + const long i, + const long j + ) + { + scalar_type quad_coef = Q(i,i)+Q(j,j)-2*Q(j,i); + if (quad_coef <= 0) + quad_coef = tau; + scalar_type delta = (df(i)-df(j))/quad_coef; + scalar_type sum = alpha(i) + alpha(j); + alpha(i) -= delta; + alpha(j) += delta; + + if(sum > 1) + { + if(alpha(i) > 1) + { + alpha(i) = 1; + alpha(j) = sum - 1; + } + else if(alpha(j) > 1) + { + alpha(j) = 1; + alpha(i) = sum - 1; + } + } + else + { + if(alpha(j) < 0) + { + alpha(j) = 0; + alpha(i) = sum; + } + else if(alpha(i) < 0) + { + alpha(i) = 0; + alpha(j) = sum; + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + const decision_function svm_nu_train ( + const typename decision_function::sample_vector_type& x, + const typename decision_function::scalar_vector_type& y, + const K& kernel_function, + const typename K::scalar_type nu, + const long cache_size = 200, + const typename K::scalar_type eps = 0.001 + ) + { + typedef typename K::scalar_type scalar_type; + typedef typename decision_function::sample_vector_type sample_vector_type; + typedef typename decision_function::scalar_vector_type scalar_vector_type; + + // make sure requires clause is not broken +#ifdef ENABLE_ASSERTS + for (long r = 0; r < y.nr(); ++r) + { + DLIB_ASSERT(y(r) == -1.0 || y(r) == 1.0, + "\tdecision_function svm_nu_train()" + << "\n\tinvalid inputs were given to this function" + << "\n\tr: " << r + << "\n\ty(r): " << y(r) + ); + + } +#endif + + DLIB_ASSERT(x.nr() > 1 && y.nr() == x.nr(), + "\tdecision_function svm_nu_train()" + << "\n\tinvalid inputs were given to this function" + << "\n\tx.nr(): " << x.nr() + << "\n\ty.nr(): " << y.nr() + << "\n\tx.nc(): " << x.nc() + << "\n\ty.nc(): " << y.nc() + ); + + DLIB_ASSERT(eps > 0 && + cache_size > 0 && + 0 < nu && nu < maximum_nu(y), + "\tdecision_function svm_nu_train()" + << "\n\tinvalid inputs were given to this function" + << "\n\teps: " << eps + << "\n\tcache_size: " << cache_size + << "\n\tnu: " << nu + << "\n\tmaximum_nu(y): " << maximum_nu(y) + ); + + + const scalar_type tau = 1e-12; + scalar_vector_type df; // delta f(alpha) + scalar_vector_type alpha; + + kernel_matrix_cache Q(x,y,kernel_function,cache_size); + + alpha.set_size(x.nr()); + df.set_size(x.nr()); + + // now initialize alpha + set_initial_alpha(y, nu, alpha); + + + // initialize df. Compute df = Q*alpha + for (long r = 0; r < df.nr(); ++r) + { + df(r) = 0; + for (long c = 0; c < alpha.nr(); ++c) + { + if (alpha(c) != 0) + df(r) += Q(c,r)*alpha(c); + } + } + + // now perform the actual optimization of alpha + long i, j; + while (find_working_group(y,alpha,Q,df,tau,eps,i,j)) + { + const scalar_type old_alpha_i = alpha(i); + const scalar_type old_alpha_j = alpha(j); + + optimize_working_pair(y,alpha,Q,df,tau,i,j); + + // update the df vector now that we have modified alpha(i) and alpha(j) + scalar_type delta_alpha_i = alpha(i) - old_alpha_i; + scalar_type delta_alpha_j = alpha(j) - old_alpha_j; + for(long k = 0; k < df.nr(); ++k) + df(k) += Q(k,i)*delta_alpha_i + Q(k,j)*delta_alpha_j; + + } + + scalar_type rho, b; + calculate_rho_and_b(y,alpha,df,rho,b); + alpha = pointwise_multiply(alpha,y)/rho; + + // count the number of support vectors + long sv_count = 0; + for (long i = 0; i < alpha.nr(); ++i) + { + if (alpha(i) != 0) + ++sv_count; + } + + scalar_vector_type sv_alpha; + sample_vector_type support_vectors; + + // size these column vectors so that they have an entry for each support vector + sv_alpha.set_size(sv_count); + support_vectors.set_size(sv_count); + + // load the support vectors and their alpha values into these new column matrices + long idx = 0; + for (long i = 0; i < alpha.nr(); ++i) + { + if (alpha(i) != 0) + { + sv_alpha(idx) = alpha(i); + support_vectors(idx) = x(i); + ++idx; + } + } + + // now return the decision function + return decision_function (sv_alpha, b, kernel_function, support_vectors); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + const matrix svm_nu_cross_validate ( + const typename decision_function::sample_vector_type& x, + const typename decision_function::scalar_vector_type& y, + const K& kernel_function, + const typename K::scalar_type nu, + const long folds, + const long cache_size = 200, + const typename K::scalar_type eps = 0.001 + ) + { + typedef typename K::scalar_type scalar_type; + typedef typename decision_function::sample_vector_type sample_vector_type; + typedef typename decision_function::scalar_vector_type scalar_vector_type; + + // make sure requires clause is not broken +#ifdef ENABLE_ASSERTS + for (long r = 0; r < y.nr(); ++r) + { + DLIB_ASSERT(y(r) == -1.0 || y(r) == 1.0, + "\tdecision_function svm_nu_cross_validate()" + << "\n\tinvalid inputs were given to this function" + << "\n\tr: " << r + << "\n\ty(r): " << y(r) + ); + + } +#endif + + DLIB_ASSERT(x.nr() > 1 && y.nr() == x.nr(), + "\tdecision_function svm_nu_cross_validate()" + << "\n\tinvalid inputs were given to this function" + << "\n\tx.nr(): " << x.nr() + << "\n\ty.nr(): " << y.nr() + << "\n\tx.nc(): " << x.nc() + << "\n\ty.nc(): " << y.nc() + ); + + DLIB_ASSERT(eps > 0 && + folds > 1 && folds <= x.nr() && + cache_size > 0 && + 0 < nu && nu < maximum_nu(y), + "\tdecision_function svm_nu_cross_validate()" + << "\n\tinvalid inputs were given to this function" + << "\n\teps: " << eps + << "\n\tfolds: " << folds + << "\n\tcache_size: " << cache_size + << "\n\tnu: " << nu + << "\n\tmaximum_nu(y): " << maximum_nu(y) + ); + + // count the number of positive and negative examples + long num_pos = 0; + long num_neg = 0; + for (long r = 0; r < y.nr(); ++r) + { + if (y(r) == +1.0) + ++num_pos; + else + ++num_neg; + } + + // figure out how many positive and negative examples we will have in each fold + const long num_pos_test_samples = num_pos/folds; + const long num_pos_train_samples = num_pos - num_pos_test_samples; + const long num_neg_test_samples = num_neg/folds; + const long num_neg_train_samples = num_neg - num_neg_test_samples; + + long num_pos_correct = 0; + long num_neg_correct = 0; + + decision_function d; + typename decision_function::sample_vector_type x_test, x_train; + typename decision_function::scalar_vector_type y_test, y_train; + x_test.set_size (num_pos_test_samples + num_neg_test_samples); + y_test.set_size (num_pos_test_samples + num_neg_test_samples); + x_train.set_size(num_pos_train_samples + num_neg_train_samples); + y_train.set_size(num_pos_train_samples + num_neg_train_samples); + + long pos_idx = 0; + long neg_idx = 0; + + for (long i = 0; i < folds; ++i) + { + long cur = 0; + + // load up our positive test samples + while (cur < num_pos_test_samples) + { + if (y(pos_idx) == +1.0) + { + x_test(cur) = x(pos_idx); + y_test(cur) = +1.0; + ++cur; + } + pos_idx = (pos_idx+1)%x.nr(); + } + + // load up our negative test samples + while (cur < x_test.nr()) + { + if (y(neg_idx) == -1.0) + { + x_test(cur) = x(neg_idx); + y_test(cur) = -1.0; + ++cur; + } + neg_idx = (neg_idx+1)%x.nr(); + } + + // load the training data from the data following whatever we loaded + // as the testing data + long train_pos_idx = pos_idx; + long train_neg_idx = neg_idx; + cur = 0; + + // load up our positive train samples + while (cur < num_pos_train_samples) + { + if (y(train_pos_idx) == +1.0) + { + x_train(cur) = x(train_pos_idx); + y_train(cur) = +1.0; + ++cur; + } + train_pos_idx = (train_pos_idx+1)%x.nr(); + } + + // load up our negative train samples + while (cur < x_train.nr()) + { + if (y(train_neg_idx) == -1.0) + { + x_train(cur) = x(train_neg_idx); + y_train(cur) = -1.0; + ++cur; + } + train_neg_idx = (train_neg_idx+1)%x.nr(); + } + + // do the training + d = svm_nu_train (x_train,y_train,kernel_function,nu,cache_size,eps); + + // now test this fold + for (long i = 0; i < x_test.nr(); ++i) + { + // if this is a positive example + if (y_test(i) == +1.0) + { + if (d(x_test(i)) >= 0) + ++num_pos_correct; + } + else if (y_test(i) == -1.0) + { + if (d(x_test(i)) < 0) + ++num_neg_correct; + } + else + { + throw dlib::error("invalid input labels to the svm_nu_cross_validate() function"); + } + } + + } // for (long i = 0; i < folds; ++i) + + matrix res; + res(0) = (scalar_type)num_pos_correct/(scalar_type)(num_pos_test_samples*folds); + res(1) = (scalar_type)num_neg_correct/(scalar_type)(num_neg_test_samples*folds); + return res; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + const probabilistic_decision_function svm_nu_train_prob ( + const typename decision_function::sample_vector_type& x, + const typename decision_function::scalar_vector_type& y, + const K& kernel_function, + const typename K::scalar_type nu, + const long folds, + const long cache_size = 200, + const typename K::scalar_type eps = 0.001 + ) + { + typedef typename K::scalar_type scalar_type; + typedef typename K::mem_manager_type mem_manager_type; + typedef typename decision_function::sample_vector_type sample_vector_type; + typedef typename decision_function::scalar_vector_type scalar_vector_type; + + /* + This function fits a sigmoid function to the output of the + svm trained by svm_nu_train(). The technique used is the one + described in the paper: + + Probabilistic Outputs for Support Vector Machines and + Comparisons to Regularized Likelihood Methods by + John C. Platt. Match 26, 1999 + */ + + // make sure requires clause is not broken +#ifdef ENABLE_ASSERTS + for (long r = 0; r < y.nr(); ++r) + { + DLIB_ASSERT(y(r) == -1.0 || y(r) == 1.0, + "\tdecision_function svm_nu_train()" + << "\n\tinvalid inputs were given to this function" + << "\n\tr: " << r + << "\n\ty(r): " << y(r) + ); + + } +#endif + + DLIB_ASSERT(x.nr() > 1 && y.nr() == x.nr(), + "\tdecision_function svm_nu_train()" + << "\n\tinvalid inputs were given to this function" + << "\n\tx.nr(): " << x.nr() + << "\n\ty.nr(): " << y.nr() + << "\n\tx.nc(): " << x.nc() + << "\n\ty.nc(): " << y.nc() + ); + + DLIB_ASSERT(eps > 0 && + folds > 1 && folds <= x.nr() && + cache_size > 0 && + 0 < nu && nu < maximum_nu(y), + "\tdecision_function svm_nu_train()" + << "\n\tinvalid inputs were given to this function" + << "\n\teps: " << eps + << "\n\tfolds: " << folds + << "\n\tcache_size: " << cache_size + << "\n\tnu: " << nu + << "\n\tmaximum_nu(y): " << maximum_nu(y) + ); + + // count the number of positive and negative examples + long num_pos = 0; + long num_neg = 0; + for (long r = 0; r < y.nr(); ++r) + { + if (y(r) == +1.0) + ++num_pos; + else + ++num_neg; + } + + // figure out how many positive and negative examples we will have in each fold + const long num_pos_test_samples = num_pos/folds; + const long num_pos_train_samples = num_pos - num_pos_test_samples; + const long num_neg_test_samples = num_neg/folds; + const long num_neg_train_samples = num_neg - num_neg_test_samples; + + decision_function d; + typename decision_function::sample_vector_type x_test, x_train; + typename decision_function::scalar_vector_type y_test, y_train; + x_test.set_size (num_pos_test_samples + num_neg_test_samples); + y_test.set_size (num_pos_test_samples + num_neg_test_samples); + x_train.set_size(num_pos_train_samples + num_neg_train_samples); + y_train.set_size(num_pos_train_samples + num_neg_train_samples); + + typedef std_allocator alloc_scalar_type_vector; + typedef std::vector dvector; + typedef std_allocator alloc_int_vector; + typedef std::vector ivector; + + dvector out; + ivector target; + + long pos_idx = 0; + long neg_idx = 0; + + for (long i = 0; i < folds; ++i) + { + long cur = 0; + + // load up our positive test samples + while (cur < num_pos_test_samples) + { + if (y(pos_idx) == +1.0) + { + x_test(cur) = x(pos_idx); + y_test(cur) = +1.0; + ++cur; + } + pos_idx = (pos_idx+1)%x.nr(); + } + + // load up our negative test samples + while (cur < x_test.nr()) + { + if (y(neg_idx) == -1.0) + { + x_test(cur) = x(neg_idx); + y_test(cur) = -1.0; + ++cur; + } + neg_idx = (neg_idx+1)%x.nr(); + } + + // load the training data from the data following whatever we loaded + // as the testing data + long train_pos_idx = pos_idx; + long train_neg_idx = neg_idx; + cur = 0; + + // load up our positive train samples + while (cur < num_pos_train_samples) + { + if (y(train_pos_idx) == +1.0) + { + x_train(cur) = x(train_pos_idx); + y_train(cur) = +1.0; + ++cur; + } + train_pos_idx = (train_pos_idx+1)%x.nr(); + } + + // load up our negative train samples + while (cur < x_train.nr()) + { + if (y(train_neg_idx) == -1.0) + { + x_train(cur) = x(train_neg_idx); + y_train(cur) = -1.0; + ++cur; + } + train_neg_idx = (train_neg_idx+1)%x.nr(); + } + + // do the training + d = svm_nu_train (x_train,y_train,kernel_function,nu,cache_size,eps); + + // now test this fold + for (long i = 0; i < x_test.nr(); ++i) + { + out.push_back(d(x_test(i))); + // if this was a positive example + if (y_test(i) == +1.0) + { + target.push_back(1); + } + else if (y_test(i) == -1.0) + { + target.push_back(0); + } + else + { + throw dlib::error("invalid input labels to the svm_nu_train_prob() function"); + } + } + + } // for (long i = 0; i < folds; ++i) + + // Now find the parameters of the sigmoid. Do so using the method from the + // above referenced paper. + scalar_type prior0 = num_pos_test_samples*folds; + scalar_type prior1 = num_neg_test_samples*folds; + scalar_type A = 0; + scalar_type B = std::log((prior0+1)/(prior1+1)); + + const scalar_type hiTarget = (prior1+1)/(prior1+2); + const scalar_type loTarget = 1.0/(prior0+2); + scalar_type lambda = 1e-3; + scalar_type olderr = std::numeric_limits::max();; + dvector pp(out.size(),(prior1+1)/(prior1+prior0+2)); + const scalar_type min_log = -200.0; + + scalar_type t = 0; + int count = 0; + for (int it = 0; it < 100; ++it) + { + scalar_type a = 0; + scalar_type b = 0; + scalar_type c = 0; + scalar_type d = 0; + scalar_type e = 0; + + // First, compute Hessian & gradient of error function with + // respect to A & B + for (unsigned long i = 0; i < out.size(); ++i) + { + if (target[i]) + t = hiTarget; + else + t = loTarget; + + const scalar_type d1 = pp[i] - t; + const scalar_type d2 = pp[i]*(1-pp[i]); + a += out[i]*out[i]*d2; + b += d2; + c += out[i]*d2; + d += out[i]*d1; + e += d1; + } + + // If gradient is really tiny, then stop. + if (std::abs(d) < 1e-9 && std::abs(e) < 1e-9) + break; + + scalar_type oldA = A; + scalar_type oldB = B; + scalar_type err = 0; + + // Loop until goodness of fit increases + while (true) + { + scalar_type det = (a+lambda)*(b+lambda)-c*c; + // if determinant of Hessian is really close to zero then increase stabilizer. + if (std::abs(det) <= std::numeric_limits::epsilon()) + { + lambda *= 10; + continue; + } + + A = oldA + ((b+lambda)*d-c*e)/det; + B = oldB + ((a+lambda)*e-c*d)/det; + + // Now, compute the goodness of fit + err = 0; + for (unsigned long i = 0; i < out.size(); ++i) + { + if (target[i]) + t = hiTarget; + else + t = loTarget; + scalar_type p = 1.0/(1.0+std::exp(out[i]*A+B)); + pp[i] = p; + // At this step, make sure log(0) returns min_log + err -= t*std::max(std::log(p),min_log) + (1-t)*std::max(std::log(1-p),min_log); + } + + if (err < olderr*(1+1e-7)) + { + lambda *= 0.1; + break; + } + + // error did not decrease: increase stabilizer by factor of 10 + // & try again + lambda *= 10; + if (lambda >= 1e6) // something is broken. Give up + break; + } + + scalar_type diff = err-olderr; + scalar_type scale = 0.5*(err+olderr+1.0); + if (diff > -1e-3*scale && diff < 1e-7*scale) + ++count; + else + count = 0; + + olderr = err; + + if (count == 3) + break; + } + + return probabilistic_decision_function( + A, B, + svm_nu_train (x,y,kernel_function,nu,cache_size,eps) ); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U + > + void randomize_samples ( + T& t, + U& u + ) + { + rand::kernel_1a r; + + long n = t.nr()-1; + while (n > 0) + { + // put a random integer into idx + unsigned long idx = r.get_random_32bit_number(); + + // make idx be less than n + idx %= n; + + // swap our randomly selected index into the n position + exchange(t(idx), t(n)); + exchange(u(idx), u(n)); + + --n; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SVm_ + diff --git a/dlib/svm/svm_abstract.h b/dlib/svm/svm_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..e32d7c63469808ae2ebe322fa21ac4606d300365 --- /dev/null +++ b/dlib/svm/svm_abstract.h @@ -0,0 +1,687 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SVm_ABSTRACT_ +#ifdef DLIB_SVm_ABSTRACT_ + +#include +#include +#include +#include "../matrix/matrix_abstract.h" +#include "../algs.h" +#include "../serialize.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +/*!A Kernel_Function_Objects */ +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + /*! + WHAT IS A KERNEL FUNCTION OBJECT? + In the context of the dlib library documentation a kernel function object + is an object with an interface with the following properties: + - a public typedef named sample_type + - a public typedef named scalar_type which should be a float, double, or + long double type. + - an overloaded operator() that operates on two items of sample_type + and returns a scalar_type. + (e.g. scalar_type val = kernel_function(sample(i),sample(j)); + would be a valid expression) + - a public typedef named mem_manager_type that is an implementation of + dlib/memory_manager/memory_manager_kernel_abstract.h or + dlib/memory_manager_global/memory_manager_global_kernel_abstract.h or + dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + + For examples of kernel functions see the following objects + (e.g. the radial_basis_kernel). + !*/ + + template < + typename T + > + struct radial_basis_kernel + { + /*! + REQUIREMENTS ON T + T must be a dlib::matrix object + + WHAT THIS OBJECT REPRESENTS + This object represents a radial basis function kernel + !*/ + + typedef typename T::type scalar_type; + typedef T sample_type; + typedef typename T::mem_manager_type mem_manager_type; + + const scalar_type gamma; + + radial_basis_kernel( + ); + /*! + ensures + - #gamma == 0.1 + !*/ + + radial_basis_kernel( + const radial_basis_kernel& k + ); + /*! + ensures + - #gamma == k.gamma + !*/ + + radial_basis_kernel( + const scalar_type g + ); + /*! + ensures + - #gamma == g + !*/ + + scalar_type operator() ( + const sample_type& a, + const sample_type& b + ) const; + /*! + requires + - a.nc() == 1 + - b.nc() == 1 + - a.nr() == b.nr() + ensures + - returns exp(-gamma * ||a-b||^2) + !*/ + + radial_basis_kernel& operator= ( + const radial_basis_kernel& k + ); + /*! + ensures + - #gamma = k.gamma + - returns *this + !*/ + + }; + + template < + typename T + > + void serialize ( + const radial_basis_kernel& item, + std::ostream& out + ); + /*! + provides serialization support for radial_basis_kernel + !*/ + + template < + typename K + > + void deserialize ( + radial_basis_kernel& item, + std::istream& in + ); + /*! + provides deserialization support for radial_basis_kernel + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + struct polynomial_kernel + { + /*! + REQUIREMENTS ON T + T must be a dlib::matrix object + + WHAT THIS OBJECT REPRESENTS + This object represents a polynomial kernel + !*/ + + typedef typename T::type scalar_type; + typedef T sample_type; + typedef typename T::mem_manager_type mem_manager_type; + + const scalar_type gamma; + const scalar_type coef; + const scalar_type degree; + + polynomial_kernel( + ); + /*! + ensures + - #gamma == 1 + - #coef == 0 + - #degree == 1 + !*/ + + polynomial_kernel( + const radial_basis_kernel& k + ); + /*! + ensures + - #gamma == k.gamma + !*/ + + polynomial_kernel( + const scalar_type g, + const scalar_type c, + const scalar_type d + ); + /*! + ensures + - #gamma == g + - #coef == c + - #degree == d + !*/ + + scalar_type operator() ( + const sample_type& a, + const sample_type& b + ) const; + /*! + requires + - a.nc() == 1 + - b.nc() == 1 + - a.nr() == b.nr() + ensures + - returns pow(gamma*trans(a)*b + coef, degree) + !*/ + + polynomial_kernel& operator= ( + const polynomial_kernel& k + ); + /*! + ensures + - #gamma = k.gamma + - #coef = k.coef + - #degree = k.degree + - returns *this + !*/ + + }; + + template < + typename T + > + void serialize ( + const polynomial_kernel& item, + std::ostream& out + ); + /*! + provides serialization support for polynomial_kernel + !*/ + + template < + typename K + > + void deserialize ( + polynomial_kernel& item, + std::istream& in + ); + /*! + provides deserialization support for polynomial_kernel + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + struct linear_kernel + { + /*! + REQUIREMENTS ON T + T must be a dlib::matrix object + + WHAT THIS OBJECT REPRESENTS + This object represents a linear function kernel + !*/ + + typedef typename T::type scalar_type; + typedef T sample_type; + typedef typename T::mem_manager_type mem_manager_type; + + scalar_type operator() ( + const sample_type& a, + const sample_type& b + ) const; + /*! + requires + - a.nc() == 1 + - b.nc() == 1 + - a.nr() == b.nr() + ensures + - returns trans(a)*b + !*/ + }; + + template < + typename T + > + void serialize ( + const linear_kernel& item, + std::ostream& out + ); + /*! + provides serialization support for linear_kernel + !*/ + + template < + typename K + > + void deserialize ( + linear_kernel& item, + std::istream& in + ); + /*! + provides deserialization support for linear_kernel + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + struct decision_function + { + /*! + REQUIREMENTS ON K + K must be a kernel function object type as defined at the top + of this document. + + WHAT THIS OBJECT REPRESENTS + This object represents a binary decision function. + !*/ + + typedef typename K::scalar_type scalar_type; + typedef typename K::sample_type sample_type; + typedef typename K::mem_manager_type mem_manager_type; + + typedef matrix scalar_vector_type; + typedef matrix sample_vector_type; + + const scalar_vector_type alpha; + const scalar_type b; + const K kernel_function; + const sample_vector_type support_vectors; + + decision_function ( + ); + /*! + ensures + - #b == 0 + - #alpha.nr() == 0 + - #support_vectors.nr() == 0 + !*/ + + decision_function ( + const decision_function& f + ); + /*! + ensures + - #*this is a copy of f + !*/ + + decision_function ( + const scalar_vector_type& alpha_, + const scalar_type& b_, + const K& kernel_function_, + const sample_vector_type& support_vectors_ + ) : alpha(alpha_), b(b_), kernel_function(kernel_function_), support_vectors(support_vectors_) {} + /*! + ensures + - populates the decision function with the given support vectors, weights(i.e. alphas), + b term, and kernel function. + !*/ + + decision_function& operator= ( + const decision_function& d + ); + /*! + ensures + - #*this is identical to d + - returns *this + !*/ + + scalar_type operator() ( + const sample_type& x + ) const + /*! + ensures + - predicts the class of x. + - if (the class is predicted to be +1) then + - returns a number >= 0 + - else + - returns a number < 0 + !*/ + { + scalar_type temp = 0; + for (long i = 0; i < alpha.nr(); ++i) + temp += alpha(i) * kernel_function(x,support_vectors(i)); + + returns temp - b; + } + }; + + template < + typename K + > + void serialize ( + const decision_function& item, + std::ostream& out + ); + /*! + provides serialization support for decision_function + !*/ + + template < + typename K + > + void deserialize ( + decision_function& item, + std::istream& in + ); + /*! + provides serialization support for decision_function + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + struct probabilistic_decision_function + { + /*! + REQUIREMENTS ON K + K must be a kernel function object type as defined at the top + of this document. + + WHAT THIS OBJECT REPRESENTS + This object represents a binary decision function that returns an + estimate of the probability that a given sample is in the +1 class. + !*/ + + typedef typename K::scalar_type scalar_type; + typedef typename K::sample_type sample_type; + typedef typename K::mem_manager_type mem_manager_type; + + const scalar_type a; + const scalar_type b; + const decision_function decision_funct; + + probabilistic_decision_function ( + ); + /*! + ensures + - #a == 0 + - #b == 0 + - #decision_function has its initial value + !*/ + + probabilistic_decision_function ( + const probabilistic_decision_function& f + ); + /*! + ensures + - #*this is a copy of f + !*/ + + probabilistic_decision_function ( + const scalar_type a_, + const scalar_type b_, + const decision_function& decision_funct_ + ) : a(a_), b(b_), decision_funct(decision_funct_) {} + /*! + ensures + - populates the probabilistic decision function with the given a, b, + and decision_function. + !*/ + + probabilistic_decision_function& operator= ( + const probabilistic_decision_function& d + ); + /*! + ensures + - #*this is identical to d + - returns *this + !*/ + + scalar_type operator() ( + const sample_type& x + ) const + /*! + ensures + - returns a number P such that: + - 0 <= P <= 1 + - P represents the probability that sample x is from + the class +1 + !*/ + { + // Evaluate the normal SVM decision function + scalar_type f = decision_funct(x); + // Now basically normalize the output so that it is a properly + // conditioned probability of x being in the +1 class given + // the output of the SVM. + return 1/(1 + std::exp(a*f + b)); + } + }; + + template < + typename K + > + void serialize ( + const probabilistic_decision_function& item, + std::ostream& out + ); + /*! + provides serialization support for probabilistic_decision_function + !*/ + + template < + typename K + > + void deserialize ( + probabilistic_decision_function& item, + std::istream& in + ); + /*! + provides serialization support for probabilistic_decision_function + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Functions that perform SVM training +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename T::type maximum_nu ( + const T& y + ); + /*! + requires + - T == a matrix object + - y.nc() == 1 + - y.nr() > 1 + - for all valid i: + - y(i) == -1 or +1 + ensures + - returns the maximum valid nu that can be used with svm_nu_train(). + (i.e. 2.0*min(number of +1 examples in y, number of -1 examples in y)/y.nr()) + !*/ + + template < + typename K + > + const decision_function svm_nu_train ( + const typename decision_function::sample_vector_type& x, + const typename decision_function::scalar_vector_type& y, + const K& kernel_function, + const typename K::scalar_type nu, + const long cache_size = 200, + const typename K::scalar_type eps = 0.001 + ); + /*! + requires + - eps > 0 + - x.nc() == 1 (i.e. x is a column vector) + - y.nc() == 1 (i.e. y is a column vector) + - x.nr() == y.nr() + - x.nr() > 1 + - cache_size > 0 + - for all valid i: + - y(i) == -1 or +1 + - y(i) is the class that should be assigned to training example x(i) + - 0 < nu < maximum_nu(y) + - kernel_function == a kernel function object type as defined at the top + of this document. + ensures + - trains a nu support vector classifier given the training samples in x and + labels in y. Training is done when the error is less than eps. + - caches approximately at most cache_size megabytes of the kernel matrix. + (bigger values of this may make training go faster but doesn't affect the + result. However, too big a value will cause you to run out of memory.) + - returns the resulting decision function + !*/ + + /* + The implementation of the nu-svm training algorithm used by this library is based + on the following excellent papers: + - Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms + - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector + machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm + */ + +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + const probabilistic_decision_function svm_nu_train_prob ( + const typename decision_function::sample_vector_type& x, + const typename decision_function::scalar_vector_type& y, + const K& kernel_function, + const typename K::scalar_type nu, + const long folds, + const long cache_size = 200, + const typename K::scalar_type eps = 0.001 + ); + /*! + requires + - eps > 0 + - 1 < folds <= x.nr() + - x.nc() == 1 (i.e. x is a column vector) + - y.nc() == 1 (i.e. y is a column vector) + - x.nr() == y.nr() + - x.nr() > 1 + - cache_size > 0 + - for all valid i: + - y(i) == -1 or +1 + - y(i) is the class that should be assigned to training example x(i) + - 0 < nu < maximum_nu(y) + - kernel_function == a kernel function object type as defined at the top + of this document. + ensures + - trains a nu support vector classifier given the training samples in x and + labels in y. Training is done when the error is less than eps. + - caches approximately at most cache_size megabytes of the kernel matrix. + (bigger values of this may make training go faster but doesn't affect the + result. However, too big a value will cause you to run out of memory.) + - returns a probabilistic_decision_function that represents the trained + svm. + - The parameters of the probability model are estimated by performing k-fold + cross validation. + - The number of folds used is given by the folds argument. + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Miscellaneous functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename K + > + const matrix svm_nu_cross_validate ( + const typename decision_function::sample_vector_type& x, + const typename decision_function::scalar_vector_type& y, + const K& kernel_function, + const typename K::scalar_type nu, + const long folds, + const long cache_size = 200, + const typename K::scalar_type eps = 0.001 + ); + /*! + requires + - eps > 0 + - 1 < folds <= x.nr() + - x.nc() == 1 (i.e. x is a column vector) + - y.nc() == 1 (i.e. y is a column vector) + - x.nr() == y.nr() + - x.nr() > 1 + - cache_size > 0 + - for all valid i: + - y(i) == -1 or +1 + - y(i) is the class that should be assigned to training example x(i) + - 0 < nu < maximum_nu(y) + - kernel_function == a kernel function object type as defined at the top + of this document. + ensures + - performs k-fold cross validation by training a nu-svm using the svm_nu_train() + function. Each fold is tested using the learned decision_function and the + average accuracy from all folds is returned. The accuracy is returned in + a column vector, let us call it R. Both quantities in R are numbers between + 0 and 1 which represent the fraction of examples correctly classified. R(0) + is the fraction of +1 examples correctly classified and R(1) is the fraction + of -1 examples correctly classified. + - The number of folds used is given by the folds argument. + - in each fold: trains a nu support vector classifier given the training samples + in x and labels in y. Training is done when the error is less than eps. + - caches approximately at most cache_size megabytes of the kernel matrix. + (bigger values of this may make training go faster but doesn't affect the + result. However, too big a value will cause you to run out of memory.) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + typename U + > + void randomize_samples ( + T& samples, + U& labels + ); + /*! + requires + - T == a matrix object that contains a swappable type + - U == a matrix object that contains a swappable type + - samples.nc() == 1 + - labels.nc() == 1 + - samples.nr() == labels.nr() + ensures + - randomizes the order of the samples and labels but preserves + the pairing between each sample and its label + - for all valid i: + - let r == the random index samples(i) was moved to. then: + - #labels(r) == labels(i) + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_SVm_ABSTRACT_ + + diff --git a/dlib/sync_extension.h b/dlib/sync_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..d688e1773b82a413287a51cfe8bf1f543474ba51 --- /dev/null +++ b/dlib/sync_extension.h @@ -0,0 +1,31 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SYNC_EXTENSIOn_ +#define DLIB_SYNC_EXTENSIOn_ + +#include "sync_extension/sync_extension_kernel_1.h" + + + +namespace dlib +{ + + template < + typename base + > + class sync_extension + { + sync_extension() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef sync_extension_kernel_1 + kernel_1a; + + }; +} + +#endif // DLIB_SYNC_EXTENSIOn_ + diff --git a/dlib/sync_extension/sync_extension_kernel_1.h b/dlib/sync_extension/sync_extension_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..6997a21daa2e542b7b1f044215253a4e38d41bed --- /dev/null +++ b/dlib/sync_extension/sync_extension_kernel_1.h @@ -0,0 +1,67 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_SYNC_EXTENSION_KERNEl_1_ +#define DLIB_SYNC_EXTENSION_KERNEl_1_ + +#include "../threads.h" +#include "../algs.h" +#include "sync_extension_kernel_abstract.h" + +namespace dlib +{ + + template < + typename base + > + class sync_extension_kernel_1 : public base + { + + rmutex m; + rsignaler s; + + public: + + sync_extension_kernel_1 () : s(m) {} + + template < typename T > + sync_extension_kernel_1 (const T& one) : base(one),s(m) {} + template < typename T, typename U > + sync_extension_kernel_1 (const T& one, const U& two) : base(one,two),s(m) {} + + + const rmutex& get_mutex( + ) const { return m; } + + void lock ( + ) const { m.lock(); } + + void unlock ( + ) const { m.unlock(); } + + void wait ( + ) const { s.wait(); } + + bool wait_or_timeout ( + unsigned long milliseconds + ) const { return s.wait_or_timeout(milliseconds); } + + void broadcast ( + ) const { s.broadcast(); } + + void signal ( + ) const { s.signal(); } + + }; + + template < + typename base + > + inline void swap ( + sync_extension_kernel_1& a, + sync_extension_kernel_1& b + ) { a.swap(b); } + +} + +#endif // DLIB_SYNC_EXTENSION_KERNEl_1_ + diff --git a/dlib/sync_extension/sync_extension_kernel_abstract.h b/dlib/sync_extension/sync_extension_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b00f6e8d33cc98762f143c1fe688fc29159b77f3 --- /dev/null +++ b/dlib/sync_extension/sync_extension_kernel_abstract.h @@ -0,0 +1,190 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_SYNC_EXTENSION_KERNEl_ABSTRACT_ +#ifdef DLIB_SYNC_EXTENSION_KERNEl_ABSTRACT_ + +#include "../threads/threads_kernel_abstract.h" +#include "../threads/rmutex_extension_abstract.h" +#include "../threads/rsignaler_extension_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + template < + typename base + > + class sync_extension : public base + { + + /*! + REQUIREMENTS ON base + base must have a default constructor + base must implement swap(base&) + + + WHAT THIS OBJECT REPRESENTS + This object represents a general extension to any object (given the + restrictions on base). This object gives any object which it extends + an integrated rmutex and rsignaler object. The extended object will + then be able to be treated as if it was also a rmutex and rsignaler. + + NOTE that just like the threading api, this object does not check + its requires clauses so be careful with it. + + Also note that swap() does not swap the rmutex and rsignaler objects. + the rmutex and rsignaler are associated with the object instance itself, + not with whatever the object represents. + !*/ + + + public: + + sync_extension ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + this is thrown if there is a problem gathering memory + - dlib::thread_error + this is thrown if there is a problem creating threading objects + - any exception thrown by the constructor for the parent class base + !*/ + + template < + typename T + > + sync_extension ( + const T& one + ); + /*! + ensures + - #*this is properly initialized + - the argument one will be passed on to the constructor for the parent + class base. + throws + - std::bad_alloc + this is thrown if there is a problem gathering memory + - dlib::thread_error + this is thrown if there is a problem creating threading objects + - any exception thrown by the constructor for the parent class base + !*/ + + template < + typename T, + typename U + > + sync_extension ( + const T& one, + const T& two + ); + /*! + ensures + - #*this is properly initialized + - the argument one will be passed on to the constructor for the parent + class base as its first argument. + - the argument two will be passed on to the constructor for the parent + class base as its second argument. + throws + - std::bad_alloc + this is thrown if there is a problem gathering memory + - dlib::thread_error + this is thrown if there is a problem creating threading objects + - any exception thrown by the constructor for the parent class base + !*/ + + + const rmutex& get_mutex ( + ) const; + /*! + ensures + - returns the rmutex embedded in this object + !*/ + + void lock ( + ) const; + /*! + requires + - the thread calling lock() does not already have a lock on *this + ensures + - if (*this is currently locked by another thread) then + - the thread that called lock() on *this is put to sleep until + it becomes available + - if (*this is currently unlocked) then + - #*this becomes locked and the current thread is NOT put to sleep + but now "owns" #*this + !*/ + + void unlock ( + ) const; + /*! + ensures + - #*this is unlocked (i.e. other threads may now lock this object) + !*/ + + + void wait ( + ) const; + /*! + requires + - *this is locked and owned by the calling thread + ensures + - atomically unlocks *this and blocks the calling thread + - calling thread will wake if another thread calls signal() or broadcast() + on *this + - when wait returns the calling thread again has a lock on #*this + !*/ + + + bool wait_or_timeout ( + unsigned long milliseconds + ) const; + /*! + requires + - *this is locked and owned by the calling thread + ensures + - atomically unlocks *this and blocks the calling thread + - calling thread will wake if another thread calls signal() or broadcast() + on *this + - after the specified number of milliseconds has elapsed the calling thread + will wake once *this is free to be locked + - when wait returns the calling thread again has a lock on #*this + + - returns false if the call to wait_or_timeout timed out + - returns true if the call did not time out + !*/ + + void signal ( + ) const; + /*! + ensures + - if (at least one thread is waiting on *this) then + - at least one of the waiting threads will wake + !*/ + + void broadcast ( + ) const; + /*! + ensures + - any and all threads waiting on *this will wake + !*/ + + }; + + template < + typename base + > + inline void swap ( + sync_extension& a, + sync_extension& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_SYNC_EXTENSION_KERNEl_ABSTRACT_ + diff --git a/dlib/test/CMakeLists.txt b/dlib/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a613050f6e5f3fae3603cb79e3f708f983ab69ff --- /dev/null +++ b/dlib/test/CMakeLists.txt @@ -0,0 +1,90 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# + +# setting this makes CMake allow normal looking IF ELSE statements +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +# This variable contains a list of all the tests we are building +# into the regression test suite. +set (tests + example.cpp + example_args.cpp + array2d.cpp + array.cpp + base64.cpp + bayes_nets.cpp + bigint.cpp + binary_search_tree_kernel_1a.cpp + binary_search_tree_kernel_2a.cpp + binary_search_tree_mm1.cpp + binary_search_tree_mm2.cpp + cmd_line_parser.cpp + cmd_line_parser_wchar_t.cpp + compress_stream.cpp + conditioning_class.cpp + conditioning_class_c.cpp + config_reader.cpp + directed_graph.cpp + graph.cpp + geometry.cpp + entropy_coder.cpp + entropy_encoder_model.cpp + hash_map.cpp + hash_set.cpp + hash_table.cpp + image.cpp + lz77_buffer.cpp + map.cpp + matrix.cpp + md5.cpp + member_function_pointer.cpp + metaprogramming.cpp + multithreaded_object.cpp + pipe.cpp + pixel.cpp + queue.cpp + rand.cpp + reference_counter.cpp + sequence.cpp + serialize.cpp + set.cpp + sliding_buffer.cpp + smart_pointers.cpp + sockets.cpp + sockstreambuf.cpp + stack.cpp + static_map.cpp + static_set.cpp + string.cpp + threads.cpp + timer.cpp + tokenizer.cpp + tuple.cpp + ) + +# create a variable called target_name and set it to the string "test" +set (target_name test) + +PROJECT(${target_name}) + +# add all the cpp files we want to compile to this list. This tells +# cmake that they are part of our target (which is the executable named test) +ADD_EXECUTABLE(${target_name} main.cpp tester.cpp ${tests}) + +# add the folder containing the dlib folder to the include path +INCLUDE_DIRECTORIES(../..) + +# There is a CMakeLists.txt file in the dlib source folder that tells cmake +# how to build the dlib library. Tell cmake about that file. +add_subdirectory(.. dlib_build) + +if (NOT DLIB_NO_GUI_SUPPORT) + add_subdirectory(gui) +endif() + +# Tell cmake to link our target executable to the non-gui version of the dlib +# library. +TARGET_LINK_LIBRARIES(${target_name} dlib ) + diff --git a/dlib/test/array.cpp b/dlib/test/array.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e86e00c6247aed548760ca7b7d94c61c70b49266 --- /dev/null +++ b/dlib/test/array.cpp @@ -0,0 +1,653 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#include +#include +#include +#include +#include +#include +#include + + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.array"); + + template < + typename array + > + void array_expand_test ( + ) + /*! + requires + - array is an implementation of array/array_sort_abstract.h + array is instantiated with unsigned long + ensures + - runs tests on array for compliance with the specs + !*/ + { + dlib::rand::kernel_1a rnd; + + + array a1, a2; + + { + array a1, a2; + + for (int k = 1; k < 100000; k += 1000) + { + for (int i = 0; i < 10; ++i) + { + a1.clear(); + a1.set_max_size(500+k); + a1.set_size(500+k); + for (unsigned long j = 0; j < a1.size(); ++j) + { + a1[j] = j; + DLIB_CASSERT(a1[j] == j,""); + } + } + } + } + + DLIB_CASSERT(a1.max_size() == 0,""); + DLIB_CASSERT(a2.max_size() == 0,""); + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + swap(a1,a2); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.move_next() == false,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + a1.reset(); + a2.reset(); + + for (unsigned long k = 0; k < 4; ++k) + { + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + swap(a1,a2); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.move_next() == false,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + a1.clear(); + a2.clear(); + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + swap(a1,a2); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.move_next() == false,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + a1.clear(); + a2.clear(); + + + + + a1.set_max_size(100000); + a2.set_max_size(100000); + a1.set_size(10000); + DLIB_CASSERT(a1.size() == 10000,""); + a2.set_size(10000); + DLIB_CASSERT(a2.size() == 10000,""); + for (unsigned long i = 0; i < a1.size(); ++i) + { + unsigned long a = static_cast(rnd.get_random_32bit_number()); + DLIB_CASSERT(a >= 0,""); + a1[i] = a; + a2[i] = i; + DLIB_CASSERT(a1[i] == a,""); + DLIB_CASSERT(a2[i] == i,""); + } + + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next(),""); + DLIB_CASSERT(a1.current_element_valid(),""); + + DLIB_CASSERT(a1.at_start() == false,""); + a1.sort(); + DLIB_CASSERT(a1.at_start(),""); + a2.sort(); + DLIB_CASSERT(a1.size() == 10000,""); + DLIB_CASSERT(a2.size() == 10000,""); + + + for (unsigned long i = 0; i < a1.size(); ++i) + { + if (i+1 < a1.size()) + { + DLIB_CASSERT(a1[i] <= a1[i+1], + "a1[i]: " << a1[i] << " a1[i+1]: " << a1[i+1] + << " i: " << i); + } + DLIB_CASSERT(a2[i] == i,"i: " << i << " a2[i]: " << a2[i]); + } + + unsigned long last = 0; + unsigned long count = 0; + while (a1.move_next()) + { + DLIB_CASSERT(last <= a1.element(),""); + last = a1.element(); + ++count; + } + DLIB_CASSERT(count == a1.size(),""); + + last = 0; + count = 0; + while (a2.move_next()) + { + DLIB_CASSERT(last <= a2.element(),""); + last = a2.element(); + ++count; + } + DLIB_CASSERT(count == a2.size(),""); + + a2.set_size(15000); + + for (unsigned long i = 0; i < a1.size(); ++i) + { + if (i+1 < a1.size()) + { + DLIB_CASSERT(a1[i] <= a1[i+1],""); + } + DLIB_CASSERT(a2[i] == i,""); + } + + for (unsigned long i = 10000; i < a2.size(); ++i) + { + a2[i] = i; + DLIB_CASSERT(a2[i] == i,""); + } + + for (unsigned long i = 0; i < a2.size(); ++i) + { + DLIB_CASSERT(a2[i] == i,""); + } + + a2.reset(); + last = 0; + while (a2.move_next()) + { + DLIB_CASSERT(last <= a2.element(),""); + last = a2.element(); + } + + a1.reset(); + last = 0; + while (a1.move_next()) + { + DLIB_CASSERT(last <= a1.element(),""); + last = a1.element(); + } + + a1.sort(); + last = 0; + while (a1.move_next()) + { + DLIB_CASSERT(last <= a1.element(),""); + last = a1.element(); + } + + swap(a2,a1); + + for (unsigned long i = 0; i < 15000; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + + + a1.clear(); + DLIB_CASSERT(a1.max_size() == 0,""); + + + + + a1.clear(); + a2.clear(); + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a2.size() == 0,""); + a1.set_max_size(100000); + a2.set_max_size(100000); + + a1.set_size(10000); + DLIB_CASSERT(a1.size() == 10000,""); + a2.set_size(10000); + DLIB_CASSERT(a2.size() == 10000,""); + for (unsigned long i = 0; i < a1.size(); ++i) + { + unsigned long a = static_cast(rnd.get_random_32bit_number()); + DLIB_CASSERT(a >= 0,""); + a1[i] = a; + a2[i] = i; + DLIB_CASSERT(a1[i] == a,""); + DLIB_CASSERT(a2[i] == i,""); + } + + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next(),""); + DLIB_CASSERT(a1.current_element_valid(),""); + + DLIB_CASSERT(a1.at_start() == false,""); + a1.sort(); + DLIB_CASSERT(a1.at_start(),""); + a2.sort(); + DLIB_CASSERT(a1.size() == 10000,""); + DLIB_CASSERT(a2.size() == 10000,""); + + + for (unsigned long i = 0; i < a1.size(); ++i) + { + if (i+1 < a1.size()) + { + DLIB_CASSERT(a1[i] <= a1[i+1],""); + } + DLIB_CASSERT(a2[i] == i,""); + } + + last = 0; + while (a1.move_next()) + { + DLIB_CASSERT(last <= a1.element(),""); + last = a1.element(); + } + + last = 0; + while (a2.move_next()) + { + DLIB_CASSERT(last <= a2.element(),""); + last = a2.element(); + } + + a2.set_size(15000); + + for (unsigned long i = 0; i < a1.size(); ++i) + { + if (i+1 < a1.size()) + { + DLIB_CASSERT(a1[i] <= a1[i+1],""); + } + DLIB_CASSERT(a2[i] == i,""); + } + + for (unsigned long i = 10000; i < a2.size(); ++i) + { + a2[i] = i; + DLIB_CASSERT(a2[i] == i,""); + } + + for (unsigned long i = 0; i < a2.size(); ++i) + { + DLIB_CASSERT(a2[i] == i,""); + } + + a2.reset(); + last = 0; + while (a2.move_next()) + { + DLIB_CASSERT(last <= a2.element(),""); + last = a2.element(); + } + + a1.reset(); + last = 0; + while (a1.move_next()) + { + DLIB_CASSERT(last <= a1.element(),""); + last = a1.element(); + } + + a1.sort(); + last = 0; + while (a1.move_next()) + { + DLIB_CASSERT(last <= a1.element(),""); + last = a1.element(); + } + + swap(a2,a1); + + for (unsigned long i = 0; i < 15000; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + + + a1.clear(); + DLIB_CASSERT(a1.max_size() == 0,""); + + a2.clear(); + print_spinner(); + } + + + + a1.set_max_size(2000000); + DLIB_CASSERT(a1.max_size() == 2000000,""); + DLIB_CASSERT(a1.size() == 0,""); + a1.set_size(2000000); + DLIB_CASSERT(a1.max_size() == 2000000,""); + DLIB_CASSERT(a1.size() == 2000000,""); + + for (unsigned long i = 0; i < a1.size(); ++i) + { + a1[i] = rnd.get_random_32bit_number(); + } + + print_spinner(); + a1.sort(); + + print_spinner(); + // serialize the state of a1, then clear a1, then + // load the state back into a1. + ostringstream sout; + serialize(a1,sout); + DLIB_CASSERT(a1.at_start() == true,""); + istringstream sin(sout.str()); + a1.clear(); + DLIB_CASSERT(a1.max_size() == 0,""); + deserialize(a1,sin); + + DLIB_CASSERT(a1.size() == 2000000,""); + + for (unsigned long i = 0; i < a1.size()-1; ++i) + { + DLIB_CASSERT(a1[i] <= a1[i+1],""); + } + + DLIB_CASSERT(a1.max_size() == 2000000,""); + DLIB_CASSERT(a1.size() == 2000000,""); + + + swap(a1,a2); + + print_spinner(); + + DLIB_CASSERT(a2.size() == 2000000,""); + + for (unsigned long i = 0; i < a2.size()-1; ++i) + { + DLIB_CASSERT(a2[i] <= a2[i+1],""); + } + + DLIB_CASSERT(a2.max_size() == 2000000,""); + DLIB_CASSERT(a2.size() == 2000000,""); + + swap(a1,a2); + + + a1.clear(); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.max_size() == 0,""); + + a1.expand(10); + DLIB_CASSERT(a1.size() == 10,""); + DLIB_CASSERT(a1.max_size() == 10,""); + + for (unsigned long i = 0; i < a1.size(); ++i) + { + a1[i] = i; + } + + print_spinner(); + a1.expand(100); + DLIB_CASSERT(a1.size() == 100,""); + DLIB_CASSERT(a1.max_size() == 100,""); + + for (unsigned long i = 0; i < 10; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + a1.expand(50); + DLIB_CASSERT(a1.size() == 50,""); + DLIB_CASSERT(a1.max_size() == 100,""); + + for (unsigned long i = 0; i < 10; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + a1.expand(10); + DLIB_CASSERT(a1.size() == 10,""); + DLIB_CASSERT(a1.max_size() == 100,""); + + for (unsigned long i = 0; i < 10; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + a1.expand(20); + DLIB_CASSERT(a1.size() == 20,""); + DLIB_CASSERT(a1.max_size() == 100,""); + + for (unsigned long i = 0; i < 10; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + + a1.expand(100); + DLIB_CASSERT(a1.size() == 100,""); + DLIB_CASSERT(a1.max_size() == 100,""); + + for (unsigned long i = 0; i < 10; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + + { + a1.clear(); + DLIB_CASSERT(a1.size() == 0,""); + for (unsigned long i = 0; i < 100; ++i) + { + unsigned long a = i; + a1.push_back(a); + DLIB_CASSERT(a1.size() == i+1,""); + DLIB_CASSERT(a1.back() == i,""); + } + for (unsigned long i = 0; i < 100; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + for (unsigned long i = 0; i < 100; ++i) + { + unsigned long a; + a1.pop_back(a); + DLIB_CASSERT(a == 99-i,""); + } + } + + { + a1.clear(); + DLIB_CASSERT(a1.size() == 0,""); + for (unsigned long i = 0; i < 100; ++i) + { + unsigned long a = i; + a1.push_back(a); + DLIB_CASSERT(a1.size() == i+1,""); + DLIB_CASSERT(a1.back() == i,""); + } + for (unsigned long i = 0; i < 100; ++i) + { + DLIB_CASSERT(a1[i] == i,""); + } + for (unsigned long i = 0; i < 100; ++i) + { + a1.pop_back(); + } + DLIB_CASSERT(a1.size() == 0,""); + } + + + } + + + class array_tester : public tester + { + public: + array_tester ( + ) : + tester ("test_array", + "Runs tests on the array component.") + {} + + void perform_test ( + ) + { + // test a checking version first for good measure + dlog << LINFO << "testing expand_1a_c"; + print_spinner(); + array_expand_test::expand_1a_c>(); + + dlog << LINFO << "testing expand_1a"; + print_spinner(); + array_expand_test::expand_1a>(); + + + dlog << LINFO << "testing expand_1b"; + print_spinner(); + array_expand_test::expand_1b>(); + + dlog << LINFO << "testing expand_1b_c"; + print_spinner(); + array_expand_test::expand_1b_c>(); + + dlog << LINFO << "testing expand_1c"; + print_spinner(); + array_expand_test::expand_1c>(); + + dlog << LINFO << "testing expand_1c_c"; + print_spinner(); + array_expand_test::expand_1c_c>(); + + dlog << LINFO << "testing expand_1d"; + print_spinner(); + array_expand_test::expand_1d>(); + + dlog << LINFO << "testing expand_1d_c"; + print_spinner(); + array_expand_test::expand_1d_c>(); + + print_spinner(); + } + } a; + + + + +} + diff --git a/dlib/test/array2d.cpp b/dlib/test/array2d.cpp new file mode 100644 index 0000000000000000000000000000000000000000..734f67bd737e79d2b61e1d1239c058dd27805a33 --- /dev/null +++ b/dlib/test/array2d.cpp @@ -0,0 +1,414 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.array2d"); + + template < + typename array2d + > + void array2d_kernel_test ( + ) + /*! + requires + - array2d is an implementation of array2d/array2d_kernel_abstract.h + is instantiated with unsigned long + ensures + - runs tests on array2d for compliance with the specs + !*/ + { + srand(static_cast(time(0))); + + array2d test,test2; + + long nc, nr; + + + + enumerable& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + + DLIB_CASSERT(e.size() == 0,""); + DLIB_CASSERT(e.at_start() == true,""); + DLIB_CASSERT(e.current_element_valid() == false, ""); + + DLIB_CASSERT (e.move_next() == false,""); + DLIB_CASSERT (e.move_next() == false,""); + DLIB_CASSERT (e.move_next() == false,""); + DLIB_CASSERT (e.move_next() == false,""); + DLIB_CASSERT (e.move_next() == false,""); + DLIB_CASSERT (e.move_next() == false,""); + + + DLIB_CASSERT(e.size() == 0,""); + DLIB_CASSERT(e.at_start() == false,""); + DLIB_CASSERT(e.current_element_valid() == false, ""); + + + e.reset(); + + DLIB_CASSERT(e.size() == 0,""); + DLIB_CASSERT(e.at_start() == true,""); + DLIB_CASSERT(e.current_element_valid() == false, ""); + + + + + + DLIB_CASSERT(test.at_start() == true,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + + test.reset(); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + test.clear(); + + + DLIB_CASSERT(test.at_start() == true,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + + + test.set_size(0,0); + + + DLIB_CASSERT(test.at_start() == true,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + DLIB_CASSERT (test.move_next() == false,""); + + swap(test,test2); + DLIB_CASSERT (test2.at_start() == false,""); + DLIB_CASSERT (test2.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + swap(test,test2); + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false, ""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + + test.reset(); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false, ""); + + + + + for (int j = 0; j < 30; ++j) + { + test2.clear(); + switch (j) + { + case 0: + nc = 10; + nr = 11; + break; + case 1: + nc = 1; + nr = 1; + break; + case 2: + nc = 100; + nr = 1; + break; + case 3: + nc = 1; + nr = 100; + break; + default: + nc = ::rand()%100 + 1; + nr = ::rand()%100 + 1; + break; + } + + test.set_size(nr,nc); + + DLIB_CASSERT(test.size() == static_cast(nc*nr),""); + DLIB_CASSERT(test.nr() == nr,""); + DLIB_CASSERT(test.nc() == nc,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + unsigned long i = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.current_element_valid() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + test.element() = i; + DLIB_CASSERT(const_cast(test).element() == i,""); + ++i; + } + DLIB_CASSERT(i == test.size(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + DLIB_CASSERT(test.nr() == nr,""); + DLIB_CASSERT(test.nc() == nc,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.size() == static_cast(nc*nr),""); + + i = 0; + for (long row = 0; row < test.nr(); ++row) + { + for (long col = 0; col < test.nc(); ++col) + { + DLIB_CASSERT(test[row][col] == i, + "\n\trow: " << row << + "\n\tcol: " << col << + "\n\ti: " << i << + "\n\ttest[row][col]: " << test[row][col]); + DLIB_CASSERT(test[row].nc() == test.nc(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + DLIB_CASSERT(test.nr() == nr,""); + DLIB_CASSERT(test.nc() == nc,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.size() == static_cast(nc*nr),""); + ++i; + } + } + + test.reset(); + + i = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element() == i,""); + ++i; + DLIB_CASSERT(test.current_element_valid() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + } + DLIB_CASSERT(i == test.size(),""); + + test.reset(); + + + + + swap(test,test2); + + DLIB_CASSERT(test2.size() == static_cast(nc*nr),""); + DLIB_CASSERT(test2.nr() == nr,""); + DLIB_CASSERT(test2.nc() == nc,""); + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + i = 0; + while (test2.move_next()) + { + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.at_start() == false,""); + test2.element() = i; + ++i; + } + DLIB_CASSERT(i == test2.size(),""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + DLIB_CASSERT(test2.nr() == nr,""); + DLIB_CASSERT(test2.nr() == test2.nr(),""); + DLIB_CASSERT(test2.nc() == nc,""); + DLIB_CASSERT(test2.nc() == test2.nc(),""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.size() == static_cast(nc*nr),""); + + i = 0; + for (long row = 0; row < test2.nr(); ++row) + { + for (long col = 0; col < test2.nc(); ++col) + { + DLIB_CASSERT(test2[row][col] == i,""); + DLIB_CASSERT(const_cast(test2)[row][col] == i,""); + DLIB_CASSERT(test2[row].nc() == test2.nc(),""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + DLIB_CASSERT(test2.nr() == nr,""); + DLIB_CASSERT(test2.nr() == test2.nr(),""); + DLIB_CASSERT(test2.nc() == nc,""); + DLIB_CASSERT(test2.nc() == test2.nc(),""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.size() == static_cast(nc*nr),""); + ++i; + } + } + + test2.reset(); + + i = 0; + while (test2.move_next()) + { + DLIB_CASSERT(test2.element() == i,""); + DLIB_CASSERT(const_cast(test2).element() == i,""); + ++i; + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.at_start() == false,""); + } + DLIB_CASSERT(i == test2.size(),""); + + + test2.clear(); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.nr() == 0,""); + DLIB_CASSERT(test2.nc() == 0,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == true,""); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.nc() == 0,""); + DLIB_CASSERT(test.nr() == 0,""); + + test.set_size(nr,nc); + DLIB_CASSERT(test.size() == static_cast(nc*nr),""); + DLIB_CASSERT(test.nc() == nc,""); + DLIB_CASSERT(test.nr() == nr,""); + + + + } + + + + + + // test the serialization + istringstream sin; + ostringstream sout; + test.clear(); + test2.clear(); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.nc() == 0,""); + DLIB_CASSERT(test.nr() == 0,""); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.nc() == 0,""); + DLIB_CASSERT(test2.nr() == 0,""); + + test.set_size(10,10); + + for (long row = 0; row < test.nr(); ++row) + { + for (long col = 0; col < test.nc(); ++col) + { + test[row][col] = row*col; + } + } + + serialize(test,sout); + sin.str(sout.str()); + deserialize(test2,sin); + + DLIB_CASSERT(test2.size() == test.size(),""); + DLIB_CASSERT(test2.nc() == test.nc(),""); + DLIB_CASSERT(test2.nr() == test.nr(),""); + DLIB_CASSERT(test2.size() == 100,""); + DLIB_CASSERT(test2.nc() == 10,""); + DLIB_CASSERT(test2.nr() == 10,""); + + + for (long row = 0; row < test.nr(); ++row) + { + for (long col = 0; col < test.nc(); ++col) + { + DLIB_CASSERT(test[row][col] == static_cast(row*col),""); + DLIB_CASSERT(test2[row][col] == static_cast(row*col),""); + } + } + + + + + + + test.set_size(10,11); + DLIB_CASSERT(test.nr() == 10,""); + DLIB_CASSERT(test.nc() == 11,""); + test.set_size(0,0); + DLIB_CASSERT(test.nr() == 0,""); + DLIB_CASSERT(test.nc() == 0,""); + + } + + + class array2d_tester : public tester + { + public: + array2d_tester ( + ) : + tester ("test_array2d", + "Runs tests on the array2d component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + array2d_kernel_test::kernel_1a> (); + print_spinner(); + dlog << LINFO << "testing kernel_1a_c"; + array2d_kernel_test::kernel_1a_c> (); + print_spinner(); + } + } a; + +} + + diff --git a/dlib/test/base64.cpp b/dlib/test/base64.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d269924c5cae70cff58c19847c94ce905facd4ab --- /dev/null +++ b/dlib/test/base64.cpp @@ -0,0 +1,208 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.base64"); + + template < + typename base64 + > + void base64_kernel_test ( + ) + /*! + requires + - base64 is an implementation of base64/base64_kernel_abstract.h + ensures + - runs tests on base64 for compliance with the specs + !*/ + { + + const unsigned int seed = static_cast(time(0)); + try + { + + srand(seed); + + base64 test; + + const string wiki_normal = "\ +Man is distinguished, not only by his reason, but by this singular passion from other \ +animals, which is a lust of the mind, that by a perseverance of delight in the continued \ +and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."; + + const string wiki_encoded = "\ +TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0\n\ +aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1\n\ +c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0\n\ +aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdl\n\ +LCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4="; + + + + string str; + + istringstream sin; + ostringstream sout; + + sin.str(wiki_encoded); + test.decode(sin,sout); + DLIB_CASSERT(sout.str() == wiki_normal, + "sout.str(): " << sout.str() << + "\nwiki_normal: " << wiki_normal); + + + sout.str(""); + sin.str(wiki_normal); + sin.clear(); + test.encode(sin,sout); + + string a(sout.str()), b(wiki_encoded); + // we want to strip all the whitespace from a and b now + sin.str(a); + a.clear(); + sin >> str; + while (sin) + { + a += str; + sin >> str; + } + + sin.clear(); + sin.str(b); + b.clear(); + sin >> str; + while (sin) + { + b += str; + sin >> str; + } + sin.clear(); + + DLIB_CASSERT(a == b, + "a: \n" << a << + "\n\nb: \n" << b); + + + + sin.clear(); + sin.str(""); + sout.str(""); + test.encode(sin,sout); + sin.str(sout.str()); + sout.str(""); + test.decode(sin,sout); + DLIB_CASSERT(sout.str() == "",""); + + sin.clear(); + sin.str("a"); + sout.str(""); + test.encode(sin,sout); + sin.str(sout.str()); + sout.str(""); + test.decode(sin,sout); + DLIB_CASSERT(sout.str() == "a",""); + + sin.clear(); + sin.str("da"); + sout.str(""); + test.encode(sin,sout); + sin.str(sout.str()); + sout.str(""); + test.decode(sin,sout); + DLIB_CASSERT(sout.str() == "da",""); + + sin.clear(); + sin.str("dav"); + sout.str(""); + test.encode(sin,sout); + sin.str(sout.str()); + sout.str(""); + test.decode(sin,sout); + DLIB_CASSERT(sout.str() == "dav",""); + + sin.clear(); + sin.str("davi"); + sout.str(""); + test.encode(sin,sout); + sin.str(sout.str()); + sout.str(""); + test.decode(sin,sout); + DLIB_CASSERT(sout.str() == "davi",""); + + + for (int i = 0; i < 1000; ++i) + { + str.clear(); + sin.clear(); + sout.str(""); + sin.str(""); + + // fill str with random garbage + const int size = rand()%2000; + for (int j = 0; j < size; ++j) + { + unsigned char ch = rand()&0xFF; + str += ch; + } + + sin.str(str); + test.encode(sin,sout); + sin.clear(); + sin.str(sout.str()); + sout.str(""); + test.decode(sin,sout); + + DLIB_CASSERT(str == sout.str(),""); + + + } + + + + + } + catch (typename base64::decode_error& e) + { + DLIB_CASSERT(false, + "decode_error thrown when it shouldn't have been (" << seed << "):\n " + << e.info); + } + } + + + class base64_tester : public tester + { + public: + base64_tester ( + ) : + tester ("test_base64", + "Runs tests on the base64 component.") + {} + + void perform_test ( + ) + { + print_spinner(); + base64_kernel_test(); + } + } a; + + + +} + + + diff --git a/dlib/test/bayes_nets.cpp b/dlib/test/bayes_nets.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06bca668444546d95e81a263302d46ec89e8931a --- /dev/null +++ b/dlib/test/bayes_nets.cpp @@ -0,0 +1,411 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include "dlib/graph_utils.h" +#include "dlib/graph.h" +#include "dlib/directed_graph.h" +#include "dlib/bayes_utils.h" +#include "dlib/set.h" +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.bayes_nets"); + enum nodes + { + A, T, S, L, O, B, D, X + }; + + template + void setup_simple_network ( + gtype& bn + ) + { + /* + A + / \ + T S + */ + + using namespace bayes_node_utils; + + bn.set_number_of_nodes(3); + bn.add_edge(A, T); + bn.add_edge(A, S); + + + set_node_num_values(bn, A, 2); + set_node_num_values(bn, T, 2); + set_node_num_values(bn, S, 2); + + assignment parents; + + // set probabilities for node A + set_node_probability(bn, A, 1, parents, 0.1); + set_node_probability(bn, A, 0, parents, 1-0.1); + + // set probabilities for node T + parents.add(A, 1); + set_node_probability(bn, T, 1, parents, 0.5); + set_node_probability(bn, T, 0, parents, 1-0.5); + parents[A] = 0; + set_node_probability(bn, T, 1, parents, 0.5); + set_node_probability(bn, T, 0, parents, 1-0.5); + + // set probabilities for node S + parents[A] = 1; + set_node_probability(bn, S, 1, parents, 0.5); + set_node_probability(bn, S, 0, parents, 1-0.5); + parents[A] = 0; + set_node_probability(bn, S, 1, parents, 0.5); + set_node_probability(bn, S, 0, parents, 1-0.5); + + + // test the serialization code here by pushing this network though it + ostringstream sout; + serialize(bn, sout); + bn.clear(); + DLIB_CASSERT(bn.number_of_nodes() == 0,""); + istringstream sin(sout.str()); + deserialize(bn, sin); + DLIB_CASSERT(bn.number_of_nodes() == 3,""); + } + + + template + void setup_dyspnea_network ( + gtype& bn, + bool deterministic_o_node = true + ) + { + /* + This is the example network used by David Zaret in his + reasoning under uncertainty class at Johns Hopkins + */ + + using namespace bayes_node_utils; + + bn.set_number_of_nodes(8); + bn.add_edge(A, T); + bn.add_edge(T, O); + + bn.add_edge(O, D); + bn.add_edge(O, X); + + bn.add_edge(S, B); + bn.add_edge(S, L); + + bn.add_edge(L, O); + bn.add_edge(B, D); + + + set_node_num_values(bn, A, 2); + set_node_num_values(bn, T, 2); + set_node_num_values(bn, O, 2); + set_node_num_values(bn, X, 2); + set_node_num_values(bn, L, 2); + set_node_num_values(bn, S, 2); + set_node_num_values(bn, B, 2); + set_node_num_values(bn, D, 2); + + assignment parents; + + // set probabilities for node A + set_node_probability(bn, A, 1, parents, 0.01); + set_node_probability(bn, A, 0, parents, 1-0.01); + + // set probabilities for node S + set_node_probability(bn, S, 1, parents, 0.5); + set_node_probability(bn, S, 0, parents, 1-0.5); + + // set probabilities for node T + parents.add(A, 1); + set_node_probability(bn, T, 1, parents, 0.05); + set_node_probability(bn, T, 0, parents, 1-0.05); + parents[A] = 0; + set_node_probability(bn, T, 1, parents, 0.01); + set_node_probability(bn, T, 0, parents, 1-0.01); + + // set probabilities for node L + parents.clear(); + parents.add(S,1); + set_node_probability(bn, L, 1, parents, 0.1); + set_node_probability(bn, L, 0, parents, 1-0.1); + parents[S] = 0; + set_node_probability(bn, L, 1, parents, 0.01); + set_node_probability(bn, L, 0, parents, 1-0.01); + + + // set probabilities for node B + parents[S] = 1; + set_node_probability(bn, B, 1, parents, 0.6); + set_node_probability(bn, B, 0, parents, 1-0.6); + parents[S] = 0; + set_node_probability(bn, B, 1, parents, 0.3); + set_node_probability(bn, B, 0, parents, 1-0.3); + + + // set probabilities for node O + double v; + if (deterministic_o_node) + v = 1; + else + v = 0.99; + + parents.clear(); + parents.add(T,1); + parents.add(L,1); + set_node_probability(bn, O, 1, parents, v); + set_node_probability(bn, O, 0, parents, 1-v); + parents[T] = 0; parents[L] = 1; + set_node_probability(bn, O, 1, parents, v); + set_node_probability(bn, O, 0, parents, 1-v); + parents[T] = 1; parents[L] = 0; + set_node_probability(bn, O, 1, parents, v); + set_node_probability(bn, O, 0, parents, 1-v); + parents[T] = 0; parents[L] = 0; + set_node_probability(bn, O, 1, parents, 1-v); + set_node_probability(bn, O, 0, parents, v); + + + // set probabilities for node D + parents.clear(); + parents.add(O,1); + parents.add(B,1); + set_node_probability(bn, D, 1, parents, 0.9); + set_node_probability(bn, D, 0, parents, 1-0.9); + parents[O] = 1; parents[B] = 0; + set_node_probability(bn, D, 1, parents, 0.7); + set_node_probability(bn, D, 0, parents, 1-0.7); + parents[O] = 0; parents[B] = 1; + set_node_probability(bn, D, 1, parents, 0.8); + set_node_probability(bn, D, 0, parents, 1-0.8); + parents[O] = 0; parents[B] = 0; + set_node_probability(bn, D, 1, parents, 0.1); + set_node_probability(bn, D, 0, parents, 1-0.1); + + + // set probabilities for node X + parents.clear(); + parents.add(O,1); + set_node_probability(bn, X, 1, parents, 0.98); + set_node_probability(bn, X, 0, parents, 1-0.98); + parents[O] = 0; + set_node_probability(bn, X, 1, parents, 0.05); + set_node_probability(bn, X, 0, parents, 1-0.05); + + + // test the serialization code here by pushing this network though it + ostringstream sout; + serialize(bn, sout); + bn.clear(); + DLIB_CASSERT(bn.number_of_nodes() == 0,""); + istringstream sin(sout.str()); + deserialize(bn, sin); + DLIB_CASSERT(bn.number_of_nodes() == 8,""); + } + + + void bayes_nets_test ( + ) + /*! + ensures + - runs tests on the bayesian network objects and functions for compliance with the specs + !*/ + { + + print_spinner(); + + directed_graph::kernel_1a_c bn; + setup_dyspnea_network(bn); + + using namespace bayes_node_utils; + + + graph::compare_1b_c, set::compare_1b_c>::kernel_1a_c join_tree; + + create_moral_graph(bn, join_tree); + create_join_tree(join_tree, join_tree); + + bayesian_network_join_tree solution(bn, join_tree); + + matrix dist; + + dist = solution.probability(A); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.01 ) < 1e-5,""); + + dist = solution.probability(T); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.0104) < 1e-5,""); + + dist = solution.probability(O); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.064828) < 1e-5,""); + + dist = solution.probability(X); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.11029004) < 1e-5,""); + + dist = solution.probability(L); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.055) < 1e-5,""); + + dist = solution.probability(S); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.5) < 1e-5,""); + + dist = solution.probability(B); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.4499999) < 1e-5,""); + + dist = solution.probability(D); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.4359706 ) < 1e-5,""); + + // now lets modify the probabilities of the bayesian network by making O + // not a deterministic node anymore but otherwise leave the network alone + setup_dyspnea_network(bn, false); + + set_node_value(bn, A, 1); + set_node_value(bn, X, 1); + set_node_value(bn, S, 1); + // lets also make some of these nodes evidence nodes + set_node_as_evidence(bn, A); + set_node_as_evidence(bn, X); + set_node_as_evidence(bn, S); + + // reload the solution now that we have changed the probabilities of node O + bayesian_network_join_tree(bn, join_tree).swap(solution); + DLIB_CASSERT(solution.number_of_nodes() == bn.number_of_nodes(),""); + + dist = solution.probability(A); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 1.0 ) < 1e-5,""); + + dist = solution.probability(T); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.253508694039 ) < 1e-5,""); + + dist = solution.probability(O); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.77856184024 ) < 1e-5,""); + + dist = solution.probability(X); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 1.0 ) < 1e-5,""); + + dist = solution.probability(L); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.5070173880 ) < 1e-5,""); + + dist = solution.probability(S); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 1.0 ) < 1e-5,""); + + dist = solution.probability(B); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.6 ) < 1e-5,""); + + dist = solution.probability(D); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.7535685520 ) < 1e-5,""); + + + // now lets test the bayesian_network_gibbs_sampler + set_node_value(bn, A, 1); + set_node_value(bn, T, 1); + set_node_value(bn, O, 1); + set_node_value(bn, X, 1); + set_node_value(bn, S, 1); + set_node_value(bn, L, 1); + set_node_value(bn, B, 1); + set_node_value(bn, D, 1); + + bayesian_network_gibbs_sampler sampler; + matrix counts; + set_all_elements(counts, 0); + const unsigned long rounds = 100000; + for (unsigned long i = 0; i < rounds; ++i) + { + sampler.sample_graph(bn); + + for (long c = 0; c < counts.nc(); ++c) + { + if (node_value(bn, c) == 1) + counts(c) += 1; + } + + if ((i&0x3FF) == 0) + { + print_spinner(); + } + } + + counts /= rounds; + + DLIB_CASSERT(abs(counts(A) - 1.0 ) < 1e-2,""); + DLIB_CASSERT(abs(counts(T) - 0.253508694039 ) < 1e-2,""); + DLIB_CASSERT(abs(counts(O) - 0.77856184024 ) < 1e-2,abs(counts(O) - 0.77856184024 ) ); + DLIB_CASSERT(abs(counts(X) - 1.0 ) < 1e-2,""); + DLIB_CASSERT(abs(counts(L) - 0.5070173880 ) < 1e-2,""); + DLIB_CASSERT(abs(counts(S) - 1.0 ) < 1e-2,""); + DLIB_CASSERT(abs(counts(B) - 0.6 ) < 1e-2,""); + DLIB_CASSERT(abs(counts(D) - 0.7535685520 ) < 1e-2,""); + + + setup_simple_network(bn); + create_moral_graph(bn, join_tree); + create_join_tree(join_tree, join_tree); + bayesian_network_join_tree(bn, join_tree).swap(solution); + DLIB_CASSERT(solution.number_of_nodes() == bn.number_of_nodes(),""); + + dist = solution.probability(A); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.1 ) < 1e-5,""); + + dist = solution.probability(T); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.5 ) < 1e-5,""); + + dist = solution.probability(S); + DLIB_CASSERT(abs(sum(dist) - 1.0) < 1e-5,""); + DLIB_CASSERT(abs(dist(1) - 0.5 ) < 1e-5,""); + + + } + + + + + class bayes_nets_tester : public tester + { + public: + bayes_nets_tester ( + ) : + tester ("test_bayes_nets", + "Runs tests on the bayes_nets objects and functions.") + {} + + void perform_test ( + ) + { + bayes_nets_test(); + } + } a; + +} + + + + diff --git a/dlib/test/bigint.cpp b/dlib/test/bigint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..348a39f531e6a5f44f445435dbdc3de17de0e5d0 --- /dev/null +++ b/dlib/test/bigint.cpp @@ -0,0 +1,513 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include + +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.bigint"); + + namespace bigint_kernel_test_helpers + { + template < + typename bint + > + bint short_fact (unsigned short value) + /*! + ensures + - returns the factorial of value + !*/ + { + using namespace relational_operators; + + bint a = 1; + for (unsigned short i = 2; i <= value; ++i) + a *= i; + + return a; + } + + template < + typename bint + > + bint short_fact_squared (unsigned short value) + /*! + ensures + - returns the square of the factorial of value + !*/ + { + using namespace relational_operators; + + bint a = 1; + for (unsigned short i = 2; i <= value; ++i) + { + a *= i; + a *= i; + } + + return a; + } + + + template < + typename bint + > + bint big_fact (unsigned short value) + /*! + ensures + - returns the factorial of value + !*/ + { + using namespace relational_operators; + + bint a = 1; + int k = 0; + for (bint i = 2; i <= value; ++i) + { + ++k; + if (k%10 == 0) + print_spinner(); + a *= i; + } + + return a; + } + } + + template < + typename bint + > + void bigint_kernel_test ( + ) + /*! + requires + - bint is an implementation of bigint/bigint_kernel_abstract.h + ensures + - runs tests on bint for compliance with the specs + !*/ + { + using namespace bigint_kernel_test_helpers; + using namespace relational_operators; + istringstream sin; + ostringstream sout; + + bint i = 0; + bint a(5), b, c(0); + + DLIB_CASSERT(5 - a == 0,""); + DLIB_CASSERT(a - 5 == 0,""); + + DLIB_CASSERT(0 - c == 0,""); + DLIB_CASSERT(c - 0 == 0,""); + + DLIB_CASSERT(0 + c == 0,""); + DLIB_CASSERT(c + 0 == 0,""); + + DLIB_CASSERT(0 + a == 5,""); + DLIB_CASSERT(a + 0 == 5,""); + + DLIB_CASSERT(0 - b == 0,""); + DLIB_CASSERT(b - 0 == 0,""); + + DLIB_CASSERT(0 + b == 0,""); + DLIB_CASSERT(b + 0 == 0,""); + + DLIB_CASSERT(i == 0,""); + DLIB_CASSERT(a == 5,""); + DLIB_CASSERT(b == 0,""); + DLIB_CASSERT(c == 0,""); + + + + a -= 5; + DLIB_CASSERT(a == 0,""); + + + + for (int k = 0; k < 100; ++k) + { + // compute the factorial of k using the O(n) multiplication algorithm + a = short_fact(k); + // compute the factorial of k using the full blown big int + // multiplication algorithm. + b = big_fact(k); + // compute the square of the factorial of k using the full blown + // big int multiplication algorithm. + c = a*b; + // make sure a and b ended up being the same number + DLIB_CASSERT(a == b, + "k: " << k << "\n" + "short_fact: " << a << "\n" + "big_fact: " << b + ); + // make sure c really is the square of the factorial of k + DLIB_CASSERT(short_fact_squared(k) == c,"k: " << k); + print_spinner(); + } + + // do the same thing as the last loop but do it with way bigger numbers + for (int k = 1000; k < 10000; k += 2000) + { + bint a = short_fact(k); + bint b = big_fact(k); + bint c = a*b; + DLIB_CASSERT(a == b, + "k: " << k << "\n" + "short_fact: " << a << "\n" + "big_fact: " << b + ); + DLIB_CASSERT(short_fact_squared(k) == c,"k: " << k); + print_spinner(); + } + + + + // test the << and >> operators a little + a = big_fact(20); + sout << a; + DLIB_CASSERT( sout.str() == "2432902008176640000","was: " << a); + + sin.str("684626312793279327952039475203945"); + sin >> a; + sout.str(""); + sout << a; + DLIB_CASSERT(sout.str() == "684626312793279327952039475203945",""); + + print_spinner(); + + DLIB_CASSERT(a > 0,""); + + + // make sure that when you try to read something that isn't a number + // into a bigint you get an error + DLIB_CASSERT(sin.fail() == false, ""); + sin.str("the cat ate some cheese"); + sin >> a; + DLIB_CASSERT(sin.fail() == true, ""); + sin.clear(); + sin.str(""); + + + + sin.str("3628913"); + sin >> i; + DLIB_CASSERT(short_fact(10) + short_fact(5) - 7 == i,""); + + sin.str("2432902008173011193"); + sin >> i; + DLIB_CASSERT(short_fact(20) - short_fact(10) - 7 == i,""); + + // test the serialization stuff + sout.str(""); + serialize(i,sout); + i = 0; + sin.str(sout.str()); + deserialize(i,sin); + + DLIB_CASSERT(short_fact(20) - short_fact(10) - 7 == i,""); + + + + + print_spinner(); + + + + + sin.str("100000"); + sin >> b; + a = b; + ++b; + DLIB_CASSERT ( a + 1 == b,"a==" << a << endl << "b==" << b << endl); + + + + + + // compute some stuff and see if you get the right value + a = 0; + b = 0; + sin.str("1000000"); + sin >> b; + int mel = 0; + for (i = a; i <= b; ++i) + { + // switch it up on em + if (i%2 == 0) + a = a + i; + else + a += i; + ++mel; + if ((mel&0xFFF) == 0) + print_spinner(); + } + DLIB_CASSERT(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl); + + + + + + + print_spinner(); + + + // compute some stuff and see if you get the right value + // this time going the other way using operator-- + a = 0; + b = 0; + sin.str("100000"); + sin >> b; + i = b; + DLIB_CASSERT(i == b,""); + DLIB_CASSERT(i > 0,"i==" << i); + mel = 0; + for (i = b; i > 0; --i) + { + // switch it up on em + if (i%2 == 0) + a = a + i; + else + a += i; + ++mel; + if ((mel&0xFF) == 0) + print_spinner(); + } + DLIB_CASSERT(a == b*(b+1)/2, "a==" << a << endl << "b*(b+1)/2==" << b*(b+1)/2 << endl); + + + + + + + + + + + + DLIB_CASSERT(short_fact(10)/short_fact(5) == 30240,""); + DLIB_CASSERT(short_fact(10)/(short_fact(5)+1) == 29990,""); + + sin.str("221172909834240000"); + sin >> a; + DLIB_CASSERT(short_fact(20)/(short_fact(5)+1) == a/11,""); + + sin.str("670442388044"); + sin >> b; + DLIB_CASSERT(short_fact(20)/(short_fact(10)+1) == b,""); + + print_spinner(); + + sin.str("1860479"); + sin >> i; + DLIB_CASSERT(short_fact(20)/(short_fact(15)+1) == i,short_fact(20)/(short_fact(15)+1)); + + // test the serialization stuff + sout.str(""); + serialize(i,sout); + i = 0; + sin.str(sout.str()); + deserialize(i,sin); + + DLIB_CASSERT(short_fact(20)/(short_fact(15)+1) == i,short_fact(20)/(short_fact(15)+1)); + + + print_spinner(); + + // test the serialization stuff + sout.str(""); + i = 0; + serialize(i,sout); + i = 1234; + sin.str(sout.str()); + deserialize(i,sin); + DLIB_CASSERT(i == 0,""); + + + DLIB_CASSERT(short_fact(10000)/short_fact(9999) == 10000,""); + + + DLIB_CASSERT(bint(5)%bint(1) == 0,""); + DLIB_CASSERT(bint(5)%bint(6) == 5,""); + DLIB_CASSERT(bint(25)%bint(6) == 1,""); + print_spinner(); + DLIB_CASSERT(bint(354)%bint(123) == 108,""); + DLIB_CASSERT(bint(20)%(bint(10)) == 0,""); + DLIB_CASSERT(bint(20)%(bint(10)+1) == 9,""); + + DLIB_CASSERT(bint(20)%(bint(15)+1) == 4,""); + + + DLIB_CASSERT(short_fact(10)%(short_fact(5)+2) == 32,""); + + sin.str("2908082"); + sin >> i; + DLIB_CASSERT(short_fact(15)%(short_fact(10)+2) == i,""); + + + + + + + // same as some of the above stuff but using big_fact + + DLIB_CASSERT(big_fact(10)%(big_fact(5)+2) == 32,""); + + sin.str("2908082"); + sin >> i; + DLIB_CASSERT(big_fact(15)%(big_fact(10)+2) == i,""); + + + print_spinner(); + + + DLIB_CASSERT(big_fact(10)/big_fact(5) == 30240,""); + DLIB_CASSERT(big_fact(10)/(big_fact(5)+1) == 29990,""); + + sin.str("221172909834240000"); + sin >> a; + DLIB_CASSERT(big_fact(20)/(big_fact(5)+1) == a/11,""); + + + sin.str("670442388044"); + sin >> b; + DLIB_CASSERT(big_fact(20)/(big_fact(10)+1) == b,""); + + + sin.str("1860479"); + sin >> i; + DLIB_CASSERT(big_fact(20)/(big_fact(15)+1) == i,big_fact(20)/(big_fact(15)+1)); + + DLIB_CASSERT(big_fact(100)/big_fact(99) == 100,""); + + + + + sout.str(""); + sout << "148571596448176149730952273362082573788556996128468876694221686370498539309"; + sout << "4065876545992131370884059645617234469978112000000000000000000000"; + sin.str(sout.str()); + sin >> a; + + sout.str(""); + sout << "933262154439441526816992388562667004907159682643816214685929638952175999932"; + sout << "299156089414639761565182862536979208272237582511852109168640000000000000000"; + sout << "000000"; + sin.str(sout.str()); + sin >> b; + + + sout.str(""); + sout << "138656248189732152054159609718432247180282092567575172939636909224427929240"; + sout << "834642263988043338170905744175653189424779336521852536242160190545537133916"; + sout << "649622615351174407746524657461692702500613722228638559932561661493048332720"; + sout << "6050692647868232055316807680000000000000000000000000000000000000000000"; + sin.str(sout.str()); + sin >> c; + + DLIB_CASSERT(a*b == c, + "a*b: " << a*b << + "\nc: " << c); + + + print_spinner(); + + i = 0; + mel = 0; + unsigned long j; + for (j = 0; i < bint(100000); ++j) + { + DLIB_CASSERT(i++ == bint(j),""); + ++mel; + if((mel&0xFF) == 0) + print_spinner(); + } + DLIB_CASSERT(j == 100000,""); + + i = 1234; + + DLIB_CASSERT(i == 1234,""); + DLIB_CASSERT(i < 2345 ,""); + DLIB_CASSERT(i > 0 ,""); + DLIB_CASSERT(i > 123 ,""); + + DLIB_CASSERT(i != 1334,""); + DLIB_CASSERT(i <= 2345,""); + DLIB_CASSERT(i >= 0 ,""); + DLIB_CASSERT(i >= 123 ,""); + DLIB_CASSERT(i >= 1234,""); + DLIB_CASSERT(i <= 1234,""); + + + DLIB_CASSERT(1234 == i,""); + DLIB_CASSERT(2345 > i,""); + DLIB_CASSERT(0 < i,""); + DLIB_CASSERT(123 < i,""); + + DLIB_CASSERT(1334 != i,""); + DLIB_CASSERT(2345 >= i,""); + DLIB_CASSERT(0 <= i,""); + DLIB_CASSERT(123 <= i,""); + DLIB_CASSERT(1234 <= i,""); + DLIB_CASSERT(1234 >= i,""); + + + a = big_fact(200); + b = big_fact(100); + + DLIB_CASSERT(a > b, ""); + DLIB_CASSERT(a != b, ""); + DLIB_CASSERT(b < a, ""); + DLIB_CASSERT(b != a, ""); + DLIB_CASSERT(b <= a, ""); + DLIB_CASSERT(a >= b, ""); + + + + } + + + + + class bigint_tester : public tester + { + public: + bigint_tester ( + ) : + tester ("test_bigint", + "Runs tests on the bigint component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + bigint_kernel_test(); + print_spinner(); + + dlog << LINFO << "testing kernel_1a_c"; + bigint_kernel_test(); + print_spinner(); + + dlog << LINFO << "testing kernel_2a"; + bigint_kernel_test(); + print_spinner(); + + dlog << LINFO << "testing kernel_2a_c"; + bigint_kernel_test(); + print_spinner(); + + } + } a; + +} + diff --git a/dlib/test/binary_search_tree.h b/dlib/test/binary_search_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..0c8a7f4257a79bfff8689cd89369df055ed549bf --- /dev/null +++ b/dlib/test/binary_search_tree.h @@ -0,0 +1,889 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_ + + +#include +#include +#include +#include + +#include +#include +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.binary_search_tree"); + + template < + typename bst + > + void binary_search_tree_kernel_test ( + ) + /*! + requires + - bst is an implementation of + binary_search_tree/binary_search_tree_kernel_abstract.h is instantiated + to map int to int + ensures + - runs tests on bst for compliance with the specs + !*/ + { + + bst test, test2; + + srand(static_cast(time(0))); + + + DLIB_CASSERT(test.count(3) == 0,""); + + enumerable >& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + DLIB_CASSERT(test.count(3) == 0,""); + + for (int i = 0; i < 4; ++i) + { + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.count(3) == 0,""); + DLIB_CASSERT(test.height() == 0,""); + DLIB_CASSERT(test[5] == 0,""); + DLIB_CASSERT(test[0] == 0,""); + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.count(3) == 0,""); + + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.count(3) == 0,""); + + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + test.clear(); + test.position_enumerator(5); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false, ""); + test.position_enumerator(5); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false, ""); + test.position_enumerator(9); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false, ""); + test.clear(); + test.position_enumerator(5); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false, ""); + test.position_enumerator(5); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false, ""); + test.position_enumerator(9); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false, ""); + test.clear(); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.count(3) == 0,""); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.height() == 0,""); + DLIB_CASSERT(test[5] == 0,""); + DLIB_CASSERT(test[0] == 0,""); + DLIB_CASSERT(const_cast(test)[5] == 0,""); + DLIB_CASSERT(const_cast(test)[0] == 0,""); + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.count(3) == 0,""); + test.reset(); + DLIB_CASSERT(test.count(3) == 0,""); + + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + + + + + int a = 0, b = 0; + + for (int i = 0; i < 10000; ++i) + { + a = ::rand()%1000; + int temp = a; + unsigned long count = test.count(a); + test.add(a,b); + DLIB_CASSERT(test.count(temp) == count+1,""); + } + + + { + unsigned long count = test.count(3); + + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + } + + + test.clear(); + + + + + + for (int i = 0; i < 10000; ++i) + { + a = ::rand()&0x7FFF; + b = 0; + int temp = a; + unsigned long count = test.count(a); + test.add(a,b); + DLIB_CASSERT(test.count(temp) == count+1,""); + } + + // serialize the state of test, then clear test, then + // load the state back into test. + ostringstream sout; + serialize(test,sout); + istringstream sin(sout.str()); + test.clear(); + deserialize(test,sin); + + DLIB_CASSERT(test.size() == 10000,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.height() > 13 && test.height() <= 26,"this is somewhat of an implementation dependent " + << "but really it should be in this range or the implementation is just crap"); + + a = 0; + unsigned long count = 0; + while (test.move_next()) + { + DLIB_CASSERT(a <= test.element().key(),"the numers are out of order but they should be in order"); + a = test.element().key(); + ++count; + + + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + DLIB_CASSERT(count == 10000,""); + + + + + DLIB_CASSERT(test.height() > 13 && test.height() <= 26,"this is somewhat of an implementation dependent " + << "but really it should be in this range or the implementation is just crap"); + + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.size() == 10000,""); + + + swap(test,test2); + + + test2.reset(); + count = 0; + a = 0; + while (test2.move_next()) + { + DLIB_CASSERT(a <= test2.element().key(),"the numers are out of order but they should be in order"); + a = test2.element().key(); + ++count; + + + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + + if (count == 5000) + { + break; + } + } + + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.move_next() == true,""); + + + test2.reset(); + + count = 0; + a = 0; + while (test2.move_next()) + { + DLIB_CASSERT(a <= test2.element().key(),"the numers are out of order but they should be in order"); + a = test2.element().key(); + ++count; + + + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + } + + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + + + + + + + + int last = 0; + asc_pair_remover& asdf = test2; + DLIB_CASSERT(asdf.size() > 0,""); + while (asdf.size() > 0) + { + asdf.remove_any(a,b); + DLIB_CASSERT(last <= a,""); + last = a; + --count; + DLIB_CASSERT(asdf.size() == count,""); + } + + + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.height() ==0,""); + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + + + + for (int i = 0; i < 10000; ++i) + { + a = i; + b = i; + test2.add(a,b); + DLIB_CASSERT(test2.size() == (unsigned int)(i +1),""); + DLIB_CASSERT(test2.count(i) == 1,""); + } + + a = 0; + test2.position_enumerator(a); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.element().key() == a, ""); + DLIB_CASSERT(test2.element().value() == a, ""); + a = 0; + test2.position_enumerator(a); + DLIB_CASSERT(test2.element().key() == a, ""); + DLIB_CASSERT(test2.element().value() == a, ""); + a = 8; + test2.position_enumerator(a); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.element().key() == a, ""); + DLIB_CASSERT(test2.element().value() == a, ""); + a = 1; + test2.position_enumerator(a); + DLIB_CASSERT(test2.element().key() == a, ""); + DLIB_CASSERT(test2.element().value() == a, ""); + a = -29; + test2.position_enumerator(a); + DLIB_CASSERT(test2.element().key() == 0, ""); + DLIB_CASSERT(test2.element().value() == 0, ""); + a = 10000; + test2.position_enumerator(a); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + a = -29; + test2.position_enumerator(a); + DLIB_CASSERT(test2.element().key() == 0, ""); + DLIB_CASSERT(test2.element().value() == 0, ""); + a = 8; + test2.position_enumerator(a); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.element().key() == a, ""); + DLIB_CASSERT(test2.element().value() == a, ""); + test2.reset(); + + + DLIB_CASSERT(test2.height() > 13 && test2.height() <= 26,"this is somewhat of an implementation dependent " + << "but really it should be in this range or the implementation is just crap"); + + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.size() == 10000,""); + + + for (int i = 0; i < 10000; ++i) + { + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.element().key() == i,""); + } + + + + DLIB_CASSERT(test2.height() > 13 && test2.height() <= 26,"this is somewhat of an implementation dependent " + << "but really it should be in this range or the implementation is just crap"); + + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.size() == 10000,""); + + + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + a = 3; + test2.add(a,b); + DLIB_CASSERT(test2.count(3) == 2,""); + + + for (int i = 0; i < 10000; ++i) + { + test2.remove(i,a,b); + DLIB_CASSERT(i == a,""); + } + test2.remove(3,a,b); + + + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.height() == 0,""); + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + + + test2.clear(); + + + int m = 0; + for (int i = 0; i < 10000; ++i) + { + a = ::rand()&0x7FFF; + m = max(a,m); + test2.add(a,b); + } + + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.move_next() == true,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.at_start() == false,""); + + for (int i = 0; i < 10000; ++i) + { + a = ::rand()&0xFFFF; + test2.position_enumerator(a); + if (test2[a]) + { + DLIB_CASSERT(test2.element().key() == a,""); + } + else if (a <= m) + { + DLIB_CASSERT(test2.element().key() > a,""); + } + } + + test2.clear(); + + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + + + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.height() == 0,""); + + + for (int i = 0; i < 20000; ++i) + { + a = ::rand()&0x7FFF; + b = a; + test2.add(a,b); + } + + + DLIB_CASSERT(test2.size() == 20000,""); + + + + // remove a bunch of elements randomly + int c; + for (int i = 0; i < 50000; ++i) + { + a = ::rand()&0x7FFF; + if (test2[a] != 0) + { + test2.remove(a,b,c); + DLIB_CASSERT(a == b,""); + } + } + + + // now add a bunch more + for (int i = 0; i < 10000; ++i) + { + a = ::rand()&0x7FFF; + b = a; + test2.add(a,b); + } + + + // now iterate over it all and then remove all elements + { + int* array = new int[test2.size()]; + int* tmp = array; + DLIB_CASSERT(test2.at_start() == true,""); + while (test2.move_next()) + { + *tmp = test2.element().key(); + ++tmp; + } + + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + tmp = array; + for (int i = 0; i < 10000; ++i) + { + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*const_cast(test2)[*tmp] == *tmp,""); + ++tmp; + } + + tmp = array; + while (test2.size() > 0) + { + unsigned long count = test2.count(*tmp); + test2.destroy(*tmp); + DLIB_CASSERT(test2.count(*tmp)+1 == count,""); + ++tmp; + } + + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + test.swap(test2); + test.reset(); + + delete [] array; + } + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.height() == 0,""); + + for (unsigned long i = 1; i < 100; ++i) + { + a = 1234; + test.add(a,b); + DLIB_CASSERT(test.count(1234) == i,""); + } + + test.clear(); + + + + + + + for (int m = 0; m < 3; ++m) + { + + test2.clear(); + + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + + + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.height() == 0,""); + + + int counter = 0; + while (counter < 10000) + { + a = ::rand()&0x7FFF; + b = ::rand()&0x7FFF; + if (test2[a] == 0) + { + test2.add(a,b); + ++counter; + } + + } + + + + DLIB_CASSERT(test2.size() == 10000,""); + + + + // remove a bunch of elements randomly + for (int i = 0; i < 20000; ++i) + { + a = ::rand()&0x7FFF; + if (test2[a] != 0) + { + test2.remove(a,b,c); + DLIB_CASSERT(a == b,""); + } + } + + + // now add a bunch more + for (int i = 0; i < 20000; ++i) + { + a = ::rand()&0x7FFF; + b = ::rand()&0x7FFF; + if (test2[a] == 0) + test2.add(a,b); + } + + + // now iterate over it all and then remove all elements + { + int* array = new int[test2.size()]; + int* array_val = new int[test2.size()]; + int* tmp = array; + int* tmp_val = array_val; + DLIB_CASSERT(test2.at_start() == true,""); + int count = 0; + while (test2.move_next()) + { + *tmp = test2.element().key(); + ++tmp; + *tmp_val = test2.element().value(); + ++tmp_val; + + DLIB_CASSERT(*test2[*(tmp-1)] == *(tmp_val-1),""); + ++count; + } + + DLIB_CASSERT(count == (int)test2.size(),""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + tmp = array; + tmp_val = array_val; + for (unsigned long i = 0; i < test2.size(); ++i) + { + DLIB_CASSERT(*test2[*tmp] == *tmp_val,i); + DLIB_CASSERT(*test2[*tmp] == *tmp_val,""); + DLIB_CASSERT(*test2[*tmp] == *tmp_val,""); + DLIB_CASSERT(*const_cast(test2)[*tmp] == *tmp_val,""); + ++tmp; + ++tmp_val; + } + + // out << "\nsize: " << test2.size() << endl; + // out << "height: " << test2.height() << endl; + + tmp = array; + while (test2.size() > 0) + { + unsigned long count = test2.count(*tmp); + test2.destroy(*tmp); + DLIB_CASSERT(test2.count(*tmp)+1 == count,""); + ++tmp; + } + + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + test.swap(test2); + test.reset(); + + delete [] array; + delete [] array_val; + } + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.height() == 0,""); + + for (unsigned long i = 1; i < 100; ++i) + { + a = 1234; + test.add(a,b); + DLIB_CASSERT(test.count(1234) == i,""); + } + + test.clear(); + + } + + + + a = 1; + b = 2; + + test.add(a,b); + + test.position_enumerator(0); + a = 0; + b = 0; + DLIB_CASSERT(test.height() == 1,""); + test.remove_current_element(a,b); + DLIB_CASSERT(a == 1, ""); + DLIB_CASSERT(b == 2, ""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.height() == 0,""); + DLIB_CASSERT(test.size() == 0,""); + + + a = 1; + b = 2; + test.add(a,b); + a = 1; + b = 2; + test.add(a,b); + + test.position_enumerator(0); + a = 0; + b = 0; + DLIB_CASSERT(test.height() == 2,""); + test.remove_current_element(a,b); + DLIB_CASSERT(a == 1, ""); + DLIB_CASSERT(b == 2, ""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + DLIB_CASSERT(test.height() == 1,""); + DLIB_CASSERT(test.size() == 1,""); + + test.remove_current_element(a,b); + DLIB_CASSERT(a == 1, ""); + DLIB_CASSERT(b == 2, ""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.height() == 0,""); + DLIB_CASSERT(test.size() == 0,""); + + for (int i = 0; i < 100; ++i) + { + a = i; + b = i; + test.add(a,b); + } + + DLIB_CASSERT(test.size() == 100,""); + test.remove_last_in_order(a,b); + DLIB_CASSERT(a == 99, ""); + DLIB_CASSERT(b == 99, ""); + DLIB_CASSERT(test.size() == 99,""); + test.remove_last_in_order(a,b); + DLIB_CASSERT(a == 98, ""); + DLIB_CASSERT(b == 98, ""); + DLIB_CASSERT(test.size() == 98,""); + + test.position_enumerator(-10); + for (int i = 0; i < 97; ++i) + { + DLIB_CASSERT(test.element().key() == i, ""); + DLIB_CASSERT(test.element().value() == i, ""); + DLIB_CASSERT(test.move_next(), ""); + } + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + test.position_enumerator(10); + for (int i = 10; i < 97; ++i) + { + DLIB_CASSERT(test.element().key() == i, ""); + DLIB_CASSERT(test.element().value() == i, ""); + DLIB_CASSERT(test.move_next(), ""); + } + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + test.reset(); + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + for (int i = 0; i < 98; ++i) + { + DLIB_CASSERT(test.move_next(), ""); + DLIB_CASSERT(test.element().key() == i, ""); + DLIB_CASSERT(test.element().value() == i, ""); + } + DLIB_CASSERT(test.size() == 98, test.size()); + DLIB_CASSERT(test.move_next() == false,""); + + test.position_enumerator(98); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + + test.position_enumerator(50); + DLIB_CASSERT(test.element().key() == 50,""); + DLIB_CASSERT(test.element().value() == 50,""); + DLIB_CASSERT(test[50] != 0,""); + test.remove_current_element(a,b); + DLIB_CASSERT(test[50] == 0,""); + DLIB_CASSERT(test.size() == 97, test.size()); + DLIB_CASSERT(a == 50,""); + DLIB_CASSERT(b == 50,""); + DLIB_CASSERT(test.element().key() == 51,""); + DLIB_CASSERT(test.element().value() == 51,""); + DLIB_CASSERT(test.current_element_valid(),""); + test.remove_current_element(a,b); + DLIB_CASSERT(test.size() == 96, test.size()); + DLIB_CASSERT(a == 51,""); + DLIB_CASSERT(b == 51,""); + DLIB_CASSERT(test.element().key() == 52,test.element().key()); + DLIB_CASSERT(test.element().value() == 52,test.element().value()); + DLIB_CASSERT(test.current_element_valid(),""); + test.remove_current_element(a,b); + DLIB_CASSERT(test.size() == 95, test.size()); + DLIB_CASSERT(a == 52,""); + DLIB_CASSERT(b == 52,""); + DLIB_CASSERT(test.element().key() == 53,test.element().key()); + DLIB_CASSERT(test.element().value() == 53,test.element().value()); + DLIB_CASSERT(test.current_element_valid(),""); + test.position_enumerator(50); + DLIB_CASSERT(test.element().key() == 53,test.element().key()); + DLIB_CASSERT(test.element().value() == 53,test.element().value()); + DLIB_CASSERT(test.current_element_valid(),""); + test.position_enumerator(51); + DLIB_CASSERT(test.element().key() == 53,test.element().key()); + DLIB_CASSERT(test.element().value() == 53,test.element().value()); + DLIB_CASSERT(test.current_element_valid(),""); + test.position_enumerator(52); + DLIB_CASSERT(test.element().key() == 53,test.element().key()); + DLIB_CASSERT(test.element().value() == 53,test.element().value()); + DLIB_CASSERT(test.current_element_valid(),""); + test.position_enumerator(53); + DLIB_CASSERT(test.element().key() == 53,test.element().key()); + DLIB_CASSERT(test.element().value() == 53,test.element().value()); + DLIB_CASSERT(test.current_element_valid(),""); + + test.reset(); + test.move_next(); + int lasta = -1, lastb = -1; + count = 0; + while (test.current_element_valid() ) + { + ++count; + int c = test.element().key(); + int d = test.element().value(); + test.remove_current_element(a,b); + DLIB_CASSERT(c == a,""); + DLIB_CASSERT(d == a,""); + DLIB_CASSERT(lasta < a,""); + DLIB_CASSERT(lastb < b,""); + lasta = a; + lastb = b; + } + DLIB_CASSERT(count == 95, count); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.height() == 0,""); + + test.clear(); + + for (int i = 0; i < 1000; ++i) + { + a = 1; + b = 1; + test.add(a,b); + } + + for (int i = 0; i < 40; ++i) + { + int num = ::rand()%800 + 1; + test.reset(); + for (int j = 0; j < num; ++j) + { + DLIB_CASSERT(test.move_next(),""); + } + DLIB_CASSERT(test.current_element_valid(),"size: " << test.size() << " num: " << num); + test.remove_current_element(a,b); + DLIB_CASSERT(test.current_element_valid(),"size: " << test.size() << " num: " << num); + test.remove_current_element(a,b); + test.position_enumerator(1); + if (test.current_element_valid()) + test.remove_current_element(a,b); + DLIB_CASSERT(a == 1,""); + DLIB_CASSERT(b == 1,""); + } + + test.clear(); + + } + + + test.clear(); + test2.clear(); + + } + +} + +#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_H_ + diff --git a/dlib/test/binary_search_tree_kernel_1a.cpp b/dlib/test/binary_search_tree_kernel_1a.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd6ff621f822afa5d4c0177cc7e8f63cbc056f37 --- /dev/null +++ b/dlib/test/binary_search_tree_kernel_1a.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ + + +#include +#include +#include +#include + +#include +#include +#include +#include "tester.h" +#include "binary_search_tree.h" + +namespace +{ + + + class binary_search_tree_tester : public tester + { + + public: + binary_search_tree_tester ( + ) : + tester ("test_binary_search_tree_kernel_1a", + "Runs tests on the binary_search_tree_kernel_1a component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + binary_search_tree_kernel_test::kernel_1a>(); + print_spinner(); + + dlog << LINFO << "testing kernel_1a_c"; + binary_search_tree_kernel_test::kernel_1a_c>(); + print_spinner(); + } + } a; + +} + +#endif diff --git a/dlib/test/binary_search_tree_kernel_2a.cpp b/dlib/test/binary_search_tree_kernel_2a.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fecb0e37efe7b1aca11c0e53d7230bbb7993ad6b --- /dev/null +++ b/dlib/test/binary_search_tree_kernel_2a.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ + + +#include +#include +#include +#include + +#include +#include +#include +#include "tester.h" +#include "binary_search_tree.h" + +namespace +{ + + class binary_search_tree_tester : public tester + { + public: + binary_search_tree_tester ( + ) : + tester ("test_binary_search_tree_kernel_2a", + "Runs tests on the binary_search_tree_kernel_2a component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_2a"; + binary_search_tree_kernel_test::kernel_2a>(); + print_spinner(); + + dlog << LINFO << "testing kernel_2a_c"; + binary_search_tree_kernel_test::kernel_2a_c>(); + print_spinner(); + } + } a; + +} + +#endif diff --git a/dlib/test/binary_search_tree_mm1.cpp b/dlib/test/binary_search_tree_mm1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b106a1a66f94fea0c9fcdc8784e8f97b959efe5 --- /dev/null +++ b/dlib/test/binary_search_tree_mm1.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ + + +#include +#include +#include +#include + +#include +#include +#include +#include "tester.h" +#include "binary_search_tree.h" + +namespace +{ + + class binary_search_tree_tester : public tester + { + struct factory + { + template + struct return_type { + typedef typename memory_manager::kernel_1c type; + }; + + template + static typename return_type::type* get_instance ( + ) + { + static typename return_type::type instance; + return &instance; + } + + }; + + + public: + binary_search_tree_tester ( + ) : + tester ("test_binary_search_tree_mm1", + "Runs tests on the binary_search_tree component with memory managers.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a /w memory_manager_global"; + binary_search_tree_kernel_test::kernel_1a>::kernel_1a>(); + print_spinner(); + + + dlog << LINFO << "testing kernel_1a /w memory_manager_stateless"; + binary_search_tree_kernel_test::kernel_1a>::kernel_1a>(); + print_spinner(); + } + } a; + +} + +#endif diff --git a/dlib/test/binary_search_tree_mm2.cpp b/dlib/test/binary_search_tree_mm2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4712a3eba557eea559d3f504b46c33f558b403af --- /dev/null +++ b/dlib/test/binary_search_tree_mm2.cpp @@ -0,0 +1,48 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ +#define DLIB_BINARY_SEARCH_TREE_KERNEl_TEST_ + + +#include +#include +#include +#include + +#include +#include +#include +#include "tester.h" +#include "binary_search_tree.h" + +namespace +{ + + class binary_search_tree_tester : public tester + { + + public: + binary_search_tree_tester ( + ) : + tester ("test_binary_search_tree_mm2", + "Runs tests on the binary_search_tree component with memory managers.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a /w memory_manager_stateless_2"; + binary_search_tree_kernel_test::kernel_2_2c>::kernel_1a>(); + print_spinner(); + + dlog << LINFO << "testing kernel_1a /w memory_manager_3"; + binary_search_tree_kernel_test::kernel_3b>::kernel_1a>(); + print_spinner(); + } + } a; + +} + +#endif diff --git a/dlib/test/cmd_line_parser.cpp b/dlib/test/cmd_line_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d2fbbc977988095b011536c11ba1df8cf03fd41 --- /dev/null +++ b/dlib/test/cmd_line_parser.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include + +#include + +#include "tester.h" + +#include "cmd_line_parser.h" +namespace +{ + + class cmd_line_parser_tester : public tester + { + public: + cmd_line_parser_tester ( + ) : + tester ("test_cmd_line_parser_char", + "Runs tests on the cmd_line_parser component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a with char"; + cmd_line_parser_kernel_test::kernel_1a>(); + print_spinner(); + + dlog << LINFO << "testing kernel_1a_c with char"; + cmd_line_parser_kernel_test::kernel_1a_c>(); + print_spinner(); + } + } a; + +} + + diff --git a/dlib/test/cmd_line_parser.h b/dlib/test/cmd_line_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..80f3063c7a16427f9629965e5687d9c8ff84fc85 --- /dev/null +++ b/dlib/test/cmd_line_parser.h @@ -0,0 +1,900 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CMD_LINE_PARSER_KERNEl_TEST_H_ +#define DLIB_CMD_LINE_PARSER_KERNEl_TEST_H_ + + +#include +#include + +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.cmd_line_parser"); + + template < + typename clp + > + void cmd_line_parser_kernel_test ( + ) + /*! + requires + - clp is an implementation of cmd_line_parser_kernel_abstract.h + ensures + - runs tests on clp for compliance with the specs + !*/ + { + typedef typename clp::char_type ct; + typedef typename clp::string_type string_type; + + + + + int argc; + const ct* argv[100]; + bool ok; + + for (int j = 0; j < 3; ++j) + { + clp test, test2; + + + + + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + + DLIB_CASSERT(test.parsed_line() == false,""); + DLIB_CASSERT(test.option_is_defined(_dT(ct,"a")) == false,""); + DLIB_CASSERT(test.option_is_defined(_dT(ct,"a")) == false,""); + DLIB_CASSERT(test.option_is_defined(_dT(ct,"a")) == false,""); + + DLIB_CASSERT(test.parsed_line() == false,""); + DLIB_CASSERT(test.option_is_defined(_dT(ct,"a")) == false,""); + DLIB_CASSERT(test.option_is_defined(_dT(ct,"b")) == false,""); + DLIB_CASSERT(test.option_is_defined(_dT(ct,"\0")) == false,""); + + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + + // program arg1 --davis arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"arg2"); + argv[4] = _dT(ct,"-cZzarg"); + argv[5] = _dT(ct,"asdf"); + argc = 6; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option")); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + try { test.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.number_of_arguments() == 2,""); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==1,test.option(_dT(ct,"c")).count()); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"),""); + + } + + + + swap(test,test2); + + + + + + // program arg1 --davis arg2 -cZ zarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"arg2"); + argv[4] = _dT(ct,"-cZ"); + argv[5] = _dT(ct,"zarg"); + argv[6] = _dT(ct,"asdf"); + argc = 7; + + + + + for (int k = 0; k < 5; ++k) + { + + try { test2.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test2.option(_dT(ct,"davis")).name() == _dT(ct,"davis"),""); + DLIB_CASSERT(test2.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test2.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test2.option(_dT(ct,"davis")).number_of_arguments() == 0,""); + DLIB_CASSERT(test2.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test2.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test2.number_of_arguments() == 2,""); + DLIB_CASSERT(test2[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test2[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test2.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test2.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test2.option(_dT(ct,"c")).count()==1,""); + DLIB_CASSERT(test2.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test2.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"),""); + DLIB_CASSERT(test2.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"), + narrow(_dT(ct,"*") + test2.option(_dT(ct,"Z")).argument(0,0) + _dT(ct,"*"))); + + + } + + + + + + // program arg1 --davis= darg darg2 arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis="); + argv[3] = _dT(ct,"darg"); + argv[4] = _dT(ct,"darg2"); + argv[5] = _dT(ct,"arg2"); + argv[6] = _dT(ct,"-cZzarg"); + argv[7] = _dT(ct,"asdf"); + argc = 8; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 2); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + try { test.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test.parsed_line(),""); + + int count = 0; + while (test.move_next()) + { + ++count; + if (test.element().name() == _dT(ct,"d")) + { + DLIB_CASSERT(test.element().count() == 0,""); + } + else + { + DLIB_CASSERT(test.element().count() == 1,""); + } + + } + DLIB_CASSERT(count == 4,count); + + DLIB_CASSERT(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.number_of_arguments() == 2,""); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument(1,0) == _dT(ct,"darg2"), + narrow(test.option(_dT(ct,"davis")).argument(1,0))); + } + + + + + + + + + + + test.clear(); + + + + + + + + // program arg1 --dav-is=darg darg2 arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--dav-is=darg"); + argv[3] = _dT(ct,"darg2"); + argv[4] = _dT(ct,"arg2"); + argv[5] = _dT(ct,"-cZzarg"); + argv[6] = _dT(ct,"asdf"); + argc = 7; + + + test.add_option(_dT(ct,"dav-is"),_dT(ct,"davis option"), 2); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + try { test.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test.parsed_line(),""); + + int count = 0; + while (test.move_next()) + { + ++count; + if (test.element().name() == _dT(ct,"d")) + { + DLIB_CASSERT(test.element().count() == 0,""); + } + else + { + DLIB_CASSERT(test.element().count() == 1,""); + } + + } + DLIB_CASSERT(count == 4,count); + + DLIB_CASSERT(test.option(_dT(ct,"dav-is")).name() == _dT(ct,"dav-is"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test.option(_dT(ct,"dav-is")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.number_of_arguments() == 2,""); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"dav-is")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"),""); + DLIB_CASSERT(test.option(_dT(ct,"dav-is")).argument(0,0) == _dT(ct,"darg"),""); + DLIB_CASSERT(test.option(_dT(ct,"dav-is")).argument(1,0) == _dT(ct,"darg2"), + narrow(test.option(_dT(ct,"dav-is")).argument(1,0))); + } + + + + + + + + + + test.clear(); + + + + + + + + // program arg1 --davis=darg darg2 arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis=darg"); + argv[3] = _dT(ct,"darg2"); + argv[4] = _dT(ct,"arg2"); + argv[5] = _dT(ct,"-cZzarg"); + argv[6] = _dT(ct,"asdf"); + argc = 7; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 2); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + try { test.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test.parsed_line(),""); + + int count = 0; + while (test.move_next()) + { + ++count; + if (test.element().name() == _dT(ct,"d")) + { + DLIB_CASSERT(test.element().count() == 0,""); + } + else + { + DLIB_CASSERT(test.element().count() == 1,""); + } + + } + DLIB_CASSERT(count == 4,count); + + DLIB_CASSERT(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.number_of_arguments() == 2,""); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument(1,0) == _dT(ct,"darg2"), + narrow(test.option(_dT(ct,"davis")).argument(1,0))); + } + + + + + + + + + + test.clear(); + + + + + + + + // program arg1 --davis=darg arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis=darg"); + argv[3] = _dT(ct,"arg2"); + argv[4] = _dT(ct,"-cZzarg"); + argv[5] = _dT(ct,"asdf"); + argc = 6; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + try { test.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test.parsed_line(),""); + + int count = 0; + while (test.move_next()) + { + ++count; + if (test.element().name() == _dT(ct,"d")) + { + DLIB_CASSERT(test.element().count() == 0,""); + } + else + { + DLIB_CASSERT(test.element().count() == 1,""); + } + + } + DLIB_CASSERT(count == 4,count); + + DLIB_CASSERT(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).number_of_arguments() == 1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.number_of_arguments() == 2,""); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(1,0) == _dT(ct,"asdf"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"),""); + } + + + + + + + + + + test.clear(); + + + + + + + // program arg1 --davis darg arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"darg"); + argv[4] = _dT(ct,"arg2"); + argv[5] = _dT(ct,"-cZzarg"); + argv[6] = _dT(ct,"asdf"); + argc = 7; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + try { test.parse(argc,argv); } + catch (error& e) + { + DLIB_CASSERT(false,e.info); + } + + DLIB_CASSERT(test.parsed_line(),""); + + int count = 0; + while (test.move_next()) + { + ++count; + if (test.element().name() == _dT(ct,"d")) + { + DLIB_CASSERT(test.element().count() == 0,""); + } + else + { + DLIB_CASSERT(test.element().count() == 1,""); + } + + } + DLIB_CASSERT(count == 4,count); + + DLIB_CASSERT(test.option(_dT(ct,"davis")).name() == _dT(ct,"davis"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).name() == _dT(ct,"c"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).name() == _dT(ct,"Z"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).number_of_arguments() == 1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).number_of_arguments() == 0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).number_of_arguments() == 2,""); + DLIB_CASSERT(test.number_of_arguments() == 2,""); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"zarg"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(1) == _dT(ct,"asdf"),""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument(0,0) == _dT(ct,"darg"),""); + } + + + + + + + + + + test.clear(); + + // this string is incorrect because there is no avis option + // program arg1 --avis darg arg2 -cZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--avis"); + argv[3] = _dT(ct,"darg"); + argv[4] = _dT(ct,"arg2"); + argv[5] = _dT(ct,"-cZzarg"); + argv[6] = _dT(ct,"asdf"); + argc = 7; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + ok = false; + try { test.parse(argc,argv); } + catch (typename clp::cmd_line_parse_error& e) + { + DLIB_CASSERT(e.type == EINVALID_OPTION,""); + DLIB_CASSERT(e.item == _dT(ct,"avis"),""); + ok = true; + } + DLIB_CASSERT(ok,""); + + + } + + + + + + + + + + + + test.clear(); + + // the c argument appears twice. make sure its count is correct + // program arg1 --davis darg arg2 -ccZzarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"darg"); + argv[4] = _dT(ct,"arg2"); + argv[5] = _dT(ct,"-ccZ"); + argv[6] = _dT(ct,"zarg"); + argv[7] = _dT(ct,"asdf"); + argc = 8; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + for (int k = 0; k < 5; ++k) + { + + ok = false; + test.parse(argc,argv); + + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==2,""); + + } + + + + + + + + + + + + + + + + test.clear(); + + // this is a bad line because the davis argument requires 2 arguments but + // only gets one. + // program arg1 --davis darg darg2 --davis zarg + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"darg"); + argv[4] = _dT(ct,"darg2"); + argv[5] = _dT(ct,"--davis"); + argv[6] = _dT(ct,"zarg"); + argc = 7; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 2); + test.add_option(_dT(ct,"b"),_dT(ct,"b option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + DLIB_CASSERT(test.option(_dT(ct,"davis")).description() == _dT(ct,"davis option"),""); + DLIB_CASSERT(test.option(_dT(ct,"b")).description() == _dT(ct,"b option"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"),""); + + for (int k = 0; k < 5; ++k) + { + + ok = false; + try { test.parse(argc,argv); } + catch (typename clp::cmd_line_parse_error& e) + { + DLIB_CASSERT(e.type == ETOO_FEW_ARGS,""); + DLIB_CASSERT(e.num == 2,""); + DLIB_CASSERT(e.item == _dT(ct,"davis"),""); + ok = true; + } + DLIB_CASSERT(ok,""); + + + + int count = 0; + while (test.move_next()) + { + ++count; + DLIB_CASSERT(test.element().count() == 0,""); + DLIB_CASSERT(test.option_is_defined(test.element().name()),""); + } + DLIB_CASSERT(count == 4,count); + + + } + + + + + + + + + + + + + + + + + + + test.clear(); + + // this is a bad line because the davis argument is not defined + // program arg1 --davis darg arg2 -davis zarg asdf + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"darg"); + argv[4] = _dT(ct,"arg2"); + argv[5] = _dT(ct,"--davis"); + argv[6] = _dT(ct,"zarg"); + argv[7] = _dT(ct,"asdf"); + argc = 8; + + + test.add_option(_dT(ct,"mavis"),_dT(ct,"mavis option"), 1); + test.add_option(_dT(ct,"b"),_dT(ct,"b option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + DLIB_CASSERT(test.option(_dT(ct,"mavis")).description() == _dT(ct,"mavis option"),""); + DLIB_CASSERT(test.option(_dT(ct,"b")).description() == _dT(ct,"b option"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"),""); + + for (int k = 0; k < 5; ++k) + { + + ok = false; + try { test.parse(argc,argv); } + catch (typename clp::cmd_line_parse_error& e) + { + DLIB_CASSERT(e.type == EINVALID_OPTION,""); + DLIB_CASSERT(e.item == _dT(ct,"davis"),""); + ok = true; + } + DLIB_CASSERT(ok,""); + + + + int count = 0; + while (test.move_next()) + { + ++count; + DLIB_CASSERT(test.element().count() == 0,""); + DLIB_CASSERT(test.option_is_defined(test.element().name()),""); + } + DLIB_CASSERT(count == 4,count); + + + } + + + + + + + + + + + + + + + + test.clear(); + + + argv[0] = _dT(ct,"program"); + argc = 1; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),2); + + + DLIB_CASSERT(test.option(_dT(ct,"davis")).description() == _dT(ct,"davis option"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).description() == _dT(ct,"c option"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"),""); + + for (int k = 0; k < 5; ++k) + { + + test.parse(argc,argv); + + + DLIB_CASSERT(test.number_of_arguments() == 0,""); + + int count = 0; + while (test.move_next()) + { + ++count; + DLIB_CASSERT(test.element().count() == 0,""); + DLIB_CASSERT(test.option_is_defined(test.element().name()),""); + } + DLIB_CASSERT(count == 4,count); + + + } + + + + + + + + + + + + + test.clear(); + + // this is to make sure the -- command works right + // program arg1 --davis -darg -- arg2 -c asdf -Zeat -Zat -Zjoe's + argv[0] = _dT(ct,"program"); + argv[1] = _dT(ct,"arg1"); + argv[2] = _dT(ct,"--davis"); + argv[3] = _dT(ct,"-darg"); + argv[4] = _dT(ct,"-Zeat"); + argv[5] = _dT(ct,"-Zat"); + argv[6] = _dT(ct,"-Zjoe's"); + argv[7] = _dT(ct,"--"); + argv[8] = _dT(ct,"arg2"); + argv[9] = _dT(ct,"-c"); + argv[10] = _dT(ct,"asdf"); + + argc = 11; + + + test.add_option(_dT(ct,"davis"),_dT(ct,"davis option"), 1); + test.add_option(_dT(ct,"c"),_dT(ct,"c option")); + test.add_option(_dT(ct,"d"),_dT(ct,"d option")); + test.add_option(_dT(ct,"Z"),_dT(ct,"Z option"),1); + + + DLIB_CASSERT(test.option(_dT(ct,"davis")).description() == _dT(ct,"davis option"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).description() == _dT(ct,"c option"),""); + DLIB_CASSERT(test.option(_dT(ct,"d")).description() == _dT(ct,"d option"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).description() == _dT(ct,"Z option"),""); + + for (int k = 0; k < 5; ++k) + { + + test.parse(argc,argv); + + DLIB_CASSERT(test.number_of_arguments() == 4,test.number_of_arguments()); + DLIB_CASSERT(test[0] == _dT(ct,"arg1"),""); + DLIB_CASSERT(test[1] == _dT(ct,"arg2"),""); + DLIB_CASSERT(test[2] == _dT(ct,"-c"),""); + DLIB_CASSERT(test[3] == _dT(ct,"asdf"),""); + + DLIB_CASSERT(test.option(_dT(ct,"davis")).count()==1,""); + DLIB_CASSERT(test.option(_dT(ct,"davis")).argument() == _dT(ct,"-darg"),""); + DLIB_CASSERT(test.option(_dT(ct,"c")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"d")).count()==0,""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).count()==3,""); + + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,0) == _dT(ct,"eat"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,1) == _dT(ct,"at"),""); + DLIB_CASSERT(test.option(_dT(ct,"Z")).argument(0,2) == _dT(ct,"joe's"),""); + + + } + + + } + } + +} + + +#endif // DLIB_CMD_LINE_PARSER_KERNEl_TEST_H_ + diff --git a/dlib/test/cmd_line_parser_wchar_t.cpp b/dlib/test/cmd_line_parser_wchar_t.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ffa005f7037b58567640487741fffd0018a80f9e --- /dev/null +++ b/dlib/test/cmd_line_parser_wchar_t.cpp @@ -0,0 +1,40 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include + +#include + +#include "tester.h" + +#include "cmd_line_parser.h" +namespace +{ + + class cmd_line_parser_tester : public tester + { + public: + cmd_line_parser_tester ( + ) : + tester ("test_cmd_line_parser_wchar_t", + "Runs tests on the cmd_line_parser component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a with wchar_t"; + cmd_line_parser_kernel_test::kernel_1a>(); + print_spinner(); + + dlog << LINFO << "testing kernel_1a_c with wchar_t"; + cmd_line_parser_kernel_test::kernel_1a_c>(); + print_spinner(); + } + } a; + +} + + diff --git a/dlib/test/compress_stream.cpp b/dlib/test/compress_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..400f7257f2e22ec0ea963de718f37e960ad537a0 --- /dev/null +++ b/dlib/test/compress_stream.cpp @@ -0,0 +1,306 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.compress_stream"); + + template < + typename cs + > + void compress_stream_kernel_test ( + unsigned long seed + ) + /*! + requires + - cs is an implementation of compress_stream/compress_stream_kernel_abstract.h + the alphabet_size for cc is 256 + ensures + - runs tests on cs for compliance with the specs + !*/ + { + + + srand(seed); + + cs test; + + + dlog << LTRACE << 1; + + int count = 0; + while (count < 2) + { + print_spinner(); + istringstream sin; + ostringstream sout; + string buffer; + buffer.reserve(10000); + // fill sin with a bunch of random data in the range 0 to 63 + for (int i = 0; i < 10000; ++i) + { + char temp = static_cast(::rand()&0x3f); + buffer.push_back(temp); + } + + print_spinner(); + sin.str(buffer); + string old_buffer = buffer; + + test.compress(sin,sout); + buffer = sout.str(); + + print_spinner(); + // corrput the data in buffer + buffer[buffer.size()/2]++; + + sin.str(buffer); + sout.str(""); + + bool detected_error = false; + try { + test.decompress(sin,sout); + } catch ( typename cs::decompression_error e ) + { + detected_error = true; + ++count; + } + + + DLIB_CASSERT(detected_error || sout.str() == old_buffer,(unsigned int)sout.str().size()); + + + + } /**/ + + + dlog << LTRACE << 2; + + for (int j = 0; j < 2; ++j) + { + + print_spinner(); + istringstream sin; + ostringstream sout; + + string buffer; + + buffer.reserve(10); + + // make sure a single char can be compressed and decompressed + for (int i = 0; i < 256; ++i) + { + sin.str(""); + sout.str(""); + char ch = static_cast(i); + buffer = ch; + sin.str(buffer); + + test.compress(sin,sout); + + sin.str(sout.str()); + sout.str(""); + test.decompress(sin,sout); + DLIB_CASSERT(sout.str() == buffer,""); + } + + print_spinner(); + + // make sure you can compress a single char, then append a new + // compressed single char. and make sure you can decode the + // two streams. Just to make sure the decoder doesn't leave + // extra bytes behind or eat more than it should. + for (int i = 0; i < 500; ++i) + { + sin.str(""); + sin.clear(); + sout.str(""); + sout.clear(); + char ch = static_cast(::rand()%256); + char ch2 = static_cast(::rand()%256); + + buffer = ch; + sin.str(buffer); + + + + test.compress(sin,sout); + + + + + buffer = ch2; + sin.str(buffer); + test.compress(sin,sout); + + sin.str(sout.str()); + + sout.str(""); + test.decompress(sin,sout); + buffer = ch; + DLIB_CASSERT(sout.str() == buffer,""); + + + + + sout.str(""); + test.decompress(sin,sout); + buffer = ch2; + DLIB_CASSERT(sout.str() == buffer,""); + + + } + print_spinner(); + + + // make sure you can compress and decompress the empty string + sout.str(""); + sin.str(""); + test.compress(sin,sout); + sin.str(sout.str()); + sout.str(""); + test.decompress(sin,sout); + DLIB_CASSERT(sout.str() == "",sout.str()); + + + + + + print_spinner(); + + sin.str(""); + sout.str(""); + buffer = ""; + + buffer.reserve(20000); + // fill buffer with a bunch of random data in the range 0 to 63 + for (int i = 0; i < 20000; ++i) + { + char temp = static_cast(::rand()&0x3f); + buffer.push_back(temp); + } + + sin.str(buffer); + + print_spinner(); + test.compress(sin,sout); + + sin.str(sout.str()); + sout.str(""); + + print_spinner(); + test.decompress(sin,sout); + + DLIB_CASSERT(sout.str() == buffer,""); + + print_spinner(); + } + + dlog << LTRACE << 3; + + // this block will try to compress a bunch of 'a' chars + { + + istringstream sin; + ostringstream sout; + + string buffer; + + + print_spinner(); + + sin.str(""); + sout.str(""); + buffer = ""; + + buffer.reserve(50000); + // fill buffer with a bunch of 'a' chars + for (int i = 0; i < 50000; ++i) + { + char temp = 'a'; + buffer.push_back(temp); + } + + sin.str(buffer); + + print_spinner(); + test.compress(sin,sout); + + sin.str(sout.str()); + sout.str(""); + + print_spinner(); + test.decompress(sin,sout); + + DLIB_CASSERT(sout.str() == buffer,""); + + print_spinner(); + + } + + dlog << LTRACE << 4; + + } + + + + + + + class compress_stream_tester : public tester + { + public: + compress_stream_tester ( + ) : + tester ("test_compress_stream", + "Runs tests on the compress_stream component.") + {} + + void perform_test ( + ) + { + const unsigned int seed = static_cast(time(0)); + dlog << LINFO << "using seed: " << seed; + + dlog << LINFO << "testing kernel_1a"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1b"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1c"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1da"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1db"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1ea"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1eb"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_1ec"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_2a"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_3a"; + compress_stream_kernel_test(seed); + dlog << LINFO << "testing kernel_3b"; + compress_stream_kernel_test(seed); + } + } a; + +} + diff --git a/dlib/test/conditioning_class.cpp b/dlib/test/conditioning_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..096e6bae9b5de46fbeb82065047b7d1b658bdf70 --- /dev/null +++ b/dlib/test/conditioning_class.cpp @@ -0,0 +1,86 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include + +#include "tester.h" +#include "conditioning_class.h" + +namespace +{ + + + class conditioning_class_tester : public tester + { + public: + conditioning_class_tester ( + ) : + tester ("test_conditioning_class", + "Runs tests on the conditioning_class component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_1a, + conditioning_class<2>::kernel_1a + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_2a"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_2a, + conditioning_class<2>::kernel_2a + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_3a"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_3a, + conditioning_class<2>::kernel_3a + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4a"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4a, + conditioning_class<2>::kernel_4a + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4b"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4b, + conditioning_class<2>::kernel_4b + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4c, + conditioning_class<2>::kernel_4c + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4d"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4d, + conditioning_class<2>::kernel_4d + >(); + print_spinner(); + + + } + } a; + + +} + diff --git a/dlib/test/conditioning_class.h b/dlib/test/conditioning_class.h new file mode 100644 index 0000000000000000000000000000000000000000..87bb0b5020f60b3479d96c245759b99728743c5e --- /dev/null +++ b/dlib/test/conditioning_class.h @@ -0,0 +1,841 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TEST_CONDITIONING_CLASs_H_ +#define DLIB_TEST_CONDITIONING_CLASs_H_ + + +#include +#include +#include +#include + +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.conditioning_class"); + + template < + typename cc, + typename cc2 + > + void conditioning_class_kernel_test ( + ) + /*! + requires + - cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + the alphabet_size for cc is 256 + - cc2 is an implementation of conditioning_class/conditioning_class_kernel_abstract.h + the alphabet_size for cc2 is 2 + ensures + - runs tests on cc for compliance with the specs + !*/ + { + + srand(static_cast(time(0))); + + + + typename cc::global_state_type gs; + typename cc2::global_state_type gs2; + + + + + for (int g = 0; g < 2; ++g) + { + print_spinner(); + unsigned long amount=g+1; + cc2 test(gs2); + cc2 test2(gs2); + + + DLIB_CASSERT(test.get_memory_usage() != 0,""); + + const unsigned long alphabet_size = 2; + + + DLIB_CASSERT(test.get_total() == 1,""); + + DLIB_CASSERT(test.get_count(alphabet_size-1)==1,""); + for (unsigned long i = 0; i < alphabet_size-1; ++i) + { + unsigned long low_count, high_count, total_count; + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == 0,i); + DLIB_CASSERT(test.get_count(i) == 0,""); + DLIB_CASSERT(test.get_total() == 1,""); + } + + + + for (unsigned long i = 0; i < alphabet_size; ++i) + { + test.increment_count(i,static_cast(amount)); + unsigned long low_count = 0, high_count = 0, total_count = 0; + + if (i ==alphabet_size-1) + { + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == 1+amount,""); + + DLIB_CASSERT(high_count == low_count+1+amount,""); + DLIB_CASSERT(total_count == test.get_total(),""); + + + DLIB_CASSERT(test.get_count(i) == 1+amount,""); + } + else + { + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == amount,""); + + DLIB_CASSERT(high_count == low_count+amount,""); + DLIB_CASSERT(total_count == test.get_total(),""); + + + DLIB_CASSERT(test.get_count(i) == amount,""); + } + DLIB_CASSERT(test.get_total() == (i+1)*amount + 1,""); + } + + + for (unsigned long i = 0; i < alphabet_size; ++i) + { + unsigned long temp = static_cast(::rand()%40); + for (unsigned long j = 0; j < temp; ++j) + { + test.increment_count(i,static_cast(amount)); + if (i == alphabet_size-1) + { + DLIB_CASSERT(test.get_count(i) == (j+1)*amount + 1 + amount,""); + } + else + { + DLIB_CASSERT(test.get_count(i) == (j+1)*amount + amount,""); + } + } + + unsigned long target = test.get_total()/2; + unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0; + + if (i == alphabet_size-1) + { + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==temp*amount+1+amount,""); + DLIB_CASSERT(high_count-low_count == temp*amount+1+amount,""); + } + else + { + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==temp*amount + amount,""); + DLIB_CASSERT(high_count-low_count == temp*amount + amount,""); + } + DLIB_CASSERT(total_count == test.get_total(),""); + + test.get_symbol(target,symbol,low_count,high_count); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + DLIB_CASSERT(low_count <= target,""); + DLIB_CASSERT(target < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + + } + + test.clear(); + + + for (unsigned long i = 0; i < alphabet_size-1; ++i) + { + test.increment_count(i); + unsigned long low_count, high_count, total_count; + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == 1,""); + + DLIB_CASSERT(high_count == low_count+1,""); + DLIB_CASSERT(total_count == test.get_total(),""); + + DLIB_CASSERT(test.get_count(i) == 1,""); + DLIB_CASSERT(test.get_total() == i+2,""); + } + + + + + unsigned long counts[alphabet_size]; + + + print_spinner(); + for (int k = 0; k < 10; ++k) + { + unsigned long range = ::rand()%50000 + 2; + + test.clear(); + + for (unsigned long i = 0; i < alphabet_size-1; ++i) + counts[i] = 0; + unsigned long total = 1; + counts[alphabet_size-1] = 1; + + + for (unsigned long i = 0; i < alphabet_size; ++i) + { + unsigned long temp = static_cast(::rand()%range); + for (unsigned long j = 0; j < temp; ++j) + { + test.increment_count(i); + + + if (total >= 65535) + { + total = 0; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + counts[i] >>= 1; + total += counts[i]; + } + if (counts[alphabet_size-1]==0) + { + counts[alphabet_size-1] = 1; + ++total; + } + } + counts[i] = counts[i] + 1; + ++total; + + + } + + + unsigned long temp_total = 0; + for (unsigned long a = 0; a < alphabet_size; ++a) + { + temp_total += test.get_count(a); + } + DLIB_CASSERT(temp_total == test.get_total(), + "temp_total == " << temp_total << endl << + "test.get_total() == " << test.get_total() + ); + + DLIB_CASSERT(test.get_count(alphabet_size-1) == counts[alphabet_size-1],""); + DLIB_CASSERT(test.get_total() == total, + "test.get_total() == " << test.get_total() << endl << + "total == " << total + ); + + unsigned long target = test.get_total()/2; + unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0; + + + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol],""); + + if (counts[symbol] != 0) + { + DLIB_CASSERT(total_count == total,""); + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + } + + + if (target < total) + { + test.get_symbol(target,symbol,low_count,high_count); + + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + DLIB_CASSERT(test.get_count(symbol) == counts[symbol],""); + } + + + + + } + + } + + print_spinner(); + + for (unsigned long h = 0; h < 10; ++h) + { + test.clear(); + DLIB_CASSERT(test.get_total() == 1,""); + + // fill out test with some numbers + unsigned long temp = ::rand()%30000 + 50000; + for (unsigned long j = 0; j < temp; ++j) + { + unsigned long symbol = (unsigned long)::rand()%alphabet_size; + test.increment_count(symbol); + } + + // make sure all symbols have a count of at least one + for (unsigned long j = 0; j < alphabet_size; ++j) + { + if (test.get_count(j) == 0) + test.increment_count(j); + } + + unsigned long temp_total = 0; + for (unsigned long j = 0; j < alphabet_size; ++j) + { + temp_total += test.get_count(j); + } + DLIB_CASSERT(temp_total == test.get_total(),""); + + + unsigned long low_counts[alphabet_size]; + unsigned long high_counts[alphabet_size]; + // iterate over all the symbols + for (unsigned long j = 0; j < alphabet_size; ++j) + { + unsigned long total; + unsigned long count = test.get_range(j,low_counts[j],high_counts[j],total); + DLIB_CASSERT(count == test.get_count(j),""); + DLIB_CASSERT(count == high_counts[j] - low_counts[j],""); + + } + + + // make sure get_symbol() matches what get_range() told us + for (unsigned long j = 0; j < alphabet_size; ++j) + { + for (unsigned long k = low_counts[j]; k < high_counts[j]; ++k) + { + unsigned long symbol, low_count, high_count; + test.get_symbol(k,symbol,low_count,high_count); + DLIB_CASSERT(high_count - low_count == test.get_count(symbol),""); + DLIB_CASSERT(j == symbol, + "j == " << j << endl << + "k == " << k << endl << + "symbol == " << symbol << endl << + "low_counts[j] == " << low_counts[j] << endl << + "high_counts[j] == " << high_counts[j] << endl << + "low_counts[symbol] == " << low_counts[symbol] << endl << + "high_counts[symbol] == " << high_counts[symbol] << endl << + "low_count == " << low_count << endl << + "high_count == " << high_count << endl << + "temp.count(j) == " << test.get_count(j) + ); + DLIB_CASSERT(low_count == low_counts[j], + "symbol: " << j << "\n" << + "target: " << k << "\n" << + "low_count: " << low_count << "\n" << + "low_counts[j]: " << low_counts[j]); + DLIB_CASSERT(high_count == high_counts[j],""); + } + + } + + } + + + + print_spinner(); + + for (int h = 0; h < 10; ++h) + { + + + test.clear(); + + for (unsigned long k = 0; k < alphabet_size-1; ++k) + { + counts[k] = 0; + } + counts[alphabet_size-1] = 1; + unsigned long total = 1; + unsigned long i = ::rand()%alphabet_size; + + unsigned long temp = 65536; + for (unsigned long j = 0; j < temp; ++j) + { + test.increment_count(i); + + + if (total >= 65535) + { + total = 0; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + counts[i] >>= 1; + total += counts[i]; + } + if (counts[alphabet_size-1] == 0) + { + ++total; + counts[alphabet_size-1] = 1; + } + } + counts[i] = counts[i] + 1; + ++total; + + } + + + DLIB_CASSERT(test.get_total() == total,""); + + unsigned long target = test.get_total()/2; + unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0; + + + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol],""); + + if (counts[symbol] != 0) + { + DLIB_CASSERT(total_count == total,""); + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + } + + + + test.get_symbol(target,symbol,low_count,high_count); + + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + DLIB_CASSERT(test.get_count(symbol) == counts[symbol],""); + + + + + + + + } + + } // for (int g = 0; g < 2; ++g) + + + + + + + + + + + + + + for (int g = 0; g < 2; ++g) + { + print_spinner(); + unsigned long amount=g+1; + cc test(gs); + cc test2(gs); + + DLIB_CASSERT(test.get_memory_usage() != 0,""); + + const unsigned long alphabet_size = 256; + + + DLIB_CASSERT(test.get_total() == 1,""); + + DLIB_CASSERT(test.get_count(alphabet_size-1)==1,""); + for (unsigned long i = 0; i < alphabet_size-1; ++i) + { + unsigned long low_count, high_count, total_count; + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == 0,""); + DLIB_CASSERT(test.get_count(i) == 0,""); + DLIB_CASSERT(test.get_total() == 1,""); + } + + + bool oom = false; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + bool status = test.increment_count(i,static_cast(amount)); + unsigned long low_count = 0, high_count = 0, total_count = 0; + if (!status) + oom = true; + + if (status) + { + if (i ==alphabet_size-1) + { + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == 1+amount,""); + + DLIB_CASSERT(high_count == low_count+1+amount,""); + DLIB_CASSERT(total_count == test.get_total(),""); + + + DLIB_CASSERT(test.get_count(i) == 1+amount,""); + } + else + { + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == amount,""); + + DLIB_CASSERT(high_count == low_count+amount,""); + DLIB_CASSERT(total_count == test.get_total(),""); + + + DLIB_CASSERT(test.get_count(i) == amount,""); + } + if (!oom) + DLIB_CASSERT(test.get_total() == (i+1)*amount + 1,""); + } + } + + + oom = false; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + unsigned long temp = static_cast(::rand()%40); + for (unsigned long j = 0; j < temp; ++j) + { + bool status = test.increment_count(i,static_cast(amount)); + if (!status) + oom = true; + if (status) + { + if (i == alphabet_size-1) + { + DLIB_CASSERT(test.get_count(i) == (j+1)*amount + 1 + amount,""); + } + else + { + DLIB_CASSERT(test.get_count(i) == (j+1)*amount + amount,""); + } + } + } + + unsigned long target = test.get_total()/2; + unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0; + + if (!oom) + { + if (i == alphabet_size-1) + { + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==temp*amount+1+amount,""); + DLIB_CASSERT(high_count-low_count == temp*amount+1+amount,""); + } + else + { + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==temp*amount + amount,""); + DLIB_CASSERT(high_count-low_count == temp*amount + amount,""); + } + DLIB_CASSERT(total_count == test.get_total(),""); + + + test.get_symbol(target,symbol,low_count,high_count); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + DLIB_CASSERT(low_count <= target,""); + DLIB_CASSERT(target < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + } + + } + + test.clear(); + + + oom = false; + for (unsigned long i = 0; i < alphabet_size-1; ++i) + { + if(!test.increment_count(i)) + oom = true; + unsigned long low_count, high_count, total_count; + + if (!oom) + { + DLIB_CASSERT(test.get_range(i,low_count,high_count,total_count) == 1,""); + + DLIB_CASSERT(high_count == low_count+1,""); + DLIB_CASSERT(total_count == test.get_total(),""); + + DLIB_CASSERT(test.get_count(i) == 1,""); + DLIB_CASSERT(test.get_total() == i+2,""); + } + } + + + + unsigned long counts[alphabet_size]; + + + for (int k = 0; k < 10; ++k) + { + unsigned long range = ::rand()%50000 + 2; + + test.clear(); + + for (unsigned long i = 0; i < alphabet_size-1; ++i) + counts[i] = 0; + unsigned long total = 1; + counts[alphabet_size-1] = 1; + + + oom = false; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + unsigned long temp = static_cast(::rand()%range); + for (unsigned long j = 0; j < temp; ++j) + { + if (!test.increment_count(i)) + oom = true; + + + if (total >= 65535) + { + + total = 0; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + counts[i] >>= 1; + total += counts[i]; + } + if (counts[alphabet_size-1]==0) + { + counts[alphabet_size-1] = 1; + ++total; + } + } + counts[i] = counts[i] + 1; + ++total; + + + } + + + unsigned long temp_total = 0; + for (unsigned long a = 0; a < alphabet_size; ++a) + { + temp_total += test.get_count(a); + } + + if (!oom) + { + DLIB_CASSERT(temp_total == test.get_total(), + "temp_total == " << temp_total << endl << + "test.get_total() == " << test.get_total() + ); + + DLIB_CASSERT(test.get_count(alphabet_size-1) == counts[alphabet_size-1],""); + DLIB_CASSERT(test.get_total() == total, + "test.get_total() == " << test.get_total() << endl << + "total == " << total + ); + } + + unsigned long target = test.get_total()/2; + unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0; + + if (!oom) + { + + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol],""); + + if (counts[symbol] != 0) + { + DLIB_CASSERT(total_count == total,""); + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + } + + + if (target < total) + { + test.get_symbol(target,symbol,low_count,high_count); + + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + DLIB_CASSERT(test.get_count(symbol) == counts[symbol],""); + } + } + + + + } + + } + + oom = false; + for (unsigned long h = 0; h < 10; ++h) + { + test.clear(); + DLIB_CASSERT(test.get_total() == 1,""); + + // fill out test with some numbers + unsigned long temp = ::rand()%30000 + 50000; + for (unsigned long j = 0; j < temp; ++j) + { + unsigned long symbol = (unsigned long)::rand()%alphabet_size; + if (!test.increment_count(symbol)) + oom = true; + } + + // make sure all symbols have a count of at least one + for (unsigned long j = 0; j < alphabet_size; ++j) + { + if (test.get_count(j) == 0) + test.increment_count(j); + } + + unsigned long temp_total = 0; + for (unsigned long j = 0; j < alphabet_size; ++j) + { + temp_total += test.get_count(j); + } + if (!oom) + DLIB_CASSERT(temp_total == test.get_total(),""); + + + unsigned long low_counts[alphabet_size]; + unsigned long high_counts[alphabet_size]; + + if (!oom) + { + + // iterate over all the symbols + for (unsigned long j = 0; j < alphabet_size; ++j) + { + unsigned long total; + unsigned long count = test.get_range(j,low_counts[j],high_counts[j],total); + DLIB_CASSERT(count == test.get_count(j),""); + DLIB_CASSERT(count == high_counts[j] - low_counts[j],""); + + } + + + + + // make sure get_symbol() matches what get_range() told us + for (unsigned long j = 0; j < alphabet_size; ++j) + { + for (unsigned long k = low_counts[j]; k < high_counts[j]; ++k) + { + unsigned long symbol, low_count, high_count; + test.get_symbol(k,symbol,low_count,high_count); + DLIB_CASSERT(high_count - low_count == test.get_count(symbol),""); + DLIB_CASSERT(j == symbol, + "j == " << j << endl << + "k == " << k << endl << + "symbol == " << symbol << endl << + "low_counts[j] == " << low_counts[j] << endl << + "high_counts[j] == " << high_counts[j] << endl << + "low_counts[symbol] == " << low_counts[symbol] << endl << + "high_counts[symbol] == " << high_counts[symbol] << endl << + "low_count == " << low_count << endl << + "high_count == " << high_count << endl << + "temp.count(j) == " << test.get_count(j) + ); + DLIB_CASSERT(low_count == low_counts[j], + "symbol: " << j << "\n" << + "target: " << k << "\n" << + "low_count: " << low_count << "\n" << + "low_counts[j]: " << low_counts[j]); + DLIB_CASSERT(high_count == high_counts[j],""); + } + + } + } + + } + + + + + for (int h = 0; h < 10; ++h) + { + + + test.clear(); + + for (unsigned long k = 0; k < alphabet_size-1; ++k) + { + counts[k] = 0; + } + counts[alphabet_size-1] = 1; + unsigned long total = 1; + unsigned long i = ::rand()%alphabet_size; + + unsigned long temp = 65536; + for (unsigned long j = 0; j < temp; ++j) + { + test.increment_count(i); + + + if (total >= 65535) + { + total = 0; + for (unsigned long i = 0; i < alphabet_size; ++i) + { + counts[i] >>= 1; + total += counts[i]; + } + if (counts[alphabet_size-1] == 0) + { + ++total; + counts[alphabet_size-1] = 1; + } + } + counts[i] = counts[i] + 1; + ++total; + + } + + + DLIB_CASSERT(test.get_total() == total,""); + + unsigned long target = test.get_total()/2; + unsigned long symbol = i, low_count = 0, high_count = 0, total_count = 0; + + + DLIB_CASSERT(test.get_range(symbol,low_count,high_count,total_count)==counts[symbol],""); + + if (counts[symbol] != 0) + { + DLIB_CASSERT(total_count == total,""); + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + } + + + + test.get_symbol(target,symbol,low_count,high_count); + + + DLIB_CASSERT(high_count <= total,""); + DLIB_CASSERT(low_count < high_count,""); + DLIB_CASSERT(high_count <= test.get_total(),""); + DLIB_CASSERT(test.get_count(symbol) == high_count-low_count,""); + DLIB_CASSERT(test.get_count(symbol) == counts[symbol],""); + + + + + + + + } + + } // for (int g = 0; g < 2; ++g) + + + } + +} + +#endif // DLIB_TEST_CONDITIONING_CLASs_H_ + diff --git a/dlib/test/conditioning_class_c.cpp b/dlib/test/conditioning_class_c.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e312600f583fbf28d6a813721af55fc05a85780c --- /dev/null +++ b/dlib/test/conditioning_class_c.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include + +#include "tester.h" +#include "conditioning_class.h" + +namespace +{ + + + class conditioning_class_tester : public tester + { + public: + conditioning_class_tester ( + ) : + tester ("test_conditioning_class_c", + "Runs tests on the conditioning_class checked components.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_1a_c, + conditioning_class<2>::kernel_1a_c + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_2a_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_2a_c, + conditioning_class<2>::kernel_2a_c + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_3a_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_3a_c, + conditioning_class<2>::kernel_3a_c + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4a_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4a_c, + conditioning_class<2>::kernel_4a_c + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4b_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4b_c, + conditioning_class<2>::kernel_4b_c + >(); + print_spinner(); + + + dlog << LINFO << "testing kernel_4c_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4c_c, + conditioning_class<2>::kernel_4c_c + >(); + print_spinner(); + + dlog << LINFO << "testing kernel_4d_c"; + conditioning_class_kernel_test< + conditioning_class<256>::kernel_4d_c, + conditioning_class<2>::kernel_4d_c + >(); + print_spinner(); + + + } + } a; + + +} + diff --git a/dlib/test/config_reader.cpp b/dlib/test/config_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04bd36c826a14ad7293a7375fa247503d57e8187 --- /dev/null +++ b/dlib/test/config_reader.cpp @@ -0,0 +1,374 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" +// so that everything you declare will have static linkage. Thus we won't have any multiply +// defined symbol errors coming out of the linker when we try to compile the test suite. +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + template < + typename config_reader + > + void do_the_tests ( + config_reader& cr + ) + { + DLIB_CASSERT(cr.is_key_defined("global"),""); + DLIB_CASSERT(cr.is_block_defined("all"),""); + DLIB_CASSERT(cr.is_key_defined("globalasfd") == false,""); + DLIB_CASSERT(cr.is_block_defined("all!") == false,""); + DLIB_CASSERT(cr.size() == 1,""); + DLIB_CASSERT(cr["global"] == "hmm",""); + DLIB_CASSERT(cr["global2"] == "hmm2",""); + DLIB_CASSERT(cr.block("all").size() == 4,""); + DLIB_CASSERT(cr.block("all").block("block1").size() == 0,""); + DLIB_CASSERT(cr.block("all").block("block2").size() == 0,""); + DLIB_CASSERT(cr.block("all").block("block3").size() == 0,""); + DLIB_CASSERT(cr.block("all").block("block4").size() == 0,""); + + DLIB_CASSERT(cr.block("all").block("block1").is_key_defined("name"),""); + DLIB_CASSERT(cr.block("all").block("block2").is_key_defined("name"),""); + DLIB_CASSERT(cr.block("all").block("block3").is_key_defined("name"),""); + DLIB_CASSERT(cr.block("all").block("block4").is_key_defined("name"),""); + DLIB_CASSERT(cr.block("all").block("block1").is_key_defined("age"),""); + DLIB_CASSERT(cr.block("all").block("block2").is_key_defined("age"),""); + DLIB_CASSERT(cr.block("all").block("block3").is_key_defined("age"),""); + DLIB_CASSERT(cr.block("all").block("block4").is_key_defined("age"),""); + + DLIB_CASSERT(cr.block("all").block("block1")["name"] == "davis king",""); + DLIB_CASSERT(cr.block("all").block("block2")["name"] == "joel",""); + DLIB_CASSERT(cr.block("all").block("block3")["name"] == "john",""); + DLIB_CASSERT(cr.block("all").block("block4")["name"] == "dude",""); + DLIB_CASSERT(cr.block("all").block("block1")["age"] == "24",""); + DLIB_CASSERT(cr.block("all").block("block2")["age"] == "24",""); + DLIB_CASSERT(cr.block("all").block("block3")["age"] == "24",""); + DLIB_CASSERT(cr.block("all").block("block4")["age"] == "53",""); + + + int count1 = 0; + int count2 = 0; + while (cr.move_next()) + { + ++count1; + DLIB_CASSERT(cr.current_block_name() == "all",""); + DLIB_CASSERT(cr.element().is_key_defined("global") == false,""); + DLIB_CASSERT(cr.element().is_key_defined("global2") == false,""); + DLIB_CASSERT(cr.element().is_key_defined("name") == false,""); + DLIB_CASSERT(cr.element().is_key_defined("age") == false,""); + while (cr.element().move_next()) + { + ++count2; + ostringstream sout; + sout << "block" << count2; + DLIB_CASSERT(cr.element().current_block_name() == sout.str(),""); + DLIB_CASSERT(cr.element().size() == 4,""); + DLIB_CASSERT(cr.element().element().size() == 0,""); + DLIB_CASSERT(cr.element().element().is_key_defined("name"),""); + DLIB_CASSERT(cr.element().element().is_key_defined("age"),""); + } + } + + DLIB_CASSERT(count1 == 1,""); + DLIB_CASSERT(count2 == 4,""); + + } + + + // Declare the logger we will use in this test. The name of the tester + // should start with "test." + logger dlog("test.config_reader"); + + template < + typename config_reader + > + void config_reader_test ( + ) + /*! + requires + - config_reader is an implementation of config_reader/config_reader_kernel_abstract.h + is instantiated with int + ensures + - runs tests on config_reader for compliance with the specs + !*/ + { + + + + ostringstream sout; + + sout << "all#comment { { } \n"; + sout << "{ \n"; + sout << " block1 \n"; + sout << " { \n"; + sout << " name = davis king \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block2 \n"; + sout << " { \n"; + sout << " name= joel \n"; + sout << " age =24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block3 \n"; + sout << " { \n"; + sout << " name = john \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " #comment \n"; + sout << "#comment \n"; + sout << " block4{ # comment"; + sout << " \n"; + sout << " name = dude \n"; + sout << " age = 53}\n"; + sout << " \n"; + sout << "} \n"; + sout << " \n"; + sout << " \n"; + sout << "global=hmm#comment \n"; + sout << "global2=hmm2 \n"; + sout << " # comment \n"; + + string data = sout.str(); + + config_reader cr2; + for (int i = 0; i < 3; ++i) + { + istringstream sin; + + sin.clear(); + sin.str(data); + + config_reader cr(sin); + sin.clear(); + sin.str(data); + + cr2.load_from(sin); + + do_the_tests(cr); + do_the_tests(cr2); + + cr.clear(); + DLIB_CASSERT(cr.size() == 0,""); + DLIB_CASSERT(cr.is_key_defined("global") == false,""); + } + + + sout.clear(); + sout.str(""); + + { + sout << "all#comment { { } \n"; + sout << "{ \n"; + sout << " block1 \n"; + sout << " { \n"; + sout << " name = davis king \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block2 \n"; + sout << " { \n"; + sout << " name= joel \n"; + sout << " age =24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block3 \n"; + sout << " {{ \n"; // error on this line + sout << " name = john \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " #comment \n"; + sout << "#comment \n"; + sout << " block4{ # comment"; + sout << " \n"; + sout << " name = dude \n"; + sout << " age = 53}\n"; + sout << " \n"; + sout << "} \n"; + sout << " \n"; + sout << " \n"; + sout << "global=hmm#comment \n"; + sout << "global2=hmm2 \n"; + sout << " # comment \n"; + + istringstream sin(sout.str()); + + bool error_found = false; + try + { + cr2.load_from(sin); + } + catch (typename config_reader::config_reader_error& e) + { + error_found = true; + DLIB_CASSERT(e.line_number == 16,""); + DLIB_CASSERT(e.redefinition == false,""); + } + DLIB_CASSERT(error_found,""); + } + + { + sout.str(""); + sout.clear(); + sout << "all#comment { { } \n"; + sout << "{ \n"; + sout << " block1 \n"; + sout << " { \n"; + sout << " name = davis king \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block2 \n"; + sout << " { \n"; + sout << " name= joel \n"; + sout << " age =24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block3 \n"; + sout << " { \n"; + sout << " name = john \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " #comment \n"; + sout << "#comment \n"; + sout << " block4{ # comment"; + sout << " \n"; + sout << " name = dude \n"; + sout << " age = 53}\n"; + sout << " \n"; + sout << "} \n"; + sout << " \n"; + sout << " \n"; + sout << "global=hmm#comment \n"; + sout << " \n"; + sout << "global=hmm2 \n"; // error on this line + sout << " # comment \n"; + + istringstream sin(sout.str()); + + bool error_found = false; + try + { + cr2.load_from(sin); + } + catch (typename config_reader::config_reader_error& e) + { + error_found = true; + DLIB_CASSERT(e.line_number == 31,e.line_number); + DLIB_CASSERT(e.redefinition == true,""); + } + DLIB_CASSERT(error_found,""); + } + + + { + sout.str(""); + sout.clear(); + sout << "all#comment { { } \n"; + sout << "{ \n"; + sout << " block1 \n"; + sout << " { \n"; + sout << " name = davis king \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " \n"; + sout << " block2 \n"; + sout << " { \n"; + sout << " name= joel \n"; + sout << " age =24 \n"; + sout << " } block2{} \n"; // error on this line + sout << " \n"; + sout << " block3 \n"; + sout << " { \n"; + sout << " name = john \n"; + sout << " age = 24 \n"; + sout << " } \n"; + sout << " #comment \n"; + sout << "#comment \n"; + sout << " block4{ # comment"; + sout << " \n"; + sout << " name = dude \n"; + sout << " age = 53}\n"; + sout << " \n"; + sout << "} \n"; + sout << " \n"; + sout << " \n"; + sout << "global=hmm#comment \n"; + sout << " \n"; + sout << " # comment \n"; + + istringstream sin(sout.str()); + + bool error_found = false; + try + { + cr2.load_from(sin); + } + catch (typename config_reader::config_reader_error& e) + { + error_found = true; + DLIB_CASSERT(e.line_number == 13,e.line_number); + DLIB_CASSERT(e.redefinition == true,""); + } + DLIB_CASSERT(error_found,""); + } + + + + } + + + + class config_reader_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a test for the config_reader object. When it is constructed + it adds itself into the testing framework. The command line switch is + specified as test_config_reader by passing that string to the tester constructor. + !*/ + public: + config_reader_tester ( + ) : + tester ("test_config_reader", + "Runs tests on the config_reader component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + print_spinner(); + config_reader_test(); + + dlog << LINFO << "testing kernel_1a_c"; + print_spinner(); + config_reader_test(); + + dlog << LINFO << "testing thread_safe_1a"; + print_spinner(); + config_reader_test(); + + dlog << LINFO << "testing thread_safe_1a_c"; + print_spinner(); + config_reader_test(); + } + } a; + +} + + diff --git a/dlib/test/directed_graph.cpp b/dlib/test/directed_graph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd13c1cd52c737406aba02e2c6a828cb1d5882f9 --- /dev/null +++ b/dlib/test/directed_graph.cpp @@ -0,0 +1,479 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" +// so that everything you declare will have static linkage. Thus we won't have any multiply +// defined symbol errors coming out of the linker when we try to compile the test suite. +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + // Declare the logger we will use in this test. The name of the tester + // should start with "test." + logger dlog("test.directed_graph"); + + template < + typename directed_graph + > + void directed_graph_test ( + ) + /*! + requires + - directed_graph is an implementation of directed_graph/directed_graph_kernel_abstract.h + is instantiated with int + ensures + - runs tests on directed_graph for compliance with the specs + !*/ + { + print_spinner(); + + COMPILE_TIME_ASSERT(is_directed_graph::value == true); + directed_graph a, b; + set::compare_1b_c s; + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + DLIB_CASSERT(a.number_of_nodes() == 0,""); + + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + + a.set_number_of_nodes(5); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + DLIB_CASSERT(graph_is_connected(a) == false,""); + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + DLIB_CASSERT(a.number_of_nodes() == 5,""); + + for (int i = 0; i < 5; ++i) + { + a.node(i).data = i; + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + a.remove_node(1); + + DLIB_CASSERT(a.number_of_nodes() == 4,""); + + + // make sure that only the number with data == 1 was remove + int count = 0; + for (int i = 0; i < 4; ++i) + { + count += a.node(i).data; + DLIB_CASSERT(a.node(i).number_of_children() == 0,""); + DLIB_CASSERT(a.node(i).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + DLIB_CASSERT(count == 9,""); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + + a.add_edge(1,1); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == true,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == true,""); + + a.add_edge(1,2); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == true,""); + + DLIB_CASSERT(a.node(1).number_of_children() == 2,""); + DLIB_CASSERT(a.node(1).number_of_parents() == 1,""); + DLIB_CASSERT(a.node(1).parent(0).index() == 1,"") + + DLIB_CASSERT(a.node(1).child(0).index() + a.node(1).child(1).index() == 3,"") + DLIB_CASSERT(a.node(2).number_of_children() == 0,""); + DLIB_CASSERT(a.node(2).number_of_parents() == 1,""); + DLIB_CASSERT(a.node(2).index() == 2,""); + + int val = a.node(1).data; + a.remove_node(1); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + + DLIB_CASSERT(a.number_of_nodes() == 3,""); + + count = 0; + for (int i = 0; i < 3; ++i) + { + count += a.node(i).data; + DLIB_CASSERT(a.node(i).number_of_children() == 0,""); + DLIB_CASSERT(a.node(i).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + DLIB_CASSERT(count == 9-val,""); + + + val = a.add_node(); + DLIB_CASSERT(val == 3,""); + DLIB_CASSERT(a.number_of_nodes() == 4,""); + + for (int i = 0; i < 4; ++i) + { + a.node(i).data = i; + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + for (int i = 0; i < 4; ++i) + { + DLIB_CASSERT(a.node(i).data == i,""); + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + a.add_edge(0, 1); + a.add_edge(0, 2); + DLIB_CASSERT(graph_is_connected(a) == false,""); + a.add_edge(1, 3); + DLIB_CASSERT(graph_is_connected(a) == true,""); + a.add_edge(2, 3); + DLIB_CASSERT(graph_is_connected(a) == true,""); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + + DLIB_CASSERT(a.has_edge(0, 1),""); + DLIB_CASSERT(a.has_edge(0, 2),""); + DLIB_CASSERT(a.has_edge(1, 3),""); + DLIB_CASSERT(a.has_edge(2, 3),""); + + DLIB_CASSERT(!a.has_edge(1, 0),""); + DLIB_CASSERT(!a.has_edge(2, 0),""); + DLIB_CASSERT(!a.has_edge(3, 1),""); + DLIB_CASSERT(!a.has_edge(3, 2),""); + + DLIB_CASSERT(a.node(0).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(0).number_of_children() == 2,""); + + DLIB_CASSERT(a.node(1).number_of_parents() == 1,""); + DLIB_CASSERT(a.node(1).number_of_children() == 1,""); + DLIB_CASSERT(a.node(1).child(0).index() == 3,""); + DLIB_CASSERT(a.node(1).parent(0).index() == 0,""); + + DLIB_CASSERT(a.node(2).number_of_parents() == 1,""); + DLIB_CASSERT(a.node(2).number_of_children() == 1,""); + DLIB_CASSERT(a.node(2).child(0).index() == 3,""); + DLIB_CASSERT(a.node(2).parent(0).index() == 0,""); + + DLIB_CASSERT(a.node(3).number_of_parents() == 2,""); + DLIB_CASSERT(a.node(3).number_of_children() == 0,""); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + + a.remove_edge(0,1); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + + DLIB_CASSERT(!a.has_edge(0, 1),""); + DLIB_CASSERT(a.has_edge(0, 2),""); + DLIB_CASSERT(a.has_edge(1, 3),""); + DLIB_CASSERT(a.has_edge(2, 3),""); + + DLIB_CASSERT(!a.has_edge(1, 0),""); + DLIB_CASSERT(!a.has_edge(2, 0),""); + DLIB_CASSERT(!a.has_edge(3, 1),""); + DLIB_CASSERT(!a.has_edge(3, 2),""); + + + DLIB_CASSERT(a.node(0).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(0).number_of_children() == 1,""); + + DLIB_CASSERT(a.node(1).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(1).number_of_children() == 1,""); + DLIB_CASSERT(a.node(1).child(0).index() == 3,""); + + DLIB_CASSERT(a.node(2).number_of_parents() == 1,""); + DLIB_CASSERT(a.node(2).number_of_children() == 1,""); + DLIB_CASSERT(a.node(2).child(0).index() == 3,""); + DLIB_CASSERT(a.node(2).parent(0).index() == 0,""); + + DLIB_CASSERT(a.node(3).number_of_parents() == 2,""); + DLIB_CASSERT(a.node(3).number_of_children() == 0,""); + + for (int i = 0; i < 4; ++i) + { + DLIB_CASSERT(a.node(i).data == i,""); + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + + + swap(a,b); + + DLIB_CASSERT(a.number_of_nodes() == 0, ""); + DLIB_CASSERT(b.number_of_nodes() == 4, ""); + DLIB_CASSERT(b.node(0).number_of_parents() == 0,""); + DLIB_CASSERT(b.node(0).number_of_children() == 1,""); + + DLIB_CASSERT(b.node(1).number_of_parents() == 0,""); + DLIB_CASSERT(b.node(1).number_of_children() == 1,""); + DLIB_CASSERT(b.node(1).child(0).index() == 3,""); + + DLIB_CASSERT(b.node(2).number_of_parents() == 1,""); + DLIB_CASSERT(b.node(2).number_of_children() == 1,""); + DLIB_CASSERT(b.node(2).child(0).index() == 3,""); + DLIB_CASSERT(b.node(2).parent(0).index() == 0,""); + + DLIB_CASSERT(b.node(3).number_of_parents() == 2,""); + DLIB_CASSERT(b.node(3).number_of_children() == 0,""); + b.node(0).child_edge(0) = static_cast(b.node(0).child(0).index()+1); + b.node(1).child_edge(0) = static_cast(b.node(1).child(0).index()+1); + b.node(2).child_edge(0) = static_cast(b.node(2).child(0).index()+1); + + DLIB_CASSERT(b.node(0).child_edge(0) == b.node(0).child(0).index()+1, + b.node(0).child_edge(0) << " " << b.node(0).child(0).index()+1); + DLIB_CASSERT(b.node(1).child_edge(0) == b.node(1).child(0).index()+1, + b.node(1).child_edge(0) << " " << b.node(1).child(0).index()+1); + DLIB_CASSERT(b.node(2).child_edge(0) == b.node(2).child(0).index()+1, + b.node(2).child_edge(0) << " " << b.node(2).child(0).index()+1); + + DLIB_CASSERT(b.node(2).parent_edge(0) == 2+1, + b.node(2).parent_edge(0) << " " << 2+1); + DLIB_CASSERT(b.node(3).parent_edge(0) == 3+1, + b.node(3).parent_edge(0) << " " << 3+1); + DLIB_CASSERT(b.node(3).parent_edge(1) == 3+1, + b.node(3).parent_edge(1) << " " << 3+1); + + ostringstream sout; + + serialize(b, sout); + + istringstream sin(sout.str()); + + a.set_number_of_nodes(20); + DLIB_CASSERT(a.number_of_nodes() == 20,""); + deserialize(a, sin); + DLIB_CASSERT(a.number_of_nodes() == 4,""); + + DLIB_CASSERT(!a.has_edge(0, 1),""); + DLIB_CASSERT(a.has_edge(0, 2),""); + DLIB_CASSERT(a.has_edge(1, 3),""); + DLIB_CASSERT(a.has_edge(2, 3),""); + + DLIB_CASSERT(!a.has_edge(1, 0),""); + DLIB_CASSERT(!a.has_edge(2, 0),""); + DLIB_CASSERT(!a.has_edge(3, 1),""); + DLIB_CASSERT(!a.has_edge(3, 2),""); + + DLIB_CASSERT(a.node(0).child_edge(0) == a.node(0).child(0).index()+1, + a.node(0).child_edge(0) << " " << a.node(0).child(0).index()+1); + DLIB_CASSERT(a.node(1).child_edge(0) == a.node(1).child(0).index()+1, + a.node(1).child_edge(0) << " " << a.node(1).child(0).index()+1); + DLIB_CASSERT(a.node(2).child_edge(0) == a.node(2).child(0).index()+1, + a.node(2).child_edge(0) << " " << a.node(2).child(0).index()+1); + DLIB_CASSERT(a.node(2).parent_edge(0) == 2+1, + a.node(2).parent_edge(0) << " " << 2+1); + DLIB_CASSERT(a.node(3).parent_edge(0) == 3+1, + a.node(3).parent_edge(0) << " " << 3+1); + DLIB_CASSERT(a.node(3).parent_edge(1) == 3+1, + a.node(3).parent_edge(1) << " " << 3+1); + + + + for (int i = 0; i < 4; ++i) + { + DLIB_CASSERT(a.node(i).data == i,""); + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + DLIB_CASSERT(b.number_of_nodes() == 4, ""); + DLIB_CASSERT(b.node(0).number_of_parents() == 0,""); + DLIB_CASSERT(b.node(0).number_of_children() == 1,""); + + DLIB_CASSERT(b.node(1).number_of_parents() == 0,""); + DLIB_CASSERT(b.node(1).number_of_children() == 1,""); + DLIB_CASSERT(b.node(1).child(0).index() == 3,""); + + DLIB_CASSERT(b.node(2).number_of_parents() == 1,""); + DLIB_CASSERT(b.node(2).number_of_children() == 1,""); + DLIB_CASSERT(b.node(2).child(0).index() == 3,""); + DLIB_CASSERT(b.node(2).parent(0).index() == 0,""); + + DLIB_CASSERT(b.node(3).number_of_parents() == 2,""); + DLIB_CASSERT(b.node(3).number_of_children() == 0,""); + + + DLIB_CASSERT(a.number_of_nodes() == 4, ""); + DLIB_CASSERT(a.node(0).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(0).number_of_children() == 1,""); + + DLIB_CASSERT(a.node(1).number_of_parents() == 0,""); + DLIB_CASSERT(a.node(1).number_of_children() == 1,""); + DLIB_CASSERT(a.node(1).child(0).index() == 3,""); + + DLIB_CASSERT(a.node(2).number_of_parents() == 1,""); + DLIB_CASSERT(a.node(2).number_of_children() == 1,""); + DLIB_CASSERT(a.node(2).child(0).index() == 3,""); + DLIB_CASSERT(a.node(2).parent(0).index() == 0,""); + + DLIB_CASSERT(a.node(3).number_of_parents() == 2,""); + DLIB_CASSERT(a.node(3).number_of_children() == 0,""); + + DLIB_CASSERT(a.number_of_nodes() == 4, ""); + a.clear(); + DLIB_CASSERT(a.number_of_nodes() == 0, ""); + + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + + a.set_number_of_nodes(10); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + + a.add_edge(0,1); + a.add_edge(1,2); + a.add_edge(1,3); + a.add_edge(2,4); + a.add_edge(3,4); + a.add_edge(4,5); + a.add_edge(5,1); + + DLIB_CASSERT(graph_contains_directed_cycle(a) == true,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + + a.remove_edge(5,1); + + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + a.add_edge(7,8); + DLIB_CASSERT(graph_contains_directed_cycle(a) == false,""); + a.add_edge(8,7); + DLIB_CASSERT(graph_contains_directed_cycle(a) == true,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + + + a.clear(); + /* + Make a graph that looks like: + 0 1 + \ / + 2 + | + 3 + */ + a.set_number_of_nodes(4); + a.add_edge(0,2); + a.add_edge(1,2); + a.add_edge(2,3); + for (unsigned long i = 0; i < 4; ++i) + a.node(i).data = i; + + graph::kernel_1a_c g; + create_moral_graph(a,g); + + graph::compare_1b_c, set::compare_1a_c>::kernel_1a_c join_tree; + set::compare_1b_c>::kernel_1b_c sos; + + create_join_tree(g, join_tree); + DLIB_CASSERT(is_join_tree(g, join_tree),""); + DLIB_CASSERT(join_tree.number_of_nodes() == 2,""); + DLIB_CASSERT(graph_contains_undirected_cycle(join_tree) == false,""); + DLIB_CASSERT(graph_is_connected(join_tree) == true,""); + + unsigned long temp; + triangulate_graph_and_find_cliques(g,sos); + + temp = 2; s.add(temp); + temp = 3; s.add(temp); + DLIB_CASSERT(sos.is_member(s),""); + s.clear(); + temp = 0; s.add(temp); + temp = 1; s.add(temp); + temp = 2; s.add(temp); + DLIB_CASSERT(sos.is_member(s),""); + DLIB_CASSERT(sos.size() == 2,""); + DLIB_CASSERT(sos.is_member(join_tree.node(0).data), ""); + DLIB_CASSERT(sos.is_member(join_tree.node(1).data), ""); + + + s.clear(); + temp = 0; s.add(temp); + DLIB_CASSERT(is_clique(g,s) == true,""); + DLIB_CASSERT(is_maximal_clique(g,s) == false,""); + temp = 3; s.add(temp); + DLIB_CASSERT(is_clique(g,s) == false,""); + s.destroy(3); + DLIB_CASSERT(is_clique(g,s) == true,""); + temp = 2; s.add(temp); + DLIB_CASSERT(is_clique(g,s) == true,""); + DLIB_CASSERT(is_maximal_clique(g,s) == false,""); + temp = 1; s.add(temp); + DLIB_CASSERT(is_clique(g,s) == true,""); + DLIB_CASSERT(is_maximal_clique(g,s) == true,""); + s.clear(); + DLIB_CASSERT(is_clique(g,s) == true,""); + temp = 3; s.add(temp); + DLIB_CASSERT(is_clique(g,s) == true,""); + temp = 2; s.add(temp); + DLIB_CASSERT(is_clique(g,s) == true,""); + DLIB_CASSERT(is_maximal_clique(g,s) == true,""); + + + DLIB_CASSERT(a.number_of_nodes() == 4,""); + DLIB_CASSERT(g.number_of_nodes() == 4,""); + for (unsigned long i = 0; i < 4; ++i) + DLIB_CASSERT( a.node(i).data == (int)i,""); + DLIB_CASSERT(g.has_edge(0,1),""); + DLIB_CASSERT(g.has_edge(0,2),""); + DLIB_CASSERT(g.has_edge(1,2),""); + DLIB_CASSERT(g.has_edge(3,2),""); + DLIB_CASSERT(g.has_edge(0,3) == false,""); + DLIB_CASSERT(g.has_edge(1,3) == false,""); + + } + + + + + class directed_graph_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a test for the directed_graph object. When it is constructed + it adds itself into the testing framework. The command line switch is + specified as test_directed_graph by passing that string to the tester constructor. + !*/ + public: + directed_graph_tester ( + ) : + tester ("test_directed_graph", + "Runs tests on the directed_graph component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a_c"; + directed_graph_test::kernel_1a_c>(); + + dlog << LINFO << "testing kernel_1a"; + directed_graph_test::kernel_1a>(); + } + } a; + + +} + + diff --git a/dlib/test/entropy_coder.cpp b/dlib/test/entropy_coder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..83c22954d492ca009e01c1e4f9556787b9429659 --- /dev/null +++ b/dlib/test/entropy_coder.cpp @@ -0,0 +1,587 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.entropy_coder"); + + namespace entropy_coder_kernel_test_helpers + { + template < + typename encoder, + typename decoder + > + std::string test ( + const std::string& input + ) + /*! + ensures + - encodes the data from in and then tries to decode it and returns + "" if it was successfully decoded else it returns the decoded string + !*/ + { + ostringstream sout; + istringstream sin; + istringstream in; + + + in.str(input); + + const unsigned long max_total = 65535; + + + + + unsigned long counts[256]; + for (int i = 0; i < 256; ++i) + { + counts[i] = 1; + } + + + encoder e; + + + + DLIB_CASSERT(e.stream_is_set() == false,""); + + e.set_stream(sout); + + DLIB_CASSERT(e.stream_is_set() == true,""); + DLIB_CASSERT(&e.get_stream() == &sout,""); + + unsigned char ch; + + unsigned long total = 256; + + while (in.read((char*)&ch,1)) + { + if (total > max_total) + { + total = 0; + for (int j = 0; j<256; ++j) + { + counts[j] >>= 1; + if (counts[j] == 0) + counts[j] = 1; + total += counts[j]; + + } + } + + unsigned long low_count = 0; + unsigned long high_count; + for (int i = 0; i < ch; ++i) + low_count += counts[i]; + high_count = low_count + counts[ch]; + + e.encode(low_count,high_count,total); + + + ++total; + counts[ch] += 1; + } + + DLIB_CASSERT(e.stream_is_set() == true,""); + DLIB_CASSERT(&e.get_stream() == &sout,""); + + + + e.clear(); + + DLIB_CASSERT(e.stream_is_set() == false,""); + + + // ***************************************** + + + decoder d; + + + DLIB_CASSERT(d.stream_is_set() == false,""); + DLIB_CASSERT(d.get_target_called() == false,""); + + sin.str(sout.str()); + sout.str(""); + + d.set_stream(sin); + + DLIB_CASSERT(d.get_target_called() == false,""); + + DLIB_CASSERT(d.stream_is_set() == true,""); + DLIB_CASSERT(&d.get_stream() == &sin,""); + + for (int i = 0; i < 256; ++i) + { + counts[i] = 1; + } + + total = 256; + + for (string::size_type i = 0; i < input.size() ; ++i) + { + if (total > max_total) + { + total = 0; + for (int j = 0; j<256; ++j) + { + counts[j] >>= 1; + if (counts[j] == 0) + counts[j] = 1; + total += counts[j]; + + } + } + + DLIB_CASSERT(d.get_target_called() == false,""); + + unsigned long target = d.get_target(total); + + DLIB_CASSERT(target < total,""); + + DLIB_CASSERT(d.get_target_called() == true,""); + + + unsigned long low_count; + unsigned long high_count = 0; + + unsigned long j; + for (j = 0; high_count <= target; ++j) + { + high_count += counts[j]; + } + --j; + low_count = high_count - counts[j]; + + + ch = static_cast(j); + + + sout.rdbuf()->sputn((char*)&ch,1); + + + + d.decode(low_count,high_count); + DLIB_CASSERT(d.get_target_called() == false,""); + ++total; + counts[ch] += 1; + + } + + DLIB_CASSERT(d.stream_is_set() == true,""); + DLIB_CASSERT(&d.get_stream() == &sin,""); + + d.clear(); + + DLIB_CASSERT(d.stream_is_set() == false,""); + DLIB_CASSERT(sout.str().size() == input.size(),"the test script is buggy"); + + + if (sout.str() == input) + return ""; + else + return sout.str(); + + } + + } + + + + + template < + typename encoder, + typename decoder + > + void entropy_coder_kernel_test ( + ) + /*! + requires + - encoder is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h + - decoder is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h + ensures + - runs tests on encoder and decoder for compliance with the specs + !*/ + { + using namespace entropy_coder_kernel_test_helpers; + + dlog << LTRACE << 1; + + print_spinner(); + string temp, temp2; + + srand(static_cast(time(0))); + + for (int k = 0; k < 10000; ++k) + { + string temp; + istringstream sin; + ostringstream sout; + decoder d; + encoder e; + + e.set_stream(sout); + + int num = ::rand() %200; + unsigned long total[200]; + unsigned long high_count[200]; + unsigned long low_count[200]; + for (int i = 0; i < num; ++i) + { + total[i] = ::rand()%256 + 20; + high_count[i] = ::rand()%total[i] + 1; + low_count[i] = ::rand()%high_count[i]; + + e.encode(low_count[i],high_count[i],total[i]); + } + + e.clear(); + + sout.rdbuf()->sputc('a'); + + sin.str(sout.str()); + + + d.set_stream(sin); + + + for (int i = 0; i < num; ++i) + { + unsigned long N = d.get_target(total[i]); + DLIB_CASSERT(low_count[i] <= N && N < high_count[i],""); + d.decode(low_count[i],high_count[i]); + } + + + + + + + DLIB_CASSERT(sin.rdbuf()->sgetc() != EOF,"num: " << num); + DLIB_CASSERT(sin.rdbuf()->sgetc() == 'a', + "sin.rdbuf()->sgetc() == " << (char)sin.rdbuf()->sgetc() << + "\nnum: " << num + ); + DLIB_CASSERT(sin.rdbuf()->sbumpc() == 'a',""); + DLIB_CASSERT(sin.rdbuf()->sgetc() == EOF,""); + + } // for (int k = 0; k < 10000; ++k) + + dlog << LTRACE << 2; + + print_spinner(); + + // the point of this block is to make sure that the return value + // from decoder.get_target(total) is a always less than total + for (int k = 0; k < 20; ++k) + { + string temp; + temp.push_back(static_cast(::rand()&0xff)); + istringstream sin(temp); + decoder d; + d.set_stream(sin); + unsigned long total = ::rand()%256 + 20; + unsigned long target = d.get_target(total); + DLIB_CASSERT(target target) + low_count = target; + + d.decode(low_count,high_count); + target = d.get_target(total); + DLIB_CASSERT(target(time(0)); + srand(seed1 ); + int array[65536]; + for (int i = 0; i < 65536; ++i) + { + array[i] = ::rand()%256; + } + for (int i = 0; i < 60; ++i) + { + int idx = ::rand()%65536; + int radius = 35; + if (idx > radius && idx <65536-radius) + { + for (int j = idx-radius; j < idx+radius; ++j) + array[j] = array[idx]; + } + } + + // test with 3 random strings of length 10000 + // but use the above array to bias the random numbers + for (int j = 0; j < 3; ++j) + { + print_spinner(); + temp = ""; + //seed2 = static_cast(time(0)); + srand(seed2 ); + for ( int i = 0; i < 10000; ++i) + { + int a = array[::rand()%65536]; + temp += (unsigned char)a; + } + string temp2; + temp2 = test(temp); + if (temp2 != "") + { + + int k = 0; + DLIB_CASSERT(temp != temp2,""); + while (temp[k] == temp2[k])++k; + } + + + DLIB_CASSERT(temp2 == "","") + } + } + + print_spinner(); + + + dlog << LTRACE << 4; + + + + + // test with a large string which contains all the same character + temp = "eeeeeeeeee"; + for (int i = 0; i < 13; ++i) + { + temp = temp + temp; + } + temp = test(temp); + if (temp != "") + { + // crop off all the e's until we find the part that is messed up + string::size_type pos = temp.find_first_not_of("e"); + temp = temp.substr(pos); + } + DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"") /**/ + + + dlog << LTRACE << 5; + + print_spinner(); + + temp = "davis"; + temp = test(temp); DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"") + + temp = ""; + temp = test(temp); DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"") + + // test for each single character + for ( int i = 0; i <= 255; ++i) + { + temp = (unsigned char)i; + temp = test(temp); DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"") + } + + dlog << LTRACE << 6; + + // test with a long string with the same thing repeated many times + temp = "davis "; + for (int i = 0; i < 10; ++i) + { + temp = temp + temp; + } + temp = test(temp); DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"") + + dlog << LTRACE << 7; + + // test with 10 random strings of length 1000 + for (int j = 0; j < 10; ++j) + { + temp = ""; + srand(static_cast(time(0))); + for ( int i = 0; i < 1000; ++i) + { + int a = ::rand()%256; + temp += (unsigned char)a; + } + temp = test(temp); DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"") + } + + + dlog << LTRACE << 8; + + print_spinner(); + + // test with 15 random strings of length 30000 + for (int j = 0; j < 15; ++j) + { + print_spinner(); + temp = ""; + unsigned long seed = static_cast(time(0)); + srand(seed); + for ( int i = 0; i < 30000; ++i) + { + int a = ::rand()%256; + temp += (unsigned char)a; + } + temp = test(temp); DLIB_CASSERT(temp == "","seed: " << seed) + } + + + dlog << LTRACE << 9; + + print_spinner(); + + // test with a large string which contains all the same character + temp = " "; + for (int i = 0; i < 10; ++i) + { + temp = temp + temp; + } + temp = test(temp); + if (temp != "") + { + // crop off all the spacess until we find the part that is messed up + string::size_type pos = temp.find_first_not_of(" "); + temp = temp.substr(pos); + } + DLIB_CASSERT(temp == "","decoded string: \"" << temp << "\"")/**/ + + + + + + + dlog << LTRACE << 10; + + + + + + + // test with a large string which contains a bunch of a's followed by a + // bunch of z's + temp = "aaaaaaaa"; + temp2 = "zzzzzzzz"; + for (int i = 0; i < 12; ++i) + { + temp = temp + temp; + temp2 = temp2 + temp2; + } + temp += temp2; + print_spinner(); + temp = test(temp); + DLIB_CASSERT(temp == "",""); + + + + dlog << LTRACE << 11; + + + + } + + + + + class entropy_coder_tester : public tester + { + public: + entropy_coder_tester ( + ) : + tester ("test_entropy_coder", + "Runs tests on the entropy_coder component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a 1"; + entropy_coder_kernel_test< + entropy_encoder::kernel_1a, + entropy_decoder::kernel_1a + >(); + + dlog << LINFO << "testing kernel_1a_c 2"; + entropy_coder_kernel_test< + entropy_encoder::kernel_1a_c, + entropy_decoder::kernel_1a_c + >(); + + dlog << LINFO << "testing kernel_1a 3"; + entropy_coder_kernel_test< + entropy_encoder::kernel_2a, + entropy_decoder::kernel_2a + >(); + + dlog << LINFO << "testing kernel_1a_c 4"; + entropy_coder_kernel_test< + entropy_encoder::kernel_2a_c, + entropy_decoder::kernel_2a_c + >(); + + dlog << LINFO << "testing kernel_1a 5"; + entropy_coder_kernel_test< + entropy_encoder::kernel_1a, + entropy_decoder::kernel_1a_c + >(); + + dlog << LINFO << "testing kernel_1a_c 6"; + entropy_coder_kernel_test< + entropy_encoder::kernel_1a_c, + entropy_decoder::kernel_1a + >(); + + dlog << LINFO << "testing kernel_1a 7"; + entropy_coder_kernel_test< + entropy_encoder::kernel_2a, + entropy_decoder::kernel_2a_c + >(); + + dlog << LINFO << "testing kernel_1a_c 8"; + entropy_coder_kernel_test< + entropy_encoder::kernel_2a_c, + entropy_decoder::kernel_2a + >(); + + } + } a; + + + + +} + diff --git a/dlib/test/entropy_encoder_model.cpp b/dlib/test/entropy_encoder_model.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ebf6a24cb85da6f2c2a746704199b44e3c6ca652 --- /dev/null +++ b/dlib/test/entropy_encoder_model.cpp @@ -0,0 +1,198 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "tester.h" + +namespace +{ + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.entropy_coder_model"); + + template < + typename ee, + typename ed + > + void entropy_encoder_model_kernel_test ( + ) + /*! + requires + - ee is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h + the alphabet_size for ee is 256 + - ed is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h + the alphabet_size for ed is 256 + - ee and ed must share the same kernel number + ensures + - runs tests on ee and ed for compliance with the specs + !*/ + { + + print_spinner(); + srand(static_cast(time(0))); + + typedef typename ee::entropy_encoder_type ee_type; + typedef typename ed::entropy_decoder_type ed_type; + + + + { + + ee_type ecoder; + ed_type dcoder; + + ee elen(ecoder); + ed dlen(dcoder); + ee elit(ecoder); + ed dlit(dcoder); + + + istringstream sin; + ostringstream sout; + + ecoder.set_stream(sout); + + + unsigned long temp; + + + elen.encode(0); + elit.encode(9); + + elen.encode(0); + elit.encode(0); + + elen.encode(0); + elit.encode(4); + + elen.encode(0); + elit.encode(0); + + elen.encode(0); + elit.encode(2); + + elen.encode(0); + elit.encode(0); + + + + + + + + ecoder.clear(); + sin.str(sout.str()); + dcoder.set_stream(sin); + + + dlen.decode(temp); + DLIB_CASSERT(temp == 0,""); + dlit.decode(temp); + DLIB_CASSERT(temp == 9,""); + + dlen.decode(temp); + DLIB_CASSERT(temp == 0,""); + dlit.decode(temp); + DLIB_CASSERT(temp == 0,""); + + dlen.decode(temp); + DLIB_CASSERT(temp == 0,""); + dlit.decode(temp); + DLIB_CASSERT(temp == 4,""); + + dlen.decode(temp); + DLIB_CASSERT(temp == 0,""); + dlit.decode(temp); + DLIB_CASSERT(temp == 0,""); + + dlen.decode(temp); + DLIB_CASSERT(temp == 0,""); + dlit.decode(temp); + DLIB_CASSERT(temp == 2,""); + + dlen.decode(temp); + DLIB_CASSERT(temp == 0,""); + dlit.decode(temp); + DLIB_CASSERT(temp == 0,""); + + + + + } + + } + + + + + class entropy_encoder_model_tester : public tester + { + public: + entropy_encoder_model_tester ( + ) : + tester ("test_entropy_coder_model", + "Runs tests on the entropy_encoder_model and entropy_decoder_model components.") + {} + + void perform_test ( + ) + { + typedef entropy_encoder::kernel_2a_c ee; + typedef entropy_decoder::kernel_2a_c ed; + + dlog << LINFO << "testing kernel_1a"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_1a, + entropy_decoder_model<256,ed>::kernel_1a>(); + + dlog << LINFO << "testing kernel_2a"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_2a, + entropy_decoder_model<256,ed>::kernel_2a>(); + + dlog << LINFO << "testing kernel_3a"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_3a, + entropy_decoder_model<256,ed>::kernel_3a>(); + + dlog << LINFO << "testing kernel_4a"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_4a, + entropy_decoder_model<256,ed>::kernel_4a>(); + + dlog << LINFO << "testing kernel_4b"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_4b, + entropy_decoder_model<256,ed>::kernel_4b>(); + + dlog << LINFO << "testing kernel_5a"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_5a, + entropy_decoder_model<256,ed>::kernel_5a>(); + + dlog << LINFO << "testing kernel_5c"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_5c, + entropy_decoder_model<256,ed>::kernel_5c>(); + + dlog << LINFO << "testing kernel_6a"; + entropy_encoder_model_kernel_test< + entropy_encoder_model<256,ee>::kernel_6a, + entropy_decoder_model<256,ed>::kernel_6a>(); + + } + } a; + +} + diff --git a/dlib/test/example.cpp b/dlib/test/example.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c72f4b8da555ef34801d07020861dbda699addaf --- /dev/null +++ b/dlib/test/example.cpp @@ -0,0 +1,69 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#include "tester.h" + +// This is called an unnamed-namespace and it has the effect of making everything +// inside this file "private" so that everything you declare will have static linkage. +// Thus we won't have any multiply defined symbol errors coming out of the linker when +// we try to compile the test suite. +namespace +{ + using namespace test; + // Declare the logger we will use in this test. The name of the logger + // should start with "test." + dlib::logger dlog("test.example"); + + + class example_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a unit test. When it is constructed + it adds itself into the testing framework. + !*/ + public: + example_tester ( + ) : + tester ( + "test_example", // the command line argument name for this test + "Run example tests.", // the command line argument description + 0 // the number of command line arguments for this test + ) + {} + + void perform_test ( + ) + { + // This message gets logged to the file debug.txt if the user has enabled logging by + // supplying the -d option on the command line (and they haven't set the logging level + // to something higher than LINFO). + dlog << dlib::LINFO << "some message you want to log"; + + // This test is considered a success if this function doesn't throw an exception. + // So we can use the DLIB_CASSERT macro to perform our tests since it throws an + // exception containing a message if its first argument is false. + + // make sure 3 is bigger than 2 + DLIB_CASSERT(3 > 2,"This message prints if your compiler doesn't know 3 is bigger than 2"); + + // make sure 5 is not equal to 9 + DLIB_CASSERT(5 != 9,"This message prints if your compiler thinks 5 is the same as 9"); + + // If your test takes a long time to run you can also call print_spinner() + // periodically. This will cause a spinning / character to display on the + // console to indicate to the user that your test is still running (rather + // than hung) + print_spinner(); + } + }; + + // Create an instance of this object. Doing this causes this test + // to be automatically inserted into the testing framework whenever this cpp file + // is linked into the project. Note that since we are inside an unnamed-namespace + // we won't get any linker errors about the symbol a being defined multple times. + example_tester a; + +} + + diff --git a/dlib/test/example_args.cpp b/dlib/test/example_args.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18fb317008b7e451fa8d02e71d69c7158825f547 --- /dev/null +++ b/dlib/test/example_args.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#include "tester.h" + +// This is called an unnamed-namespace and it has the effect of making everything +// inside this file "private" so that everything you declare will have static linkage. +// Thus we won't have any multiply defined symbol errors coming out of the linker when +// we try to compile the test suite. +namespace +{ + // Declare the logger we will use in this test. The name of the logger + // should start with "test." + dlib::logger dlog("test.example_args"); + + using namespace test; + + class example_args_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a unit test. When it is constructed + it adds itself into the testing framework. + + This particular test requires the user to supply a command line + argument when they run it. + !*/ + public: + example_args_tester ( + ) : + tester ( + "test_example_args", // the command line argument name for this test + "Run example tests with argument.", // the command line argument description + 1 // the number of command line arguments for this test + ) + {} + + void perform_test ( + const std::string& arg + ) + { + // This message gets logged to the file debug.txt if the user has enabled logging by + // supplying the -d option on the command line (and they haven't set the logging level + // to something higher than LINFO). + dlog << dlib::LINFO << "some message you want to log"; + dlog << dlib::LINFO << "the argument passed to this test was " << arg; + + // This test is considered a success if this function doesn't throw an exception. + // So we can use the DLIB_CASSERT macro to perform our tests since it throws an + // exception containing a message if its first argument is false. + + // make sure 3 is bigger than 2 + DLIB_CASSERT(3 > 2,"This message prints if your compiler doesn't know 3 is bigger than 2"); + + // make sure 5 is not equal to 9 + DLIB_CASSERT(5 != 9,"This message prints if your compiler thinks 5 is the same as 9"); + + // If your test takes a long time to run you can also call print_spinner() + // periodically. This will cause a spinning / character to display on the + // console to indicate to the user that your test is still running (rather + // than hung) + print_spinner(); + } + + }; + + // Create an instance of this object. Doing this causes this test + // to be automatically inserted into the testing framework whenever this cpp file + // is linked into the project. Note that since we are inside an unnamed-namespace + // we won't get any linker errors about the symbol a being defined multiple times. + example_args_tester a; +} + + + diff --git a/dlib/test/geometry.cpp b/dlib/test/geometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef59146276f7d2084f7fb98539082b380dbb8bb0 --- /dev/null +++ b/dlib/test/geometry.cpp @@ -0,0 +1,131 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.geometry"); + + void geometry_test ( + ) + /*! + ensures + - runs tests on the geometry stuff compliance with the specs + !*/ + { + print_spinner(); + + point p1; + point p2(2,3); + + DLIB_CASSERT(p1.x() == 0,""); + DLIB_CASSERT(p1.y() == 0,""); + DLIB_CASSERT(p2.x() == 2,""); + DLIB_CASSERT(p2.y() == 3,""); + + p2 += p2; + DLIB_CASSERT(p2.x() == 4,""); + DLIB_CASSERT(p2.y() == 6,""); + + dlib::vector v1 = point(1,0); + dlib::vector v2(0,0,1); + + p1 = v2.cross(v1); + DLIB_CASSERT(p1 == point(0,1),""); + DLIB_CASSERT(p1 != point(1,1),""); + DLIB_CASSERT(p1 != point(1,0),""); + + p1 = point(2,3); + rectangle rect1 = p1; + DLIB_CASSERT(rect1.width() == 1,""); + DLIB_CASSERT(rect1.height() == 1,""); + p2 = point(1,1); + + rect1 += p2; + DLIB_CASSERT(rect1.left() == 1,""); + DLIB_CASSERT(rect1.top() == 1,""); + DLIB_CASSERT(rect1.right() == 2,""); + DLIB_CASSERT(rect1.bottom() == 3,""); + + DLIB_CASSERT(rect1.width() == 2,""); + DLIB_CASSERT(rect1.height() == 3,""); + + // test the iostream << and >> operators (via string_cast and cast_to_string) + DLIB_CASSERT(string_cast(" (1, 2 )") == point(1,2),""); + DLIB_CASSERT(string_cast(" ( -1, 2 )") == point(-1,2),""); + DLIB_CASSERT(string_cast(" [(1, 2 )(3,4)]") == rectangle(1,2,3,4),""); + DLIB_CASSERT(string_cast >(" (1, 2 , 3.5)") == dlib::vector(1,2,3.5),""); + + DLIB_CASSERT(string_cast(cast_to_string(rect1)) == rect1,""); + DLIB_CASSERT(string_cast(cast_to_string(p1)) == p1,""); + DLIB_CASSERT(string_cast >(cast_to_string(v1)) == v1,""); + + rectangle rect2; + + // test the serialization code + ostringstream sout; + serialize(rect1,sout); + serialize(p1,sout); + serialize(v1,sout); + serialize(rect1,sout); + serialize(p1,sout); + serialize(v1,sout); + + istringstream sin(sout.str()); + + deserialize(rect2,sin); + deserialize(p2,sin); + deserialize(v2,sin); + DLIB_CASSERT(rect2 == rect1,""); + DLIB_CASSERT(p2 == p1,""); + DLIB_CASSERT(v2 == v1,""); + deserialize(rect2,sin); + deserialize(p2,sin); + deserialize(v2,sin); + DLIB_CASSERT(rect2 == rect1,""); + DLIB_CASSERT(p2 == p1,""); + DLIB_CASSERT(v2 == v1,""); + DLIB_CASSERT(sin,""); + DLIB_CASSERT(sin.get() == EOF,""); + + } + + + + + + + class geometry_tester : public tester + { + public: + geometry_tester ( + ) : + tester ("test_geometry", + "Runs tests on the geometry stuff.") + {} + + void perform_test ( + ) + { + geometry_test(); + } + } a; + +} + + + diff --git a/dlib/test/graph.cpp b/dlib/test/graph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f5f22c976e599f5b050856c8a6569cd5d6d86a2 --- /dev/null +++ b/dlib/test/graph.cpp @@ -0,0 +1,359 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" +// so that everything you declare will have static linkage. Thus we won't have any multiply +// defined symbol errors coming out of the linker when we try to compile the test suite. +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + + + // Declare the logger we will use in this test. The name of the tester + // should start with "test." + logger dlog("test.graph"); + + template < + typename graph + > + void graph_test ( + ) + /*! + requires + - graph is an implementation of graph/graph_kernel_abstract.h + is instantiated with int + ensures + - runs tests on graph for compliance with the specs + !*/ + { + + print_spinner(); + + COMPILE_TIME_ASSERT(is_graph::value); + + graph a, b; + set::compare_1b_c s; + + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + DLIB_CASSERT(a.number_of_nodes() == 0,""); + + a.set_number_of_nodes(5); + DLIB_CASSERT(graph_is_connected(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + DLIB_CASSERT(a.number_of_nodes() == 5,""); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + + for (int i = 0; i < 5; ++i) + { + a.node(i).data = i; + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + a.remove_node(1); + + DLIB_CASSERT(a.number_of_nodes() == 4,""); + + + // make sure that only the number with data == 1 was removed + int count = 0; + for (int i = 0; i < 4; ++i) + { + count += a.node(i).data; + DLIB_CASSERT(a.node(i).number_of_neighbors() == 0,""); + DLIB_CASSERT(a.node(i).index() == (unsigned int)i,""); + } + + DLIB_CASSERT(count == 9,""); + + + a.add_edge(1,1); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == true,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + DLIB_CASSERT(a.has_edge(1,1),""); + DLIB_CASSERT(a.node(1).number_of_neighbors() == 1,""); + + a.add_edge(1,3); + DLIB_CASSERT(a.node(1).number_of_neighbors() == 2,""); + DLIB_CASSERT(a.node(2).number_of_neighbors() == 0,""); + DLIB_CASSERT(a.node(3).number_of_neighbors() == 1,""); + DLIB_CASSERT(a.has_edge(1,1),""); + DLIB_CASSERT(a.has_edge(1,3),""); + DLIB_CASSERT(a.has_edge(3,1),""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + a.remove_edge(1,1); + DLIB_CASSERT(graph_contains_length_one_cycle(a) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + DLIB_CASSERT(a.node(1).number_of_neighbors() == 1,""); + DLIB_CASSERT(a.node(2).number_of_neighbors() == 0,""); + DLIB_CASSERT(a.node(3).number_of_neighbors() == 1,""); + DLIB_CASSERT(a.has_edge(1,1) == false,""); + DLIB_CASSERT(a.has_edge(1,3),""); + DLIB_CASSERT(a.has_edge(3,1),""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + swap(a,b); + + + DLIB_CASSERT(graph_contains_undirected_cycle(b) == false,""); + DLIB_CASSERT(b.node(1).number_of_neighbors() == 1,""); + DLIB_CASSERT(b.node(2).number_of_neighbors() == 0,""); + DLIB_CASSERT(b.node(3).number_of_neighbors() == 1,""); + DLIB_CASSERT(b.has_edge(1,1) == false,""); + DLIB_CASSERT(b.has_edge(1,3),""); + DLIB_CASSERT(b.has_edge(3,1),""); + DLIB_CASSERT(graph_contains_undirected_cycle(b) == false,""); + + DLIB_CASSERT(a.number_of_nodes() == 0,""); + DLIB_CASSERT(b.number_of_nodes() == 4,""); + + copy_graph_structure(b,b); + DLIB_CASSERT(b.number_of_nodes() == 4,""); + + b.add_edge(1,2); + DLIB_CASSERT(graph_contains_undirected_cycle(b) == false,""); + DLIB_CASSERT(graph_contains_undirected_cycle(b) == false,""); + b.add_edge(3,2); + DLIB_CASSERT(graph_contains_undirected_cycle(b) == true,""); + b.add_edge(1,1); + DLIB_CASSERT(graph_is_connected(b) == false,""); + b.add_edge(0,2); + DLIB_CASSERT(graph_is_connected(b) == true,""); + + DLIB_CASSERT(graph_contains_undirected_cycle(b) == true,""); + + DLIB_CASSERT(a.number_of_nodes() == 0,""); + + for (unsigned long i = 0; i < b.number_of_nodes(); ++i) + { + for (unsigned long j = 0; j < b.node(i).number_of_neighbors(); ++j) + { + b.node(i).edge(j) = 'c'; + } + } + + b.node(1).edge(0) = 'a'; + const unsigned long e1 = b.node(1).neighbor(0).index(); + b.node(0).edge(0) = 'n'; + const unsigned long e2 = b.node(0).neighbor(0).index(); + + ostringstream sout; + serialize(b, sout); + istringstream sin(sout.str()); + + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + a.set_number_of_nodes(10); + deserialize(a, sin); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + + for (unsigned long i = 0; i < a.number_of_nodes(); ++i) + { + for (unsigned long j = 0; j < a.node(i).number_of_neighbors(); ++j) + { + if (i == 0 && a.node(i).neighbor(j).index() == e2 || + i == e2 && a.node(i).neighbor(j).index() == 0 ) + { + DLIB_CASSERT(a.node(i).edge(j) == 'n',""); + } + else if (i == 1 && a.node(i).neighbor(j).index() == e1 || + i == e1 && a.node(i).neighbor(j).index() == 1) + { + DLIB_CASSERT(a.node(i).edge(j) == 'a',""); + } + else + { + DLIB_CASSERT(i != 0 || a.node(i).neighbor(j).index() != e2,""); + DLIB_CASSERT(a.node(i).edge(j) == 'c',a.node(i).edge(j)); + } + } + } + + DLIB_CASSERT(a.number_of_nodes() == 4,""); + DLIB_CASSERT(a.has_edge(1,2) == true,""); + DLIB_CASSERT(a.has_edge(3,2) == true,""); + DLIB_CASSERT(a.has_edge(1,1) == true,""); + DLIB_CASSERT(a.has_edge(0,2) == true,""); + DLIB_CASSERT(a.has_edge(1,3) == true,""); + DLIB_CASSERT(a.has_edge(0,1) == false,""); + DLIB_CASSERT(a.has_edge(0,3) == false,""); + DLIB_CASSERT(a.has_edge(0,0) == false,""); + DLIB_CASSERT(a.has_edge(1,0) == false,""); + DLIB_CASSERT(a.has_edge(3,0) == false,""); + + + for (unsigned long i = 0; i < a.number_of_nodes(); ++i) + { + a.node(i).data = static_cast(i); + } + + a.remove_node(2); + DLIB_CASSERT(a.number_of_nodes() == 3,""); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + + count = 0; + for (unsigned long i = 0; i < a.number_of_nodes(); ++i) + { + if (a.node(i).data == 0) + { + DLIB_CASSERT(a.node(i).number_of_neighbors() == 0,""); + } + else if (a.node(i).data == 1) + { + DLIB_CASSERT(a.node(i).number_of_neighbors() == 2,""); + } + else if (a.node(i).data == 3) + { + DLIB_CASSERT(a.node(i).number_of_neighbors() == 1,""); + } + else + { + DLIB_CASSERT(false,"this is impossible"); + } + + for (unsigned long j = 0; j < a.number_of_nodes(); ++j) + { + if (a.node(i).data == 1 && a.node(j).data == 1 || + a.node(i).data == 1 && a.node(j).data == 3 || + a.node(i).data == 3 && a.node(j).data == 1) + { + DLIB_CASSERT(a.has_edge(i,j) == true,""); + ++count; + } + else + { + DLIB_CASSERT(a.has_edge(i,j) == false,""); + } + } + } + DLIB_CASSERT(count == 3,count); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == true,""); + a.remove_edge(1,1); + DLIB_CASSERT(graph_contains_undirected_cycle(a) == false,""); + + DLIB_CASSERT(b.number_of_nodes() == 4,""); + b.clear(); + DLIB_CASSERT(b.number_of_nodes() == 0,""); + + + a.clear(); + + /* + 1 7 + | / \ + 2 6 0 + \ / | + 3 / + / \ / + 4 5 + */ + a.set_number_of_nodes(8); + a.add_edge(1,2); + a.add_edge(2,3); + a.add_edge(3,4); + a.add_edge(3,5); + a.add_edge(3,6); + a.add_edge(6,7); + a.add_edge(7,0); + a.add_edge(0,5); + + DLIB_CASSERT(graph_is_connected(a),""); + + set::compare_1b_c>::kernel_1b_c sos; + + dlib::graph::compare_1b_c, set::compare_1b_c>::kernel_1a_c join_tree; + unsigned long temp; + triangulate_graph_and_find_cliques(a,sos); + DLIB_CASSERT(a.number_of_nodes() == 8,""); + + create_join_tree(a, join_tree); + DLIB_CASSERT(join_tree.number_of_nodes() == 6,""); + DLIB_CASSERT(graph_is_connected(join_tree) == true,""); + DLIB_CASSERT(graph_contains_undirected_cycle(join_tree) == false,""); + DLIB_CASSERT(is_join_tree(a, join_tree),""); + + // check old edges + DLIB_CASSERT(a.has_edge(1,2),""); + DLIB_CASSERT(a.has_edge(2,3),""); + DLIB_CASSERT(a.has_edge(3,4),""); + DLIB_CASSERT(a.has_edge(3,5),""); + DLIB_CASSERT(a.has_edge(3,6),""); + DLIB_CASSERT(a.has_edge(6,7),""); + DLIB_CASSERT(a.has_edge(7,0),""); + DLIB_CASSERT(a.has_edge(0,5),""); + + DLIB_CASSERT(graph_is_connected(a),""); + + DLIB_CASSERT(sos.size() == 6,""); + + + temp = 1; s.add(temp); + temp = 2; s.add(temp); + DLIB_CASSERT(sos.is_member(s),""); + s.clear(); + temp = 2; s.add(temp); + temp = 3; s.add(temp); + DLIB_CASSERT(sos.is_member(s),""); + s.clear(); + temp = 4; s.add(temp); + temp = 3; s.add(temp); + DLIB_CASSERT(sos.is_member(s),""); + + sos.reset(); + while (sos.move_next()) + { + DLIB_CASSERT(is_clique(a, sos.element()),""); + DLIB_CASSERT(is_maximal_clique(a, sos.element()),""); + } + + } + + + + + + class graph_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a test for the graph object. When it is constructed + it adds itself into the testing framework. The command line switch is + specified as test_directed_graph by passing that string to the tester constructor. + !*/ + public: + graph_tester ( + ) : + tester ("test_graph", + "Runs tests on the graph component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a_c"; + graph_test::kernel_1a_c>(); + + dlog << LINFO << "testing kernel_1a"; + graph_test::kernel_1a>(); + } + } a; + + +} + + + diff --git a/dlib/test/gui/CMakeLists.txt b/dlib/test/gui/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3149f88e2d9112369ebc2460eb3ab686d2b1a87 --- /dev/null +++ b/dlib/test/gui/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# + +# create a variable called target_name and set it to the string "test" +set (target_name gui) + +PROJECT(${target_name}) + +# add all the cpp files we want to compile to this list. This tells +# cmake that they are part of our target (which is the executable named test) +ADD_EXECUTABLE(${target_name} main.cpp ) + +# add the folder containing the dlib folder to the include path +INCLUDE_DIRECTORIES(../../..) + +# There is a CMakeLists.txt file in the dlib source folder that tells cmake +# how to build the dlib library. Tell cmake about that file. + + +# Tell cmake to link our target executable to the non-gui version of the dlib +# library. +TARGET_LINK_LIBRARIES(${target_name} dlib ) + diff --git a/dlib/test/gui/main.cpp b/dlib/test/gui/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24a17f4d89e06bf507d7a4300d3895634ef57fd0 --- /dev/null +++ b/dlib/test/gui/main.cpp @@ -0,0 +1,737 @@ +#include "dlib/image_io.h" +#include "dlib/array2d.h" +#include "dlib/gui_core.h" +#include "dlib/assert.h" +#include "dlib/misc_api.h" +#include +#include "dlib/image_transforms.h" + +#include "dlib/timer.h" + +#include "dlib/gui_widgets.h" +#include "dlib/queue.h" +#include +#include +#include + +using namespace dlib; +using namespace std; + + +typedef dlib::array2d::kernel_1a_c image; + + + + +#include "dlib/base64.h" + + + + +class color_box : public dragable +{ + unsigned char red, green,blue; + +public: + color_box ( + drawable_window& w, + rectangle area, + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) : + dragable(w), + red(red_), + green(green_), + blue(blue_), + t(*this,&color_box::action) + { + rect = area; + + t.set_delay_time(4); + // t.start(); + + set_dragable_area(rectangle(10,10,500,500)); + + enable_events(); + } + + ~color_box() + { + disable_events(); + } + +private: + + void action ( + ) + { + ++red; + parent.invalidate_rectangle(rect); + } + + void draw ( + const canvas& c + ) const + { + if (hidden == false ) + { + fill_rect(c,rect,rgb_pixel(red,green,blue)); + } + } + + + void on_window_resized () + { + dragable::on_window_resized(); + } + timer::kernel_1a t; +}; + + + + + + +class win : public drawable_window +{ + + label lbl_last_keydown; + label lbl_mod_shift; + label lbl_mod_control; + label lbl_mod_alt; + label lbl_mod_meta; + label lbl_mod_caps_lock; + label lbl_mod_num_lock; + label lbl_mod_scroll_lock; + void on_keydown ( + unsigned long key, + bool is_printable, + unsigned long state + ) + { + if (is_printable) + lbl_last_keydown.set_text(string("last keydown: ") + (char)key); + else + lbl_last_keydown.set_text(string("last keydown: nonprintable")); + + if (state&base_window::KBD_MOD_SHIFT) + lbl_mod_shift.set_text("shift is on"); + else + lbl_mod_shift.set_text("shift is off"); + + if (state&base_window::KBD_MOD_CONTROL) + lbl_mod_control.set_text("control is on"); + else + lbl_mod_control.set_text("control is off"); + + if (state&base_window::KBD_MOD_ALT) + lbl_mod_alt.set_text("alt is on"); + else + lbl_mod_alt.set_text("alt is off"); + + + if (state&base_window::KBD_MOD_META) + lbl_mod_meta.set_text("meta is on"); + else + lbl_mod_meta.set_text("meta is off"); + + if (state&base_window::KBD_MOD_CAPS_LOCK) + lbl_mod_caps_lock.set_text("caps_lock is on"); + else + lbl_mod_caps_lock.set_text("caps_lock is off"); + + if (state&base_window::KBD_MOD_NUM_LOCK) + lbl_mod_num_lock.set_text("num_lock is on"); + else + lbl_mod_num_lock.set_text("num_lock is off"); + + + if (state&base_window::KBD_MOD_SCROLL_LOCK) + lbl_mod_scroll_lock.set_text("scroll_lock is on"); + else + lbl_mod_scroll_lock.set_text("scroll_lock is off"); + + drawable_window::on_keydown(key,is_printable,state); + } + + void rb_click ( + ) + { + if (rb.is_checked()) + rb.set_name("radio button checked"); + else + rb.set_name("radio button"); + rb.set_checked(); + } + + void cb_sb_enabled ( + toggle_button& + ) + { + if (sb_enabled.is_checked()) + { + sb.enable(); + lb.enable(); + b.enable(); + } + else + { + lb.disable(); + sb.disable(); + b.disable(); + } + + if (sb_enabled.is_checked()) + rb.enable(); + else + rb.disable(); + + if (sb_enabled.is_checked()) + tabs.enable(); + else + tabs.disable(); + + if (sb_enabled.is_checked()) + tf.enable(); + else + tf.disable(); + + } + + void cb_sb_shown ( + ) + { + if (sb_shown.is_checked()) + { + sb.show(); + tabs.show(); + lb.show(); + } + else + { + sb.hide(); + tabs.hide(); + lb.hide(); + } + } + + + void tab_change ( + unsigned long new_idx, + unsigned long old_idx + ) + { + tab_label.set_text(tabs.tab_name(new_idx)); + } + + void scroll_handler ( + ) + { + ostringstream sout; + sout << "scroll bar pos: " << sb.slider_pos(); + sbl.set_text(sout.str()); + } + + void scroll2_handler ( + ) + { + sb.set_length(sb2.slider_pos()); + ostringstream sout; + sout << "scroll bar2 pos: " << sb2.slider_pos(); + sbl2.set_text(sout.str()); + scroll_handler(); + } + + void scroll3_handler ( + ) + { + sb.set_max_slider_pos(sb3.slider_pos()); + ostringstream sout; + sout << "scroll bar3 pos: " << sb3.slider_pos(); + sbl3.set_text(sout.str()); + scroll_handler(); + } + + void lb_double_click ( + unsigned long idx + ) + { + dlib::queue::kernel_2a_c sel; + lb.get_selected(sel); + sel.reset(); + while (sel.move_next()) + { + cout << lb[sel.element()] << endl; + } + //message_box("list_box",lb[idx]); + } + + void msg_box ( + ) + { + message_box("title","you clicked the ok button!\n HURRAY!"); + } + + static void try_this_junk ( + void* param + ) + { + win& p = *reinterpret_cast(param); + put_on_clipboard(p.tf.text() + "\nfoobar"); + + + } + + void on_set_clipboard ( + ) + { + create_new_thread(try_this_junk,this); + //try_this_junk(this); + } + + static void try_this_junk2 ( + void* param + ) + { + + string temp; + get_from_clipboard(temp); + message_box("clipboard",temp); + + } + void on_get_clipboard ( + ) + { + create_new_thread(try_this_junk2,this); + } + + + void on_show_msg_click ( + ) + { + message_box("title","This is a test message.",*this,&win::msg_box); + } + + void on_menu_help ( + ) + { + message_box("About","This is the messy dlib gui regression test program"); + } + +public: + + ~win() + { + close_window(); + } + + void cbox_clicked ( + ) + { + if (cbox.is_checked()) + cbl.set_text(cbox.name() + " box is checked"); + else + cbl.set_text("box NOT is checked"); + } + + win ( + ): + drawable_window(true), + lbl_last_keydown(*this), + lbl_mod_shift(*this), + lbl_mod_control(*this), + lbl_mod_alt(*this), + lbl_mod_meta(*this), + lbl_mod_caps_lock(*this), + lbl_mod_num_lock(*this), + lbl_mod_scroll_lock(*this), + b(*this), + btn_count(*this), + btn_get_clipboard(*this), + btn_set_clipboard(*this), + btn_show_message(*this), + cb1(*this,rectangle(100,100,200,200),255,0,0), + cb2(*this,rectangle(150,150,250,240),0,255,0), + cbl(*this), + cbox(*this), + group1(*this), + group2(*this), + group3(*this), + keyboard_count(1), + keydown(*this), + keyup(*this), + l1(*this), + l2(*this), + l3(*this), + lb(*this), + leave_count(*this), + left_down(*this), + left_up(*this), + middle_down(*this), + middle_up(*this), + mouse_state(*this), + mt(*this), + nrect(*this), + pos(*this), + rb(*this), + right_down(*this), + right_up(*this), + sb2(*this,scroll_bar::VERTICAL), + sb3(*this,scroll_bar::VERTICAL), + sb_enabled(*this), + sbl2(*this), + sbl3(*this), + sbl(*this), + sb_shown(*this), + sb(*this,scroll_bar::HORIZONTAL), + scroll(*this), + tab_label(*this), + tabs(*this), + tf(*this), + mbar(*this) + { + bool use_bdf_fonts = false; + + + if (use_bdf_fonts) + { + ifstream fin("/home/davis/source/10x20.bdf"); + f.read_bdf_file(fin,0xFFFF); + + mt.set_main_font(&f); + } + //mt.hide(); + mt.set_pos(5,200); + + + lbl_last_keydown.set_text("?"); + lbl_mod_shift.set_text("?"); + lbl_mod_control.set_text("?"); + lbl_mod_alt.set_text("?"); + lbl_mod_meta.set_text("?"); + lbl_mod_caps_lock.set_text("?"); + lbl_mod_num_lock.set_text("?"); + lbl_mod_scroll_lock.set_text("?"); + + lbl_last_keydown.set_pos(20,420); + lbl_mod_shift.set_pos(20,lbl_last_keydown.bottom()+5); + lbl_mod_control.set_pos(20,lbl_mod_shift.bottom()+5); + lbl_mod_alt.set_pos(20,lbl_mod_control.bottom()+5); + lbl_mod_meta.set_pos(20,lbl_mod_alt.bottom()+5); + lbl_mod_caps_lock.set_pos(20,lbl_mod_meta.bottom()+5); + lbl_mod_num_lock.set_pos(20,lbl_mod_caps_lock.bottom()+5); + lbl_mod_scroll_lock.set_pos(20,lbl_mod_num_lock.bottom()+5); + + lb.set_pos(580,200); + lb.set_size(200,300); + if (use_bdf_fonts) + lb.set_main_font(&f); + + dlib::queue::kernel_2a_c qos; + string a; + a = "Davis"; qos.enqueue(a); + a = "king"; qos.enqueue(a); + a = "one"; qos.enqueue(a); + a = "two"; qos.enqueue(a); + a = "three"; qos.enqueue(a); + a = "yo yo yo alsdkjf asfj lsa jfsf\n this is a long phrase"; qos.enqueue(a); + a = "four"; qos.enqueue(a); + a = "five"; qos.enqueue(a); + a = "six"; qos.enqueue(a); + a = "seven"; qos.enqueue(a); + a = "eight"; qos.enqueue(a); + a = "nine"; qos.enqueue(a); + a = "ten"; qos.enqueue(a); + a = "eleven"; qos.enqueue(a); + a = "twelve"; qos.enqueue(a); + for (int i = 0; i < 1000; ++i) + { + a = "thirteen"; qos.enqueue(a); + } + lb.load(qos); + lb.select(1); + lb.select(2); + lb.select(3); + lb.select(5); + lb.enable_multiple_select(); + lb.set_double_click_handler(*this,&win::lb_double_click); + // lb.disable_multiple_select(); + + btn_show_message.set_pos(50,350); + btn_show_message.set_name("message_box()"); + mbar.set_number_of_menus(2); + mbar.set_menu_name(0,"File",'F'); + mbar.set_menu_name(1,"Help",'H'); + mbar.menu(0).add_menu_item(menu_item_text("show msg click",*this,&win::on_show_msg_click,'s')); + mbar.menu(0).add_menu_item(menu_item_text("get clipboard",*this,&win::on_get_clipboard,'g')); + mbar.menu(0).add_menu_item(menu_item_text("set clipboard",*this,&win::on_set_clipboard,'c')); + mbar.menu(0).add_menu_item(menu_item_separator()); + mbar.menu(0).add_submenu(menu_item_submenu("submenu",'m'), submenu); + submenu.add_menu_item(menu_item_separator()); + submenu.add_menu_item(menu_item_separator()); + submenu.add_menu_item(menu_item_text("show msg click",*this,&win::on_show_msg_click,'s')); + submenu.add_menu_item(menu_item_text("get clipboard",*this,&win::on_get_clipboard,'g')); + submenu.add_menu_item(menu_item_text("set clipboard",*this,&win::on_set_clipboard,'c')); + submenu.add_menu_item(menu_item_separator()); + submenu.add_menu_item(menu_item_separator()); + mbar.menu(1).add_menu_item(menu_item_text("About",*this,&win::on_menu_help,'A')); + + btn_show_message.set_click_handler(*this,&win::on_show_msg_click); + btn_get_clipboard.set_pos(btn_show_message.right()+5,btn_show_message.top()); + btn_get_clipboard.set_name("get_from_clipboard()"); + btn_get_clipboard.set_click_handler(*this,&win::on_get_clipboard); + + btn_get_clipboard.set_style(button_style_toolbar1()); + btn_set_clipboard.set_pos(btn_get_clipboard.right()+5,btn_get_clipboard.top()); + btn_set_clipboard.set_name("put_on_clipboard()"); + btn_set_clipboard.set_click_handler(*this,&win::on_set_clipboard); + + nrect.set_size(700,500); + nrect.set_name("test widgets"); + nrect.set_pos(2,mbar.bottom()+2); + + //throw dlib::error("holy crap batman"); + tab_label.set_pos(10,440); + + tabs.set_click_handler(*this,&win::tab_change); + tabs.set_pos(5,mbar.bottom()+10); + tabs.set_size(280,100); + tabs.set_number_of_tabs(3); + tabs.set_tab_name(0,"davis"); + tabs.set_tab_name(1,"edward"); + tabs.set_tab_name(2,"king alsklsdkfj asfd"); + tabs.set_tab_group(0,group1); + tabs.set_tab_group(1,group2); + tabs.set_tab_group(2,group3); + + l1.set_text("group one"); + l2.set_text("group two"); + l3.set_text("group three"); + + group1.add(l1,0,0); + group2.add(l2,20,10); + group3.add(l3,0,0); + + + + sb_enabled.set_name("enabled"); + sb_shown.set_name("shown"); + sb_shown.set_checked(); + sb_enabled.set_checked(); + sb_shown.set_click_handler(*this,&win::cb_sb_shown); + sb_enabled.set_click_handler(*this,&win::cb_sb_enabled); + + sb_shown.set_tooltip_text("I'm a checkbox"); + + rb.set_click_handler(*this,&win::rb_click); + + + sb3.set_pos(440,mbar.bottom()+10); + sb3.set_max_slider_pos(300); + sb3.set_slider_pos(150); + sb3.set_length(300); + sb2.set_pos(470,mbar.bottom()+10); + sb2.set_max_slider_pos(300); + sb2.set_length(300); + sb.set_pos(500,mbar.bottom()+10); + sb.set_max_slider_pos(30); + sb.set_length(300); + + + sb.set_scroll_handler(*this,&win::scroll_handler); + sb2.set_scroll_handler(*this,&win::scroll2_handler); + sb3.set_scroll_handler(*this,&win::scroll3_handler); + sbl.set_pos(540,mbar.bottom()+20); + sbl2.set_pos(540,mbar.bottom()+40); + sbl3.set_pos(540,mbar.bottom()+60); + + cbox.set_pos(300,mbar.bottom()+30); + cbox.set_name("davis king"); + cbox.set_click_handler(*this,&win::cbox_clicked); + + cbl.set_pos(300,cbox.get_rect().bottom()+1); + cbox.set_checked(); + sb_enabled.set_pos(cbox.get_rect().left(),cbox.get_rect().bottom()+20); + sb_shown.set_pos(sb_enabled.get_rect().left(),sb_enabled.get_rect().bottom()+2); + + + + if (use_bdf_fonts) + rb.set_main_font(&f); + rb.set_name("radio button"); + rb.set_pos(sb_shown.get_rect().left(),sb_shown.get_rect().bottom()+2); + + + cb1.set_z_order(10); + cb2.set_z_order(20); + + pos.set_pos(50,50); + left_up.set_pos(50,70); + left_down.set_pos(50,90); + middle_up.set_pos(50,110); + middle_down.set_pos(50,130); + right_up.set_pos(50,150); + right_down.set_pos(50,170); + + mouse_state.set_pos(50,190); + + leave_count.set_pos(50,210); + + scroll_count = 0; + scroll.set_pos(50,230); + + btn_count.set_pos(50,250); + + + keydown.set_pos(50,270); + keyup.set_pos(50,290); + + tf.set_pos(50,310); + tf.set_text("Davis685g@"); + tf.set_width(500); + tf.set_text_color(rgb_pixel(255,0,0)); + + + button_count = 0; + count = 0; + b.set_name("button"); + b.set_pos(540,100); + b.set_click_handler(*this,&win::on_click); + b.set_tooltip_text("hurray i'm a button!"); + if (use_bdf_fonts) + b.set_main_font(&f); + + + set_size(800,500); + + nrect.wrap_around( + cbox.get_rect() + + rb.get_rect() + + sb_enabled.get_rect() + + sb_shown.get_rect()); + + flip = 0; + open_file_box(*this,&win::on_open_file); + open_existing_file_box(*this,&win::on_open_file); + save_file_box(*this,&win::on_open_file); + + if (use_bdf_fonts) + tf.set_main_font(&f); + if (use_bdf_fonts) + tabs.set_main_font(&f); + + } + +private: + + void on_open_file (const std::string& file) + { + message_box("file opened",file); + } + + + void on_click ( + ) + { + ostringstream sout; + sout << "text field: " << tf.text(); + ++button_count; + btn_count.set_text(sout.str()); + + if (flip == 0) + { + flip = 1; + lb.set_size(200,200); + } + else if (flip == 1) + { + flip = 2; + lb.set_size(150,200); + } + else if (flip == 2) + { + flip = 3; + lb.set_size(150,300); + } + else + { + flip = 0; + lb.set_size(200,300); + } + } + + + button b; + label btn_count; + button btn_get_clipboard; + button btn_set_clipboard; + button btn_show_message; + int button_count; + color_box cb1; + color_box cb2; + label cbl; + check_box cbox; + int count; + bdf_font f; + int flip; + widget_group group1; + widget_group group2; + widget_group group3; + int keyboard_count; + label keydown; + label keyup; + label l1; + label l2; + label l3; + list_box lb; + label leave_count; + label left_down; + label left_up; + label middle_down; + label middle_up; + label mouse_state; + mouse_tracker mt; + named_rectangle nrect; + label pos; + radio_button rb; + label right_down; + label right_up; + scroll_bar sb2; + scroll_bar sb3; + check_box sb_enabled; + label sbl2; + label sbl3; + label sbl; + check_box sb_shown; + scroll_bar sb; + int scroll_count; + label scroll; + label tab_label; + tabbed_display tabs; + text_field tf; + menu_bar mbar; + popup_menu submenu; + +}; + + + +int main() +{ + + try + { + win w; + w.set_pos (100,200); + w.set_title("test window"); + w.show(); + + w.wait_until_closed(); + } + catch (exception& e) + { + cout << e.what() << endl; + } + +} diff --git a/dlib/test/hash_map.cpp b/dlib/test/hash_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c7c7c4f9940bbb3f7279a6ebab7661efc44ed34 --- /dev/null +++ b/dlib/test/hash_map.cpp @@ -0,0 +1,450 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.hash_map"); + + template < + typename hash_map + > + void hash_map_kernel_test ( + ) + /*! + requires + - hash_map is an implementation of hash_map/hash_map_kernel_abstract.h and + is instantiated to map int to int + ensures + - runs tests on hash_map for compliance with the specs + !*/ + { + + srand(static_cast(time(0))); + + print_spinner(); + + + hash_map test, test2; + + enumerable >& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + for (int j = 0; j < 4; ++j) + { + print_spinner(); + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + + + int a,b; + a = 8; + b = 94; + test.add(a,b); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(test.is_in_domain(8) == true,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + DLIB_CASSERT(test[8] == 94,""); + a = 53; + b = 4; + test.add(a,b); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test.is_in_domain(53) == true,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + DLIB_CASSERT(test[53] == 4,""); + + + swap(test,test2); + + + DLIB_CASSERT(test2.size() == 2,test2.size()); + DLIB_CASSERT(test2.is_in_domain(8) == true,""); + DLIB_CASSERT(test2.is_in_domain(5) == false,""); + DLIB_CASSERT(test2.is_in_domain(0) == false,""); + DLIB_CASSERT(test2.is_in_domain(-999) == false,""); + DLIB_CASSERT(test2.is_in_domain(4999) == false,""); + DLIB_CASSERT(test2[8] == 94,""); + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(test2.is_in_domain(53) == true,""); + DLIB_CASSERT(test2.is_in_domain(5) == false,""); + DLIB_CASSERT(test2.is_in_domain(0) == false,""); + DLIB_CASSERT(test2.is_in_domain(-999) == false,""); + DLIB_CASSERT(test2.is_in_domain(4999) == false,""); + DLIB_CASSERT(test2[53] == 4,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_in_domain(8) == false,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_in_domain(53) == false,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + + + test.clear(); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + DLIB_CASSERT(test.size() == 10000,""); + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + DLIB_CASSERT(test.size() == 10000,""); + + int count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.element().value() == test.element().value(),""); + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.element().value() == test.element().value(),""); + + + + ++count; + } + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + DLIB_CASSERT(count == 10000,""); + + test.swap(test2); + + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test2.size() == 10000,""); + count = 0; + test2.reset(); + + test2.move_next(); + test2.element().value() = 99; + DLIB_CASSERT(test2[test2.element().key()] == 99,""); + DLIB_CASSERT(test2.element().value() == 99,""); + + test2.reset(); + + while (test2.move_next()) + { + DLIB_CASSERT(test2[test2.element().key()] == test2.element().value(),""); + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(test2.element().value() == test2.element().value(),""); + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(test2.element().value() == test2.element().value(),""); + + ++count; + } + DLIB_CASSERT(test2.size() == 10000,""); + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + + + test2.clear(); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.at_start() == true,""); + + while (test.size() < 20000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + DLIB_CASSERT(test.at_start() == true,""); + + { + int* array1 = new int[test.size()]; + int* array2 = new int[test.size()]; + + int* tmp1 = array1; + int* tmp2 = array2; + + + + // serialize the state of test, then clear test, then + // load the state back into test. + ostringstream sout; + serialize(test,sout); + DLIB_CASSERT(test.at_start() == true,""); + istringstream sin(sout.str()); + test.clear(); + deserialize(test,sin); + DLIB_CASSERT(test.at_start() == true,""); + + + count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.element().value() == test.element().value(),""); + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.current_element_valid() == true,""); + *tmp1 = test.element().key(); + *tmp2 = test.element().value(); + ++tmp1; + ++tmp2; + ++count; + } + DLIB_CASSERT(count == 20000,""); + + tmp1 = array1; + tmp2 = array2; + for (int i = 0; i < 20000; ++i) + { + DLIB_CASSERT(test.is_in_domain(*tmp1) == true,""); + DLIB_CASSERT(test[*tmp1] == *tmp2,""); + ++tmp1; + ++tmp2; + } + + DLIB_CASSERT(test.size() == 20000,""); + + tmp1 = array1; + tmp2 = array2; + count = 0; + while (test.size() > 10000) + { + test.remove(*tmp1,a,b); + DLIB_CASSERT(*tmp1 == a,""); + DLIB_CASSERT(*tmp2 == b,""); + ++tmp1; + ++tmp2; + ++count; + } + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.move_next()) + { + DLIB_CASSERT(test.element().key() == *tmp1,""); + DLIB_CASSERT(test.element().key() == *tmp1,""); + DLIB_CASSERT(test.element().key() == *tmp1,""); + DLIB_CASSERT(test.element().value() == *tmp2,""); + DLIB_CASSERT(test.element().value() == *tmp2,""); + DLIB_CASSERT(test.element().value() == *tmp2,""); + ++tmp1; + ++tmp2; + ++count; + } + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.size() < 20000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + test2.swap(test); + + count = 0; + while (test2.move_next()) + { + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(test2.element().value() == test2.element().value(),""); + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + + ++count; + } + + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test2.size() == 20000,""); + + int c = 0; + while (test2.size()>0) + { + test2.remove_any(b,c); + + } + + DLIB_CASSERT(test2.size() == 0,""); + delete [] array1; + delete [] array2; + } + + test.clear(); + test2.clear(); + while (test.size() < 10000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + count = 0; + while (test.move_next()) + { + + DLIB_CASSERT(test[test.element().key()] == test.element().value(),""); + + ++count; + if (count == 5000) + break; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + test.reset(); + + count = 0; + + while (test.move_next()) + { + + ++count; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + DLIB_CASSERT(count == 10000,""); + + + test.clear(); + test2.clear(); + } + + + + + { + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + int a = 5; + int b = 6; + test.add(a,b); + a = 7; + b = 8; + test.add(a,b); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test[7] == 8,""); + DLIB_CASSERT(test[5] == 6,""); + DLIB_CASSERT(test.is_in_domain(7),""); + DLIB_CASSERT(test.is_in_domain(5),""); + test.destroy(7); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(!test.is_in_domain(7),""); + DLIB_CASSERT(test.is_in_domain(5),""); + test.destroy(5); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(!test.is_in_domain(7),""); + DLIB_CASSERT(!test.is_in_domain(5),""); + } + + + + } + + + + + + class hash_map_tester : public tester + { + public: + hash_map_tester ( + ) : + tester ("test_hash_map", + "Runs tests on the hash_map component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + hash_map_kernel_test::kernel_1a>(); + + dlog << LINFO << "testing kernel_1b_c"; + hash_map_kernel_test::kernel_1a_c>(); + + dlog << LINFO << "testing kernel_1b"; + hash_map_kernel_test::kernel_1b>(); + + dlog << LINFO << "testing kernel_1a_c"; + hash_map_kernel_test::kernel_1b_c>(); + + dlog << LINFO << "testing kernel_1c"; + hash_map_kernel_test::kernel_1c>(); + + dlog << LINFO << "testing kernel_1c_c"; + hash_map_kernel_test::kernel_1c_c>(); + } + } a; + +} + diff --git a/dlib/test/hash_set.cpp b/dlib/test/hash_set.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c870b9d30901804afa38ee0d28a2d8b9d176857 --- /dev/null +++ b/dlib/test/hash_set.cpp @@ -0,0 +1,387 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.hash_set"); + + template < + typename hash_set + > + void hash_set_kernel_test ( + ) + /*! + requires + - hash_set is an implementation of hash_set/hash_set_kernel_abstract.h and + is instantiated with int + ensures + - runs tests on hash_set for compliance with the specs + !*/ + { + + + srand(static_cast(time(0))); + + + print_spinner(); + + hash_set test, test2; + + + enumerable& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + + for (int j = 0; j < 4; ++j) + { + print_spinner(); + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + + + int a,b = 0; + a = 8; + test.add(a); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(test.is_member(8) == true,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + a = 53; + test.add(a); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test.is_member(53) == true,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + + + swap(test,test2); + + + + DLIB_CASSERT(test2.is_member(8) == true,""); + DLIB_CASSERT(test2.is_member(5) == false,""); + DLIB_CASSERT(test2.is_member(0) == false,""); + DLIB_CASSERT(test2.is_member(-999) == false,""); + DLIB_CASSERT(test2.is_member(4999) == false,""); + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(test2.is_member(53) == true,""); + DLIB_CASSERT(test2.is_member(5) == false,""); + DLIB_CASSERT(test2.is_member(0) == false,""); + DLIB_CASSERT(test2.is_member(-999) == false,""); + DLIB_CASSERT(test2.is_member(4999) == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_member(8) == false,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_member(53) == false,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + + + test.clear(); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + DLIB_CASSERT(test.size() == 10000,""); + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + DLIB_CASSERT(test.size() == 10000,""); + + int count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + + + ++count; + } + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + DLIB_CASSERT(count == 10000,""); + + test.swap(test2); + + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test2.size() == 10000,""); + count = 0; + test2.reset(); + while (test2.move_next()) + { + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + + ++count; + } + DLIB_CASSERT(test2.size() == 10000,""); + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + + + test2.clear(); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.at_start() == true,""); + + while (test.size() < 20000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + DLIB_CASSERT(test.at_start() == true,""); + + { + int* array = new int[test.size()]; + int* tmp = array; + + // serialize the state of test, then clear test, then + // load the state back into test. + ostringstream sout; + serialize(test,sout); + DLIB_CASSERT(test.at_start() == true,""); + istringstream sin(sout.str()); + test.clear(); + deserialize(test,sin); + + + + count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + *tmp = test.element(); + ++tmp; + ++count; + } + DLIB_CASSERT(count == 20000,""); + + tmp = array; + for (int i = 0; i < 20000; ++i) + { + DLIB_CASSERT(test.is_member(*tmp) == true,""); + ++tmp; + } + + DLIB_CASSERT(test.size() == 20000,""); + + tmp = array; + count = 0; + while (test.size() > 10000) + { + test.remove(*tmp,a); + DLIB_CASSERT(*tmp == a,""); + ++tmp; + ++count; + } + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.move_next()) + { + ++count; + } + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.size() < 20000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + test2.swap(test); + + count = 0; + while (test2.move_next()) + { + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + + ++count; + } + + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test2.size() == 20000,""); + + + while (test2.size()>0) + { + test2.remove_any(b); + } + + DLIB_CASSERT(test2.size() == 0,""); + delete [] array; + } + + test.clear(); + test2.clear(); + while (test.size() < 10000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + count = 0; + while (test.move_next()) + { + ++count; + if (count == 5000) + break; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + test.reset(); + + count = 0; + while (test.move_next()) + { + ++count; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + DLIB_CASSERT(count == 10000,""); + + + test.clear(); + test2.clear(); + } + + + { + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + int a = 5; + test.add(a); + a = 7; + test.add(a); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test.is_member(7),""); + DLIB_CASSERT(test.is_member(5),""); + test.destroy(7); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(!test.is_member(7),""); + DLIB_CASSERT(test.is_member(5),""); + test.destroy(5); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(!test.is_member(7),""); + DLIB_CASSERT(!test.is_member(5),""); + } + + } + + + + + class hash_set_tester : public tester + { + public: + hash_set_tester ( + ) : + tester ("test_hash_set", + "Runs tests on the hash_set component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + hash_set_kernel_test::kernel_1a>(); + dlog << LINFO << "testing kernel_1a_c"; + hash_set_kernel_test::kernel_1a_c>(); + dlog << LINFO << "testing kernel_1b"; + hash_set_kernel_test::kernel_1b>(); + dlog << LINFO << "testing kernel_1b_c"; + hash_set_kernel_test::kernel_1b_c>(); + dlog << LINFO << "testing kernel_1c"; + hash_set_kernel_test::kernel_1c>(); + dlog << LINFO << "testing kernel_1c_c"; + hash_set_kernel_test::kernel_1c_c>(); + } + } a; + +} + diff --git a/dlib/test/hash_table.cpp b/dlib/test/hash_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..349e8910dbe554b9b7c9ba4de9a39b6c807a7e1d --- /dev/null +++ b/dlib/test/hash_table.cpp @@ -0,0 +1,663 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.hash_table"); + + template < + typename hash_table + > + void hash_table_kernel_test ( + ) + /*! + requires + - hash_table is an implementation of hash_table/hash_table_kernel_abstract.h + and is instantiated to map ints to ints + ensures + - runs tests on hash_table for compliance with the specs + !*/ + { + + srand(static_cast(time(0))); + + + + + { + hash_table test(16); + + DLIB_CASSERT(test.count(3) == 0,""); + + enumerable >& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + hash_table test2(16); + + hash_table test3(0); + hash_table test4(0); + + + print_spinner(); + + int b; + for (int j = 0; j < 4; ++j) + { + int a = 4; + b = 5; + test2.add(a,b); + DLIB_CASSERT(test2.size() == 1,""); + DLIB_CASSERT(*test2[4] == 5,""); + DLIB_CASSERT(test2[99] == 0,""); + + DLIB_CASSERT(test2.move_next(),""); + DLIB_CASSERT(test2.element().key() == 4,""); + DLIB_CASSERT(test2.element().value() == 5,""); + + swap(test,test2); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(*test[4] == 5,""); + DLIB_CASSERT(test[99] == 0,""); + + test.swap(test2); + + a = 99; + b = 35; + test2.add(a,b); + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(*test2[4] == 5,""); + DLIB_CASSERT(*test2[99] == 35,""); + DLIB_CASSERT(test2[99] != 0,""); + DLIB_CASSERT(test2[949] == 0,""); + + test2.destroy(4); + DLIB_CASSERT(test2.size() == 1,""); + DLIB_CASSERT(test2[4] == 0,""); + DLIB_CASSERT(*test2[99] == 35,""); + DLIB_CASSERT(test2[99] != 0,""); + DLIB_CASSERT(test2[949] == 0,""); + + + + test2.destroy(99); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2[4] == 0,""); + DLIB_CASSERT(test2[99] == 0,""); + DLIB_CASSERT(test2[949] == 0,""); + + + + test2.clear(); + } + + + print_spinner(); + + + + + for (int j = 0; j < 4; ++j) + { + + DLIB_CASSERT(test.count(3) == 0,""); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + int a; + + for (int i = 0; i < 10000; ++i) + { + a = ::rand()%1000; + int temp = a; + unsigned long count = test.count(a); + test.add(a,b); + DLIB_CASSERT(test.count(temp) == count+1,""); + } + + { + unsigned long count = test.count(3); + + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + } + + + test.clear(); + + + for (int i = 0; i < 10000; ++i) + { + a = b = i; + unsigned long count = test.count(a); + test.add(a,b); + DLIB_CASSERT(test.count(i) == count+1,""); + } + + DLIB_CASSERT(test.size() == 10000,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + + + test.reset(); + + DLIB_CASSERT(test.size() == 10000,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + if (test.size() > 0) + { + int* array = new int[test.size()]; + int* tmp = array; + + int count = 0; + while (test.move_next()) + { + ++count; + *tmp = test.element().key(); + DLIB_CASSERT(test[*tmp] != 0,""); + DLIB_CASSERT(*tmp == test.element().key(),""); + DLIB_CASSERT(*tmp == test.element().value(),""); + DLIB_CASSERT(*tmp == test.element().key(),""); + DLIB_CASSERT(test.current_element_valid() == true,""); + ++tmp; + } + + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + DLIB_CASSERT(test.size() == 10000,""); + + swap(test,test2); + + + + + // serialize the state of test2, then clear test2, then + // load the state back into test2. + ostringstream sout; + serialize(test2,sout); + DLIB_CASSERT(test2.at_start() == true,""); + istringstream sin(sout.str()); + test2.clear(); + deserialize(test2,sin); + DLIB_CASSERT(test2.at_start() == true,""); + + + + + tmp = array; + for (int i = 0; i < 10000; ++i) + { + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + ++tmp; + } + + test2.swap(test); + test.reset(); + + DLIB_CASSERT(test.at_start() == true,""); + count = 0; + tmp = array; + while (test.size() > 0) + { + test.remove(*tmp,a,b); + + ++tmp; + ++count; + } + + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.size() == 0,""); + + + + DLIB_CASSERT(count == 10000,""); + + + + + + + + delete [] array; + } + + test.move_next(); + + for (int i = 0; i < 10000; ++i) + { + a = ::rand(); + test.add(a,b); + } + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == true,""); + + DLIB_CASSERT(test.size() == 10000,""); + + for (int i = 0; i < 10000; ++i) + { + test.remove_any(a,b); + } + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.size() == 0,""); + + test.clear(); + + + + + + + + + + int* dtmp = new int[10000]; + int* rtmp = new int[10000]; + + int* d = dtmp; + int* r = rtmp; + for (unsigned long i = 0; i < 10000; ++i) + { + a = ::rand(); + b = ::rand(); + *d = a; + *r = b; + if (test[a] != 0) + { + --i; + continue; + } + test.add(a,b); + ++d; + ++r; + DLIB_CASSERT(test.size() == i+1,""); + } + + DLIB_CASSERT(test.size() == 10000,""); + + for (int i = 0; i < 10000; ++i) + { + DLIB_CASSERT(*test[dtmp[i]] == rtmp[i],""); + } + + + delete [] dtmp; + delete [] rtmp; + + test.clear(); + }} + + + print_spinner(); + + + + + + + + + + + + + + + + + + + + + + + + + // now do the same thing as above but with a much smaller hash table + { + hash_table test(13); + + DLIB_CASSERT(test.count(3) == 0,""); + + enumerable >& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + hash_table test2(16); + + hash_table test3(0); + hash_table test4(0); + + + int b; + for (int j = 0; j < 4; ++j) + { + int a = 4; + b = 5; + test2.add(a,b); + DLIB_CASSERT(test2.size() == 1,""); + DLIB_CASSERT(*test2[4] == 5,""); + DLIB_CASSERT(test2[99] == 0,""); + + + DLIB_CASSERT(test2.move_next(),""); + DLIB_CASSERT(test2.element().key() == 4,""); + DLIB_CASSERT(test2.element().value() == 5,""); + + swap(test,test2); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(*test[4] == 5,""); + DLIB_CASSERT(test[99] == 0,""); + + test.swap(test2); + + a = 99; + b = 35; + test2.add(a,b); + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(*test2[4] == 5,""); + DLIB_CASSERT(*test2[99] == 35,""); + DLIB_CASSERT(test2[99] != 0,""); + DLIB_CASSERT(test2[949] == 0,""); + + test2.destroy(4); + DLIB_CASSERT(test2.size() == 1,""); + DLIB_CASSERT(test2[4] == 0,""); + DLIB_CASSERT(*test2[99] == 35,""); + DLIB_CASSERT(test2[99] != 0,""); + DLIB_CASSERT(test2[949] == 0,""); + + + + test2.destroy(99); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2[4] == 0,""); + DLIB_CASSERT(test2[99] == 0,""); + DLIB_CASSERT(test2[949] == 0,""); + + + + test2.clear(); + } + + + print_spinner(); + + + + + for (int j = 0; j < 4; ++j) + { + + DLIB_CASSERT(test.count(3) == 0,""); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + int a; + + for (int i = 0; i < 10000; ++i) + { + a = ::rand()%1000; + int temp = a; + unsigned long count = test.count(a); + test.add(a,b); + DLIB_CASSERT(test.count(temp) == count+1,""); + } + + { + unsigned long count = test.count(3); + + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + a = 3; test.add(a,b); ++count; + DLIB_CASSERT(test.count(3) == count,""); + } + + + test.clear(); + + + for (int i = 0; i < 10000; ++i) + { + a = b = i; + unsigned long count = test.count(a); + test.add(a,b); + DLIB_CASSERT(test.count(i) == count+1,""); + } + + DLIB_CASSERT(test.size() == 10000,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + + + test.reset(); + + DLIB_CASSERT(test.size() == 10000,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + if (test.size() > 0) + { + int* array = new int[test.size()]; + int* tmp = array; + + int count = 0; + while (test.move_next()) + { + ++count; + *tmp = test.element().key(); + DLIB_CASSERT(test[*tmp] != 0,""); + DLIB_CASSERT(*tmp == test.element().key(),""); + DLIB_CASSERT(*tmp == test.element().value(),""); + DLIB_CASSERT(*tmp == test.element().key(),""); + DLIB_CASSERT(test.current_element_valid() == true,""); + ++tmp; + } + + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + DLIB_CASSERT(test.size() == 10000,""); + + swap(test,test2); + + tmp = array; + for (int i = 0; i < 10000; ++i) + { + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + DLIB_CASSERT(*test2[*tmp] == *tmp,""); + ++tmp; + } + + test2.swap(test); + test.reset(); + + DLIB_CASSERT(test.at_start() == true,""); + count = 0; + tmp = array; + while (test.size() > 0) + { + test.remove(*tmp,a,b); + + ++tmp; + ++count; + } + + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.size() == 0,""); + + + + DLIB_CASSERT(count == 10000,""); + + + + + + + + delete [] array; + } + + test.move_next(); + + for (int i = 0; i < 10000; ++i) + { + a = ::rand(); + test.add(a,b); + } + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == true,""); + + DLIB_CASSERT(test.size() == 10000,""); + + for (int i = 0; i < 10000; ++i) + { + test.remove_any(a,b); + } + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.size() == 0,""); + + test.clear(); + + + + + + + + + int* dtmp = new int[10000]; + int* rtmp = new int[10000]; + + int* d = dtmp; + int* r = rtmp; + for (unsigned long i = 0; i < 10000; ++i) + { + a = ::rand(); + b = ::rand(); + *d = a; + *r = b; + if (test[a] != 0) + { + --i; + continue; + } + test.add(a,b); + ++d; + ++r; + DLIB_CASSERT(test.size() == i+1,""); + } + + DLIB_CASSERT(test.size() == 10000,""); + + for (int i = 0; i < 10000; ++i) + { + DLIB_CASSERT(*test[dtmp[i]] == rtmp[i],""); + } + + + delete [] dtmp; + delete [] rtmp; + + test.clear(); + }} + + } + + + + + class hash_table_tester : public tester + { + public: + hash_table_tester ( + ) : + tester ("test_hash_table", + "Runs tests on the hash_table component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + hash_table_kernel_test::kernel_1a> (); + dlog << LINFO << "testing kernel_1a_c"; + hash_table_kernel_test::kernel_1a_c>(); + dlog << LINFO << "testing kernel_2a"; + hash_table_kernel_test::kernel_2a> (); + dlog << LINFO << "testing kernel_2a_c"; + hash_table_kernel_test::kernel_2a_c>(); + } + } a; + +} + diff --git a/dlib/test/image.cpp b/dlib/test/image.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfed920844dfb73564f953cc9ab784600b90ba86 --- /dev/null +++ b/dlib/test/image.cpp @@ -0,0 +1,420 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.image"); + + + void image_test ( + ) + /*! + ensures + - runs tests on pixel objects and functions for compliance with the specs + !*/ + { + + print_spinner(); + + array2d::kernel_1a_c img1, img2; + + img1.set_size(100,100); + + assign_all_pixels(img1,7); + + assign_image(img2, img1); + + DLIB_CASSERT(img1.nr() == 100 && img1.nc() == 100 && + img2.nr() == 100 && img2.nc() == 100,""); + + + for (long r = 0; r < img1.nr(); ++r) + { + for (long c = 0; c < img1.nc(); ++c) + { + DLIB_CASSERT(img1[r][c] == 7,""); + DLIB_CASSERT(img2[r][c] == 7,""); + } + } + + + threshold_image(img1, img2, 4); + + for (long r = 0; r < img1.nr(); ++r) + { + for (long c = 0; c < img1.nc(); ++c) + { + DLIB_CASSERT(img1[r][c] == 7,""); + DLIB_CASSERT(img2[r][c] == on_pixel,""); + } + } + + { + array2d::kernel_1a img; + img.set_size(14,15); + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + img[r][c].h = static_cast(r*14 + c + 1); + img[r][c].s = static_cast(r*14 + c + 2); + img[r][c].i = static_cast(r*14 + c + 3); + } + } + + ostringstream sout; + save_dng(img, sout); + istringstream sin(sout.str()); + + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_dng(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c].h == r*14 + c + 1, ""); + DLIB_CASSERT(img[r][c].s == r*14 + c + 2, ""); + DLIB_CASSERT(img[r][c].i == r*14 + c + 3, ""); + } + } + } + + + + + { + array2d::kernel_1a img; + img.set_size(14,15); + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + img[r][c].red = static_cast(r*14 + c + 1); + img[r][c].green = static_cast(r*14 + c + 2); + img[r][c].blue = static_cast(r*14 + c + 3); + img[r][c].alpha = static_cast(r*14 + c + 4); + } + } + + ostringstream sout; + save_dng(img, sout); + istringstream sin(sout.str()); + + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_dng(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c].red == r*14 + c + 1, ""); + DLIB_CASSERT(img[r][c].green == r*14 + c + 2, ""); + DLIB_CASSERT(img[r][c].blue == r*14 + c + 3, ""); + DLIB_CASSERT(img[r][c].alpha == r*14 + c + 4, ""); + } + } + } + + + + { + array2d::kernel_1a img; + img.set_size(14,15); + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + img[r][c].red = static_cast(r*14 + c + 1); + img[r][c].green = static_cast(r*14 + c + 2); + img[r][c].blue = static_cast(r*14 + c + 3); + } + } + + ostringstream sout; + save_dng(img, sout); + save_bmp(img, sout); + save_dng(img, sout); + save_bmp(img, sout); + istringstream sin(sout.str()); + + for (int i = 0; i < 2; ++i) + { + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_dng(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c].red == r*14 + c + 1, ""); + DLIB_CASSERT(img[r][c].green == r*14 + c + 2, ""); + DLIB_CASSERT(img[r][c].blue == r*14 + c + 3, ""); + } + } + + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_bmp(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c].red == r*14 + c + 1, "got " << (int)img[r][c].red << " but expected " << r*14 + c + 1); + DLIB_CASSERT(img[r][c].green == r*14 + c + 2, ""); + DLIB_CASSERT(img[r][c].blue == r*14 + c + 3, ""); + } + } + } + } + + + + + { + array2d::kernel_1a img; + img.set_size(14,15); + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + img[r][c] = static_cast(r*14 + c + 0xFF); + } + } + + ostringstream sout; + save_dng(img, sout); + istringstream sin(sout.str()); + + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_dng(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c] == r*14 + c + 0xFF, ""); + } + } + } + + + + { + array2d::kernel_1a img; + img.set_size(14,15); + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + img[r][c] = static_cast(r*14 + c); + } + } + + ostringstream sout; + save_dng(img, sout); + save_bmp(img, sout); + save_dng(img, sout); + save_bmp(img, sout); + istringstream sin(sout.str()); + + for (int i = 0; i < 2; ++i) + { + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_dng(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c] == r*14 + c, ""); + } + } + + + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_bmp(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c] == r*14 + c, ""); + } + } + } + } + + + + { + // in this test we will only assign pixel values that can be + // represented with 8 bits even though we are using a wider pixel type. + array2d::kernel_1a img; + img.set_size(14,15); + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + img[r][c] = static_cast(r*14 + c); + } + } + + ostringstream sout; + save_dng(img, sout); + save_bmp(img, sout); + save_dng(img, sout); + save_bmp(img, sout); + istringstream sin(sout.str()); + + for (int i = 0; i < 2; ++i) + { + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_dng(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c] == r*14 + c, ""); + } + } + + + img.clear(); + DLIB_CASSERT(img.nr() == 0,""); + DLIB_CASSERT(img.nc() == 0,""); + + load_bmp(img, sin); + + DLIB_CASSERT(img.nr() == 14,""); + DLIB_CASSERT(img.nc() == 15,""); + + for (long r = 0; r < 14; ++r) + { + for (long c = 0; c < 15; ++c) + { + DLIB_CASSERT(img[r][c] == r*14 + c, ""); + } + } + } + } + + { + array2d::kernel_1a_c img1; + array2d::kernel_1a_c img2; + img1.set_size(10,10); + assign_all_pixels(img1, 0); + + img1[5][5] = 10000; + img1[7][7] = 10000; + + equalize_histogram(img1, img2); + + for (long r = 0; r < img1.nr(); ++r) + { + for (long c = 0; c < img2.nc(); ++c) + { + if (r == 5 && c == 5 || + r == 7 && c == 7) + { + DLIB_CASSERT(img2[r][c] == 255, ""); + } + else + { + DLIB_CASSERT(img2[r][c] == 0, ""); + } + } + } + + } + + + + } + + + + + class image_tester : public tester + { + public: + image_tester ( + ) : + tester ("test_image", + "Runs tests on the image processing objects and functions.") + {} + + void perform_test ( + ) + { + image_test(); + } + } a; + +} + + + diff --git a/dlib/test/lz77_buffer.cpp b/dlib/test/lz77_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd0abaa3650fe64fb0e339ffb72b1e6f11f002e2 --- /dev/null +++ b/dlib/test/lz77_buffer.cpp @@ -0,0 +1,569 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.lz77_buffer"); + + template < + typename buf + > + void lz77_buffer_kernel_test ( + ) + /*! + requires + - buf is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h + ensures + - runs tests on buf for compliance with the specs + !*/ + { + typedef dlib::sliding_buffer::kernel_1a sbuf; + + buf test(8,20); + srand(static_cast(time(0))); + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,test.get_history_buffer_limit()); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + for (int g = 0; g < 2; ++g) + { + test.clear(); + + for (int i = 0; i < 1000; ++i) + { + test.add('a'); + } + DLIB_CASSERT(test.get_lookahead_buffer_size() == 20,""); + + + test.shift_buffers(5); + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 15,""); + + + + unsigned long index, length, temp; + temp = test.get_lookahead_buffer_size(); + test.find_match(index,length,5); + + + DLIB_CASSERT(length <= temp, + "length: " << length << + "\ntemp: " << temp); + DLIB_CASSERT(test.get_lookahead_buffer_size() <= 15,""); + + + } + + + for (int g = 0; g < 2; ++g) + { + + + + test.clear(); + + + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + unsigned long a,b, temp = test.get_lookahead_buffer_size(); + test.find_match(a,b,0); + DLIB_CASSERT(b <= temp,""); + DLIB_CASSERT(b == 0,""); + + test.find_match(a,b,5); + DLIB_CASSERT(b == 0,""); + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + + ostringstream sout; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,);\n"; + istringstream sin(sout.str()); + + sout.str(""); + sout.clear(); + + unsigned char ch; + sbuf sbuffer; + sbuffer.set_size(8); + + + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + DLIB_CASSERT(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch,""); + DLIB_CASSERT(test.get_lookahead_buffer_size() == 1,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + DLIB_CASSERT(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch,""); + DLIB_CASSERT(test.get_lookahead_buffer_size() == 2,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + DLIB_CASSERT(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch,""); + DLIB_CASSERT(test.get_lookahead_buffer_size() == 3,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + + // add 17 chars to test so that the lookahead buffer will be full + for (int i = 0; i < 17; ++i) + { + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + DLIB_CASSERT(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch,""); + } + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 20,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.lookahead_buffer(0) == sbuffer[20],""); + + + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + DLIB_CASSERT(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch,""); + DLIB_CASSERT(test.get_lookahead_buffer_size() == 20,""); + DLIB_CASSERT(test.get_history_buffer_size() == 1,""); + + + + + + + // add the above text to test and make sure it gives the correct results + ch = sin.get(); + while (sin) + { + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + DLIB_CASSERT(test.lookahead_buffer(test.get_lookahead_buffer_size()-1) == ch,""); + DLIB_CASSERT(test.history_buffer(0) == sbuffer[21],""); + DLIB_CASSERT(test.history_buffer(1) == sbuffer[22],""); + + ch = sin.get(); + } + + + + // make sure the contents of lookahead_buffer and history_buffer + // match what is in sbuffer + sbuffer.rotate_right(1); + for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i),""); + } + for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i),""); + } + sbuffer.rotate_left(1); + + + + + + + + + + + sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] + + unsigned long match_index, match_length; + unsigned long ltemp = test.get_lookahead_buffer_size(); + test.find_match(match_index,match_length,0); + DLIB_CASSERT(match_length <= ltemp,""); + + + // verify the match with sbuffer + for (unsigned int i = 0; i < match_length; ++i) + { + DLIB_CASSERT(sbuffer[19-i] == sbuffer[match_index+20-i],i); + } + + + sin.str(""); + sin.clear(); + + } // for (int g = 0; g < 2; ++g) + + + for (int g = 0; g < 8; ++g) + { + test.clear(); + + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + sbuf sbuffer; + sbuffer.set_size(8); + + ostringstream sout; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + sout << "DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + sout << "DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,);\n"; + istringstream sin(sout.str()); + + unsigned char ch; + for (int i = 0; i < 100; ++i) + { + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + } + + // make sure the contents of lookahead_buffer and history_buffer + // match what is in sbuffer + sbuffer.rotate_right(1); + for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i),""); + } + for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i),""); + } + sbuffer.rotate_left(1); + + + + + unsigned long match_index, match_length; + unsigned long ltemp = test.get_lookahead_buffer_size(); + test.find_match(match_index,match_length,0); + DLIB_CASSERT(match_length <= ltemp,""); + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 20-match_length,""); + + sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] + // verify the match with sbuffer + for (unsigned int i = 0; i < match_length; ++i) + { + DLIB_CASSERT(sbuffer[i+20-match_length] == sbuffer[i+1+match_index+20-match_length],""); + } + sbuffer.rotate_left(1); // free up sbuffer[0] for new data + + + + + for (int i = 0; i < 7+g*2; ++i) + { + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + } + + ch = '?'; + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + ch = 'a'; + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + ch = 'v'; + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + ch = 'i'; + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + ch = 's'; + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + + + // adjust sbuffer due to the last call to test.find_match() + // but only if we haven't already added enough (20 or more) chars + // to fill the lookahead buffer already. + if (match_length > static_cast(12+g*2)) + sbuffer.rotate_left(match_length-(12+g*2)); + + + + + + // make sure the contents of lookahead_buffer and history_buffer + // match what is in sbuffer + sbuffer.rotate_right(1); + for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i),""); + } + for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i),""); + } + sbuffer.rotate_left(1); + + + + + test.find_match(match_index,match_length,10+g); + + if (match_length > 0) + DLIB_CASSERT(match_length >= static_cast(10+g) , ""); + + + sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] + // verify the match with sbuffer + for (unsigned int i = 0; i < match_length; ++i) + { + DLIB_CASSERT(sbuffer[i+20-match_length] == sbuffer[i+1+match_index+20-match_length],""); + } + sbuffer.rotate_left(1); // free up sbuffer[0] for new data + + } // for (int g = 0; g < 8; ++g) + + + + + + + + srand(static_cast(time(0))); + + for (int g = 0; g < 200; ++g) + { + test.clear(); + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + sbuf sbuffer; + sbuffer.set_size(8); + + ostringstream sout; + int l = ::rand()%500; + for (int i = 0; i < l; ++i) + { + char temp = static_cast(::rand()%256); + sout << temp; + } + istringstream sin(sout.str()); + + unsigned char ch; + for (int i = 0; i < l; ++i) + { + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + } + + // make sure the contents of lookahead_buffer and history_buffer + // match what is in sbuffer + sbuffer.rotate_right(1); + + // adjust so that sbuffer[19] is the same as lookahead_buffer[0] + if (test.get_lookahead_buffer_size() < 20) + sbuffer.rotate_left(20-test.get_lookahead_buffer_size()); + + for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i),""); + } + for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i),""); + } + sbuffer.rotate_left(1); + + + + unsigned long match_index, match_length; + unsigned long lookahead_size_before = test.get_lookahead_buffer_size(); + test.find_match(match_index,match_length,0); + DLIB_CASSERT(match_length <= lookahead_size_before,""); + + + DLIB_CASSERT(test.get_lookahead_buffer_size() == lookahead_size_before-match_length,""); + + sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] + // verify the match with sbuffer + for (unsigned int i = 0; i < match_length; ++i) + { + DLIB_CASSERT(sbuffer[19-i] == sbuffer[match_index+20-i],i); + } + sbuffer.rotate_left(1); // free up sbuffer[0] for new data + + } // for (int g = 0; g < 200; ++g) + + + + + + + + + srand(static_cast(time(0))); + + for (int g = 0; g < 300; ++g) + { + test.clear(); + + DLIB_CASSERT(test.get_lookahead_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_size() == 0,""); + DLIB_CASSERT(test.get_history_buffer_limit() == 256-20,""); + DLIB_CASSERT(test.get_lookahead_buffer_limit() == 20,""); + + + sbuf sbuffer; + sbuffer.set_size(8); + + ostringstream sout; + int l = ::rand()%500; + for (int i = 0; i < l; ++i) + { + char temp = static_cast(::rand()%20); + sout << temp; + sout << temp; + sout << temp; + sout << temp; + sout << temp; + sout << temp; + } + istringstream sin(sout.str()); + + unsigned char ch; + for (int i = 0; i < l; ++i) + { + ch = sin.get(); + sbuffer[0] = ch; sbuffer.rotate_left(1); + test.add(ch); + } + + // make sure the contents of lookahead_buffer and history_buffer + // match what is in sbuffer + sbuffer.rotate_right(1); + + // adjust so that sbuffer[19] is the same as lookahead_buffer[0] + if (test.get_lookahead_buffer_size() < 20) + sbuffer.rotate_left(20-test.get_lookahead_buffer_size()); + + for (unsigned int i = 0; i < test.get_history_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()+i] == test.history_buffer(i),""); + } + for (unsigned int i = 0; i < test.get_lookahead_buffer_size(); ++i) + { + DLIB_CASSERT(sbuffer[test.get_lookahead_buffer_limit()-1-i] == test.lookahead_buffer(i),""); + } + sbuffer.rotate_left(1); + + + + unsigned long match_index, match_length; + unsigned long lookahead_size_before = test.get_lookahead_buffer_size(); + unsigned long history_size_before = test.get_history_buffer_size(); + test.find_match(match_index,match_length,2); + + if (match_length != 0) + { + DLIB_CASSERT(match_index < history_size_before, + "match_index: " << match_index << + "\nhistory_size_before: " << history_size_before); + + } + + + DLIB_CASSERT(test.get_lookahead_buffer_size() == lookahead_size_before-match_length,""); + + sbuffer.rotate_right(1); // do this because we never put anything in sbuffer[0] + // verify the match with sbuffer + for (unsigned int i = 0; i < match_length; ++i) + { + DLIB_CASSERT(sbuffer[19-i] == sbuffer[match_index+20-i],i); + } + sbuffer.rotate_left(1); // free up sbuffer[0] for new data + + + + } // for (int g = 0; g < 300; ++g) + + } + + + + + class lz77_buffer_tester : public tester + { + public: + lz77_buffer_tester ( + ) : + tester ("test_lz77_buffer", + "Runs tests on the lz77_buffer component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + lz77_buffer_kernel_test (); + dlog << LINFO << "testing kernel_1a_c"; + lz77_buffer_kernel_test(); + dlog << LINFO << "testing kernel_2a"; + lz77_buffer_kernel_test (); + dlog << LINFO << "testing kernel_2a_c"; + lz77_buffer_kernel_test(); + } + } a; + +} + diff --git a/dlib/test/main.cpp b/dlib/test/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3164a19e4c03072bf2d2a1df276e90025a9c9e62 --- /dev/null +++ b/dlib/test/main.cpp @@ -0,0 +1,193 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include "tester.h" +#include + + +using namespace std; +using namespace dlib; +using namespace test; + +typedef cmd_line_parser::check_1a_c clp; + +static logger dlog("test.main"); + +int main (int argc, char** argv) +{ + try + { + clp parser; + + parser.add_option("runall","Run all the tests that don't take any arguments."); + parser.add_option("h","Displays this information."); + parser.add_option("n","How many times to run the selected tests. The default is 1.",1); + parser.add_option("d","log debugging statements to file debug.txt."); + parser.add_option("l","Set the logging level (all, trace, debug, info, warn, error, or fatal), the default is all.",1); + parser.add_option("a","Append debugging messsages to debug.txt rather than clearning the file at program startup."); + + unsigned long num = 1; + + // add the options for all the different tests + testers().reset(); + while (testers().move_next()) + { + tester& test = *testers().element().value(); + parser.add_option(test.cmd_line_switch(), test.description(), test.num_of_args()); + } + + parser.parse(argc,argv); + + parser.check_option_arg_range("n",1,1000000000); + const char* singles[] = {"d","l","a","n","h","runall"}; + parser.check_one_time_options(singles); + const char* d_sub[] = {"l","a"}; + const char* l_args[] = {"all", "trace", "debug", "info", "warn", "error", "fatal"}; + parser.check_sub_options("d",d_sub); + parser.check_option_arg_range("l",l_args); + + + if (parser.option("n")) + { + num = string_cast(parser.option("n").argument()); + } + + if (parser.option("h")) + { + cout << "Usage: test [options]\n"; + parser.print_options(cout); + cout << "\n\n"; + return 0; + } + + ofstream fout; + if (parser.option("d")) + { + logger l("test"); + if (parser.option("a")) + fout.open("debug.txt",ios::app); + else + fout.open("debug.txt"); + + l.set_output_stream(fout); + if (parser.option("l").count() == 0) + l.set_level(LALL); + else if (parser.option("l").argument() == "all") + l.set_level(LALL); + else if (parser.option("l").argument() == "trace") + l.set_level(LTRACE); + else if (parser.option("l").argument() == "debug") + l.set_level(LDEBUG); + else if (parser.option("l").argument() == "info") + l.set_level(LINFO); + else if (parser.option("l").argument() == "warn") + l.set_level(LWARN); + else if (parser.option("l").argument() == "error") + l.set_level(LERROR); + else if (parser.option("l").argument() == "fatal") + l.set_level(LFATAL); + } + else + { + logger l("test"); + l.set_level(LNONE); + } + + unsigned long num_of_failed_tests = 0; + unsigned long num_of_passed_tests = 0; + for (unsigned long i = 0; i < num; ++i) + { + dlog << LINFO << "************ Starting Test Run " << i+1 << " of " << num << ". ************"; + + // loop over all the testers and see if they are supposed to run + testers().reset(); + while (testers().move_next()) + { + tester& test= *testers().element().value(); + const clp::option_type& opt = parser.option(test.cmd_line_switch()); + // run the test for this option as many times as the user has requested. + for (unsigned long j = 0; j < parser.option("runall").count() + opt.count(); ++j) + { + // quit this loop if this option has arguments and this round through the loop is + // from the runall option being present. + if (test.num_of_args() > 0 && j == opt.count()) + break; + + cout << "Running " << test.cmd_line_switch() << " " << flush; + dlog << LINFO << "Running " << test.cmd_line_switch(); + try + { + switch (test.num_of_args()) + { + case 0: + test.perform_test(); + break; + case 1: + test.perform_test(opt.argument(0,j)); + break; + case 2: + test.perform_test(opt.argument(0,j), opt.argument(1,j)); + break; + default: + cerr << "\n\nThe test '" << test.cmd_line_switch() << "' requested " << test.num_of_args() + << " arguments but only 2 are supported." << endl; + dlog << LINFO << "The test '" << test.cmd_line_switch() << "' requested " << test.num_of_args() + << " arguments but only 2 are supported."; + break; + } + cout << "\r \r"; + ++num_of_passed_tests; + + } + catch (std::exception& e) + { + cout << "\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; + cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TEST FAILED: " << test.cmd_line_switch() + << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; + cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"; + cout << "Failure message from test: " << e.what() << endl; + + + dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; + dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TEST FAILED: " << test.cmd_line_switch() + << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; + dlog << LERROR << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; + dlog << LERROR << "Failure message from test: " << e.what(); + ++num_of_failed_tests; + } + } + } + } + dlog << LINFO << "Testing Finished"; + if (num_of_passed_tests == 0 && num_of_failed_tests == 0) + { + cout << "You didn't select any tests to run.\n"; + cout << "Try the -h option for more information.\n"; + } + else if (num_of_failed_tests == 0) + { + cout << "\n\nTesting Finished\n"; + cout << "All tests completed successfully\n\n"; + dlog << LINFO << "All tests completed successfully"; + } + else + { + cout << "\n\nTesting Finished\n"; + cout << "Number of failed tests: " << num_of_failed_tests << "\n"; + cout << "Number of passed tests: " << num_of_passed_tests << "\n\n"; + dlog << LWARN << "Number of failed tests: " << num_of_failed_tests; + dlog << LWARN << "Number of passed tests: " << num_of_passed_tests; + } + } + catch (exception& e) + { + cout << e.what() << endl; + cout << "\nTry the -h option for more information.\n"; + cout << endl; + } +} + diff --git a/dlib/test/makefile b/dlib/test/makefile new file mode 100644 index 0000000000000000000000000000000000000000..0abe2af277b8fe1ca26c1de2bb9a2aefa83e9c72 --- /dev/null +++ b/dlib/test/makefile @@ -0,0 +1,6216 @@ +# This is the makefile used to build the dlib C++ library's regression test suite +# on Debian Linux using the gcc compiler. + +# this is the name of the output executable +TARGET = test + +# these are the compile time flags passed to gcc +CFLAGS = -ggdb -DDEBUG -DDLIB_NO_GUI_SUPPORT -I ../.. -Wall + +# These are the link time flags passed to gcc +LFLAGS = -lpthread -lnsl + +# The name of the compiler. If you only have one version of +# gcc installed then you probably want to change this to just g++ +CC = nice g++-3.3 + +#################################################### +#################################################### +# Here we list all the cpp files we want to compile + +SRC = main.cpp +SRC += tester.cpp +SRC += ../all/source.cpp + +SRC += example.cpp +SRC += example_args.cpp + +SRC += array2d.cpp +SRC += array.cpp +SRC += base64.cpp +SRC += bayes_nets.cpp +SRC += bigint.cpp +SRC += binary_search_tree_kernel_1a.cpp +SRC += binary_search_tree_kernel_2a.cpp +SRC += binary_search_tree_mm1.cpp +SRC += binary_search_tree_mm2.cpp +SRC += cmd_line_parser.cpp +SRC += cmd_line_parser_wchar_t.cpp +SRC += compress_stream.cpp +SRC += conditioning_class.cpp +SRC += conditioning_class_c.cpp +SRC += config_reader.cpp +SRC += directed_graph.cpp +SRC += graph.cpp +SRC += geometry.cpp +SRC += entropy_coder.cpp +SRC += entropy_encoder_model.cpp +SRC += hash_map.cpp +SRC += hash_set.cpp +SRC += hash_table.cpp +SRC += image.cpp +SRC += lz77_buffer.cpp +SRC += map.cpp +SRC += matrix.cpp +SRC += md5.cpp +SRC += member_function_pointer.cpp +SRC += metaprogramming.cpp +SRC += multithreaded_object.cpp +SRC += pipe.cpp +SRC += pixel.cpp +SRC += queue.cpp +SRC += rand.cpp +SRC += reference_counter.cpp +SRC += sequence.cpp +SRC += serialize.cpp +SRC += set.cpp +SRC += sliding_buffer.cpp +SRC += smart_pointers.cpp +SRC += sockets.cpp +SRC += sockstreambuf.cpp +SRC += stack.cpp +SRC += static_map.cpp +SRC += static_set.cpp +SRC += string.cpp +SRC += threads.cpp +SRC += timer.cpp +SRC += tokenizer.cpp +SRC += tuple.cpp + + +#################################################### + +TMP = $(SRC:.cpp=.o) +OBJ = $(TMP:.c=.o) + +$(TARGET): $(OBJ) + @echo Linking $@ + @$(CC) $(LFLAGS) $(OBJ) -o $@ + @echo Build Complete + +.cpp.o: $< + @echo Compiling $< + @$(CC) -c $(CFLAGS) $< -o $@ + +clean: + @rm -f $(OBJ) $(TARGET) + @echo All object files and binaries removed + +dep: + @echo Running makedepend + @makedepend -- $(CFLAGS) -- $(SRC) 2> /dev/null + @echo Completed makedepend + +############################################################################### +########## Stuff from makedepend ##### +########## type make dep at the command line to rebuild the dependencies ##### +########## Also, DON'T edit the contents of this file beyond this line. ##### +############################################################################### + +# DO NOT DELETE + +main.o: ../../dlib/cmd_line_parser.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_1.h ../algs.h +main.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +main.o: ../interfaces/enumerable.h ../interfaces/cmd_line_parser_option.h +main.o: ../assert.h ../string.h ../string/string.h ../error.h +main.o: ../string/string_abstract.h ../uintn.h ../enable_if.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_c.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_print_1.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_print_abstract.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_check_1.h +main.o: ../../dlib/cmd_line_parser/cmd_line_parser_check_c.h ../../dlib/map.h +main.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +main.o: ../interfaces/map_pair.h ../interfaces/remover.h ../serialize.h +main.o: ../algs.h ../uintn.h ../interfaces/enumerable.h +main.o: ../interfaces/map_pair.h ../enable_if.h ../memory_manager.h +main.o: ../memory_manager/memory_manager_kernel_1.h +main.o: ../memory_manager/memory_manager_kernel_abstract.h +main.o: ../memory_manager/memory_manager_kernel_2.h +main.o: ../memory_manager/memory_manager_kernel_3.h +main.o: ../memory_manager/memory_manager_kernel_2.h +main.o: ../binary_search_tree/binary_search_tree_kernel_2.h +main.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +main.o: ../../dlib/map/map_kernel_c.h binary_search_tree.h +main.o: ../../dlib/memory_manager_global.h +main.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +main.o: ../memory_manager/memory_manager_kernel_abstract.h +main.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +main.o: ../../dlib/memory_manager.h ../../dlib/memory_manager_stateless.h +main.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +main.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +main.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +main.o: ../threads.h ../threads/threads_kernel.h ../platform.h +main.o: ../threads/posix.h ../threads/threads_kernel_2.h +main.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +main.o: /usr/include/features.h /usr/include/sys/cdefs.h +main.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +main.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +main.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +main.o: /usr/include/time.h /usr/include/bits/sched.h /usr/include/signal.h +main.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +main.o: /usr/include/bits/setjmp.h /usr/include/errno.h +main.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +main.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +main.o: /usr/include/asm-generic/errno.h +main.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +main.o: /usr/include/bits/time.h /usr/include/sys/select.h +main.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +main.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +main.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +main.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +main.o: ../binary_search_tree/binary_search_tree_kernel_1.h +main.o: ../binary_search_tree/binary_search_tree_kernel_2.h +main.o: ../binary_search_tree/binary_search_tree_kernel_c.h +main.o: ../member_function_pointer.h +main.o: ../member_function_pointer/member_function_pointer_kernel_1.h +main.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +main.o: ../member_function_pointer/member_function_pointer_kernel_c.h +main.o: ../queue.h ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +main.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +main.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +main.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +main.o: ../set/set_kernel_c.h ../set/set_compare_1.h +main.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +main.o: ../threads/auto_unlock_extension.h +main.o: ../threads/auto_unlock_extension_abstract.h +main.o: ../threads/create_new_thread_extension.h +main.o: ../threads/create_new_thread_extension_abstract.h +main.o: ../threads/multithreaded_object_extension.h +main.o: ../threads/multithreaded_object_extension_abstract.h +main.o: ../threads/rsignaler_extension.h +main.o: ../threads/rsignaler_extension_abstract.h ../map.h +main.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +main.o: ../threads/threaded_object_extension.h +main.o: ../threads/threaded_object_extension_abstract.h +main.o: ../threads/thread_specific_data_extension.h +main.o: ../threads/thread_specific_data_extension_abstract.h +main.o: ../threads/thread_function_extension.h +main.o: ../threads/thread_function_extension_abstract.h +main.o: ../threads/threaded_object_extension.h +main.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +main.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../misc_api.h +main.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +main.o: ../misc_api/misc_api_kernel_abstract.h +main.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +main.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +main.o: ../smart_pointers/scoped_ptr_abstract.h +main.o: ../smart_pointers/shared_ptr.h +main.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +main.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +main.o: ../../dlib/logger/extra_logger_headers.h +main.o: ../../dlib/logger/logger_kernel_1.h +main.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +main.o: ../config_reader/config_reader_kernel_1.h +main.o: ../config_reader/config_reader_kernel_abstract.h ../tokenizer.h +main.o: ../tokenizer/tokenizer_kernel_1.h +main.o: ../tokenizer/tokenizer_kernel_abstract.h +main.o: ../tokenizer/tokenizer_kernel_c.h +main.o: ../config_reader/config_reader_thread_safe_1.h +main.o: ../config_reader/config_reader_thread_safe_abstract.h +main.o: ../../dlib/assert.h ../../dlib/algs.h ../../dlib/sequence.h +main.o: ../../dlib/sequence/sequence_kernel_1.h +main.o: ../../dlib/sequence/sequence_kernel_abstract.h +main.o: ../../dlib/sequence/sequence_kernel_2.h +main.o: ../../dlib/sequence/sequence_kernel_c.h +main.o: ../../dlib/sequence/sequence_compare_1.h +main.o: ../../dlib/sequence/sequence_compare_abstract.h +main.o: ../../dlib/sequence/sequence_sort_1.h +main.o: ../../dlib/sequence/sequence_sort_abstract.h +main.o: ../../dlib/sequence/sequence_sort_2.h ../../dlib/string.h +tester.o: tester.h ../../dlib/map.h ../../dlib/logger.h +tester.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +tester.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +tester.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +tester.o: /usr/include/pthread.h /usr/include/features.h +tester.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +tester.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +tester.o: /usr/include/sched.h /usr/include/bits/types.h +tester.o: /usr/include/bits/typesizes.h /usr/include/time.h +tester.o: /usr/include/bits/sched.h /usr/include/signal.h +tester.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +tester.o: /usr/include/bits/setjmp.h /usr/include/errno.h +tester.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +tester.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +tester.o: /usr/include/asm-generic/errno.h +tester.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +tester.o: /usr/include/bits/time.h /usr/include/sys/select.h +tester.o: /usr/include/bits/select.h ../algs.h ../platform.h ../assert.h +tester.o: ../error.h ../noncopyable.h ../threads/threads_kernel_shared.h +tester.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +tester.o: ../threads/rmutex_extension.h +tester.o: ../threads/rmutex_extension_abstract.h +tester.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +tester.o: ../binary_search_tree/binary_search_tree_kernel_1.h +tester.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +tester.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +tester.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +tester.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +tester.o: ../binary_search_tree/binary_search_tree_kernel_2.h +tester.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +tester.o: ../../dlib/memory_manager.h ../member_function_pointer.h +tester.o: ../member_function_pointer/member_function_pointer_kernel_1.h +tester.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +tester.o: ../member_function_pointer/member_function_pointer_kernel_c.h +tester.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +tester.o: ../memory_manager/memory_manager_kernel_abstract.h +tester.o: ../memory_manager/memory_manager_kernel_2.h +tester.o: ../memory_manager/memory_manager_kernel_3.h +tester.o: ../memory_manager/memory_manager_kernel_2.h +tester.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +tester.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +tester.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +tester.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +tester.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +tester.o: ../set/set_kernel_c.h binary_search_tree.h +tester.o: ../../dlib/memory_manager_global.h +tester.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +tester.o: ../memory_manager/memory_manager_kernel_abstract.h +tester.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +tester.o: ../../dlib/memory_manager_stateless.h +tester.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +tester.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +tester.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +tester.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +tester.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +tester.o: ../threads/auto_unlock_extension.h +tester.o: ../threads/auto_unlock_extension_abstract.h +tester.o: ../threads/create_new_thread_extension.h +tester.o: ../threads/create_new_thread_extension_abstract.h +tester.o: ../threads/multithreaded_object_extension.h +tester.o: ../threads/multithreaded_object_extension_abstract.h +tester.o: ../threads/rsignaler_extension.h +tester.o: ../threads/rsignaler_extension_abstract.h ../map.h +tester.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +tester.o: ../threads/threaded_object_extension.h +tester.o: ../threads/threaded_object_extension_abstract.h +tester.o: ../threads/thread_specific_data_extension.h +tester.o: ../threads/thread_specific_data_extension_abstract.h +tester.o: ../threads/thread_function_extension.h +tester.o: ../threads/thread_function_extension_abstract.h +tester.o: ../threads/threaded_object_extension.h ../misc_api.h +tester.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +tester.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +tester.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +tester.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +tester.o: ../smart_pointers/scoped_ptr_abstract.h +tester.o: ../smart_pointers/shared_ptr.h +tester.o: ../smart_pointers/shared_ptr_abstract.h +tester.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +tester.o: ../smart_pointers/weak_ptr_abstract.h +tester.o: ../../dlib/logger/extra_logger_headers.h +tester.o: ../../dlib/logger/logger_kernel_1.h +tester.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +tester.o: ../config_reader/config_reader_kernel_1.h +tester.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +tester.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +tester.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +tester.o: ../tokenizer/tokenizer_kernel_1.h +tester.o: ../tokenizer/tokenizer_kernel_abstract.h +tester.o: ../tokenizer/tokenizer_kernel_c.h +tester.o: ../config_reader/config_reader_thread_safe_1.h +tester.o: ../config_reader/config_reader_thread_safe_abstract.h +tester.o: ../../dlib/assert.h ../../dlib/algs.h ../../dlib/threads.h +../all/source.o: ../base64/base64_kernel_1.cpp ../base64/base64_kernel_1.h +../all/source.o: ../algs.h ../platform.h ../assert.h ../error.h +../all/source.o: ../noncopyable.h ../bigint/bigint_kernel_1.cpp +../all/source.o: ../bigint/bigint_kernel_1.h +../all/source.o: ../bigint/bigint_kernel_abstract.h ../serialize.h ../algs.h +../all/source.o: ../uintn.h ../interfaces/enumerable.h +../all/source.o: ../interfaces/map_pair.h ../enable_if.h ../uintn.h +../all/source.o: ../bigint/bigint_kernel_2.cpp ../bigint/bigint_kernel_2.h +../all/source.o: ../bit_stream/bit_stream_kernel_1.cpp +../all/source.o: ../bit_stream/bit_stream_kernel_1.h +../all/source.o: ../bit_stream/bit_stream_kernel_abstract.h +../all/source.o: ../entropy_decoder/entropy_decoder_kernel_1.cpp +../all/source.o: ../entropy_decoder/entropy_decoder_kernel_1.h +../all/source.o: ../entropy_decoder/entropy_decoder_kernel_abstract.h +../all/source.o: ../assert.h ../entropy_decoder/entropy_decoder_kernel_2.cpp +../all/source.o: ../entropy_decoder/entropy_decoder_kernel_2.h +../all/source.o: ../entropy_encoder/entropy_encoder_kernel_1.cpp +../all/source.o: ../entropy_encoder/entropy_encoder_kernel_1.h +../all/source.o: ../entropy_encoder/entropy_encoder_kernel_abstract.h +../all/source.o: ../entropy_encoder/entropy_encoder_kernel_2.cpp +../all/source.o: ../entropy_encoder/entropy_encoder_kernel_2.h +../all/source.o: ../md5/md5_kernel_1.cpp ../md5/md5_kernel_1.h +../all/source.o: ../md5/md5_kernel_abstract.h ../pixel.cpp ../pixel.h +../all/source.o: ../serialize.h ../tokenizer/tokenizer_kernel_1.cpp +../all/source.o: ../tokenizer/tokenizer_kernel_1.h +../all/source.o: ../tokenizer/tokenizer_kernel_abstract.h +../all/source.o: ../sockets/sockets_kernel_1.cpp ../platform.h +../all/source.o: ../dir_nav/dir_nav_kernel_1.cpp +../all/source.o: ../dir_nav/dir_nav_kernel_2.cpp +../all/source.o: ../dir_nav/dir_nav_kernel_2.h +../all/source.o: ../dir_nav/dir_nav_kernel_abstract.h +../all/source.o: /usr/include/sys/types.h /usr/include/features.h +../all/source.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +../all/source.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +../all/source.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +../all/source.o: /usr/include/time.h /usr/include/endian.h +../all/source.o: /usr/include/bits/endian.h /usr/include/sys/select.h +../all/source.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +../all/source.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +../all/source.o: /usr/include/bits/pthreadtypes.h /usr/include/dirent.h +../all/source.o: /usr/include/bits/dirent.h /usr/include/bits/posix1_lim.h +../all/source.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h +../all/source.o: /usr/include/libgen.h /usr/include/unistd.h +../all/source.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +../all/source.o: /usr/include/getopt.h /usr/include/sys/stat.h +../all/source.o: /usr/include/bits/stat.h /usr/include/errno.h +../all/source.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +../all/source.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +../all/source.o: /usr/include/asm-generic/errno.h +../all/source.o: /usr/include/asm-generic/errno-base.h /usr/include/stdlib.h +../all/source.o: /usr/include/alloca.h ../linker/linker_kernel_1.cpp +../all/source.o: ../linker/linker_kernel_1.h +../all/source.o: ../linker/linker_kernel_abstract.h ../threads.h +../all/source.o: ../threads/threads_kernel.h ../threads/posix.h +../all/source.o: ../threads/threads_kernel_2.h +../all/source.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +../all/source.o: /usr/include/sched.h /usr/include/bits/sched.h +../all/source.o: /usr/include/signal.h /usr/include/bits/setjmp.h +../all/source.o: /usr/include/sys/time.h ../threads/threads_kernel_shared.h +../all/source.o: ../threads/auto_mutex_extension.h +../all/source.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +../all/source.o: ../threads/rmutex_extension_abstract.h +../all/source.o: ../threads/auto_mutex_extension_abstract.h +../all/source.o: ../binary_search_tree.h +../all/source.o: ../binary_search_tree/binary_search_tree_kernel_1.h +../all/source.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +../all/source.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +../all/source.o: ../interfaces/remover.h +../all/source.o: ../binary_search_tree/binary_search_tree_kernel_2.h +../all/source.o: ../binary_search_tree/binary_search_tree_kernel_c.h +../all/source.o: ../../dlib/memory_manager.h ../member_function_pointer.h +../all/source.o: ../member_function_pointer/member_function_pointer_kernel_1.h +../all/source.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +../all/source.o: ../member_function_pointer/member_function_pointer_kernel_c.h +../all/source.o: ../memory_manager.h +../all/source.o: ../memory_manager/memory_manager_kernel_1.h +../all/source.o: ../memory_manager/memory_manager_kernel_abstract.h +../all/source.o: ../memory_manager/memory_manager_kernel_2.h +../all/source.o: ../memory_manager/memory_manager_kernel_3.h +../all/source.o: ../memory_manager/memory_manager_kernel_2.h +../all/source.o: ../binary_search_tree/binary_search_tree_kernel_2.h +../all/source.o: ../queue.h ../queue/queue_kernel_1.h +../all/source.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +../all/source.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +../all/source.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +../all/source.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +../all/source.o: ../set/set_kernel_c.h binary_search_tree.h +../all/source.o: ../../dlib/memory_manager_global.h +../all/source.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +../all/source.o: ../memory_manager/memory_manager_kernel_abstract.h +../all/source.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +../all/source.o: ../../dlib/memory_manager_stateless.h +../all/source.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +../all/source.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +../all/source.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +../all/source.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +../all/source.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +../all/source.o: ../misc_api.h ../misc_api/posix.h +../all/source.o: ../misc_api/misc_api_kernel_2.h +../all/source.o: ../misc_api/misc_api_kernel_abstract.h +../all/source.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +../all/source.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +../all/source.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +../all/source.o: ../smart_pointers/shared_ptr.h +../all/source.o: ../smart_pointers/shared_ptr_abstract.h +../all/source.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +../all/source.o: ../smart_pointers/weak_ptr_abstract.h +../all/source.o: ../../dlib/logger/extra_logger_headers.h +../all/source.o: ../../dlib/logger/logger_kernel_1.h +../all/source.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +../all/source.o: ../config_reader/config_reader_kernel_1.h +../all/source.o: ../config_reader/config_reader_kernel_abstract.h +../all/source.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +../all/source.o: ../../dlib/map/map_kernel_abstract.h +../all/source.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +../all/source.o: ../tokenizer/tokenizer_kernel_1.h +../all/source.o: ../tokenizer/tokenizer_kernel_c.h +../all/source.o: ../config_reader/config_reader_thread_safe_1.h +../all/source.o: ../config_reader/config_reader_thread_safe_abstract.h +../all/source.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +../all/source.o: ../set/set_compare_abstract.h +../all/source.o: ../threads/auto_mutex_extension.h +../all/source.o: ../threads/auto_unlock_extension.h +../all/source.o: ../threads/auto_unlock_extension_abstract.h +../all/source.o: ../threads/create_new_thread_extension.h +../all/source.o: ../threads/create_new_thread_extension_abstract.h +../all/source.o: ../threads/multithreaded_object_extension.h +../all/source.o: ../threads/multithreaded_object_extension_abstract.h +../all/source.o: ../threads/rsignaler_extension.h +../all/source.o: ../threads/rsignaler_extension_abstract.h +../all/source.o: ../threads/rmutex_extension.h +../all/source.o: ../threads/rsignaler_extension.h +../all/source.o: ../threads/threaded_object_extension.h +../all/source.o: ../threads/threaded_object_extension_abstract.h +../all/source.o: ../threads/thread_specific_data_extension.h +../all/source.o: ../threads/thread_specific_data_extension_abstract.h +../all/source.o: ../threads/thread_function_extension.h +../all/source.o: ../threads/thread_function_extension_abstract.h +../all/source.o: ../threads/threaded_object_extension.h ../sockets.h +../all/source.o: ../sockets/posix.h ../sockets/sockets_kernel_2.h +../all/source.o: ../sockets/sockets_kernel_abstract.h +../all/source.o: /usr/include/sys/socket.h /usr/include/sys/uio.h +../all/source.o: /usr/include/bits/uio.h /usr/include/bits/socket.h +../all/source.o: /usr/include/limits.h /usr/include/bits/posix2_lim.h +../all/source.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h +../all/source.o: /usr/include/asm-i386/socket.h /usr/include/asm/sockios.h +../all/source.o: /usr/include/asm-i386/sockios.h /usr/include/arpa/inet.h +../all/source.o: /usr/include/netinet/in.h /usr/include/stdint.h +../all/source.o: /usr/include/bits/wchar.h /usr/include/bits/in.h +../all/source.o: /usr/include/bits/byteswap.h /usr/include/inttypes.h +../all/source.o: /usr/include/netdb.h /usr/include/rpc/netdb.h +../all/source.o: /usr/include/bits/netdb.h /usr/include/sys/param.h +../all/source.o: /usr/include/linux/param.h /usr/include/asm/param.h +../all/source.o: /usr/include/asm-i386/param.h +../all/source.o: ../sockets/sockets_extensions.h +../all/source.o: ../sockets/sockets_extensions_abstract.h +../all/source.o: ../logger/extra_logger_headers.cpp +../all/source.o: ../logger/extra_logger_headers.h +../all/source.o: ../logger/logger_kernel_1.cpp +../all/source.o: ../logger/logger_config_file.cpp +../all/source.o: ../logger/logger_config_file.h ../error.h ../string.h +../all/source.o: ../string/string.h ../string/string_abstract.h +../all/source.o: ../enable_if.h ../misc_api/misc_api_kernel_1.cpp +../all/source.o: ../misc_api/misc_api_kernel_2.cpp +../all/source.o: ../sockets/sockets_extensions.cpp +../all/source.o: ../sockets/sockets_extensions.h ../timer.h +../all/source.o: ../timer/timer_kernel_1.h ../timer/timer_kernel_abstract.h +../all/source.o: ../timer/timer_kernel_2.h ../timeout.h +../all/source.o: ../timeout/timeout_kernel_1.h +../all/source.o: ../timeout/timeout_kernel_abstract.h +../all/source.o: ../sockets/sockets_kernel_2.cpp /usr/include/fcntl.h +../all/source.o: /usr/include/bits/fcntl.h +../all/source.o: ../sockstreambuf/sockstreambuf_kernel_1.cpp +../all/source.o: ../sockstreambuf/sockstreambuf_kernel_1.h +../all/source.o: ../sockstreambuf/sockstreambuf_kernel_abstract.h +../all/source.o: ../sockstreambuf/sockstreambuf_kernel_2.cpp +../all/source.o: ../sockstreambuf/sockstreambuf_kernel_2.h +../all/source.o: ../threads/multithreaded_object_extension.cpp +../all/source.o: ../threads/multithreaded_object_extension.h +../all/source.o: ../threads/threaded_object_extension.cpp +../all/source.o: ../threads/create_new_thread_extension.h +../all/source.o: ../threads/threads_kernel_1.cpp +../all/source.o: ../threads/threads_kernel_2.cpp +../all/source.o: ../threads/threads_kernel_shared.cpp +../all/source.o: ../timer/timer_kernel_2.cpp ../timer/timer_kernel_2.h +example.o: tester.h ../../dlib/map.h ../../dlib/logger.h +example.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +example.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +example.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +example.o: /usr/include/pthread.h /usr/include/features.h +example.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +example.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +example.o: /usr/include/sched.h /usr/include/bits/types.h +example.o: /usr/include/bits/typesizes.h /usr/include/time.h +example.o: /usr/include/bits/sched.h /usr/include/signal.h +example.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +example.o: /usr/include/bits/setjmp.h /usr/include/errno.h +example.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +example.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +example.o: /usr/include/asm-generic/errno.h +example.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +example.o: /usr/include/bits/time.h /usr/include/sys/select.h +example.o: /usr/include/bits/select.h ../algs.h ../platform.h ../assert.h +example.o: ../error.h ../noncopyable.h ../threads/threads_kernel_shared.h +example.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +example.o: ../threads/rmutex_extension.h +example.o: ../threads/rmutex_extension_abstract.h +example.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +example.o: ../binary_search_tree/binary_search_tree_kernel_1.h +example.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +example.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +example.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +example.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +example.o: ../binary_search_tree/binary_search_tree_kernel_2.h +example.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +example.o: ../../dlib/memory_manager.h ../member_function_pointer.h +example.o: ../member_function_pointer/member_function_pointer_kernel_1.h +example.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +example.o: ../member_function_pointer/member_function_pointer_kernel_c.h +example.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +example.o: ../memory_manager/memory_manager_kernel_abstract.h +example.o: ../memory_manager/memory_manager_kernel_2.h +example.o: ../memory_manager/memory_manager_kernel_3.h +example.o: ../memory_manager/memory_manager_kernel_2.h +example.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +example.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +example.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +example.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +example.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +example.o: ../set/set_kernel_c.h binary_search_tree.h +example.o: ../../dlib/memory_manager_global.h +example.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +example.o: ../memory_manager/memory_manager_kernel_abstract.h +example.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +example.o: ../../dlib/memory_manager_stateless.h +example.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +example.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +example.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +example.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +example.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +example.o: ../threads/auto_unlock_extension.h +example.o: ../threads/auto_unlock_extension_abstract.h +example.o: ../threads/create_new_thread_extension.h +example.o: ../threads/create_new_thread_extension_abstract.h +example.o: ../threads/multithreaded_object_extension.h +example.o: ../threads/multithreaded_object_extension_abstract.h +example.o: ../threads/rsignaler_extension.h +example.o: ../threads/rsignaler_extension_abstract.h ../map.h +example.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +example.o: ../threads/threaded_object_extension.h +example.o: ../threads/threaded_object_extension_abstract.h +example.o: ../threads/thread_specific_data_extension.h +example.o: ../threads/thread_specific_data_extension_abstract.h +example.o: ../threads/thread_function_extension.h +example.o: ../threads/thread_function_extension_abstract.h +example.o: ../threads/threaded_object_extension.h ../misc_api.h +example.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +example.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +example.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +example.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +example.o: ../smart_pointers/scoped_ptr_abstract.h +example.o: ../smart_pointers/shared_ptr.h +example.o: ../smart_pointers/shared_ptr_abstract.h +example.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +example.o: ../smart_pointers/weak_ptr_abstract.h +example.o: ../../dlib/logger/extra_logger_headers.h +example.o: ../../dlib/logger/logger_kernel_1.h +example.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +example.o: ../config_reader/config_reader_kernel_1.h +example.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +example.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +example.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +example.o: ../tokenizer/tokenizer_kernel_1.h +example.o: ../tokenizer/tokenizer_kernel_abstract.h +example.o: ../tokenizer/tokenizer_kernel_c.h +example.o: ../config_reader/config_reader_thread_safe_1.h +example.o: ../config_reader/config_reader_thread_safe_abstract.h +example.o: ../../dlib/assert.h ../../dlib/algs.h +example_args.o: tester.h ../../dlib/map.h ../../dlib/logger.h +example_args.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +example_args.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +example_args.o: ../threads/threads_kernel_2.h +example_args.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +example_args.o: /usr/include/features.h /usr/include/sys/cdefs.h +example_args.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +example_args.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +example_args.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +example_args.o: /usr/include/time.h /usr/include/bits/sched.h +example_args.o: /usr/include/signal.h /usr/include/bits/sigset.h +example_args.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +example_args.o: /usr/include/errno.h /usr/include/bits/errno.h +example_args.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +example_args.o: /usr/include/asm-i386/errno.h +example_args.o: /usr/include/asm-generic/errno.h +example_args.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +example_args.o: /usr/include/bits/time.h /usr/include/sys/select.h +example_args.o: /usr/include/bits/select.h ../algs.h ../platform.h +example_args.o: ../assert.h ../error.h ../noncopyable.h +example_args.o: ../threads/threads_kernel_shared.h +example_args.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +example_args.o: ../threads/rmutex_extension.h +example_args.o: ../threads/rmutex_extension_abstract.h +example_args.o: ../threads/auto_mutex_extension_abstract.h +example_args.o: ../binary_search_tree.h +example_args.o: ../binary_search_tree/binary_search_tree_kernel_1.h +example_args.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +example_args.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +example_args.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +example_args.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +example_args.o: ../enable_if.h +example_args.o: ../binary_search_tree/binary_search_tree_kernel_2.h +example_args.o: ../binary_search_tree/binary_search_tree_kernel_c.h +example_args.o: ../assert.h ../../dlib/memory_manager.h +example_args.o: ../member_function_pointer.h +example_args.o: ../member_function_pointer/member_function_pointer_kernel_1.h +example_args.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +example_args.o: ../member_function_pointer/member_function_pointer_kernel_c.h +example_args.o: ../memory_manager.h +example_args.o: ../memory_manager/memory_manager_kernel_1.h +example_args.o: ../memory_manager/memory_manager_kernel_abstract.h +example_args.o: ../memory_manager/memory_manager_kernel_2.h +example_args.o: ../memory_manager/memory_manager_kernel_3.h +example_args.o: ../memory_manager/memory_manager_kernel_2.h +example_args.o: ../binary_search_tree/binary_search_tree_kernel_2.h +example_args.o: ../queue.h ../queue/queue_kernel_1.h +example_args.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +example_args.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +example_args.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +example_args.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +example_args.o: ../set/set_kernel_c.h binary_search_tree.h +example_args.o: ../../dlib/memory_manager_global.h +example_args.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +example_args.o: ../memory_manager/memory_manager_kernel_abstract.h +example_args.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +example_args.o: ../../dlib/memory_manager_stateless.h +example_args.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +example_args.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +example_args.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +example_args.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +example_args.o: ../set/set_compare_abstract.h +example_args.o: ../threads/auto_mutex_extension.h +example_args.o: ../threads/auto_unlock_extension.h +example_args.o: ../threads/auto_unlock_extension_abstract.h +example_args.o: ../threads/create_new_thread_extension.h +example_args.o: ../threads/create_new_thread_extension_abstract.h +example_args.o: ../threads/multithreaded_object_extension.h +example_args.o: ../threads/multithreaded_object_extension_abstract.h +example_args.o: ../threads/rsignaler_extension.h +example_args.o: ../threads/rsignaler_extension_abstract.h ../map.h +example_args.o: ../threads/rmutex_extension.h +example_args.o: ../threads/rsignaler_extension.h +example_args.o: ../threads/threaded_object_extension.h +example_args.o: ../threads/threaded_object_extension_abstract.h +example_args.o: ../threads/thread_specific_data_extension.h +example_args.o: ../threads/thread_specific_data_extension_abstract.h +example_args.o: ../threads/thread_function_extension.h +example_args.o: ../threads/thread_function_extension_abstract.h +example_args.o: ../threads/threaded_object_extension.h ../misc_api.h +example_args.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +example_args.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +example_args.o: ../../dlib/logger/logger_kernel_abstract.h +example_args.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +example_args.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +example_args.o: ../smart_pointers/shared_ptr.h +example_args.o: ../smart_pointers/shared_ptr_abstract.h +example_args.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +example_args.o: ../smart_pointers/weak_ptr_abstract.h +example_args.o: ../../dlib/logger/extra_logger_headers.h +example_args.o: ../../dlib/logger/logger_kernel_1.h +example_args.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +example_args.o: ../config_reader/config_reader_kernel_1.h +example_args.o: ../config_reader/config_reader_kernel_abstract.h +example_args.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +example_args.o: ../../dlib/map/map_kernel_abstract.h +example_args.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +example_args.o: ../tokenizer/tokenizer_kernel_1.h +example_args.o: ../tokenizer/tokenizer_kernel_abstract.h +example_args.o: ../tokenizer/tokenizer_kernel_c.h +example_args.o: ../config_reader/config_reader_thread_safe_1.h +example_args.o: ../config_reader/config_reader_thread_safe_abstract.h +example_args.o: ../../dlib/assert.h ../../dlib/algs.h +array2d.o: ../../dlib/interfaces/enumerable.h ../../dlib/array2d.h +array2d.o: ../../dlib/array2d/array2d_kernel_1.h +array2d.o: ../../dlib/array2d/array2d_kernel_abstract.h ../algs.h +array2d.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +array2d.o: ../interfaces/enumerable.h ../serialize.h ../algs.h ../uintn.h +array2d.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +array2d.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +array2d.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +array2d.o: ../memory_manager/memory_manager_kernel_2.h +array2d.o: ../memory_manager/memory_manager_kernel_3.h +array2d.o: ../memory_manager/memory_manager_kernel_2.h +array2d.o: ../binary_search_tree/binary_search_tree_kernel_2.h +array2d.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +array2d.o: ../interfaces/map_pair.h ../interfaces/remover.h +array2d.o: ../../dlib/array2d/array2d_kernel_c.h ../../dlib/memory_manager.h +array2d.o: tester.h ../../dlib/map.h ../../dlib/logger.h +array2d.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +array2d.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +array2d.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +array2d.o: /usr/include/pthread.h /usr/include/features.h +array2d.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +array2d.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +array2d.o: /usr/include/sched.h /usr/include/bits/types.h +array2d.o: /usr/include/bits/typesizes.h /usr/include/time.h +array2d.o: /usr/include/bits/sched.h /usr/include/signal.h +array2d.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +array2d.o: /usr/include/bits/setjmp.h /usr/include/errno.h +array2d.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +array2d.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +array2d.o: /usr/include/asm-generic/errno.h +array2d.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +array2d.o: /usr/include/bits/time.h /usr/include/sys/select.h +array2d.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +array2d.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +array2d.o: ../threads/rmutex_extension.h +array2d.o: ../threads/rmutex_extension_abstract.h +array2d.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +array2d.o: ../binary_search_tree/binary_search_tree_kernel_1.h +array2d.o: ../binary_search_tree/binary_search_tree_kernel_2.h +array2d.o: ../binary_search_tree/binary_search_tree_kernel_c.h +array2d.o: ../member_function_pointer.h +array2d.o: ../member_function_pointer/member_function_pointer_kernel_1.h +array2d.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +array2d.o: ../member_function_pointer/member_function_pointer_kernel_c.h +array2d.o: ../queue.h ../queue/queue_kernel_1.h +array2d.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +array2d.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +array2d.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +array2d.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +array2d.o: ../set/set_kernel_c.h binary_search_tree.h +array2d.o: ../../dlib/memory_manager_global.h +array2d.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +array2d.o: ../memory_manager/memory_manager_kernel_abstract.h +array2d.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +array2d.o: ../../dlib/memory_manager_stateless.h +array2d.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +array2d.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +array2d.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +array2d.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +array2d.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +array2d.o: ../threads/auto_unlock_extension.h +array2d.o: ../threads/auto_unlock_extension_abstract.h +array2d.o: ../threads/create_new_thread_extension.h +array2d.o: ../threads/create_new_thread_extension_abstract.h +array2d.o: ../threads/multithreaded_object_extension.h +array2d.o: ../threads/multithreaded_object_extension_abstract.h +array2d.o: ../threads/rsignaler_extension.h +array2d.o: ../threads/rsignaler_extension_abstract.h ../map.h +array2d.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +array2d.o: ../threads/threaded_object_extension.h +array2d.o: ../threads/threaded_object_extension_abstract.h +array2d.o: ../threads/thread_specific_data_extension.h +array2d.o: ../threads/thread_specific_data_extension_abstract.h +array2d.o: ../threads/thread_function_extension.h +array2d.o: ../threads/thread_function_extension_abstract.h +array2d.o: ../threads/threaded_object_extension.h ../misc_api.h +array2d.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +array2d.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +array2d.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +array2d.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +array2d.o: ../smart_pointers/scoped_ptr_abstract.h +array2d.o: ../smart_pointers/shared_ptr.h +array2d.o: ../smart_pointers/shared_ptr_abstract.h +array2d.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +array2d.o: ../smart_pointers/weak_ptr_abstract.h +array2d.o: ../../dlib/logger/extra_logger_headers.h +array2d.o: ../../dlib/logger/logger_kernel_1.h +array2d.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +array2d.o: ../config_reader/config_reader_kernel_1.h +array2d.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +array2d.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +array2d.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +array2d.o: ../tokenizer/tokenizer_kernel_1.h +array2d.o: ../tokenizer/tokenizer_kernel_abstract.h +array2d.o: ../tokenizer/tokenizer_kernel_c.h +array2d.o: ../config_reader/config_reader_thread_safe_1.h +array2d.o: ../config_reader/config_reader_thread_safe_abstract.h +array2d.o: ../../dlib/assert.h ../../dlib/algs.h +array.o: ../../dlib/interfaces/enumerable.h ../../dlib/array.h +array.o: ../../dlib/array/array_kernel_1.h +array.o: ../../dlib/array/array_kernel_abstract.h ../interfaces/enumerable.h +array.o: ../algs.h ../platform.h ../assert.h ../error.h ../noncopyable.h +array.o: ../serialize.h ../algs.h ../uintn.h ../interfaces/enumerable.h +array.o: ../interfaces/map_pair.h ../enable_if.h ../memory_manager.h +array.o: ../memory_manager/memory_manager_kernel_1.h +array.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +array.o: ../memory_manager/memory_manager_kernel_2.h +array.o: ../memory_manager/memory_manager_kernel_3.h +array.o: ../memory_manager/memory_manager_kernel_2.h +array.o: ../binary_search_tree/binary_search_tree_kernel_2.h +array.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +array.o: ../interfaces/map_pair.h ../interfaces/remover.h +array.o: ../../dlib/array/array_kernel_2.h ../../dlib/array/array_kernel_c.h +array.o: ../../dlib/array/array_sort_1.h +array.o: ../../dlib/array/array_sort_abstract.h ../sort.h +array.o: ../../dlib/array/array_sort_2.h ../../dlib/array/array_expand_1.h +array.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +array.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../threads.h +array.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +array.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +array.o: /usr/include/pthread.h /usr/include/features.h +array.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +array.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +array.o: /usr/include/sched.h /usr/include/bits/types.h +array.o: /usr/include/bits/typesizes.h /usr/include/time.h +array.o: /usr/include/bits/sched.h /usr/include/signal.h +array.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +array.o: /usr/include/bits/setjmp.h /usr/include/errno.h +array.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +array.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +array.o: /usr/include/asm-generic/errno.h +array.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +array.o: /usr/include/bits/time.h /usr/include/sys/select.h +array.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +array.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +array.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +array.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +array.o: ../binary_search_tree/binary_search_tree_kernel_1.h +array.o: ../binary_search_tree/binary_search_tree_kernel_2.h +array.o: ../binary_search_tree/binary_search_tree_kernel_c.h +array.o: ../member_function_pointer.h +array.o: ../member_function_pointer/member_function_pointer_kernel_1.h +array.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +array.o: ../member_function_pointer/member_function_pointer_kernel_c.h +array.o: ../queue.h ../queue/queue_kernel_1.h +array.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +array.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +array.o: ../queue/queue_sort_abstract.h ../set.h ../set/set_kernel_1.h +array.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +array.o: binary_search_tree.h ../../dlib/memory_manager_global.h +array.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +array.o: ../memory_manager/memory_manager_kernel_abstract.h +array.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +array.o: ../../dlib/memory_manager_stateless.h +array.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +array.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +array.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +array.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +array.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +array.o: ../threads/auto_unlock_extension.h +array.o: ../threads/auto_unlock_extension_abstract.h +array.o: ../threads/create_new_thread_extension.h +array.o: ../threads/create_new_thread_extension_abstract.h +array.o: ../threads/multithreaded_object_extension.h +array.o: ../threads/multithreaded_object_extension_abstract.h +array.o: ../threads/rsignaler_extension.h +array.o: ../threads/rsignaler_extension_abstract.h ../map.h +array.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +array.o: ../threads/threaded_object_extension.h +array.o: ../threads/threaded_object_extension_abstract.h +array.o: ../threads/thread_specific_data_extension.h +array.o: ../threads/thread_specific_data_extension_abstract.h +array.o: ../threads/thread_function_extension.h +array.o: ../threads/thread_function_extension_abstract.h +array.o: ../threads/threaded_object_extension.h ../misc_api.h +array.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +array.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +array.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +array.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +array.o: ../smart_pointers/scoped_ptr_abstract.h +array.o: ../smart_pointers/shared_ptr.h +array.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +array.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +array.o: ../../dlib/logger/extra_logger_headers.h +array.o: ../../dlib/logger/logger_kernel_1.h +array.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +array.o: ../config_reader/config_reader_kernel_1.h +array.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +array.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +array.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +array.o: ../tokenizer/tokenizer_kernel_1.h +array.o: ../tokenizer/tokenizer_kernel_abstract.h +array.o: ../tokenizer/tokenizer_kernel_c.h +array.o: ../config_reader/config_reader_thread_safe_1.h +array.o: ../config_reader/config_reader_thread_safe_abstract.h +array.o: ../../dlib/assert.h ../../dlib/algs.h +base64.o: ../../dlib/base64.h ../../dlib/base64/base64_kernel_1.h ../algs.h +base64.o: ../platform.h ../assert.h ../error.h ../noncopyable.h tester.h +base64.o: ../../dlib/map.h ../../dlib/logger.h +base64.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +base64.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +base64.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +base64.o: /usr/include/pthread.h /usr/include/features.h +base64.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +base64.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +base64.o: /usr/include/sched.h /usr/include/bits/types.h +base64.o: /usr/include/bits/typesizes.h /usr/include/time.h +base64.o: /usr/include/bits/sched.h /usr/include/signal.h +base64.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +base64.o: /usr/include/bits/setjmp.h /usr/include/errno.h +base64.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +base64.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +base64.o: /usr/include/asm-generic/errno.h +base64.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +base64.o: /usr/include/bits/time.h /usr/include/sys/select.h +base64.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +base64.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +base64.o: ../threads/rmutex_extension.h +base64.o: ../threads/rmutex_extension_abstract.h +base64.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +base64.o: ../binary_search_tree/binary_search_tree_kernel_1.h +base64.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +base64.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +base64.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +base64.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +base64.o: ../binary_search_tree/binary_search_tree_kernel_2.h +base64.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +base64.o: ../../dlib/memory_manager.h ../member_function_pointer.h +base64.o: ../member_function_pointer/member_function_pointer_kernel_1.h +base64.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +base64.o: ../member_function_pointer/member_function_pointer_kernel_c.h +base64.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +base64.o: ../memory_manager/memory_manager_kernel_abstract.h +base64.o: ../memory_manager/memory_manager_kernel_2.h +base64.o: ../memory_manager/memory_manager_kernel_3.h +base64.o: ../memory_manager/memory_manager_kernel_2.h +base64.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +base64.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +base64.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +base64.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +base64.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +base64.o: ../set/set_kernel_c.h binary_search_tree.h +base64.o: ../../dlib/memory_manager_global.h +base64.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +base64.o: ../memory_manager/memory_manager_kernel_abstract.h +base64.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +base64.o: ../../dlib/memory_manager_stateless.h +base64.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +base64.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +base64.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +base64.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +base64.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +base64.o: ../threads/auto_unlock_extension.h +base64.o: ../threads/auto_unlock_extension_abstract.h +base64.o: ../threads/create_new_thread_extension.h +base64.o: ../threads/create_new_thread_extension_abstract.h +base64.o: ../threads/multithreaded_object_extension.h +base64.o: ../threads/multithreaded_object_extension_abstract.h +base64.o: ../threads/rsignaler_extension.h +base64.o: ../threads/rsignaler_extension_abstract.h ../map.h +base64.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +base64.o: ../threads/threaded_object_extension.h +base64.o: ../threads/threaded_object_extension_abstract.h +base64.o: ../threads/thread_specific_data_extension.h +base64.o: ../threads/thread_specific_data_extension_abstract.h +base64.o: ../threads/thread_function_extension.h +base64.o: ../threads/thread_function_extension_abstract.h +base64.o: ../threads/threaded_object_extension.h ../misc_api.h +base64.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +base64.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +base64.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +base64.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +base64.o: ../smart_pointers/scoped_ptr_abstract.h +base64.o: ../smart_pointers/shared_ptr.h +base64.o: ../smart_pointers/shared_ptr_abstract.h +base64.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +base64.o: ../smart_pointers/weak_ptr_abstract.h +base64.o: ../../dlib/logger/extra_logger_headers.h +base64.o: ../../dlib/logger/logger_kernel_1.h +base64.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +base64.o: ../config_reader/config_reader_kernel_1.h +base64.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +base64.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +base64.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +base64.o: ../tokenizer/tokenizer_kernel_1.h +base64.o: ../tokenizer/tokenizer_kernel_abstract.h +base64.o: ../tokenizer/tokenizer_kernel_c.h +base64.o: ../config_reader/config_reader_thread_safe_1.h +base64.o: ../config_reader/config_reader_thread_safe_abstract.h +base64.o: ../../dlib/assert.h ../../dlib/algs.h +bayes_nets.o: ../../dlib/graph_utils.h ../../dlib/graph_utils/graph_utils.h +bayes_nets.o: ../algs.h ../platform.h ../assert.h ../error.h ../noncopyable.h +bayes_nets.o: ../../dlib/graph_utils/graph_utils_abstract.h ../is_kind.h +bayes_nets.o: ../enable_if.h ../set.h ../set/set_kernel_1.h +bayes_nets.o: ../set/set_kernel_abstract.h ../interfaces/enumerable.h +bayes_nets.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +bayes_nets.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +bayes_nets.o: ../enable_if.h ../memory_manager.h +bayes_nets.o: ../memory_manager/memory_manager_kernel_1.h +bayes_nets.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +bayes_nets.o: ../memory_manager/memory_manager_kernel_2.h +bayes_nets.o: ../memory_manager/memory_manager_kernel_3.h +bayes_nets.o: ../memory_manager/memory_manager_kernel_2.h +bayes_nets.o: ../binary_search_tree/binary_search_tree_kernel_2.h +bayes_nets.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +bayes_nets.o: ../interfaces/map_pair.h ../set/set_kernel_c.h +bayes_nets.o: binary_search_tree.h ../../dlib/memory_manager_global.h +bayes_nets.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +bayes_nets.o: ../memory_manager/memory_manager_kernel_abstract.h +bayes_nets.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +bayes_nets.o: ../../dlib/memory_manager.h +bayes_nets.o: ../../dlib/memory_manager_stateless.h +bayes_nets.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +bayes_nets.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +bayes_nets.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +bayes_nets.o: ../threads.h ../threads/threads_kernel.h ../platform.h +bayes_nets.o: ../threads/posix.h ../threads/threads_kernel_2.h +bayes_nets.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +bayes_nets.o: /usr/include/features.h /usr/include/sys/cdefs.h +bayes_nets.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +bayes_nets.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +bayes_nets.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +bayes_nets.o: /usr/include/time.h /usr/include/bits/sched.h +bayes_nets.o: /usr/include/signal.h /usr/include/bits/sigset.h +bayes_nets.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +bayes_nets.o: /usr/include/errno.h /usr/include/bits/errno.h +bayes_nets.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +bayes_nets.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +bayes_nets.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +bayes_nets.o: /usr/include/bits/time.h /usr/include/sys/select.h +bayes_nets.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +bayes_nets.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +bayes_nets.o: ../threads/rmutex_extension.h +bayes_nets.o: ../threads/rmutex_extension_abstract.h +bayes_nets.o: ../threads/auto_mutex_extension_abstract.h +bayes_nets.o: ../binary_search_tree.h +bayes_nets.o: ../binary_search_tree/binary_search_tree_kernel_1.h +bayes_nets.o: ../binary_search_tree/binary_search_tree_kernel_2.h +bayes_nets.o: ../binary_search_tree/binary_search_tree_kernel_c.h +bayes_nets.o: ../member_function_pointer.h +bayes_nets.o: ../member_function_pointer/member_function_pointer_kernel_1.h +bayes_nets.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +bayes_nets.o: ../member_function_pointer/member_function_pointer_kernel_c.h +bayes_nets.o: ../queue.h ../queue/queue_kernel_1.h +bayes_nets.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +bayes_nets.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +bayes_nets.o: ../queue/queue_sort_abstract.h ../sort.h +bayes_nets.o: ../threads/auto_mutex_extension.h +bayes_nets.o: ../threads/auto_unlock_extension.h +bayes_nets.o: ../threads/auto_unlock_extension_abstract.h +bayes_nets.o: ../threads/create_new_thread_extension.h +bayes_nets.o: ../threads/create_new_thread_extension_abstract.h +bayes_nets.o: ../threads/multithreaded_object_extension.h +bayes_nets.o: ../threads/multithreaded_object_extension_abstract.h +bayes_nets.o: ../threads/rsignaler_extension.h +bayes_nets.o: ../threads/rsignaler_extension_abstract.h ../map.h +bayes_nets.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +bayes_nets.o: ../threads/threaded_object_extension.h +bayes_nets.o: ../threads/threaded_object_extension_abstract.h +bayes_nets.o: ../threads/thread_specific_data_extension.h +bayes_nets.o: ../threads/thread_specific_data_extension_abstract.h +bayes_nets.o: ../threads/thread_function_extension.h +bayes_nets.o: ../threads/thread_function_extension_abstract.h +bayes_nets.o: ../threads/threaded_object_extension.h +bayes_nets.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +bayes_nets.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +bayes_nets.o: ../misc_api.h ../misc_api/posix.h +bayes_nets.o: ../misc_api/misc_api_kernel_2.h +bayes_nets.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +bayes_nets.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +bayes_nets.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +bayes_nets.o: ../smart_pointers/scoped_ptr_abstract.h +bayes_nets.o: ../smart_pointers/shared_ptr.h +bayes_nets.o: ../smart_pointers/shared_ptr_abstract.h +bayes_nets.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +bayes_nets.o: ../smart_pointers/weak_ptr_abstract.h +bayes_nets.o: ../../dlib/logger/extra_logger_headers.h +bayes_nets.o: ../../dlib/logger/logger_kernel_1.h +bayes_nets.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +bayes_nets.o: ../config_reader/config_reader_kernel_1.h +bayes_nets.o: ../config_reader/config_reader_kernel_abstract.h +bayes_nets.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +bayes_nets.o: ../../dlib/map/map_kernel_abstract.h +bayes_nets.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +bayes_nets.o: ../tokenizer/tokenizer_kernel_1.h +bayes_nets.o: ../tokenizer/tokenizer_kernel_abstract.h +bayes_nets.o: ../tokenizer/tokenizer_kernel_c.h +bayes_nets.o: ../config_reader/config_reader_thread_safe_1.h +bayes_nets.o: ../config_reader/config_reader_thread_safe_abstract.h +bayes_nets.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +bayes_nets.o: ../set/set_compare_abstract.h ../set_utils.h +bayes_nets.o: ../set_utils/set_utils.h ../set_utils/set_utils_abstract.h +bayes_nets.o: ../../dlib/graph.h ../../dlib/graph/graph_kernel_1.h +bayes_nets.o: ../std_allocator.h ../../dlib/graph/graph_kernel_abstract.h +bayes_nets.o: ../../dlib/directed_graph.h +bayes_nets.o: ../../dlib/directed_graph/directed_graph_kernel_1.h +bayes_nets.o: ../../dlib/directed_graph/directed_graph_kernel_abstract.h +bayes_nets.o: ../../dlib/bayes_utils.h ../../dlib/bayes_utils/bayes_utils.h +bayes_nets.o: ../../dlib/bayes_utils/bayes_utils_abstract.h ../string.h +bayes_nets.o: ../string/string.h ../error.h ../string/string_abstract.h +bayes_nets.o: ../matrix.h ../matrix/matrix.h ../matrix/matrix_abstract.h +bayes_nets.o: ../matrix/matrix_utilities.h +bayes_nets.o: ../matrix/matrix_utilities_abstract.h ../matrix/matrix.h +bayes_nets.o: ../pixel.h ../serialize.h ../matrix/matrix_math_functions.h +bayes_nets.o: ../matrix/matrix_utilities.h ../rand.h ../rand/rand_kernel_1.h +bayes_nets.o: ../rand/rand_kernel_abstract.h ../rand/mersenne_twister.h +bayes_nets.o: ../rand/rand_float_1.h ../rand/rand_float_abstract.h ../array.h +bayes_nets.o: ../../dlib/array/array_kernel_1.h +bayes_nets.o: ../../dlib/array/array_kernel_abstract.h +bayes_nets.o: ../../dlib/array/array_kernel_2.h +bayes_nets.o: ../../dlib/array/array_kernel_c.h +bayes_nets.o: ../../dlib/array/array_sort_1.h +bayes_nets.o: ../../dlib/array/array_sort_abstract.h +bayes_nets.o: ../../dlib/array/array_sort_2.h +bayes_nets.o: ../../dlib/array/array_expand_1.h ../graph.h ../../dlib/set.h +bigint.o: ../../dlib/bigint.h ../../dlib/bigint/bigint_kernel_1.h +bigint.o: ../bigint/bigint_kernel_abstract.h ../algs.h ../platform.h +bigint.o: ../assert.h ../error.h ../noncopyable.h ../serialize.h ../algs.h +bigint.o: ../uintn.h ../interfaces/enumerable.h ../interfaces/map_pair.h +bigint.o: ../enable_if.h ../uintn.h ../../dlib/bigint/bigint_kernel_2.h +bigint.o: ../../dlib/bigint/bigint_kernel_c.h ../assert.h tester.h +bigint.o: ../../dlib/map.h ../../dlib/logger.h +bigint.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +bigint.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +bigint.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +bigint.o: /usr/include/pthread.h /usr/include/features.h +bigint.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +bigint.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +bigint.o: /usr/include/sched.h /usr/include/bits/types.h +bigint.o: /usr/include/bits/typesizes.h /usr/include/time.h +bigint.o: /usr/include/bits/sched.h /usr/include/signal.h +bigint.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +bigint.o: /usr/include/bits/setjmp.h /usr/include/errno.h +bigint.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +bigint.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +bigint.o: /usr/include/asm-generic/errno.h +bigint.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +bigint.o: /usr/include/bits/time.h /usr/include/sys/select.h +bigint.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +bigint.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +bigint.o: ../threads/rmutex_extension.h +bigint.o: ../threads/rmutex_extension_abstract.h +bigint.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +bigint.o: ../binary_search_tree/binary_search_tree_kernel_1.h +bigint.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +bigint.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +bigint.o: ../interfaces/remover.h +bigint.o: ../binary_search_tree/binary_search_tree_kernel_2.h +bigint.o: ../binary_search_tree/binary_search_tree_kernel_c.h +bigint.o: ../../dlib/memory_manager.h ../member_function_pointer.h +bigint.o: ../member_function_pointer/member_function_pointer_kernel_1.h +bigint.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +bigint.o: ../member_function_pointer/member_function_pointer_kernel_c.h +bigint.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +bigint.o: ../memory_manager/memory_manager_kernel_abstract.h +bigint.o: ../memory_manager/memory_manager_kernel_2.h +bigint.o: ../memory_manager/memory_manager_kernel_3.h +bigint.o: ../memory_manager/memory_manager_kernel_2.h +bigint.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +bigint.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +bigint.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +bigint.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +bigint.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +bigint.o: ../set/set_kernel_c.h binary_search_tree.h +bigint.o: ../../dlib/memory_manager_global.h +bigint.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +bigint.o: ../memory_manager/memory_manager_kernel_abstract.h +bigint.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +bigint.o: ../../dlib/memory_manager_stateless.h +bigint.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +bigint.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +bigint.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +bigint.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +bigint.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +bigint.o: ../threads/auto_unlock_extension.h +bigint.o: ../threads/auto_unlock_extension_abstract.h +bigint.o: ../threads/create_new_thread_extension.h +bigint.o: ../threads/create_new_thread_extension_abstract.h +bigint.o: ../threads/multithreaded_object_extension.h +bigint.o: ../threads/multithreaded_object_extension_abstract.h +bigint.o: ../threads/rsignaler_extension.h +bigint.o: ../threads/rsignaler_extension_abstract.h ../map.h +bigint.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +bigint.o: ../threads/threaded_object_extension.h +bigint.o: ../threads/threaded_object_extension_abstract.h +bigint.o: ../threads/thread_specific_data_extension.h +bigint.o: ../threads/thread_specific_data_extension_abstract.h +bigint.o: ../threads/thread_function_extension.h +bigint.o: ../threads/thread_function_extension_abstract.h +bigint.o: ../threads/threaded_object_extension.h ../misc_api.h +bigint.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +bigint.o: ../misc_api/misc_api_kernel_abstract.h +bigint.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +bigint.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +bigint.o: ../smart_pointers/scoped_ptr_abstract.h +bigint.o: ../smart_pointers/shared_ptr.h +bigint.o: ../smart_pointers/shared_ptr_abstract.h +bigint.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +bigint.o: ../smart_pointers/weak_ptr_abstract.h +bigint.o: ../../dlib/logger/extra_logger_headers.h +bigint.o: ../../dlib/logger/logger_kernel_1.h +bigint.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +bigint.o: ../config_reader/config_reader_kernel_1.h +bigint.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +bigint.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +bigint.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +bigint.o: ../tokenizer/tokenizer_kernel_1.h +bigint.o: ../tokenizer/tokenizer_kernel_abstract.h +bigint.o: ../tokenizer/tokenizer_kernel_c.h +bigint.o: ../config_reader/config_reader_thread_safe_1.h +bigint.o: ../config_reader/config_reader_thread_safe_abstract.h +bigint.o: ../../dlib/assert.h ../../dlib/algs.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_global.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +binary_search_tree_kernel_1a.o: ../algs.h ../platform.h ../assert.h +binary_search_tree_kernel_1a.o: ../error.h ../noncopyable.h +binary_search_tree_kernel_1a.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_stateless.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +binary_search_tree_kernel_1a.o: ../threads.h ../threads/threads_kernel.h +binary_search_tree_kernel_1a.o: ../platform.h ../threads/posix.h +binary_search_tree_kernel_1a.o: ../threads/threads_kernel_2.h +binary_search_tree_kernel_1a.o: ../threads/threads_kernel_abstract.h +binary_search_tree_kernel_1a.o: /usr/include/pthread.h +binary_search_tree_kernel_1a.o: /usr/include/features.h +binary_search_tree_kernel_1a.o: /usr/include/sys/cdefs.h +binary_search_tree_kernel_1a.o: /usr/include/bits/wordsize.h +binary_search_tree_kernel_1a.o: /usr/include/gnu/stubs.h +binary_search_tree_kernel_1a.o: /usr/include/gnu/stubs-32.h +binary_search_tree_kernel_1a.o: /usr/include/sched.h +binary_search_tree_kernel_1a.o: /usr/include/bits/types.h +binary_search_tree_kernel_1a.o: /usr/include/bits/typesizes.h +binary_search_tree_kernel_1a.o: /usr/include/time.h /usr/include/bits/sched.h +binary_search_tree_kernel_1a.o: /usr/include/signal.h +binary_search_tree_kernel_1a.o: /usr/include/bits/sigset.h +binary_search_tree_kernel_1a.o: /usr/include/bits/pthreadtypes.h +binary_search_tree_kernel_1a.o: /usr/include/bits/setjmp.h +binary_search_tree_kernel_1a.o: /usr/include/errno.h +binary_search_tree_kernel_1a.o: /usr/include/bits/errno.h +binary_search_tree_kernel_1a.o: /usr/include/linux/errno.h +binary_search_tree_kernel_1a.o: /usr/include/asm/errno.h +binary_search_tree_kernel_1a.o: /usr/include/asm-i386/errno.h +binary_search_tree_kernel_1a.o: /usr/include/asm-generic/errno.h +binary_search_tree_kernel_1a.o: /usr/include/asm-generic/errno-base.h +binary_search_tree_kernel_1a.o: /usr/include/sys/time.h +binary_search_tree_kernel_1a.o: /usr/include/bits/time.h +binary_search_tree_kernel_1a.o: /usr/include/sys/select.h +binary_search_tree_kernel_1a.o: /usr/include/bits/select.h +binary_search_tree_kernel_1a.o: ../threads/threads_kernel_shared.h +binary_search_tree_kernel_1a.o: ../threads/auto_mutex_extension.h +binary_search_tree_kernel_1a.o: ../threads/threads_kernel.h +binary_search_tree_kernel_1a.o: ../threads/rmutex_extension.h +binary_search_tree_kernel_1a.o: ../threads/rmutex_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/auto_mutex_extension_abstract.h +binary_search_tree_kernel_1a.o: ../binary_search_tree.h +binary_search_tree_kernel_1a.o: ../binary_search_tree/binary_search_tree_kernel_1.h +binary_search_tree_kernel_1a.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../interfaces/map_pair.h +binary_search_tree_kernel_1a.o: ../interfaces/enumerable.h +binary_search_tree_kernel_1a.o: ../interfaces/remover.h ../serialize.h +binary_search_tree_kernel_1a.o: ../algs.h ../uintn.h +binary_search_tree_kernel_1a.o: ../interfaces/enumerable.h +binary_search_tree_kernel_1a.o: ../interfaces/map_pair.h ../enable_if.h +binary_search_tree_kernel_1a.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_kernel_1a.o: ../binary_search_tree/binary_search_tree_kernel_c.h +binary_search_tree_kernel_1a.o: ../assert.h ../member_function_pointer.h +binary_search_tree_kernel_1a.o: ../member_function_pointer/member_function_pointer_kernel_1.h +binary_search_tree_kernel_1a.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../member_function_pointer/member_function_pointer_kernel_c.h +binary_search_tree_kernel_1a.o: ../memory_manager.h +binary_search_tree_kernel_1a.o: ../memory_manager/memory_manager_kernel_1.h +binary_search_tree_kernel_1a.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_kernel_1a.o: ../memory_manager/memory_manager_kernel_3.h +binary_search_tree_kernel_1a.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_kernel_1a.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_kernel_1a.o: ../queue.h ../queue/queue_kernel_1.h +binary_search_tree_kernel_1a.o: ../queue/queue_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../queue/queue_kernel_2.h +binary_search_tree_kernel_1a.o: ../queue/queue_kernel_c.h +binary_search_tree_kernel_1a.o: ../queue/queue_sort_1.h +binary_search_tree_kernel_1a.o: ../queue/queue_sort_abstract.h ../sort.h +binary_search_tree_kernel_1a.o: ../set.h ../set/set_kernel_1.h +binary_search_tree_kernel_1a.o: ../set/set_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../set/set_kernel_c.h binary_search_tree.h +binary_search_tree_kernel_1a.o: ../../dlib/binary_search_tree.h tester.h +binary_search_tree_kernel_1a.o: ../../dlib/map.h ../../dlib/logger.h +binary_search_tree_kernel_1a.o: ../../dlib/logger/logger_kernel_1.h +binary_search_tree_kernel_1a.o: ../misc_api.h ../misc_api/posix.h +binary_search_tree_kernel_1a.o: ../misc_api/misc_api_kernel_2.h +binary_search_tree_kernel_1a.o: ../misc_api/misc_api_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../uintn.h +binary_search_tree_kernel_1a.o: ../../dlib/logger/logger_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../map.h ../smart_pointers.h +binary_search_tree_kernel_1a.o: ../smart_pointers/scoped_ptr.h +binary_search_tree_kernel_1a.o: ../noncopyable.h +binary_search_tree_kernel_1a.o: ../smart_pointers/scoped_ptr_abstract.h +binary_search_tree_kernel_1a.o: ../smart_pointers/shared_ptr.h +binary_search_tree_kernel_1a.o: ../smart_pointers/shared_ptr_abstract.h +binary_search_tree_kernel_1a.o: ../smart_pointers/weak_ptr.h +binary_search_tree_kernel_1a.o: ../smart_pointers/shared_ptr.h +binary_search_tree_kernel_1a.o: ../smart_pointers/weak_ptr_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/logger/extra_logger_headers.h +binary_search_tree_kernel_1a.o: ../../dlib/logger/logger_kernel_1.h +binary_search_tree_kernel_1a.o: ../../dlib/logger/logger_config_file.h +binary_search_tree_kernel_1a.o: ../config_reader.h +binary_search_tree_kernel_1a.o: ../config_reader/config_reader_kernel_1.h +binary_search_tree_kernel_1a.o: ../config_reader/config_reader_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/map.h +binary_search_tree_kernel_1a.o: ../../dlib/map/map_kernel_1.h +binary_search_tree_kernel_1a.o: ../../dlib/map/map_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +binary_search_tree_kernel_1a.o: ../tokenizer/tokenizer_kernel_1.h +binary_search_tree_kernel_1a.o: ../tokenizer/tokenizer_kernel_abstract.h +binary_search_tree_kernel_1a.o: ../tokenizer/tokenizer_kernel_c.h +binary_search_tree_kernel_1a.o: ../config_reader/config_reader_thread_safe_1.h +binary_search_tree_kernel_1a.o: ../config_reader/config_reader_thread_safe_abstract.h +binary_search_tree_kernel_1a.o: ../../dlib/assert.h ../../dlib/algs.h +binary_search_tree_kernel_1a.o: ../set/set_compare_1.h +binary_search_tree_kernel_1a.o: ../set/set_compare_abstract.h +binary_search_tree_kernel_1a.o: ../threads/auto_mutex_extension.h +binary_search_tree_kernel_1a.o: ../threads/auto_unlock_extension.h +binary_search_tree_kernel_1a.o: ../threads/auto_unlock_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/create_new_thread_extension.h +binary_search_tree_kernel_1a.o: ../threads/create_new_thread_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/multithreaded_object_extension.h +binary_search_tree_kernel_1a.o: ../threads/multithreaded_object_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/rsignaler_extension.h +binary_search_tree_kernel_1a.o: ../threads/rsignaler_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/rmutex_extension.h +binary_search_tree_kernel_1a.o: ../threads/rsignaler_extension.h +binary_search_tree_kernel_1a.o: ../threads/threaded_object_extension.h +binary_search_tree_kernel_1a.o: ../threads/threaded_object_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/thread_specific_data_extension.h +binary_search_tree_kernel_1a.o: ../threads/thread_specific_data_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/thread_function_extension.h +binary_search_tree_kernel_1a.o: ../threads/thread_function_extension_abstract.h +binary_search_tree_kernel_1a.o: ../threads/threaded_object_extension.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_global.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +binary_search_tree_kernel_2a.o: ../algs.h ../platform.h ../assert.h +binary_search_tree_kernel_2a.o: ../error.h ../noncopyable.h +binary_search_tree_kernel_2a.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_stateless.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +binary_search_tree_kernel_2a.o: ../threads.h ../threads/threads_kernel.h +binary_search_tree_kernel_2a.o: ../platform.h ../threads/posix.h +binary_search_tree_kernel_2a.o: ../threads/threads_kernel_2.h +binary_search_tree_kernel_2a.o: ../threads/threads_kernel_abstract.h +binary_search_tree_kernel_2a.o: /usr/include/pthread.h +binary_search_tree_kernel_2a.o: /usr/include/features.h +binary_search_tree_kernel_2a.o: /usr/include/sys/cdefs.h +binary_search_tree_kernel_2a.o: /usr/include/bits/wordsize.h +binary_search_tree_kernel_2a.o: /usr/include/gnu/stubs.h +binary_search_tree_kernel_2a.o: /usr/include/gnu/stubs-32.h +binary_search_tree_kernel_2a.o: /usr/include/sched.h +binary_search_tree_kernel_2a.o: /usr/include/bits/types.h +binary_search_tree_kernel_2a.o: /usr/include/bits/typesizes.h +binary_search_tree_kernel_2a.o: /usr/include/time.h /usr/include/bits/sched.h +binary_search_tree_kernel_2a.o: /usr/include/signal.h +binary_search_tree_kernel_2a.o: /usr/include/bits/sigset.h +binary_search_tree_kernel_2a.o: /usr/include/bits/pthreadtypes.h +binary_search_tree_kernel_2a.o: /usr/include/bits/setjmp.h +binary_search_tree_kernel_2a.o: /usr/include/errno.h +binary_search_tree_kernel_2a.o: /usr/include/bits/errno.h +binary_search_tree_kernel_2a.o: /usr/include/linux/errno.h +binary_search_tree_kernel_2a.o: /usr/include/asm/errno.h +binary_search_tree_kernel_2a.o: /usr/include/asm-i386/errno.h +binary_search_tree_kernel_2a.o: /usr/include/asm-generic/errno.h +binary_search_tree_kernel_2a.o: /usr/include/asm-generic/errno-base.h +binary_search_tree_kernel_2a.o: /usr/include/sys/time.h +binary_search_tree_kernel_2a.o: /usr/include/bits/time.h +binary_search_tree_kernel_2a.o: /usr/include/sys/select.h +binary_search_tree_kernel_2a.o: /usr/include/bits/select.h +binary_search_tree_kernel_2a.o: ../threads/threads_kernel_shared.h +binary_search_tree_kernel_2a.o: ../threads/auto_mutex_extension.h +binary_search_tree_kernel_2a.o: ../threads/threads_kernel.h +binary_search_tree_kernel_2a.o: ../threads/rmutex_extension.h +binary_search_tree_kernel_2a.o: ../threads/rmutex_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/auto_mutex_extension_abstract.h +binary_search_tree_kernel_2a.o: ../binary_search_tree.h +binary_search_tree_kernel_2a.o: ../binary_search_tree/binary_search_tree_kernel_1.h +binary_search_tree_kernel_2a.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../interfaces/map_pair.h +binary_search_tree_kernel_2a.o: ../interfaces/enumerable.h +binary_search_tree_kernel_2a.o: ../interfaces/remover.h ../serialize.h +binary_search_tree_kernel_2a.o: ../algs.h ../uintn.h +binary_search_tree_kernel_2a.o: ../interfaces/enumerable.h +binary_search_tree_kernel_2a.o: ../interfaces/map_pair.h ../enable_if.h +binary_search_tree_kernel_2a.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_kernel_2a.o: ../binary_search_tree/binary_search_tree_kernel_c.h +binary_search_tree_kernel_2a.o: ../assert.h ../member_function_pointer.h +binary_search_tree_kernel_2a.o: ../member_function_pointer/member_function_pointer_kernel_1.h +binary_search_tree_kernel_2a.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../member_function_pointer/member_function_pointer_kernel_c.h +binary_search_tree_kernel_2a.o: ../memory_manager.h +binary_search_tree_kernel_2a.o: ../memory_manager/memory_manager_kernel_1.h +binary_search_tree_kernel_2a.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_kernel_2a.o: ../memory_manager/memory_manager_kernel_3.h +binary_search_tree_kernel_2a.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_kernel_2a.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_kernel_2a.o: ../queue.h ../queue/queue_kernel_1.h +binary_search_tree_kernel_2a.o: ../queue/queue_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../queue/queue_kernel_2.h +binary_search_tree_kernel_2a.o: ../queue/queue_kernel_c.h +binary_search_tree_kernel_2a.o: ../queue/queue_sort_1.h +binary_search_tree_kernel_2a.o: ../queue/queue_sort_abstract.h ../sort.h +binary_search_tree_kernel_2a.o: ../set.h ../set/set_kernel_1.h +binary_search_tree_kernel_2a.o: ../set/set_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../set/set_kernel_c.h binary_search_tree.h +binary_search_tree_kernel_2a.o: ../../dlib/binary_search_tree.h tester.h +binary_search_tree_kernel_2a.o: ../../dlib/map.h ../../dlib/logger.h +binary_search_tree_kernel_2a.o: ../../dlib/logger/logger_kernel_1.h +binary_search_tree_kernel_2a.o: ../misc_api.h ../misc_api/posix.h +binary_search_tree_kernel_2a.o: ../misc_api/misc_api_kernel_2.h +binary_search_tree_kernel_2a.o: ../misc_api/misc_api_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../uintn.h +binary_search_tree_kernel_2a.o: ../../dlib/logger/logger_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../map.h ../smart_pointers.h +binary_search_tree_kernel_2a.o: ../smart_pointers/scoped_ptr.h +binary_search_tree_kernel_2a.o: ../noncopyable.h +binary_search_tree_kernel_2a.o: ../smart_pointers/scoped_ptr_abstract.h +binary_search_tree_kernel_2a.o: ../smart_pointers/shared_ptr.h +binary_search_tree_kernel_2a.o: ../smart_pointers/shared_ptr_abstract.h +binary_search_tree_kernel_2a.o: ../smart_pointers/weak_ptr.h +binary_search_tree_kernel_2a.o: ../smart_pointers/shared_ptr.h +binary_search_tree_kernel_2a.o: ../smart_pointers/weak_ptr_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/logger/extra_logger_headers.h +binary_search_tree_kernel_2a.o: ../../dlib/logger/logger_kernel_1.h +binary_search_tree_kernel_2a.o: ../../dlib/logger/logger_config_file.h +binary_search_tree_kernel_2a.o: ../config_reader.h +binary_search_tree_kernel_2a.o: ../config_reader/config_reader_kernel_1.h +binary_search_tree_kernel_2a.o: ../config_reader/config_reader_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/map.h +binary_search_tree_kernel_2a.o: ../../dlib/map/map_kernel_1.h +binary_search_tree_kernel_2a.o: ../../dlib/map/map_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +binary_search_tree_kernel_2a.o: ../tokenizer/tokenizer_kernel_1.h +binary_search_tree_kernel_2a.o: ../tokenizer/tokenizer_kernel_abstract.h +binary_search_tree_kernel_2a.o: ../tokenizer/tokenizer_kernel_c.h +binary_search_tree_kernel_2a.o: ../config_reader/config_reader_thread_safe_1.h +binary_search_tree_kernel_2a.o: ../config_reader/config_reader_thread_safe_abstract.h +binary_search_tree_kernel_2a.o: ../../dlib/assert.h ../../dlib/algs.h +binary_search_tree_kernel_2a.o: ../set/set_compare_1.h +binary_search_tree_kernel_2a.o: ../set/set_compare_abstract.h +binary_search_tree_kernel_2a.o: ../threads/auto_mutex_extension.h +binary_search_tree_kernel_2a.o: ../threads/auto_unlock_extension.h +binary_search_tree_kernel_2a.o: ../threads/auto_unlock_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/create_new_thread_extension.h +binary_search_tree_kernel_2a.o: ../threads/create_new_thread_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/multithreaded_object_extension.h +binary_search_tree_kernel_2a.o: ../threads/multithreaded_object_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/rsignaler_extension.h +binary_search_tree_kernel_2a.o: ../threads/rsignaler_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/rmutex_extension.h +binary_search_tree_kernel_2a.o: ../threads/rsignaler_extension.h +binary_search_tree_kernel_2a.o: ../threads/threaded_object_extension.h +binary_search_tree_kernel_2a.o: ../threads/threaded_object_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/thread_specific_data_extension.h +binary_search_tree_kernel_2a.o: ../threads/thread_specific_data_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/thread_function_extension.h +binary_search_tree_kernel_2a.o: ../threads/thread_function_extension_abstract.h +binary_search_tree_kernel_2a.o: ../threads/threaded_object_extension.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_global.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +binary_search_tree_mm1.o: ../algs.h ../platform.h ../assert.h ../error.h +binary_search_tree_mm1.o: ../noncopyable.h +binary_search_tree_mm1.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +binary_search_tree_mm1.o: ../../dlib/memory_manager.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_stateless.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +binary_search_tree_mm1.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +binary_search_tree_mm1.o: ../threads.h ../threads/threads_kernel.h +binary_search_tree_mm1.o: ../platform.h ../threads/posix.h +binary_search_tree_mm1.o: ../threads/threads_kernel_2.h +binary_search_tree_mm1.o: ../threads/threads_kernel_abstract.h +binary_search_tree_mm1.o: /usr/include/pthread.h /usr/include/features.h +binary_search_tree_mm1.o: /usr/include/sys/cdefs.h +binary_search_tree_mm1.o: /usr/include/bits/wordsize.h +binary_search_tree_mm1.o: /usr/include/gnu/stubs.h +binary_search_tree_mm1.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +binary_search_tree_mm1.o: /usr/include/bits/types.h +binary_search_tree_mm1.o: /usr/include/bits/typesizes.h /usr/include/time.h +binary_search_tree_mm1.o: /usr/include/bits/sched.h /usr/include/signal.h +binary_search_tree_mm1.o: /usr/include/bits/sigset.h +binary_search_tree_mm1.o: /usr/include/bits/pthreadtypes.h +binary_search_tree_mm1.o: /usr/include/bits/setjmp.h /usr/include/errno.h +binary_search_tree_mm1.o: /usr/include/bits/errno.h +binary_search_tree_mm1.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +binary_search_tree_mm1.o: /usr/include/asm-i386/errno.h +binary_search_tree_mm1.o: /usr/include/asm-generic/errno.h +binary_search_tree_mm1.o: /usr/include/asm-generic/errno-base.h +binary_search_tree_mm1.o: /usr/include/sys/time.h /usr/include/bits/time.h +binary_search_tree_mm1.o: /usr/include/sys/select.h +binary_search_tree_mm1.o: /usr/include/bits/select.h +binary_search_tree_mm1.o: ../threads/threads_kernel_shared.h +binary_search_tree_mm1.o: ../threads/auto_mutex_extension.h +binary_search_tree_mm1.o: ../threads/threads_kernel.h +binary_search_tree_mm1.o: ../threads/rmutex_extension.h +binary_search_tree_mm1.o: ../threads/rmutex_extension_abstract.h +binary_search_tree_mm1.o: ../threads/auto_mutex_extension_abstract.h +binary_search_tree_mm1.o: ../binary_search_tree.h +binary_search_tree_mm1.o: ../binary_search_tree/binary_search_tree_kernel_1.h +binary_search_tree_mm1.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +binary_search_tree_mm1.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +binary_search_tree_mm1.o: ../interfaces/remover.h ../serialize.h ../algs.h +binary_search_tree_mm1.o: ../uintn.h ../interfaces/enumerable.h +binary_search_tree_mm1.o: ../interfaces/map_pair.h ../enable_if.h +binary_search_tree_mm1.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_mm1.o: ../binary_search_tree/binary_search_tree_kernel_c.h +binary_search_tree_mm1.o: ../assert.h ../member_function_pointer.h +binary_search_tree_mm1.o: ../member_function_pointer/member_function_pointer_kernel_1.h +binary_search_tree_mm1.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +binary_search_tree_mm1.o: ../member_function_pointer/member_function_pointer_kernel_c.h +binary_search_tree_mm1.o: ../memory_manager.h +binary_search_tree_mm1.o: ../memory_manager/memory_manager_kernel_1.h +binary_search_tree_mm1.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_mm1.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_mm1.o: ../memory_manager/memory_manager_kernel_3.h +binary_search_tree_mm1.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_mm1.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_mm1.o: ../queue.h ../queue/queue_kernel_1.h +binary_search_tree_mm1.o: ../queue/queue_kernel_abstract.h +binary_search_tree_mm1.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +binary_search_tree_mm1.o: ../queue/queue_sort_1.h +binary_search_tree_mm1.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +binary_search_tree_mm1.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +binary_search_tree_mm1.o: ../set/set_kernel_c.h binary_search_tree.h +binary_search_tree_mm1.o: ../../dlib/binary_search_tree.h tester.h +binary_search_tree_mm1.o: ../../dlib/map.h ../../dlib/logger.h +binary_search_tree_mm1.o: ../../dlib/logger/logger_kernel_1.h ../misc_api.h +binary_search_tree_mm1.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +binary_search_tree_mm1.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +binary_search_tree_mm1.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +binary_search_tree_mm1.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +binary_search_tree_mm1.o: ../noncopyable.h +binary_search_tree_mm1.o: ../smart_pointers/scoped_ptr_abstract.h +binary_search_tree_mm1.o: ../smart_pointers/shared_ptr.h +binary_search_tree_mm1.o: ../smart_pointers/shared_ptr_abstract.h +binary_search_tree_mm1.o: ../smart_pointers/weak_ptr.h +binary_search_tree_mm1.o: ../smart_pointers/shared_ptr.h +binary_search_tree_mm1.o: ../smart_pointers/weak_ptr_abstract.h +binary_search_tree_mm1.o: ../../dlib/logger/extra_logger_headers.h +binary_search_tree_mm1.o: ../../dlib/logger/logger_kernel_1.h +binary_search_tree_mm1.o: ../../dlib/logger/logger_config_file.h +binary_search_tree_mm1.o: ../config_reader.h +binary_search_tree_mm1.o: ../config_reader/config_reader_kernel_1.h +binary_search_tree_mm1.o: ../config_reader/config_reader_kernel_abstract.h +binary_search_tree_mm1.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +binary_search_tree_mm1.o: ../../dlib/map/map_kernel_abstract.h +binary_search_tree_mm1.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +binary_search_tree_mm1.o: ../tokenizer/tokenizer_kernel_1.h +binary_search_tree_mm1.o: ../tokenizer/tokenizer_kernel_abstract.h +binary_search_tree_mm1.o: ../tokenizer/tokenizer_kernel_c.h +binary_search_tree_mm1.o: ../config_reader/config_reader_thread_safe_1.h +binary_search_tree_mm1.o: ../config_reader/config_reader_thread_safe_abstract.h +binary_search_tree_mm1.o: ../../dlib/assert.h ../../dlib/algs.h +binary_search_tree_mm1.o: ../set/set_compare_1.h +binary_search_tree_mm1.o: ../set/set_compare_abstract.h +binary_search_tree_mm1.o: ../threads/auto_mutex_extension.h +binary_search_tree_mm1.o: ../threads/auto_unlock_extension.h +binary_search_tree_mm1.o: ../threads/auto_unlock_extension_abstract.h +binary_search_tree_mm1.o: ../threads/create_new_thread_extension.h +binary_search_tree_mm1.o: ../threads/create_new_thread_extension_abstract.h +binary_search_tree_mm1.o: ../threads/multithreaded_object_extension.h +binary_search_tree_mm1.o: ../threads/multithreaded_object_extension_abstract.h +binary_search_tree_mm1.o: ../threads/rsignaler_extension.h +binary_search_tree_mm1.o: ../threads/rsignaler_extension_abstract.h +binary_search_tree_mm1.o: ../threads/rmutex_extension.h +binary_search_tree_mm1.o: ../threads/rsignaler_extension.h +binary_search_tree_mm1.o: ../threads/threaded_object_extension.h +binary_search_tree_mm1.o: ../threads/threaded_object_extension_abstract.h +binary_search_tree_mm1.o: ../threads/thread_specific_data_extension.h +binary_search_tree_mm1.o: ../threads/thread_specific_data_extension_abstract.h +binary_search_tree_mm1.o: ../threads/thread_function_extension.h +binary_search_tree_mm1.o: ../threads/thread_function_extension_abstract.h +binary_search_tree_mm1.o: ../threads/threaded_object_extension.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_global.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +binary_search_tree_mm2.o: ../algs.h ../platform.h ../assert.h ../error.h +binary_search_tree_mm2.o: ../noncopyable.h +binary_search_tree_mm2.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +binary_search_tree_mm2.o: ../../dlib/memory_manager.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_stateless.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +binary_search_tree_mm2.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +binary_search_tree_mm2.o: ../threads.h ../threads/threads_kernel.h +binary_search_tree_mm2.o: ../platform.h ../threads/posix.h +binary_search_tree_mm2.o: ../threads/threads_kernel_2.h +binary_search_tree_mm2.o: ../threads/threads_kernel_abstract.h +binary_search_tree_mm2.o: /usr/include/pthread.h /usr/include/features.h +binary_search_tree_mm2.o: /usr/include/sys/cdefs.h +binary_search_tree_mm2.o: /usr/include/bits/wordsize.h +binary_search_tree_mm2.o: /usr/include/gnu/stubs.h +binary_search_tree_mm2.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +binary_search_tree_mm2.o: /usr/include/bits/types.h +binary_search_tree_mm2.o: /usr/include/bits/typesizes.h /usr/include/time.h +binary_search_tree_mm2.o: /usr/include/bits/sched.h /usr/include/signal.h +binary_search_tree_mm2.o: /usr/include/bits/sigset.h +binary_search_tree_mm2.o: /usr/include/bits/pthreadtypes.h +binary_search_tree_mm2.o: /usr/include/bits/setjmp.h /usr/include/errno.h +binary_search_tree_mm2.o: /usr/include/bits/errno.h +binary_search_tree_mm2.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +binary_search_tree_mm2.o: /usr/include/asm-i386/errno.h +binary_search_tree_mm2.o: /usr/include/asm-generic/errno.h +binary_search_tree_mm2.o: /usr/include/asm-generic/errno-base.h +binary_search_tree_mm2.o: /usr/include/sys/time.h /usr/include/bits/time.h +binary_search_tree_mm2.o: /usr/include/sys/select.h +binary_search_tree_mm2.o: /usr/include/bits/select.h +binary_search_tree_mm2.o: ../threads/threads_kernel_shared.h +binary_search_tree_mm2.o: ../threads/auto_mutex_extension.h +binary_search_tree_mm2.o: ../threads/threads_kernel.h +binary_search_tree_mm2.o: ../threads/rmutex_extension.h +binary_search_tree_mm2.o: ../threads/rmutex_extension_abstract.h +binary_search_tree_mm2.o: ../threads/auto_mutex_extension_abstract.h +binary_search_tree_mm2.o: ../binary_search_tree.h +binary_search_tree_mm2.o: ../binary_search_tree/binary_search_tree_kernel_1.h +binary_search_tree_mm2.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +binary_search_tree_mm2.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +binary_search_tree_mm2.o: ../interfaces/remover.h ../serialize.h ../algs.h +binary_search_tree_mm2.o: ../uintn.h ../interfaces/enumerable.h +binary_search_tree_mm2.o: ../interfaces/map_pair.h ../enable_if.h +binary_search_tree_mm2.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_mm2.o: ../binary_search_tree/binary_search_tree_kernel_c.h +binary_search_tree_mm2.o: ../assert.h ../member_function_pointer.h +binary_search_tree_mm2.o: ../member_function_pointer/member_function_pointer_kernel_1.h +binary_search_tree_mm2.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +binary_search_tree_mm2.o: ../member_function_pointer/member_function_pointer_kernel_c.h +binary_search_tree_mm2.o: ../memory_manager.h +binary_search_tree_mm2.o: ../memory_manager/memory_manager_kernel_1.h +binary_search_tree_mm2.o: ../memory_manager/memory_manager_kernel_abstract.h +binary_search_tree_mm2.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_mm2.o: ../memory_manager/memory_manager_kernel_3.h +binary_search_tree_mm2.o: ../memory_manager/memory_manager_kernel_2.h +binary_search_tree_mm2.o: ../binary_search_tree/binary_search_tree_kernel_2.h +binary_search_tree_mm2.o: ../queue.h ../queue/queue_kernel_1.h +binary_search_tree_mm2.o: ../queue/queue_kernel_abstract.h +binary_search_tree_mm2.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +binary_search_tree_mm2.o: ../queue/queue_sort_1.h +binary_search_tree_mm2.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +binary_search_tree_mm2.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +binary_search_tree_mm2.o: ../set/set_kernel_c.h binary_search_tree.h +binary_search_tree_mm2.o: ../../dlib/binary_search_tree.h tester.h +binary_search_tree_mm2.o: ../../dlib/map.h ../../dlib/logger.h +binary_search_tree_mm2.o: ../../dlib/logger/logger_kernel_1.h ../misc_api.h +binary_search_tree_mm2.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +binary_search_tree_mm2.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +binary_search_tree_mm2.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +binary_search_tree_mm2.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +binary_search_tree_mm2.o: ../noncopyable.h +binary_search_tree_mm2.o: ../smart_pointers/scoped_ptr_abstract.h +binary_search_tree_mm2.o: ../smart_pointers/shared_ptr.h +binary_search_tree_mm2.o: ../smart_pointers/shared_ptr_abstract.h +binary_search_tree_mm2.o: ../smart_pointers/weak_ptr.h +binary_search_tree_mm2.o: ../smart_pointers/shared_ptr.h +binary_search_tree_mm2.o: ../smart_pointers/weak_ptr_abstract.h +binary_search_tree_mm2.o: ../../dlib/logger/extra_logger_headers.h +binary_search_tree_mm2.o: ../../dlib/logger/logger_kernel_1.h +binary_search_tree_mm2.o: ../../dlib/logger/logger_config_file.h +binary_search_tree_mm2.o: ../config_reader.h +binary_search_tree_mm2.o: ../config_reader/config_reader_kernel_1.h +binary_search_tree_mm2.o: ../config_reader/config_reader_kernel_abstract.h +binary_search_tree_mm2.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +binary_search_tree_mm2.o: ../../dlib/map/map_kernel_abstract.h +binary_search_tree_mm2.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +binary_search_tree_mm2.o: ../tokenizer/tokenizer_kernel_1.h +binary_search_tree_mm2.o: ../tokenizer/tokenizer_kernel_abstract.h +binary_search_tree_mm2.o: ../tokenizer/tokenizer_kernel_c.h +binary_search_tree_mm2.o: ../config_reader/config_reader_thread_safe_1.h +binary_search_tree_mm2.o: ../config_reader/config_reader_thread_safe_abstract.h +binary_search_tree_mm2.o: ../../dlib/assert.h ../../dlib/algs.h +binary_search_tree_mm2.o: ../set/set_compare_1.h +binary_search_tree_mm2.o: ../set/set_compare_abstract.h +binary_search_tree_mm2.o: ../threads/auto_mutex_extension.h +binary_search_tree_mm2.o: ../threads/auto_unlock_extension.h +binary_search_tree_mm2.o: ../threads/auto_unlock_extension_abstract.h +binary_search_tree_mm2.o: ../threads/create_new_thread_extension.h +binary_search_tree_mm2.o: ../threads/create_new_thread_extension_abstract.h +binary_search_tree_mm2.o: ../threads/multithreaded_object_extension.h +binary_search_tree_mm2.o: ../threads/multithreaded_object_extension_abstract.h +binary_search_tree_mm2.o: ../threads/rsignaler_extension.h +binary_search_tree_mm2.o: ../threads/rsignaler_extension_abstract.h +binary_search_tree_mm2.o: ../threads/rmutex_extension.h +binary_search_tree_mm2.o: ../threads/rsignaler_extension.h +binary_search_tree_mm2.o: ../threads/threaded_object_extension.h +binary_search_tree_mm2.o: ../threads/threaded_object_extension_abstract.h +binary_search_tree_mm2.o: ../threads/thread_specific_data_extension.h +binary_search_tree_mm2.o: ../threads/thread_specific_data_extension_abstract.h +binary_search_tree_mm2.o: ../threads/thread_function_extension.h +binary_search_tree_mm2.o: ../threads/thread_function_extension_abstract.h +binary_search_tree_mm2.o: ../threads/threaded_object_extension.h +cmd_line_parser.o: ../../dlib/string.h ../../dlib/cmd_line_parser.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_1.h +cmd_line_parser.o: ../algs.h ../platform.h ../assert.h ../error.h +cmd_line_parser.o: ../noncopyable.h ../interfaces/enumerable.h +cmd_line_parser.o: ../interfaces/cmd_line_parser_option.h ../assert.h +cmd_line_parser.o: ../string.h ../string/string.h ../error.h +cmd_line_parser.o: ../string/string_abstract.h ../uintn.h ../enable_if.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_c.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_print_1.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_print_abstract.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_check_1.h +cmd_line_parser.o: ../../dlib/cmd_line_parser/cmd_line_parser_check_c.h +cmd_line_parser.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +cmd_line_parser.o: ../../dlib/map/map_kernel_abstract.h +cmd_line_parser.o: ../interfaces/map_pair.h ../interfaces/remover.h +cmd_line_parser.o: ../serialize.h ../algs.h ../uintn.h +cmd_line_parser.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +cmd_line_parser.o: ../enable_if.h ../memory_manager.h +cmd_line_parser.o: ../memory_manager/memory_manager_kernel_1.h +cmd_line_parser.o: ../memory_manager/memory_manager_kernel_abstract.h +cmd_line_parser.o: ../memory_manager/memory_manager_kernel_2.h +cmd_line_parser.o: ../memory_manager/memory_manager_kernel_3.h +cmd_line_parser.o: ../memory_manager/memory_manager_kernel_2.h +cmd_line_parser.o: ../binary_search_tree/binary_search_tree_kernel_2.h +cmd_line_parser.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +cmd_line_parser.o: ../../dlib/map/map_kernel_c.h binary_search_tree.h +cmd_line_parser.o: ../../dlib/memory_manager_global.h +cmd_line_parser.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +cmd_line_parser.o: ../memory_manager/memory_manager_kernel_abstract.h +cmd_line_parser.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +cmd_line_parser.o: ../../dlib/memory_manager.h +cmd_line_parser.o: ../../dlib/memory_manager_stateless.h +cmd_line_parser.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +cmd_line_parser.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +cmd_line_parser.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +cmd_line_parser.o: ../threads.h ../threads/threads_kernel.h ../platform.h +cmd_line_parser.o: ../threads/posix.h ../threads/threads_kernel_2.h +cmd_line_parser.o: ../threads/threads_kernel_abstract.h +cmd_line_parser.o: /usr/include/pthread.h /usr/include/features.h +cmd_line_parser.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +cmd_line_parser.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +cmd_line_parser.o: /usr/include/sched.h /usr/include/bits/types.h +cmd_line_parser.o: /usr/include/bits/typesizes.h /usr/include/time.h +cmd_line_parser.o: /usr/include/bits/sched.h /usr/include/signal.h +cmd_line_parser.o: /usr/include/bits/sigset.h +cmd_line_parser.o: /usr/include/bits/pthreadtypes.h +cmd_line_parser.o: /usr/include/bits/setjmp.h /usr/include/errno.h +cmd_line_parser.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +cmd_line_parser.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +cmd_line_parser.o: /usr/include/asm-generic/errno.h +cmd_line_parser.o: /usr/include/asm-generic/errno-base.h +cmd_line_parser.o: /usr/include/sys/time.h /usr/include/bits/time.h +cmd_line_parser.o: /usr/include/sys/select.h /usr/include/bits/select.h +cmd_line_parser.o: ../threads/threads_kernel_shared.h +cmd_line_parser.o: ../threads/auto_mutex_extension.h +cmd_line_parser.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +cmd_line_parser.o: ../threads/rmutex_extension_abstract.h +cmd_line_parser.o: ../threads/auto_mutex_extension_abstract.h +cmd_line_parser.o: ../binary_search_tree.h +cmd_line_parser.o: ../binary_search_tree/binary_search_tree_kernel_1.h +cmd_line_parser.o: ../binary_search_tree/binary_search_tree_kernel_2.h +cmd_line_parser.o: ../binary_search_tree/binary_search_tree_kernel_c.h +cmd_line_parser.o: ../member_function_pointer.h +cmd_line_parser.o: ../member_function_pointer/member_function_pointer_kernel_1.h +cmd_line_parser.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +cmd_line_parser.o: ../member_function_pointer/member_function_pointer_kernel_c.h +cmd_line_parser.o: ../queue.h ../queue/queue_kernel_1.h +cmd_line_parser.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +cmd_line_parser.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +cmd_line_parser.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +cmd_line_parser.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +cmd_line_parser.o: ../set/set_kernel_c.h ../set/set_compare_1.h +cmd_line_parser.o: ../set/set_compare_abstract.h +cmd_line_parser.o: ../threads/auto_mutex_extension.h +cmd_line_parser.o: ../threads/auto_unlock_extension.h +cmd_line_parser.o: ../threads/auto_unlock_extension_abstract.h +cmd_line_parser.o: ../threads/create_new_thread_extension.h +cmd_line_parser.o: ../threads/create_new_thread_extension_abstract.h +cmd_line_parser.o: ../threads/multithreaded_object_extension.h +cmd_line_parser.o: ../threads/multithreaded_object_extension_abstract.h +cmd_line_parser.o: ../threads/rsignaler_extension.h +cmd_line_parser.o: ../threads/rsignaler_extension_abstract.h ../map.h +cmd_line_parser.o: ../threads/rmutex_extension.h +cmd_line_parser.o: ../threads/rsignaler_extension.h +cmd_line_parser.o: ../threads/threaded_object_extension.h +cmd_line_parser.o: ../threads/threaded_object_extension_abstract.h +cmd_line_parser.o: ../threads/thread_specific_data_extension.h +cmd_line_parser.o: ../threads/thread_specific_data_extension_abstract.h +cmd_line_parser.o: ../threads/thread_function_extension.h +cmd_line_parser.o: ../threads/thread_function_extension_abstract.h +cmd_line_parser.o: ../threads/threaded_object_extension.h +cmd_line_parser.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +cmd_line_parser.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +cmd_line_parser.o: ../misc_api.h ../misc_api/posix.h +cmd_line_parser.o: ../misc_api/misc_api_kernel_2.h +cmd_line_parser.o: ../misc_api/misc_api_kernel_abstract.h +cmd_line_parser.o: ../../dlib/logger/logger_kernel_abstract.h +cmd_line_parser.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +cmd_line_parser.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +cmd_line_parser.o: ../smart_pointers/shared_ptr.h +cmd_line_parser.o: ../smart_pointers/shared_ptr_abstract.h +cmd_line_parser.o: ../smart_pointers/weak_ptr.h +cmd_line_parser.o: ../smart_pointers/shared_ptr.h +cmd_line_parser.o: ../smart_pointers/weak_ptr_abstract.h +cmd_line_parser.o: ../../dlib/logger/extra_logger_headers.h +cmd_line_parser.o: ../../dlib/logger/logger_kernel_1.h +cmd_line_parser.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +cmd_line_parser.o: ../config_reader/config_reader_kernel_1.h +cmd_line_parser.o: ../config_reader/config_reader_kernel_abstract.h +cmd_line_parser.o: ../tokenizer.h ../tokenizer/tokenizer_kernel_1.h +cmd_line_parser.o: ../tokenizer/tokenizer_kernel_abstract.h +cmd_line_parser.o: ../tokenizer/tokenizer_kernel_c.h +cmd_line_parser.o: ../config_reader/config_reader_thread_safe_1.h +cmd_line_parser.o: ../config_reader/config_reader_thread_safe_abstract.h +cmd_line_parser.o: ../../dlib/assert.h ../../dlib/algs.h +cmd_line_parser.o: ../../dlib/sequence.h +cmd_line_parser.o: ../../dlib/sequence/sequence_kernel_1.h +cmd_line_parser.o: ../../dlib/sequence/sequence_kernel_abstract.h +cmd_line_parser.o: ../../dlib/sequence/sequence_kernel_2.h +cmd_line_parser.o: ../../dlib/sequence/sequence_kernel_c.h +cmd_line_parser.o: ../../dlib/sequence/sequence_compare_1.h +cmd_line_parser.o: ../../dlib/sequence/sequence_compare_abstract.h +cmd_line_parser.o: ../../dlib/sequence/sequence_sort_1.h +cmd_line_parser.o: ../../dlib/sequence/sequence_sort_abstract.h +cmd_line_parser.o: ../../dlib/sequence/sequence_sort_2.h cmd_line_parser.h +cmd_line_parser_wchar_t.o: ../../dlib/string.h ../../dlib/cmd_line_parser.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_1.h +cmd_line_parser_wchar_t.o: ../algs.h ../platform.h ../assert.h ../error.h +cmd_line_parser_wchar_t.o: ../noncopyable.h ../interfaces/enumerable.h +cmd_line_parser_wchar_t.o: ../interfaces/cmd_line_parser_option.h ../assert.h +cmd_line_parser_wchar_t.o: ../string.h ../string/string.h ../error.h +cmd_line_parser_wchar_t.o: ../string/string_abstract.h ../uintn.h +cmd_line_parser_wchar_t.o: ../enable_if.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_c.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_print_1.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_print_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_check_1.h +cmd_line_parser_wchar_t.o: ../../dlib/cmd_line_parser/cmd_line_parser_check_c.h +cmd_line_parser_wchar_t.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +cmd_line_parser_wchar_t.o: ../../dlib/map/map_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../interfaces/map_pair.h ../interfaces/remover.h +cmd_line_parser_wchar_t.o: ../serialize.h ../algs.h ../uintn.h +cmd_line_parser_wchar_t.o: ../interfaces/enumerable.h +cmd_line_parser_wchar_t.o: ../interfaces/map_pair.h ../enable_if.h +cmd_line_parser_wchar_t.o: ../memory_manager.h +cmd_line_parser_wchar_t.o: ../memory_manager/memory_manager_kernel_1.h +cmd_line_parser_wchar_t.o: ../memory_manager/memory_manager_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../memory_manager/memory_manager_kernel_2.h +cmd_line_parser_wchar_t.o: ../memory_manager/memory_manager_kernel_3.h +cmd_line_parser_wchar_t.o: ../memory_manager/memory_manager_kernel_2.h +cmd_line_parser_wchar_t.o: ../binary_search_tree/binary_search_tree_kernel_2.h +cmd_line_parser_wchar_t.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/map/map_kernel_c.h binary_search_tree.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_global.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +cmd_line_parser_wchar_t.o: ../memory_manager/memory_manager_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_stateless.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +cmd_line_parser_wchar_t.o: ../threads.h ../threads/threads_kernel.h +cmd_line_parser_wchar_t.o: ../platform.h ../threads/posix.h +cmd_line_parser_wchar_t.o: ../threads/threads_kernel_2.h +cmd_line_parser_wchar_t.o: ../threads/threads_kernel_abstract.h +cmd_line_parser_wchar_t.o: /usr/include/pthread.h /usr/include/features.h +cmd_line_parser_wchar_t.o: /usr/include/sys/cdefs.h +cmd_line_parser_wchar_t.o: /usr/include/bits/wordsize.h +cmd_line_parser_wchar_t.o: /usr/include/gnu/stubs.h +cmd_line_parser_wchar_t.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +cmd_line_parser_wchar_t.o: /usr/include/bits/types.h +cmd_line_parser_wchar_t.o: /usr/include/bits/typesizes.h /usr/include/time.h +cmd_line_parser_wchar_t.o: /usr/include/bits/sched.h /usr/include/signal.h +cmd_line_parser_wchar_t.o: /usr/include/bits/sigset.h +cmd_line_parser_wchar_t.o: /usr/include/bits/pthreadtypes.h +cmd_line_parser_wchar_t.o: /usr/include/bits/setjmp.h /usr/include/errno.h +cmd_line_parser_wchar_t.o: /usr/include/bits/errno.h +cmd_line_parser_wchar_t.o: /usr/include/linux/errno.h +cmd_line_parser_wchar_t.o: /usr/include/asm/errno.h +cmd_line_parser_wchar_t.o: /usr/include/asm-i386/errno.h +cmd_line_parser_wchar_t.o: /usr/include/asm-generic/errno.h +cmd_line_parser_wchar_t.o: /usr/include/asm-generic/errno-base.h +cmd_line_parser_wchar_t.o: /usr/include/sys/time.h /usr/include/bits/time.h +cmd_line_parser_wchar_t.o: /usr/include/sys/select.h +cmd_line_parser_wchar_t.o: /usr/include/bits/select.h +cmd_line_parser_wchar_t.o: ../threads/threads_kernel_shared.h +cmd_line_parser_wchar_t.o: ../threads/auto_mutex_extension.h +cmd_line_parser_wchar_t.o: ../threads/threads_kernel.h +cmd_line_parser_wchar_t.o: ../threads/rmutex_extension.h +cmd_line_parser_wchar_t.o: ../threads/rmutex_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/auto_mutex_extension_abstract.h +cmd_line_parser_wchar_t.o: ../binary_search_tree.h +cmd_line_parser_wchar_t.o: ../binary_search_tree/binary_search_tree_kernel_1.h +cmd_line_parser_wchar_t.o: ../binary_search_tree/binary_search_tree_kernel_2.h +cmd_line_parser_wchar_t.o: ../binary_search_tree/binary_search_tree_kernel_c.h +cmd_line_parser_wchar_t.o: ../member_function_pointer.h +cmd_line_parser_wchar_t.o: ../member_function_pointer/member_function_pointer_kernel_1.h +cmd_line_parser_wchar_t.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../member_function_pointer/member_function_pointer_kernel_c.h +cmd_line_parser_wchar_t.o: ../queue.h ../queue/queue_kernel_1.h +cmd_line_parser_wchar_t.o: ../queue/queue_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../queue/queue_kernel_2.h +cmd_line_parser_wchar_t.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +cmd_line_parser_wchar_t.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +cmd_line_parser_wchar_t.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../set/set_kernel_c.h ../set/set_compare_1.h +cmd_line_parser_wchar_t.o: ../set/set_compare_abstract.h +cmd_line_parser_wchar_t.o: ../threads/auto_mutex_extension.h +cmd_line_parser_wchar_t.o: ../threads/auto_unlock_extension.h +cmd_line_parser_wchar_t.o: ../threads/auto_unlock_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/create_new_thread_extension.h +cmd_line_parser_wchar_t.o: ../threads/create_new_thread_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/multithreaded_object_extension.h +cmd_line_parser_wchar_t.o: ../threads/multithreaded_object_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/rsignaler_extension.h +cmd_line_parser_wchar_t.o: ../threads/rsignaler_extension_abstract.h ../map.h +cmd_line_parser_wchar_t.o: ../threads/rmutex_extension.h +cmd_line_parser_wchar_t.o: ../threads/rsignaler_extension.h +cmd_line_parser_wchar_t.o: ../threads/threaded_object_extension.h +cmd_line_parser_wchar_t.o: ../threads/threaded_object_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/thread_specific_data_extension.h +cmd_line_parser_wchar_t.o: ../threads/thread_specific_data_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/thread_function_extension.h +cmd_line_parser_wchar_t.o: ../threads/thread_function_extension_abstract.h +cmd_line_parser_wchar_t.o: ../threads/threaded_object_extension.h +cmd_line_parser_wchar_t.o: ../../dlib/binary_search_tree.h tester.h +cmd_line_parser_wchar_t.o: ../../dlib/map.h ../../dlib/logger.h +cmd_line_parser_wchar_t.o: ../../dlib/logger/logger_kernel_1.h ../misc_api.h +cmd_line_parser_wchar_t.o: ../misc_api/posix.h +cmd_line_parser_wchar_t.o: ../misc_api/misc_api_kernel_2.h +cmd_line_parser_wchar_t.o: ../misc_api/misc_api_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/logger/logger_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +cmd_line_parser_wchar_t.o: ../noncopyable.h +cmd_line_parser_wchar_t.o: ../smart_pointers/scoped_ptr_abstract.h +cmd_line_parser_wchar_t.o: ../smart_pointers/shared_ptr.h +cmd_line_parser_wchar_t.o: ../smart_pointers/shared_ptr_abstract.h +cmd_line_parser_wchar_t.o: ../smart_pointers/weak_ptr.h +cmd_line_parser_wchar_t.o: ../smart_pointers/shared_ptr.h +cmd_line_parser_wchar_t.o: ../smart_pointers/weak_ptr_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/logger/extra_logger_headers.h +cmd_line_parser_wchar_t.o: ../../dlib/logger/logger_kernel_1.h +cmd_line_parser_wchar_t.o: ../../dlib/logger/logger_config_file.h +cmd_line_parser_wchar_t.o: ../config_reader.h +cmd_line_parser_wchar_t.o: ../config_reader/config_reader_kernel_1.h +cmd_line_parser_wchar_t.o: ../config_reader/config_reader_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../tokenizer.h ../tokenizer/tokenizer_kernel_1.h +cmd_line_parser_wchar_t.o: ../tokenizer/tokenizer_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../tokenizer/tokenizer_kernel_c.h +cmd_line_parser_wchar_t.o: ../config_reader/config_reader_thread_safe_1.h +cmd_line_parser_wchar_t.o: ../config_reader/config_reader_thread_safe_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/assert.h ../../dlib/algs.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_kernel_1.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_kernel_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_kernel_2.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_kernel_c.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_compare_1.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_compare_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_sort_1.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_sort_abstract.h +cmd_line_parser_wchar_t.o: ../../dlib/sequence/sequence_sort_2.h +cmd_line_parser_wchar_t.o: cmd_line_parser.h +compress_stream.o: ../../dlib/compress_stream.h +compress_stream.o: ../../dlib/compress_stream/compress_stream_kernel_1.h +compress_stream.o: ../algs.h ../platform.h ../assert.h ../error.h +compress_stream.o: ../noncopyable.h +compress_stream.o: ../../dlib/compress_stream/compress_stream_kernel_abstract.h +compress_stream.o: ../../dlib/compress_stream/compress_stream_kernel_2.h +compress_stream.o: ../../dlib/compress_stream/compress_stream_kernel_3.h +compress_stream.o: ../assert.h conditioning_class.h +compress_stream.o: ../../dlib/conditioning_class.h +compress_stream.o: ../../dlib/conditioning_class/conditioning_class_kernel_1.h +compress_stream.o: ../../dlib/conditioning_class/conditioning_class_kernel_abstract.h +compress_stream.o: ../../dlib/conditioning_class/conditioning_class_kernel_2.h +compress_stream.o: ../../dlib/conditioning_class/conditioning_class_kernel_3.h +compress_stream.o: ../../dlib/conditioning_class/conditioning_class_kernel_4.h +compress_stream.o: ../../dlib/conditioning_class/conditioning_class_kernel_c.h +compress_stream.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +compress_stream.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +compress_stream.o: ../threads.h ../threads/threads_kernel.h ../platform.h +compress_stream.o: ../threads/posix.h ../threads/threads_kernel_2.h +compress_stream.o: ../threads/threads_kernel_abstract.h +compress_stream.o: /usr/include/pthread.h /usr/include/features.h +compress_stream.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +compress_stream.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +compress_stream.o: /usr/include/sched.h /usr/include/bits/types.h +compress_stream.o: /usr/include/bits/typesizes.h /usr/include/time.h +compress_stream.o: /usr/include/bits/sched.h /usr/include/signal.h +compress_stream.o: /usr/include/bits/sigset.h +compress_stream.o: /usr/include/bits/pthreadtypes.h +compress_stream.o: /usr/include/bits/setjmp.h /usr/include/errno.h +compress_stream.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +compress_stream.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +compress_stream.o: /usr/include/asm-generic/errno.h +compress_stream.o: /usr/include/asm-generic/errno-base.h +compress_stream.o: /usr/include/sys/time.h /usr/include/bits/time.h +compress_stream.o: /usr/include/sys/select.h /usr/include/bits/select.h +compress_stream.o: ../threads/threads_kernel_shared.h +compress_stream.o: ../threads/auto_mutex_extension.h +compress_stream.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +compress_stream.o: ../threads/rmutex_extension_abstract.h +compress_stream.o: ../threads/auto_mutex_extension_abstract.h +compress_stream.o: ../binary_search_tree.h +compress_stream.o: ../binary_search_tree/binary_search_tree_kernel_1.h +compress_stream.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +compress_stream.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +compress_stream.o: ../interfaces/remover.h ../serialize.h ../algs.h +compress_stream.o: ../uintn.h ../interfaces/enumerable.h +compress_stream.o: ../interfaces/map_pair.h ../enable_if.h +compress_stream.o: ../binary_search_tree/binary_search_tree_kernel_2.h +compress_stream.o: ../binary_search_tree/binary_search_tree_kernel_c.h +compress_stream.o: ../member_function_pointer.h +compress_stream.o: ../member_function_pointer/member_function_pointer_kernel_1.h +compress_stream.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +compress_stream.o: ../member_function_pointer/member_function_pointer_kernel_c.h +compress_stream.o: ../memory_manager.h +compress_stream.o: ../memory_manager/memory_manager_kernel_1.h +compress_stream.o: ../memory_manager/memory_manager_kernel_abstract.h +compress_stream.o: ../memory_manager/memory_manager_kernel_2.h +compress_stream.o: ../memory_manager/memory_manager_kernel_3.h +compress_stream.o: ../memory_manager/memory_manager_kernel_2.h +compress_stream.o: ../binary_search_tree/binary_search_tree_kernel_2.h +compress_stream.o: ../queue.h ../queue/queue_kernel_1.h +compress_stream.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +compress_stream.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +compress_stream.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +compress_stream.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +compress_stream.o: ../set/set_kernel_c.h binary_search_tree.h +compress_stream.o: ../../dlib/memory_manager_global.h +compress_stream.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +compress_stream.o: ../memory_manager/memory_manager_kernel_abstract.h +compress_stream.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +compress_stream.o: ../../dlib/memory_manager_stateless.h +compress_stream.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +compress_stream.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +compress_stream.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +compress_stream.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +compress_stream.o: ../set/set_compare_abstract.h +compress_stream.o: ../threads/auto_mutex_extension.h +compress_stream.o: ../threads/auto_unlock_extension.h +compress_stream.o: ../threads/auto_unlock_extension_abstract.h +compress_stream.o: ../threads/create_new_thread_extension.h +compress_stream.o: ../threads/create_new_thread_extension_abstract.h +compress_stream.o: ../threads/multithreaded_object_extension.h +compress_stream.o: ../threads/multithreaded_object_extension_abstract.h +compress_stream.o: ../threads/rsignaler_extension.h +compress_stream.o: ../threads/rsignaler_extension_abstract.h ../map.h +compress_stream.o: ../threads/rmutex_extension.h +compress_stream.o: ../threads/rsignaler_extension.h +compress_stream.o: ../threads/threaded_object_extension.h +compress_stream.o: ../threads/threaded_object_extension_abstract.h +compress_stream.o: ../threads/thread_specific_data_extension.h +compress_stream.o: ../threads/thread_specific_data_extension_abstract.h +compress_stream.o: ../threads/thread_function_extension.h +compress_stream.o: ../threads/thread_function_extension_abstract.h +compress_stream.o: ../threads/threaded_object_extension.h ../misc_api.h +compress_stream.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +compress_stream.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +compress_stream.o: ../../dlib/logger/logger_kernel_abstract.h +compress_stream.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +compress_stream.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +compress_stream.o: ../smart_pointers/shared_ptr.h +compress_stream.o: ../smart_pointers/shared_ptr_abstract.h +compress_stream.o: ../smart_pointers/weak_ptr.h +compress_stream.o: ../smart_pointers/shared_ptr.h +compress_stream.o: ../smart_pointers/weak_ptr_abstract.h +compress_stream.o: ../../dlib/logger/extra_logger_headers.h +compress_stream.o: ../../dlib/logger/logger_kernel_1.h +compress_stream.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +compress_stream.o: ../config_reader/config_reader_kernel_1.h +compress_stream.o: ../config_reader/config_reader_kernel_abstract.h +compress_stream.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +compress_stream.o: ../../dlib/map/map_kernel_abstract.h +compress_stream.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +compress_stream.o: ../tokenizer/tokenizer_kernel_1.h +compress_stream.o: ../tokenizer/tokenizer_kernel_abstract.h +compress_stream.o: ../tokenizer/tokenizer_kernel_c.h +compress_stream.o: ../config_reader/config_reader_thread_safe_1.h +compress_stream.o: ../config_reader/config_reader_thread_safe_abstract.h +compress_stream.o: ../../dlib/assert.h ../../dlib/algs.h +compress_stream.o: ../../dlib/entropy_encoder.h +compress_stream.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_1.h +compress_stream.o: ../entropy_encoder/entropy_encoder_kernel_abstract.h +compress_stream.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_2.h +compress_stream.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_c.h +compress_stream.o: ../../dlib/entropy_decoder.h +compress_stream.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_1.h +compress_stream.o: ../entropy_decoder/entropy_decoder_kernel_abstract.h +compress_stream.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_2.h +compress_stream.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_c.h +compress_stream.o: ../../dlib/entropy_encoder_model.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h +compress_stream.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h +compress_stream.o: ../../dlib/sliding_buffer.h +compress_stream.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_1.h +compress_stream.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_abstract.h +compress_stream.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_c.h +compress_stream.o: ../../dlib/entropy_decoder_model.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h +compress_stream.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h +compress_stream.o: ../../dlib/lz77_buffer.h +compress_stream.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_1.h +compress_stream.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_abstract.h +compress_stream.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_2.h +compress_stream.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_c.h +compress_stream.o: ../../dlib/lzp_buffer.h +compress_stream.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_1.h +compress_stream.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_abstract.h +compress_stream.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_2.h +compress_stream.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_c.h +compress_stream.o: ../../dlib/crc32.h ../../dlib/crc32/crc32_kernel_1.h +compress_stream.o: ../../dlib/crc32/crc32_kernel_abstract.h +conditioning_class.o: ../../dlib/conditioning_class.h +conditioning_class.o: ../../dlib/conditioning_class/conditioning_class_kernel_1.h +conditioning_class.o: ../../dlib/conditioning_class/conditioning_class_kernel_abstract.h +conditioning_class.o: ../assert.h ../algs.h ../platform.h ../assert.h +conditioning_class.o: ../error.h ../noncopyable.h +conditioning_class.o: ../../dlib/conditioning_class/conditioning_class_kernel_2.h +conditioning_class.o: ../../dlib/conditioning_class/conditioning_class_kernel_3.h +conditioning_class.o: ../../dlib/conditioning_class/conditioning_class_kernel_4.h +conditioning_class.o: ../../dlib/conditioning_class/conditioning_class_kernel_c.h +conditioning_class.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +conditioning_class.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +conditioning_class.o: ../threads.h ../threads/threads_kernel.h ../platform.h +conditioning_class.o: ../threads/posix.h ../threads/threads_kernel_2.h +conditioning_class.o: ../threads/threads_kernel_abstract.h +conditioning_class.o: /usr/include/pthread.h /usr/include/features.h +conditioning_class.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +conditioning_class.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +conditioning_class.o: /usr/include/sched.h /usr/include/bits/types.h +conditioning_class.o: /usr/include/bits/typesizes.h /usr/include/time.h +conditioning_class.o: /usr/include/bits/sched.h /usr/include/signal.h +conditioning_class.o: /usr/include/bits/sigset.h +conditioning_class.o: /usr/include/bits/pthreadtypes.h +conditioning_class.o: /usr/include/bits/setjmp.h /usr/include/errno.h +conditioning_class.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +conditioning_class.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +conditioning_class.o: /usr/include/asm-generic/errno.h +conditioning_class.o: /usr/include/asm-generic/errno-base.h +conditioning_class.o: /usr/include/sys/time.h /usr/include/bits/time.h +conditioning_class.o: /usr/include/sys/select.h /usr/include/bits/select.h +conditioning_class.o: ../threads/threads_kernel_shared.h +conditioning_class.o: ../threads/auto_mutex_extension.h +conditioning_class.o: ../threads/threads_kernel.h +conditioning_class.o: ../threads/rmutex_extension.h +conditioning_class.o: ../threads/rmutex_extension_abstract.h +conditioning_class.o: ../threads/auto_mutex_extension_abstract.h +conditioning_class.o: ../binary_search_tree.h +conditioning_class.o: ../binary_search_tree/binary_search_tree_kernel_1.h +conditioning_class.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +conditioning_class.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +conditioning_class.o: ../interfaces/remover.h ../serialize.h ../algs.h +conditioning_class.o: ../uintn.h ../interfaces/enumerable.h +conditioning_class.o: ../interfaces/map_pair.h ../enable_if.h +conditioning_class.o: ../binary_search_tree/binary_search_tree_kernel_2.h +conditioning_class.o: ../binary_search_tree/binary_search_tree_kernel_c.h +conditioning_class.o: ../member_function_pointer.h +conditioning_class.o: ../member_function_pointer/member_function_pointer_kernel_1.h +conditioning_class.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +conditioning_class.o: ../member_function_pointer/member_function_pointer_kernel_c.h +conditioning_class.o: ../memory_manager.h +conditioning_class.o: ../memory_manager/memory_manager_kernel_1.h +conditioning_class.o: ../memory_manager/memory_manager_kernel_abstract.h +conditioning_class.o: ../memory_manager/memory_manager_kernel_2.h +conditioning_class.o: ../memory_manager/memory_manager_kernel_3.h +conditioning_class.o: ../memory_manager/memory_manager_kernel_2.h +conditioning_class.o: ../binary_search_tree/binary_search_tree_kernel_2.h +conditioning_class.o: ../queue.h ../queue/queue_kernel_1.h +conditioning_class.o: ../queue/queue_kernel_abstract.h +conditioning_class.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +conditioning_class.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h +conditioning_class.o: ../sort.h ../set.h ../set/set_kernel_1.h +conditioning_class.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +conditioning_class.o: binary_search_tree.h ../../dlib/memory_manager_global.h +conditioning_class.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +conditioning_class.o: ../memory_manager/memory_manager_kernel_abstract.h +conditioning_class.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +conditioning_class.o: ../../dlib/memory_manager_stateless.h +conditioning_class.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +conditioning_class.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +conditioning_class.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +conditioning_class.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +conditioning_class.o: ../set/set_compare_abstract.h +conditioning_class.o: ../threads/auto_mutex_extension.h +conditioning_class.o: ../threads/auto_unlock_extension.h +conditioning_class.o: ../threads/auto_unlock_extension_abstract.h +conditioning_class.o: ../threads/create_new_thread_extension.h +conditioning_class.o: ../threads/create_new_thread_extension_abstract.h +conditioning_class.o: ../threads/multithreaded_object_extension.h +conditioning_class.o: ../threads/multithreaded_object_extension_abstract.h +conditioning_class.o: ../threads/rsignaler_extension.h +conditioning_class.o: ../threads/rsignaler_extension_abstract.h ../map.h +conditioning_class.o: ../threads/rmutex_extension.h +conditioning_class.o: ../threads/rsignaler_extension.h +conditioning_class.o: ../threads/threaded_object_extension.h +conditioning_class.o: ../threads/threaded_object_extension_abstract.h +conditioning_class.o: ../threads/thread_specific_data_extension.h +conditioning_class.o: ../threads/thread_specific_data_extension_abstract.h +conditioning_class.o: ../threads/thread_function_extension.h +conditioning_class.o: ../threads/thread_function_extension_abstract.h +conditioning_class.o: ../threads/threaded_object_extension.h ../misc_api.h +conditioning_class.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +conditioning_class.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +conditioning_class.o: ../../dlib/logger/logger_kernel_abstract.h +conditioning_class.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +conditioning_class.o: ../noncopyable.h +conditioning_class.o: ../smart_pointers/scoped_ptr_abstract.h +conditioning_class.o: ../smart_pointers/shared_ptr.h +conditioning_class.o: ../smart_pointers/shared_ptr_abstract.h +conditioning_class.o: ../smart_pointers/weak_ptr.h +conditioning_class.o: ../smart_pointers/shared_ptr.h +conditioning_class.o: ../smart_pointers/weak_ptr_abstract.h +conditioning_class.o: ../../dlib/logger/extra_logger_headers.h +conditioning_class.o: ../../dlib/logger/logger_kernel_1.h +conditioning_class.o: ../../dlib/logger/logger_config_file.h +conditioning_class.o: ../config_reader.h +conditioning_class.o: ../config_reader/config_reader_kernel_1.h +conditioning_class.o: ../config_reader/config_reader_kernel_abstract.h +conditioning_class.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +conditioning_class.o: ../../dlib/map/map_kernel_abstract.h +conditioning_class.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +conditioning_class.o: ../tokenizer/tokenizer_kernel_1.h +conditioning_class.o: ../tokenizer/tokenizer_kernel_abstract.h +conditioning_class.o: ../tokenizer/tokenizer_kernel_c.h +conditioning_class.o: ../config_reader/config_reader_thread_safe_1.h +conditioning_class.o: ../config_reader/config_reader_thread_safe_abstract.h +conditioning_class.o: ../../dlib/assert.h ../../dlib/algs.h +conditioning_class.o: conditioning_class.h +conditioning_class_c.o: ../../dlib/conditioning_class.h +conditioning_class_c.o: ../../dlib/conditioning_class/conditioning_class_kernel_1.h +conditioning_class_c.o: ../../dlib/conditioning_class/conditioning_class_kernel_abstract.h +conditioning_class_c.o: ../assert.h ../algs.h ../platform.h ../assert.h +conditioning_class_c.o: ../error.h ../noncopyable.h +conditioning_class_c.o: ../../dlib/conditioning_class/conditioning_class_kernel_2.h +conditioning_class_c.o: ../../dlib/conditioning_class/conditioning_class_kernel_3.h +conditioning_class_c.o: ../../dlib/conditioning_class/conditioning_class_kernel_4.h +conditioning_class_c.o: ../../dlib/conditioning_class/conditioning_class_kernel_c.h +conditioning_class_c.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +conditioning_class_c.o: ../../dlib/logger.h +conditioning_class_c.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +conditioning_class_c.o: ../threads/threads_kernel.h ../platform.h +conditioning_class_c.o: ../threads/posix.h ../threads/threads_kernel_2.h +conditioning_class_c.o: ../threads/threads_kernel_abstract.h +conditioning_class_c.o: /usr/include/pthread.h /usr/include/features.h +conditioning_class_c.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +conditioning_class_c.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +conditioning_class_c.o: /usr/include/sched.h /usr/include/bits/types.h +conditioning_class_c.o: /usr/include/bits/typesizes.h /usr/include/time.h +conditioning_class_c.o: /usr/include/bits/sched.h /usr/include/signal.h +conditioning_class_c.o: /usr/include/bits/sigset.h +conditioning_class_c.o: /usr/include/bits/pthreadtypes.h +conditioning_class_c.o: /usr/include/bits/setjmp.h /usr/include/errno.h +conditioning_class_c.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +conditioning_class_c.o: /usr/include/asm/errno.h +conditioning_class_c.o: /usr/include/asm-i386/errno.h +conditioning_class_c.o: /usr/include/asm-generic/errno.h +conditioning_class_c.o: /usr/include/asm-generic/errno-base.h +conditioning_class_c.o: /usr/include/sys/time.h /usr/include/bits/time.h +conditioning_class_c.o: /usr/include/sys/select.h /usr/include/bits/select.h +conditioning_class_c.o: ../threads/threads_kernel_shared.h +conditioning_class_c.o: ../threads/auto_mutex_extension.h +conditioning_class_c.o: ../threads/threads_kernel.h +conditioning_class_c.o: ../threads/rmutex_extension.h +conditioning_class_c.o: ../threads/rmutex_extension_abstract.h +conditioning_class_c.o: ../threads/auto_mutex_extension_abstract.h +conditioning_class_c.o: ../binary_search_tree.h +conditioning_class_c.o: ../binary_search_tree/binary_search_tree_kernel_1.h +conditioning_class_c.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +conditioning_class_c.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +conditioning_class_c.o: ../interfaces/remover.h ../serialize.h ../algs.h +conditioning_class_c.o: ../uintn.h ../interfaces/enumerable.h +conditioning_class_c.o: ../interfaces/map_pair.h ../enable_if.h +conditioning_class_c.o: ../binary_search_tree/binary_search_tree_kernel_2.h +conditioning_class_c.o: ../binary_search_tree/binary_search_tree_kernel_c.h +conditioning_class_c.o: ../member_function_pointer.h +conditioning_class_c.o: ../member_function_pointer/member_function_pointer_kernel_1.h +conditioning_class_c.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +conditioning_class_c.o: ../member_function_pointer/member_function_pointer_kernel_c.h +conditioning_class_c.o: ../memory_manager.h +conditioning_class_c.o: ../memory_manager/memory_manager_kernel_1.h +conditioning_class_c.o: ../memory_manager/memory_manager_kernel_abstract.h +conditioning_class_c.o: ../memory_manager/memory_manager_kernel_2.h +conditioning_class_c.o: ../memory_manager/memory_manager_kernel_3.h +conditioning_class_c.o: ../memory_manager/memory_manager_kernel_2.h +conditioning_class_c.o: ../binary_search_tree/binary_search_tree_kernel_2.h +conditioning_class_c.o: ../queue.h ../queue/queue_kernel_1.h +conditioning_class_c.o: ../queue/queue_kernel_abstract.h +conditioning_class_c.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +conditioning_class_c.o: ../queue/queue_sort_1.h +conditioning_class_c.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +conditioning_class_c.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +conditioning_class_c.o: ../set/set_kernel_c.h binary_search_tree.h +conditioning_class_c.o: ../../dlib/memory_manager_global.h +conditioning_class_c.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +conditioning_class_c.o: ../memory_manager/memory_manager_kernel_abstract.h +conditioning_class_c.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +conditioning_class_c.o: ../../dlib/memory_manager_stateless.h +conditioning_class_c.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +conditioning_class_c.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +conditioning_class_c.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +conditioning_class_c.o: ../../dlib/binary_search_tree.h +conditioning_class_c.o: ../set/set_compare_1.h ../set/set_compare_abstract.h +conditioning_class_c.o: ../threads/auto_mutex_extension.h +conditioning_class_c.o: ../threads/auto_unlock_extension.h +conditioning_class_c.o: ../threads/auto_unlock_extension_abstract.h +conditioning_class_c.o: ../threads/create_new_thread_extension.h +conditioning_class_c.o: ../threads/create_new_thread_extension_abstract.h +conditioning_class_c.o: ../threads/multithreaded_object_extension.h +conditioning_class_c.o: ../threads/multithreaded_object_extension_abstract.h +conditioning_class_c.o: ../threads/rsignaler_extension.h +conditioning_class_c.o: ../threads/rsignaler_extension_abstract.h ../map.h +conditioning_class_c.o: ../threads/rmutex_extension.h +conditioning_class_c.o: ../threads/rsignaler_extension.h +conditioning_class_c.o: ../threads/threaded_object_extension.h +conditioning_class_c.o: ../threads/threaded_object_extension_abstract.h +conditioning_class_c.o: ../threads/thread_specific_data_extension.h +conditioning_class_c.o: ../threads/thread_specific_data_extension_abstract.h +conditioning_class_c.o: ../threads/thread_function_extension.h +conditioning_class_c.o: ../threads/thread_function_extension_abstract.h +conditioning_class_c.o: ../threads/threaded_object_extension.h ../misc_api.h +conditioning_class_c.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +conditioning_class_c.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +conditioning_class_c.o: ../../dlib/logger/logger_kernel_abstract.h +conditioning_class_c.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +conditioning_class_c.o: ../noncopyable.h +conditioning_class_c.o: ../smart_pointers/scoped_ptr_abstract.h +conditioning_class_c.o: ../smart_pointers/shared_ptr.h +conditioning_class_c.o: ../smart_pointers/shared_ptr_abstract.h +conditioning_class_c.o: ../smart_pointers/weak_ptr.h +conditioning_class_c.o: ../smart_pointers/shared_ptr.h +conditioning_class_c.o: ../smart_pointers/weak_ptr_abstract.h +conditioning_class_c.o: ../../dlib/logger/extra_logger_headers.h +conditioning_class_c.o: ../../dlib/logger/logger_kernel_1.h +conditioning_class_c.o: ../../dlib/logger/logger_config_file.h +conditioning_class_c.o: ../config_reader.h +conditioning_class_c.o: ../config_reader/config_reader_kernel_1.h +conditioning_class_c.o: ../config_reader/config_reader_kernel_abstract.h +conditioning_class_c.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +conditioning_class_c.o: ../../dlib/map/map_kernel_abstract.h +conditioning_class_c.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +conditioning_class_c.o: ../tokenizer/tokenizer_kernel_1.h +conditioning_class_c.o: ../tokenizer/tokenizer_kernel_abstract.h +conditioning_class_c.o: ../tokenizer/tokenizer_kernel_c.h +conditioning_class_c.o: ../config_reader/config_reader_thread_safe_1.h +conditioning_class_c.o: ../config_reader/config_reader_thread_safe_abstract.h +conditioning_class_c.o: ../../dlib/assert.h ../../dlib/algs.h +conditioning_class_c.o: conditioning_class.h +config_reader.o: ../../dlib/config_reader.h +config_reader.o: ../config_reader/config_reader_kernel_1.h +config_reader.o: ../config_reader/config_reader_kernel_abstract.h ../algs.h +config_reader.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +config_reader.o: ../interfaces/enumerable.h ../../dlib/map.h +config_reader.o: ../../dlib/map/map_kernel_1.h +config_reader.o: ../../dlib/map/map_kernel_abstract.h +config_reader.o: ../interfaces/map_pair.h ../interfaces/remover.h +config_reader.o: ../serialize.h ../algs.h ../uintn.h +config_reader.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +config_reader.o: ../enable_if.h ../memory_manager.h +config_reader.o: ../memory_manager/memory_manager_kernel_1.h +config_reader.o: ../memory_manager/memory_manager_kernel_abstract.h +config_reader.o: ../assert.h ../memory_manager/memory_manager_kernel_2.h +config_reader.o: ../memory_manager/memory_manager_kernel_3.h +config_reader.o: ../memory_manager/memory_manager_kernel_2.h +config_reader.o: ../binary_search_tree/binary_search_tree_kernel_2.h +config_reader.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +config_reader.o: ../../dlib/map/map_kernel_c.h binary_search_tree.h +config_reader.o: ../../dlib/memory_manager_global.h +config_reader.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +config_reader.o: ../memory_manager/memory_manager_kernel_abstract.h +config_reader.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +config_reader.o: ../../dlib/memory_manager.h +config_reader.o: ../../dlib/memory_manager_stateless.h +config_reader.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +config_reader.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +config_reader.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +config_reader.o: ../threads.h ../threads/threads_kernel.h ../platform.h +config_reader.o: ../threads/posix.h ../threads/threads_kernel_2.h +config_reader.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +config_reader.o: /usr/include/features.h /usr/include/sys/cdefs.h +config_reader.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +config_reader.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +config_reader.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +config_reader.o: /usr/include/time.h /usr/include/bits/sched.h +config_reader.o: /usr/include/signal.h /usr/include/bits/sigset.h +config_reader.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +config_reader.o: /usr/include/errno.h /usr/include/bits/errno.h +config_reader.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +config_reader.o: /usr/include/asm-i386/errno.h +config_reader.o: /usr/include/asm-generic/errno.h +config_reader.o: /usr/include/asm-generic/errno-base.h +config_reader.o: /usr/include/sys/time.h /usr/include/bits/time.h +config_reader.o: /usr/include/sys/select.h /usr/include/bits/select.h +config_reader.o: ../threads/threads_kernel_shared.h +config_reader.o: ../threads/auto_mutex_extension.h +config_reader.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +config_reader.o: ../threads/rmutex_extension_abstract.h +config_reader.o: ../threads/auto_mutex_extension_abstract.h +config_reader.o: ../binary_search_tree.h +config_reader.o: ../binary_search_tree/binary_search_tree_kernel_1.h +config_reader.o: ../binary_search_tree/binary_search_tree_kernel_2.h +config_reader.o: ../binary_search_tree/binary_search_tree_kernel_c.h +config_reader.o: ../member_function_pointer.h +config_reader.o: ../member_function_pointer/member_function_pointer_kernel_1.h +config_reader.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +config_reader.o: ../member_function_pointer/member_function_pointer_kernel_c.h +config_reader.o: ../queue.h ../queue/queue_kernel_1.h +config_reader.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +config_reader.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +config_reader.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +config_reader.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +config_reader.o: ../set/set_kernel_c.h ../set/set_compare_1.h +config_reader.o: ../set/set_compare_abstract.h +config_reader.o: ../threads/auto_mutex_extension.h +config_reader.o: ../threads/auto_unlock_extension.h +config_reader.o: ../threads/auto_unlock_extension_abstract.h +config_reader.o: ../threads/create_new_thread_extension.h +config_reader.o: ../threads/create_new_thread_extension_abstract.h +config_reader.o: ../threads/multithreaded_object_extension.h +config_reader.o: ../threads/multithreaded_object_extension_abstract.h +config_reader.o: ../threads/rsignaler_extension.h +config_reader.o: ../threads/rsignaler_extension_abstract.h ../map.h +config_reader.o: ../threads/rmutex_extension.h +config_reader.o: ../threads/rsignaler_extension.h +config_reader.o: ../threads/threaded_object_extension.h +config_reader.o: ../threads/threaded_object_extension_abstract.h +config_reader.o: ../threads/thread_specific_data_extension.h +config_reader.o: ../threads/thread_specific_data_extension_abstract.h +config_reader.o: ../threads/thread_function_extension.h +config_reader.o: ../threads/thread_function_extension_abstract.h +config_reader.o: ../threads/threaded_object_extension.h +config_reader.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +config_reader.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +config_reader.o: ../misc_api.h ../misc_api/posix.h +config_reader.o: ../misc_api/misc_api_kernel_2.h +config_reader.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +config_reader.o: ../../dlib/logger/logger_kernel_abstract.h +config_reader.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +config_reader.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +config_reader.o: ../smart_pointers/shared_ptr.h +config_reader.o: ../smart_pointers/shared_ptr_abstract.h +config_reader.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +config_reader.o: ../smart_pointers/weak_ptr_abstract.h +config_reader.o: ../../dlib/logger/extra_logger_headers.h +config_reader.o: ../../dlib/logger/logger_kernel_1.h +config_reader.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +config_reader.o: ../tokenizer.h ../tokenizer/tokenizer_kernel_1.h +config_reader.o: ../tokenizer/tokenizer_kernel_abstract.h +config_reader.o: ../tokenizer/tokenizer_kernel_c.h +config_reader.o: ../config_reader/config_reader_thread_safe_1.h +config_reader.o: ../config_reader/config_reader_thread_safe_abstract.h +config_reader.o: ../../dlib/assert.h ../../dlib/algs.h +directed_graph.o: ../../dlib/directed_graph.h +directed_graph.o: ../../dlib/directed_graph/directed_graph_kernel_1.h +directed_graph.o: ../serialize.h ../algs.h ../assert.h ../error.h ../uintn.h +directed_graph.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +directed_graph.o: ../enable_if.h ../noncopyable.h ../std_allocator.h +directed_graph.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +directed_graph.o: ../algs.h ../platform.h ../noncopyable.h +directed_graph.o: ../smart_pointers/scoped_ptr_abstract.h +directed_graph.o: ../smart_pointers/shared_ptr.h +directed_graph.o: ../smart_pointers/shared_ptr_abstract.h +directed_graph.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +directed_graph.o: ../smart_pointers/weak_ptr_abstract.h ../memory_manager.h +directed_graph.o: ../memory_manager/memory_manager_kernel_1.h +directed_graph.o: ../memory_manager/memory_manager_kernel_abstract.h +directed_graph.o: ../assert.h ../memory_manager/memory_manager_kernel_2.h +directed_graph.o: ../memory_manager/memory_manager_kernel_3.h +directed_graph.o: ../memory_manager/memory_manager_kernel_2.h +directed_graph.o: ../binary_search_tree/binary_search_tree_kernel_2.h +directed_graph.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +directed_graph.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +directed_graph.o: ../interfaces/remover.h +directed_graph.o: ../../dlib/directed_graph/directed_graph_kernel_abstract.h +directed_graph.o: ../is_kind.h ../../dlib/memory_manager.h ../../dlib/graph.h +directed_graph.o: ../../dlib/graph/graph_kernel_1.h +directed_graph.o: ../../dlib/graph/graph_kernel_abstract.h +directed_graph.o: ../../dlib/graph_utils.h +directed_graph.o: ../../dlib/graph_utils/graph_utils.h +directed_graph.o: ../../dlib/graph_utils/graph_utils_abstract.h +directed_graph.o: ../enable_if.h ../set.h ../set/set_kernel_1.h +directed_graph.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +directed_graph.o: binary_search_tree.h ../../dlib/memory_manager_global.h +directed_graph.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +directed_graph.o: ../memory_manager/memory_manager_kernel_abstract.h +directed_graph.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +directed_graph.o: ../../dlib/memory_manager_stateless.h +directed_graph.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +directed_graph.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +directed_graph.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +directed_graph.o: ../threads.h ../threads/threads_kernel.h ../platform.h +directed_graph.o: ../threads/posix.h ../threads/threads_kernel_2.h +directed_graph.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +directed_graph.o: /usr/include/features.h /usr/include/sys/cdefs.h +directed_graph.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +directed_graph.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +directed_graph.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +directed_graph.o: /usr/include/time.h /usr/include/bits/sched.h +directed_graph.o: /usr/include/signal.h /usr/include/bits/sigset.h +directed_graph.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +directed_graph.o: /usr/include/errno.h /usr/include/bits/errno.h +directed_graph.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +directed_graph.o: /usr/include/asm-i386/errno.h +directed_graph.o: /usr/include/asm-generic/errno.h +directed_graph.o: /usr/include/asm-generic/errno-base.h +directed_graph.o: /usr/include/sys/time.h /usr/include/bits/time.h +directed_graph.o: /usr/include/sys/select.h /usr/include/bits/select.h +directed_graph.o: ../threads/threads_kernel_shared.h +directed_graph.o: ../threads/auto_mutex_extension.h +directed_graph.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +directed_graph.o: ../threads/rmutex_extension_abstract.h +directed_graph.o: ../threads/auto_mutex_extension_abstract.h +directed_graph.o: ../binary_search_tree.h +directed_graph.o: ../binary_search_tree/binary_search_tree_kernel_1.h +directed_graph.o: ../binary_search_tree/binary_search_tree_kernel_2.h +directed_graph.o: ../binary_search_tree/binary_search_tree_kernel_c.h +directed_graph.o: ../member_function_pointer.h +directed_graph.o: ../member_function_pointer/member_function_pointer_kernel_1.h +directed_graph.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +directed_graph.o: ../member_function_pointer/member_function_pointer_kernel_c.h +directed_graph.o: ../queue.h ../queue/queue_kernel_1.h +directed_graph.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +directed_graph.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +directed_graph.o: ../queue/queue_sort_abstract.h ../sort.h +directed_graph.o: ../threads/auto_mutex_extension.h +directed_graph.o: ../threads/auto_unlock_extension.h +directed_graph.o: ../threads/auto_unlock_extension_abstract.h +directed_graph.o: ../threads/create_new_thread_extension.h +directed_graph.o: ../threads/create_new_thread_extension_abstract.h +directed_graph.o: ../threads/multithreaded_object_extension.h +directed_graph.o: ../threads/multithreaded_object_extension_abstract.h +directed_graph.o: ../threads/rsignaler_extension.h +directed_graph.o: ../threads/rsignaler_extension_abstract.h ../map.h +directed_graph.o: ../threads/rmutex_extension.h +directed_graph.o: ../threads/rsignaler_extension.h +directed_graph.o: ../threads/threaded_object_extension.h +directed_graph.o: ../threads/threaded_object_extension_abstract.h +directed_graph.o: ../threads/thread_specific_data_extension.h +directed_graph.o: ../threads/thread_specific_data_extension_abstract.h +directed_graph.o: ../threads/thread_function_extension.h +directed_graph.o: ../threads/thread_function_extension_abstract.h +directed_graph.o: ../threads/threaded_object_extension.h +directed_graph.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +directed_graph.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +directed_graph.o: ../misc_api.h ../misc_api/posix.h +directed_graph.o: ../misc_api/misc_api_kernel_2.h +directed_graph.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +directed_graph.o: ../../dlib/logger/logger_kernel_abstract.h +directed_graph.o: ../../dlib/logger/extra_logger_headers.h +directed_graph.o: ../../dlib/logger/logger_kernel_1.h +directed_graph.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +directed_graph.o: ../config_reader/config_reader_kernel_1.h +directed_graph.o: ../config_reader/config_reader_kernel_abstract.h +directed_graph.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +directed_graph.o: ../../dlib/map/map_kernel_abstract.h +directed_graph.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +directed_graph.o: ../tokenizer/tokenizer_kernel_1.h +directed_graph.o: ../tokenizer/tokenizer_kernel_abstract.h +directed_graph.o: ../tokenizer/tokenizer_kernel_c.h +directed_graph.o: ../config_reader/config_reader_thread_safe_1.h +directed_graph.o: ../config_reader/config_reader_thread_safe_abstract.h +directed_graph.o: ../../dlib/assert.h ../../dlib/algs.h +directed_graph.o: ../set/set_compare_1.h ../set/set_compare_abstract.h +directed_graph.o: ../set_utils.h ../set_utils/set_utils.h +directed_graph.o: ../set_utils/set_utils_abstract.h ../../dlib/set.h +graph.o: ../../dlib/graph.h ../../dlib/graph/graph_kernel_1.h ../serialize.h +graph.o: ../algs.h ../assert.h ../error.h ../uintn.h +graph.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +graph.o: ../noncopyable.h ../std_allocator.h ../smart_pointers.h +graph.o: ../smart_pointers/scoped_ptr.h ../algs.h ../platform.h +graph.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +graph.o: ../smart_pointers/shared_ptr.h +graph.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +graph.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +graph.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +graph.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +graph.o: ../memory_manager/memory_manager_kernel_2.h +graph.o: ../memory_manager/memory_manager_kernel_3.h +graph.o: ../memory_manager/memory_manager_kernel_2.h +graph.o: ../binary_search_tree/binary_search_tree_kernel_2.h +graph.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +graph.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +graph.o: ../interfaces/remover.h ../../dlib/graph/graph_kernel_abstract.h +graph.o: ../is_kind.h ../../dlib/memory_manager.h ../../dlib/graph_utils.h +graph.o: ../../dlib/graph_utils/graph_utils.h +graph.o: ../../dlib/graph_utils/graph_utils_abstract.h ../enable_if.h +graph.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +graph.o: ../set/set_kernel_c.h binary_search_tree.h +graph.o: ../../dlib/memory_manager_global.h +graph.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +graph.o: ../memory_manager/memory_manager_kernel_abstract.h +graph.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +graph.o: ../../dlib/memory_manager_stateless.h +graph.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +graph.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +graph.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +graph.o: ../threads.h ../threads/threads_kernel.h ../platform.h +graph.o: ../threads/posix.h ../threads/threads_kernel_2.h +graph.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +graph.o: /usr/include/features.h /usr/include/sys/cdefs.h +graph.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +graph.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +graph.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +graph.o: /usr/include/time.h /usr/include/bits/sched.h /usr/include/signal.h +graph.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +graph.o: /usr/include/bits/setjmp.h /usr/include/errno.h +graph.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +graph.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +graph.o: /usr/include/asm-generic/errno.h +graph.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +graph.o: /usr/include/bits/time.h /usr/include/sys/select.h +graph.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +graph.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +graph.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +graph.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +graph.o: ../binary_search_tree/binary_search_tree_kernel_1.h +graph.o: ../binary_search_tree/binary_search_tree_kernel_2.h +graph.o: ../binary_search_tree/binary_search_tree_kernel_c.h +graph.o: ../member_function_pointer.h +graph.o: ../member_function_pointer/member_function_pointer_kernel_1.h +graph.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +graph.o: ../member_function_pointer/member_function_pointer_kernel_c.h +graph.o: ../queue.h ../queue/queue_kernel_1.h +graph.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +graph.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +graph.o: ../queue/queue_sort_abstract.h ../sort.h +graph.o: ../threads/auto_mutex_extension.h ../threads/auto_unlock_extension.h +graph.o: ../threads/auto_unlock_extension_abstract.h +graph.o: ../threads/create_new_thread_extension.h +graph.o: ../threads/create_new_thread_extension_abstract.h +graph.o: ../threads/multithreaded_object_extension.h +graph.o: ../threads/multithreaded_object_extension_abstract.h +graph.o: ../threads/rsignaler_extension.h +graph.o: ../threads/rsignaler_extension_abstract.h ../map.h +graph.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +graph.o: ../threads/threaded_object_extension.h +graph.o: ../threads/threaded_object_extension_abstract.h +graph.o: ../threads/thread_specific_data_extension.h +graph.o: ../threads/thread_specific_data_extension_abstract.h +graph.o: ../threads/thread_function_extension.h +graph.o: ../threads/thread_function_extension_abstract.h +graph.o: ../threads/threaded_object_extension.h +graph.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +graph.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +graph.o: ../misc_api.h ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +graph.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +graph.o: ../../dlib/logger/logger_kernel_abstract.h +graph.o: ../../dlib/logger/extra_logger_headers.h +graph.o: ../../dlib/logger/logger_kernel_1.h +graph.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +graph.o: ../config_reader/config_reader_kernel_1.h +graph.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +graph.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +graph.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +graph.o: ../tokenizer/tokenizer_kernel_1.h +graph.o: ../tokenizer/tokenizer_kernel_abstract.h +graph.o: ../tokenizer/tokenizer_kernel_c.h +graph.o: ../config_reader/config_reader_thread_safe_1.h +graph.o: ../config_reader/config_reader_thread_safe_abstract.h +graph.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +graph.o: ../set/set_compare_abstract.h ../set_utils.h +graph.o: ../set_utils/set_utils.h ../set_utils/set_utils_abstract.h +graph.o: ../../dlib/set.h +entropy_coder.o: ../../dlib/entropy_encoder.h +entropy_coder.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_1.h +entropy_coder.o: ../algs.h ../platform.h ../assert.h ../error.h +entropy_coder.o: ../noncopyable.h +entropy_coder.o: ../entropy_encoder/entropy_encoder_kernel_abstract.h +entropy_coder.o: ../uintn.h +entropy_coder.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_2.h +entropy_coder.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_c.h +entropy_coder.o: ../assert.h ../../dlib/entropy_decoder.h +entropy_coder.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_1.h +entropy_coder.o: ../entropy_decoder/entropy_decoder_kernel_abstract.h +entropy_coder.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_2.h +entropy_coder.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_c.h +entropy_coder.o: tester.h ../../dlib/map.h ../../dlib/logger.h +entropy_coder.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +entropy_coder.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +entropy_coder.o: ../threads/threads_kernel_2.h +entropy_coder.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +entropy_coder.o: /usr/include/features.h /usr/include/sys/cdefs.h +entropy_coder.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +entropy_coder.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +entropy_coder.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +entropy_coder.o: /usr/include/time.h /usr/include/bits/sched.h +entropy_coder.o: /usr/include/signal.h /usr/include/bits/sigset.h +entropy_coder.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +entropy_coder.o: /usr/include/errno.h /usr/include/bits/errno.h +entropy_coder.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +entropy_coder.o: /usr/include/asm-i386/errno.h +entropy_coder.o: /usr/include/asm-generic/errno.h +entropy_coder.o: /usr/include/asm-generic/errno-base.h +entropy_coder.o: /usr/include/sys/time.h /usr/include/bits/time.h +entropy_coder.o: /usr/include/sys/select.h /usr/include/bits/select.h +entropy_coder.o: ../threads/threads_kernel_shared.h +entropy_coder.o: ../threads/auto_mutex_extension.h +entropy_coder.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +entropy_coder.o: ../threads/rmutex_extension_abstract.h +entropy_coder.o: ../threads/auto_mutex_extension_abstract.h +entropy_coder.o: ../binary_search_tree.h +entropy_coder.o: ../binary_search_tree/binary_search_tree_kernel_1.h +entropy_coder.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +entropy_coder.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +entropy_coder.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +entropy_coder.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +entropy_coder.o: ../enable_if.h +entropy_coder.o: ../binary_search_tree/binary_search_tree_kernel_2.h +entropy_coder.o: ../binary_search_tree/binary_search_tree_kernel_c.h +entropy_coder.o: ../../dlib/memory_manager.h ../member_function_pointer.h +entropy_coder.o: ../member_function_pointer/member_function_pointer_kernel_1.h +entropy_coder.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +entropy_coder.o: ../member_function_pointer/member_function_pointer_kernel_c.h +entropy_coder.o: ../memory_manager.h +entropy_coder.o: ../memory_manager/memory_manager_kernel_1.h +entropy_coder.o: ../memory_manager/memory_manager_kernel_abstract.h +entropy_coder.o: ../memory_manager/memory_manager_kernel_2.h +entropy_coder.o: ../memory_manager/memory_manager_kernel_3.h +entropy_coder.o: ../memory_manager/memory_manager_kernel_2.h +entropy_coder.o: ../binary_search_tree/binary_search_tree_kernel_2.h +entropy_coder.o: ../queue.h ../queue/queue_kernel_1.h +entropy_coder.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +entropy_coder.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +entropy_coder.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +entropy_coder.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +entropy_coder.o: ../set/set_kernel_c.h binary_search_tree.h +entropy_coder.o: ../../dlib/memory_manager_global.h +entropy_coder.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +entropy_coder.o: ../memory_manager/memory_manager_kernel_abstract.h +entropy_coder.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +entropy_coder.o: ../../dlib/memory_manager_stateless.h +entropy_coder.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +entropy_coder.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +entropy_coder.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +entropy_coder.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +entropy_coder.o: ../set/set_compare_abstract.h +entropy_coder.o: ../threads/auto_mutex_extension.h +entropy_coder.o: ../threads/auto_unlock_extension.h +entropy_coder.o: ../threads/auto_unlock_extension_abstract.h +entropy_coder.o: ../threads/create_new_thread_extension.h +entropy_coder.o: ../threads/create_new_thread_extension_abstract.h +entropy_coder.o: ../threads/multithreaded_object_extension.h +entropy_coder.o: ../threads/multithreaded_object_extension_abstract.h +entropy_coder.o: ../threads/rsignaler_extension.h +entropy_coder.o: ../threads/rsignaler_extension_abstract.h ../map.h +entropy_coder.o: ../threads/rmutex_extension.h +entropy_coder.o: ../threads/rsignaler_extension.h +entropy_coder.o: ../threads/threaded_object_extension.h +entropy_coder.o: ../threads/threaded_object_extension_abstract.h +entropy_coder.o: ../threads/thread_specific_data_extension.h +entropy_coder.o: ../threads/thread_specific_data_extension_abstract.h +entropy_coder.o: ../threads/thread_function_extension.h +entropy_coder.o: ../threads/thread_function_extension_abstract.h +entropy_coder.o: ../threads/threaded_object_extension.h ../misc_api.h +entropy_coder.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +entropy_coder.o: ../misc_api/misc_api_kernel_abstract.h +entropy_coder.o: ../../dlib/logger/logger_kernel_abstract.h +entropy_coder.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +entropy_coder.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +entropy_coder.o: ../smart_pointers/shared_ptr.h +entropy_coder.o: ../smart_pointers/shared_ptr_abstract.h +entropy_coder.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +entropy_coder.o: ../smart_pointers/weak_ptr_abstract.h +entropy_coder.o: ../../dlib/logger/extra_logger_headers.h +entropy_coder.o: ../../dlib/logger/logger_kernel_1.h +entropy_coder.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +entropy_coder.o: ../config_reader/config_reader_kernel_1.h +entropy_coder.o: ../config_reader/config_reader_kernel_abstract.h +entropy_coder.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +entropy_coder.o: ../../dlib/map/map_kernel_abstract.h +entropy_coder.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +entropy_coder.o: ../tokenizer/tokenizer_kernel_1.h +entropy_coder.o: ../tokenizer/tokenizer_kernel_abstract.h +entropy_coder.o: ../tokenizer/tokenizer_kernel_c.h +entropy_coder.o: ../config_reader/config_reader_thread_safe_1.h +entropy_coder.o: ../config_reader/config_reader_thread_safe_abstract.h +entropy_coder.o: ../../dlib/assert.h ../../dlib/algs.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h +entropy_encoder_model.o: ../algs.h ../platform.h ../assert.h ../error.h +entropy_encoder_model.o: ../noncopyable.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h +entropy_encoder_model.o: ../assert.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h +entropy_encoder_model.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h +entropy_encoder_model.o: conditioning_class.h ../../dlib/conditioning_class.h +entropy_encoder_model.o: ../../dlib/conditioning_class/conditioning_class_kernel_1.h +entropy_encoder_model.o: ../../dlib/conditioning_class/conditioning_class_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/conditioning_class/conditioning_class_kernel_2.h +entropy_encoder_model.o: ../../dlib/conditioning_class/conditioning_class_kernel_3.h +entropy_encoder_model.o: ../../dlib/conditioning_class/conditioning_class_kernel_4.h +entropy_encoder_model.o: ../../dlib/conditioning_class/conditioning_class_kernel_c.h +entropy_encoder_model.o: ../../dlib/memory_manager.h tester.h +entropy_encoder_model.o: ../../dlib/map.h ../../dlib/logger.h +entropy_encoder_model.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +entropy_encoder_model.o: ../threads/threads_kernel.h ../platform.h +entropy_encoder_model.o: ../threads/posix.h ../threads/threads_kernel_2.h +entropy_encoder_model.o: ../threads/threads_kernel_abstract.h +entropy_encoder_model.o: /usr/include/pthread.h /usr/include/features.h +entropy_encoder_model.o: /usr/include/sys/cdefs.h +entropy_encoder_model.o: /usr/include/bits/wordsize.h +entropy_encoder_model.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +entropy_encoder_model.o: /usr/include/sched.h /usr/include/bits/types.h +entropy_encoder_model.o: /usr/include/bits/typesizes.h /usr/include/time.h +entropy_encoder_model.o: /usr/include/bits/sched.h /usr/include/signal.h +entropy_encoder_model.o: /usr/include/bits/sigset.h +entropy_encoder_model.o: /usr/include/bits/pthreadtypes.h +entropy_encoder_model.o: /usr/include/bits/setjmp.h /usr/include/errno.h +entropy_encoder_model.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +entropy_encoder_model.o: /usr/include/asm/errno.h +entropy_encoder_model.o: /usr/include/asm-i386/errno.h +entropy_encoder_model.o: /usr/include/asm-generic/errno.h +entropy_encoder_model.o: /usr/include/asm-generic/errno-base.h +entropy_encoder_model.o: /usr/include/sys/time.h /usr/include/bits/time.h +entropy_encoder_model.o: /usr/include/sys/select.h /usr/include/bits/select.h +entropy_encoder_model.o: ../threads/threads_kernel_shared.h +entropy_encoder_model.o: ../threads/auto_mutex_extension.h +entropy_encoder_model.o: ../threads/threads_kernel.h +entropy_encoder_model.o: ../threads/rmutex_extension.h +entropy_encoder_model.o: ../threads/rmutex_extension_abstract.h +entropy_encoder_model.o: ../threads/auto_mutex_extension_abstract.h +entropy_encoder_model.o: ../binary_search_tree.h +entropy_encoder_model.o: ../binary_search_tree/binary_search_tree_kernel_1.h +entropy_encoder_model.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +entropy_encoder_model.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +entropy_encoder_model.o: ../interfaces/remover.h ../serialize.h ../algs.h +entropy_encoder_model.o: ../uintn.h ../interfaces/enumerable.h +entropy_encoder_model.o: ../interfaces/map_pair.h ../enable_if.h +entropy_encoder_model.o: ../binary_search_tree/binary_search_tree_kernel_2.h +entropy_encoder_model.o: ../binary_search_tree/binary_search_tree_kernel_c.h +entropy_encoder_model.o: ../member_function_pointer.h +entropy_encoder_model.o: ../member_function_pointer/member_function_pointer_kernel_1.h +entropy_encoder_model.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +entropy_encoder_model.o: ../member_function_pointer/member_function_pointer_kernel_c.h +entropy_encoder_model.o: ../memory_manager.h +entropy_encoder_model.o: ../memory_manager/memory_manager_kernel_1.h +entropy_encoder_model.o: ../memory_manager/memory_manager_kernel_abstract.h +entropy_encoder_model.o: ../memory_manager/memory_manager_kernel_2.h +entropy_encoder_model.o: ../memory_manager/memory_manager_kernel_3.h +entropy_encoder_model.o: ../memory_manager/memory_manager_kernel_2.h +entropy_encoder_model.o: ../binary_search_tree/binary_search_tree_kernel_2.h +entropy_encoder_model.o: ../queue.h ../queue/queue_kernel_1.h +entropy_encoder_model.o: ../queue/queue_kernel_abstract.h +entropy_encoder_model.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +entropy_encoder_model.o: ../queue/queue_sort_1.h +entropy_encoder_model.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +entropy_encoder_model.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +entropy_encoder_model.o: ../set/set_kernel_c.h binary_search_tree.h +entropy_encoder_model.o: ../../dlib/memory_manager_global.h +entropy_encoder_model.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +entropy_encoder_model.o: ../memory_manager/memory_manager_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/memory_manager_stateless.h +entropy_encoder_model.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +entropy_encoder_model.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +entropy_encoder_model.o: ../../dlib/binary_search_tree.h +entropy_encoder_model.o: ../set/set_compare_1.h ../set/set_compare_abstract.h +entropy_encoder_model.o: ../threads/auto_mutex_extension.h +entropy_encoder_model.o: ../threads/auto_unlock_extension.h +entropy_encoder_model.o: ../threads/auto_unlock_extension_abstract.h +entropy_encoder_model.o: ../threads/create_new_thread_extension.h +entropy_encoder_model.o: ../threads/create_new_thread_extension_abstract.h +entropy_encoder_model.o: ../threads/multithreaded_object_extension.h +entropy_encoder_model.o: ../threads/multithreaded_object_extension_abstract.h +entropy_encoder_model.o: ../threads/rsignaler_extension.h +entropy_encoder_model.o: ../threads/rsignaler_extension_abstract.h ../map.h +entropy_encoder_model.o: ../threads/rmutex_extension.h +entropy_encoder_model.o: ../threads/rsignaler_extension.h +entropy_encoder_model.o: ../threads/threaded_object_extension.h +entropy_encoder_model.o: ../threads/threaded_object_extension_abstract.h +entropy_encoder_model.o: ../threads/thread_specific_data_extension.h +entropy_encoder_model.o: ../threads/thread_specific_data_extension_abstract.h +entropy_encoder_model.o: ../threads/thread_function_extension.h +entropy_encoder_model.o: ../threads/thread_function_extension_abstract.h +entropy_encoder_model.o: ../threads/threaded_object_extension.h ../misc_api.h +entropy_encoder_model.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +entropy_encoder_model.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +entropy_encoder_model.o: ../../dlib/logger/logger_kernel_abstract.h +entropy_encoder_model.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +entropy_encoder_model.o: ../noncopyable.h +entropy_encoder_model.o: ../smart_pointers/scoped_ptr_abstract.h +entropy_encoder_model.o: ../smart_pointers/shared_ptr.h +entropy_encoder_model.o: ../smart_pointers/shared_ptr_abstract.h +entropy_encoder_model.o: ../smart_pointers/weak_ptr.h +entropy_encoder_model.o: ../smart_pointers/shared_ptr.h +entropy_encoder_model.o: ../smart_pointers/weak_ptr_abstract.h +entropy_encoder_model.o: ../../dlib/logger/extra_logger_headers.h +entropy_encoder_model.o: ../../dlib/logger/logger_kernel_1.h +entropy_encoder_model.o: ../../dlib/logger/logger_config_file.h +entropy_encoder_model.o: ../config_reader.h +entropy_encoder_model.o: ../config_reader/config_reader_kernel_1.h +entropy_encoder_model.o: ../config_reader/config_reader_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +entropy_encoder_model.o: ../../dlib/map/map_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +entropy_encoder_model.o: ../tokenizer/tokenizer_kernel_1.h +entropy_encoder_model.o: ../tokenizer/tokenizer_kernel_abstract.h +entropy_encoder_model.o: ../tokenizer/tokenizer_kernel_c.h +entropy_encoder_model.o: ../config_reader/config_reader_thread_safe_1.h +entropy_encoder_model.o: ../config_reader/config_reader_thread_safe_abstract.h +entropy_encoder_model.o: ../../dlib/assert.h ../../dlib/algs.h +entropy_encoder_model.o: ../../dlib/sliding_buffer.h +entropy_encoder_model.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_1.h +entropy_encoder_model.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_c.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h +entropy_encoder_model.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h +entropy_encoder_model.o: ../../dlib/entropy_encoder.h +entropy_encoder_model.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_1.h +entropy_encoder_model.o: ../entropy_encoder/entropy_encoder_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_2.h +entropy_encoder_model.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_c.h +entropy_encoder_model.o: ../../dlib/entropy_decoder.h +entropy_encoder_model.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_1.h +entropy_encoder_model.o: ../entropy_decoder/entropy_decoder_kernel_abstract.h +entropy_encoder_model.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_2.h +entropy_encoder_model.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_c.h +hash_map.o: ../../dlib/hash_map.h ../../dlib/hash_map/hash_map_kernel_1.h +hash_map.o: ../../dlib/hash_map/hash_map_kernel_abstract.h ../algs.h +hash_map.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +hash_map.o: ../general_hash/general_hash.h ../interfaces/enumerable.h +hash_map.o: ../interfaces/map_pair.h ../interfaces/remover.h ../assert.h +hash_map.o: ../serialize.h ../algs.h ../uintn.h ../interfaces/enumerable.h +hash_map.o: ../interfaces/map_pair.h ../enable_if.h ../memory_manager.h +hash_map.o: ../memory_manager/memory_manager_kernel_1.h +hash_map.o: ../memory_manager/memory_manager_kernel_abstract.h +hash_map.o: ../memory_manager/memory_manager_kernel_2.h +hash_map.o: ../memory_manager/memory_manager_kernel_3.h +hash_map.o: ../memory_manager/memory_manager_kernel_2.h +hash_map.o: ../binary_search_tree/binary_search_tree_kernel_2.h +hash_map.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +hash_map.o: ../../dlib/hash_map/hash_map_kernel_c.h ../../dlib/hash_table.h +hash_map.o: ../../dlib/hash_table/hash_table_kernel_1.h +hash_map.o: ../../dlib/hash_table/hash_table_kernel_abstract.h +hash_map.o: ../../dlib/hash_table/hash_table_kernel_2.h +hash_map.o: ../../dlib/hash_table/hash_table_kernel_c.h +hash_map.o: ../../dlib/memory_manager.h binary_search_tree.h +hash_map.o: ../../dlib/memory_manager_global.h +hash_map.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +hash_map.o: ../memory_manager/memory_manager_kernel_abstract.h +hash_map.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +hash_map.o: ../../dlib/memory_manager_stateless.h +hash_map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +hash_map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +hash_map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +hash_map.o: ../threads.h ../threads/threads_kernel.h ../platform.h +hash_map.o: ../threads/posix.h ../threads/threads_kernel_2.h +hash_map.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +hash_map.o: /usr/include/features.h /usr/include/sys/cdefs.h +hash_map.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +hash_map.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +hash_map.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +hash_map.o: /usr/include/time.h /usr/include/bits/sched.h +hash_map.o: /usr/include/signal.h /usr/include/bits/sigset.h +hash_map.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +hash_map.o: /usr/include/errno.h /usr/include/bits/errno.h +hash_map.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +hash_map.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +hash_map.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +hash_map.o: /usr/include/bits/time.h /usr/include/sys/select.h +hash_map.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +hash_map.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +hash_map.o: ../threads/rmutex_extension.h +hash_map.o: ../threads/rmutex_extension_abstract.h +hash_map.o: ../threads/auto_mutex_extension_abstract.h +hash_map.o: ../binary_search_tree.h +hash_map.o: ../binary_search_tree/binary_search_tree_kernel_1.h +hash_map.o: ../binary_search_tree/binary_search_tree_kernel_2.h +hash_map.o: ../binary_search_tree/binary_search_tree_kernel_c.h +hash_map.o: ../member_function_pointer.h +hash_map.o: ../member_function_pointer/member_function_pointer_kernel_1.h +hash_map.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +hash_map.o: ../member_function_pointer/member_function_pointer_kernel_c.h +hash_map.o: ../queue.h ../queue/queue_kernel_1.h +hash_map.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +hash_map.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +hash_map.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +hash_map.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +hash_map.o: ../set/set_kernel_c.h ../set/set_compare_1.h +hash_map.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +hash_map.o: ../threads/auto_unlock_extension.h +hash_map.o: ../threads/auto_unlock_extension_abstract.h +hash_map.o: ../threads/create_new_thread_extension.h +hash_map.o: ../threads/create_new_thread_extension_abstract.h +hash_map.o: ../threads/multithreaded_object_extension.h +hash_map.o: ../threads/multithreaded_object_extension_abstract.h +hash_map.o: ../threads/rsignaler_extension.h +hash_map.o: ../threads/rsignaler_extension_abstract.h ../map.h +hash_map.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +hash_map.o: ../threads/threaded_object_extension.h +hash_map.o: ../threads/threaded_object_extension_abstract.h +hash_map.o: ../threads/thread_specific_data_extension.h +hash_map.o: ../threads/thread_specific_data_extension_abstract.h +hash_map.o: ../threads/thread_function_extension.h +hash_map.o: ../threads/thread_function_extension_abstract.h +hash_map.o: ../threads/threaded_object_extension.h +hash_map.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +hash_map.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +hash_map.o: ../misc_api.h ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +hash_map.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +hash_map.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +hash_map.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +hash_map.o: ../smart_pointers/scoped_ptr_abstract.h +hash_map.o: ../smart_pointers/shared_ptr.h +hash_map.o: ../smart_pointers/shared_ptr_abstract.h +hash_map.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +hash_map.o: ../smart_pointers/weak_ptr_abstract.h +hash_map.o: ../../dlib/logger/extra_logger_headers.h +hash_map.o: ../../dlib/logger/logger_kernel_1.h +hash_map.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +hash_map.o: ../config_reader/config_reader_kernel_1.h +hash_map.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +hash_map.o: ../../dlib/map/map_kernel_1.h +hash_map.o: ../../dlib/map/map_kernel_abstract.h +hash_map.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +hash_map.o: ../tokenizer/tokenizer_kernel_1.h +hash_map.o: ../tokenizer/tokenizer_kernel_abstract.h +hash_map.o: ../tokenizer/tokenizer_kernel_c.h +hash_map.o: ../config_reader/config_reader_thread_safe_1.h +hash_map.o: ../config_reader/config_reader_thread_safe_abstract.h +hash_map.o: ../../dlib/assert.h ../../dlib/algs.h +hash_set.o: ../../dlib/hash_set.h ../../dlib/hash_set/hash_set_kernel_1.h +hash_set.o: ../../dlib/hash_set/hash_set_kernel_abstract.h ../algs.h +hash_set.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +hash_set.o: ../general_hash/general_hash.h ../interfaces/enumerable.h +hash_set.o: ../interfaces/remover.h ../assert.h ../serialize.h ../algs.h +hash_set.o: ../uintn.h ../interfaces/enumerable.h ../interfaces/map_pair.h +hash_set.o: ../enable_if.h ../memory_manager.h +hash_set.o: ../memory_manager/memory_manager_kernel_1.h +hash_set.o: ../memory_manager/memory_manager_kernel_abstract.h +hash_set.o: ../memory_manager/memory_manager_kernel_2.h +hash_set.o: ../memory_manager/memory_manager_kernel_3.h +hash_set.o: ../memory_manager/memory_manager_kernel_2.h +hash_set.o: ../binary_search_tree/binary_search_tree_kernel_2.h +hash_set.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +hash_set.o: ../interfaces/map_pair.h ../../dlib/hash_set/hash_set_kernel_c.h +hash_set.o: ../../dlib/hash_table.h +hash_set.o: ../../dlib/hash_table/hash_table_kernel_1.h +hash_set.o: ../../dlib/hash_table/hash_table_kernel_abstract.h +hash_set.o: ../../dlib/hash_table/hash_table_kernel_2.h +hash_set.o: ../../dlib/hash_table/hash_table_kernel_c.h +hash_set.o: ../../dlib/memory_manager.h binary_search_tree.h +hash_set.o: ../../dlib/memory_manager_global.h +hash_set.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +hash_set.o: ../memory_manager/memory_manager_kernel_abstract.h +hash_set.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +hash_set.o: ../../dlib/memory_manager_stateless.h +hash_set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +hash_set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +hash_set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +hash_set.o: ../threads.h ../threads/threads_kernel.h ../platform.h +hash_set.o: ../threads/posix.h ../threads/threads_kernel_2.h +hash_set.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +hash_set.o: /usr/include/features.h /usr/include/sys/cdefs.h +hash_set.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +hash_set.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +hash_set.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +hash_set.o: /usr/include/time.h /usr/include/bits/sched.h +hash_set.o: /usr/include/signal.h /usr/include/bits/sigset.h +hash_set.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +hash_set.o: /usr/include/errno.h /usr/include/bits/errno.h +hash_set.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +hash_set.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +hash_set.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +hash_set.o: /usr/include/bits/time.h /usr/include/sys/select.h +hash_set.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +hash_set.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +hash_set.o: ../threads/rmutex_extension.h +hash_set.o: ../threads/rmutex_extension_abstract.h +hash_set.o: ../threads/auto_mutex_extension_abstract.h +hash_set.o: ../binary_search_tree.h +hash_set.o: ../binary_search_tree/binary_search_tree_kernel_1.h +hash_set.o: ../binary_search_tree/binary_search_tree_kernel_2.h +hash_set.o: ../binary_search_tree/binary_search_tree_kernel_c.h +hash_set.o: ../member_function_pointer.h +hash_set.o: ../member_function_pointer/member_function_pointer_kernel_1.h +hash_set.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +hash_set.o: ../member_function_pointer/member_function_pointer_kernel_c.h +hash_set.o: ../queue.h ../queue/queue_kernel_1.h +hash_set.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +hash_set.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +hash_set.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +hash_set.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +hash_set.o: ../set/set_kernel_c.h ../set/set_compare_1.h +hash_set.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +hash_set.o: ../threads/auto_unlock_extension.h +hash_set.o: ../threads/auto_unlock_extension_abstract.h +hash_set.o: ../threads/create_new_thread_extension.h +hash_set.o: ../threads/create_new_thread_extension_abstract.h +hash_set.o: ../threads/multithreaded_object_extension.h +hash_set.o: ../threads/multithreaded_object_extension_abstract.h +hash_set.o: ../threads/rsignaler_extension.h +hash_set.o: ../threads/rsignaler_extension_abstract.h ../map.h +hash_set.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +hash_set.o: ../threads/threaded_object_extension.h +hash_set.o: ../threads/threaded_object_extension_abstract.h +hash_set.o: ../threads/thread_specific_data_extension.h +hash_set.o: ../threads/thread_specific_data_extension_abstract.h +hash_set.o: ../threads/thread_function_extension.h +hash_set.o: ../threads/thread_function_extension_abstract.h +hash_set.o: ../threads/threaded_object_extension.h +hash_set.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +hash_set.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +hash_set.o: ../misc_api.h ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +hash_set.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +hash_set.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +hash_set.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +hash_set.o: ../smart_pointers/scoped_ptr_abstract.h +hash_set.o: ../smart_pointers/shared_ptr.h +hash_set.o: ../smart_pointers/shared_ptr_abstract.h +hash_set.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +hash_set.o: ../smart_pointers/weak_ptr_abstract.h +hash_set.o: ../../dlib/logger/extra_logger_headers.h +hash_set.o: ../../dlib/logger/logger_kernel_1.h +hash_set.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +hash_set.o: ../config_reader/config_reader_kernel_1.h +hash_set.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +hash_set.o: ../../dlib/map/map_kernel_1.h +hash_set.o: ../../dlib/map/map_kernel_abstract.h +hash_set.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +hash_set.o: ../tokenizer/tokenizer_kernel_1.h +hash_set.o: ../tokenizer/tokenizer_kernel_abstract.h +hash_set.o: ../tokenizer/tokenizer_kernel_c.h +hash_set.o: ../config_reader/config_reader_thread_safe_1.h +hash_set.o: ../config_reader/config_reader_thread_safe_abstract.h +hash_set.o: ../../dlib/assert.h ../../dlib/algs.h +hash_table.o: ../../dlib/hash_table.h +hash_table.o: ../../dlib/hash_table/hash_table_kernel_1.h +hash_table.o: ../../dlib/hash_table/hash_table_kernel_abstract.h +hash_table.o: ../general_hash/general_hash.h ../algs.h ../platform.h +hash_table.o: ../assert.h ../error.h ../noncopyable.h +hash_table.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +hash_table.o: ../interfaces/remover.h ../assert.h ../serialize.h ../algs.h +hash_table.o: ../uintn.h ../interfaces/enumerable.h ../interfaces/map_pair.h +hash_table.o: ../enable_if.h ../memory_manager.h +hash_table.o: ../memory_manager/memory_manager_kernel_1.h +hash_table.o: ../memory_manager/memory_manager_kernel_abstract.h +hash_table.o: ../memory_manager/memory_manager_kernel_2.h +hash_table.o: ../memory_manager/memory_manager_kernel_3.h +hash_table.o: ../memory_manager/memory_manager_kernel_2.h +hash_table.o: ../binary_search_tree/binary_search_tree_kernel_2.h +hash_table.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +hash_table.o: ../../dlib/hash_table/hash_table_kernel_2.h +hash_table.o: ../../dlib/hash_table/hash_table_kernel_c.h +hash_table.o: ../../dlib/memory_manager.h binary_search_tree.h +hash_table.o: ../../dlib/memory_manager_global.h +hash_table.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +hash_table.o: ../memory_manager/memory_manager_kernel_abstract.h +hash_table.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +hash_table.o: ../../dlib/memory_manager_stateless.h +hash_table.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +hash_table.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +hash_table.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +hash_table.o: ../threads.h ../threads/threads_kernel.h ../platform.h +hash_table.o: ../threads/posix.h ../threads/threads_kernel_2.h +hash_table.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +hash_table.o: /usr/include/features.h /usr/include/sys/cdefs.h +hash_table.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +hash_table.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +hash_table.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +hash_table.o: /usr/include/time.h /usr/include/bits/sched.h +hash_table.o: /usr/include/signal.h /usr/include/bits/sigset.h +hash_table.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +hash_table.o: /usr/include/errno.h /usr/include/bits/errno.h +hash_table.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +hash_table.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +hash_table.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +hash_table.o: /usr/include/bits/time.h /usr/include/sys/select.h +hash_table.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +hash_table.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +hash_table.o: ../threads/rmutex_extension.h +hash_table.o: ../threads/rmutex_extension_abstract.h +hash_table.o: ../threads/auto_mutex_extension_abstract.h +hash_table.o: ../binary_search_tree.h +hash_table.o: ../binary_search_tree/binary_search_tree_kernel_1.h +hash_table.o: ../binary_search_tree/binary_search_tree_kernel_2.h +hash_table.o: ../binary_search_tree/binary_search_tree_kernel_c.h +hash_table.o: ../member_function_pointer.h +hash_table.o: ../member_function_pointer/member_function_pointer_kernel_1.h +hash_table.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +hash_table.o: ../member_function_pointer/member_function_pointer_kernel_c.h +hash_table.o: ../queue.h ../queue/queue_kernel_1.h +hash_table.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +hash_table.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +hash_table.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +hash_table.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +hash_table.o: ../set/set_kernel_c.h ../set/set_compare_1.h +hash_table.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +hash_table.o: ../threads/auto_unlock_extension.h +hash_table.o: ../threads/auto_unlock_extension_abstract.h +hash_table.o: ../threads/create_new_thread_extension.h +hash_table.o: ../threads/create_new_thread_extension_abstract.h +hash_table.o: ../threads/multithreaded_object_extension.h +hash_table.o: ../threads/multithreaded_object_extension_abstract.h +hash_table.o: ../threads/rsignaler_extension.h +hash_table.o: ../threads/rsignaler_extension_abstract.h ../map.h +hash_table.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +hash_table.o: ../threads/threaded_object_extension.h +hash_table.o: ../threads/threaded_object_extension_abstract.h +hash_table.o: ../threads/thread_specific_data_extension.h +hash_table.o: ../threads/thread_specific_data_extension_abstract.h +hash_table.o: ../threads/thread_function_extension.h +hash_table.o: ../threads/thread_function_extension_abstract.h +hash_table.o: ../threads/threaded_object_extension.h +hash_table.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +hash_table.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +hash_table.o: ../misc_api.h ../misc_api/posix.h +hash_table.o: ../misc_api/misc_api_kernel_2.h +hash_table.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +hash_table.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +hash_table.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +hash_table.o: ../smart_pointers/scoped_ptr_abstract.h +hash_table.o: ../smart_pointers/shared_ptr.h +hash_table.o: ../smart_pointers/shared_ptr_abstract.h +hash_table.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +hash_table.o: ../smart_pointers/weak_ptr_abstract.h +hash_table.o: ../../dlib/logger/extra_logger_headers.h +hash_table.o: ../../dlib/logger/logger_kernel_1.h +hash_table.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +hash_table.o: ../config_reader/config_reader_kernel_1.h +hash_table.o: ../config_reader/config_reader_kernel_abstract.h +hash_table.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +hash_table.o: ../../dlib/map/map_kernel_abstract.h +hash_table.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +hash_table.o: ../tokenizer/tokenizer_kernel_1.h +hash_table.o: ../tokenizer/tokenizer_kernel_abstract.h +hash_table.o: ../tokenizer/tokenizer_kernel_c.h +hash_table.o: ../config_reader/config_reader_thread_safe_1.h +hash_table.o: ../config_reader/config_reader_thread_safe_abstract.h +hash_table.o: ../../dlib/assert.h ../../dlib/algs.h +image.o: ../../dlib/pixel.h ../serialize.h ../algs.h ../uintn.h +image.o: ../enable_if.h ../../dlib/array2d.h +image.o: ../../dlib/array2d/array2d_kernel_1.h +image.o: ../../dlib/array2d/array2d_kernel_abstract.h ../algs.h ../platform.h +image.o: ../assert.h ../error.h ../noncopyable.h ../interfaces/enumerable.h +image.o: ../serialize.h ../interfaces/enumerable.h ../interfaces/map_pair.h +image.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +image.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +image.o: ../memory_manager/memory_manager_kernel_2.h +image.o: ../memory_manager/memory_manager_kernel_3.h +image.o: ../memory_manager/memory_manager_kernel_2.h +image.o: ../binary_search_tree/binary_search_tree_kernel_2.h +image.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +image.o: ../interfaces/map_pair.h ../interfaces/remover.h +image.o: ../../dlib/array2d/array2d_kernel_c.h ../../dlib/memory_manager.h +image.o: ../../dlib/image_transforms.h +image.o: ../../dlib/image_transforms/assign_image.h ../pixel.h +image.o: ../../dlib/image_transforms/assign_image_abstract.h +image.o: ../../dlib/image_transforms/equalize_histogram.h +image.o: ../../dlib/image_transforms/equalize_histogram_abstract.h +image.o: ../enable_if.h ../matrix.h ../matrix/matrix.h +image.o: ../matrix/matrix_abstract.h ../matrix/matrix_utilities.h +image.o: ../matrix/matrix_utilities_abstract.h ../matrix/matrix.h +image.o: ../matrix/matrix_math_functions.h ../matrix/matrix_utilities.h +image.o: ../../dlib/image_transforms/morphological_operations.h +image.o: ../../dlib/image_transforms/thresholding.h +image.o: ../../dlib/image_transforms/thresholding_abstract.h +image.o: ../../dlib/image_transforms/equalize_histogram.h +image.o: ../../dlib/image_transforms/morphological_operations_abstract.h +image.o: ../../dlib/image_transforms/spatial_filtering.h +image.o: ../../dlib/image_transforms/spatial_filtering_abstract.h +image.o: ../../dlib/image_transforms/thresholding.h +image.o: ../../dlib/image_transforms/edge_detector.h +image.o: ../../dlib/image_transforms/edge_detector_abstract.h ../array2d.h +image.o: tester.h ../../dlib/map.h ../../dlib/logger.h +image.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +image.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +image.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +image.o: /usr/include/pthread.h /usr/include/features.h +image.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +image.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +image.o: /usr/include/sched.h /usr/include/bits/types.h +image.o: /usr/include/bits/typesizes.h /usr/include/time.h +image.o: /usr/include/bits/sched.h /usr/include/signal.h +image.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +image.o: /usr/include/bits/setjmp.h /usr/include/errno.h +image.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +image.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +image.o: /usr/include/asm-generic/errno.h +image.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +image.o: /usr/include/bits/time.h /usr/include/sys/select.h +image.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +image.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +image.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +image.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +image.o: ../binary_search_tree/binary_search_tree_kernel_1.h +image.o: ../binary_search_tree/binary_search_tree_kernel_2.h +image.o: ../binary_search_tree/binary_search_tree_kernel_c.h +image.o: ../member_function_pointer.h +image.o: ../member_function_pointer/member_function_pointer_kernel_1.h +image.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +image.o: ../member_function_pointer/member_function_pointer_kernel_c.h +image.o: ../queue.h ../queue/queue_kernel_1.h +image.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +image.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +image.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +image.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +image.o: ../set/set_kernel_c.h binary_search_tree.h +image.o: ../../dlib/memory_manager_global.h +image.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +image.o: ../memory_manager/memory_manager_kernel_abstract.h +image.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +image.o: ../../dlib/memory_manager_stateless.h +image.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +image.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +image.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +image.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +image.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +image.o: ../threads/auto_unlock_extension.h +image.o: ../threads/auto_unlock_extension_abstract.h +image.o: ../threads/create_new_thread_extension.h +image.o: ../threads/create_new_thread_extension_abstract.h +image.o: ../threads/multithreaded_object_extension.h +image.o: ../threads/multithreaded_object_extension_abstract.h +image.o: ../threads/rsignaler_extension.h +image.o: ../threads/rsignaler_extension_abstract.h ../map.h +image.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +image.o: ../threads/threaded_object_extension.h +image.o: ../threads/threaded_object_extension_abstract.h +image.o: ../threads/thread_specific_data_extension.h +image.o: ../threads/thread_specific_data_extension_abstract.h +image.o: ../threads/thread_function_extension.h +image.o: ../threads/thread_function_extension_abstract.h +image.o: ../threads/threaded_object_extension.h ../misc_api.h +image.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +image.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +image.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +image.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +image.o: ../smart_pointers/scoped_ptr_abstract.h +image.o: ../smart_pointers/shared_ptr.h +image.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +image.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +image.o: ../../dlib/logger/extra_logger_headers.h +image.o: ../../dlib/logger/logger_kernel_1.h +image.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +image.o: ../config_reader/config_reader_kernel_1.h +image.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +image.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +image.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +image.o: ../tokenizer/tokenizer_kernel_1.h +image.o: ../tokenizer/tokenizer_kernel_abstract.h +image.o: ../tokenizer/tokenizer_kernel_c.h +image.o: ../config_reader/config_reader_thread_safe_1.h +image.o: ../config_reader/config_reader_thread_safe_abstract.h +image.o: ../../dlib/assert.h ../../dlib/algs.h +lz77_buffer.o: ../../dlib/sliding_buffer.h +lz77_buffer.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_1.h +lz77_buffer.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_abstract.h +lz77_buffer.o: ../algs.h ../platform.h ../assert.h ../error.h +lz77_buffer.o: ../noncopyable.h ../interfaces/enumerable.h ../serialize.h +lz77_buffer.o: ../algs.h ../uintn.h ../interfaces/enumerable.h +lz77_buffer.o: ../interfaces/map_pair.h ../enable_if.h +lz77_buffer.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_c.h +lz77_buffer.o: ../assert.h ../../dlib/lz77_buffer.h +lz77_buffer.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_1.h +lz77_buffer.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_abstract.h +lz77_buffer.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_2.h +lz77_buffer.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_c.h +lz77_buffer.o: ../../dlib/sliding_buffer.h tester.h ../../dlib/map.h +lz77_buffer.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +lz77_buffer.o: ../threads.h ../threads/threads_kernel.h ../platform.h +lz77_buffer.o: ../threads/posix.h ../threads/threads_kernel_2.h +lz77_buffer.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +lz77_buffer.o: /usr/include/features.h /usr/include/sys/cdefs.h +lz77_buffer.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +lz77_buffer.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +lz77_buffer.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +lz77_buffer.o: /usr/include/time.h /usr/include/bits/sched.h +lz77_buffer.o: /usr/include/signal.h /usr/include/bits/sigset.h +lz77_buffer.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +lz77_buffer.o: /usr/include/errno.h /usr/include/bits/errno.h +lz77_buffer.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +lz77_buffer.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +lz77_buffer.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +lz77_buffer.o: /usr/include/bits/time.h /usr/include/sys/select.h +lz77_buffer.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +lz77_buffer.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +lz77_buffer.o: ../threads/rmutex_extension.h +lz77_buffer.o: ../threads/rmutex_extension_abstract.h +lz77_buffer.o: ../threads/auto_mutex_extension_abstract.h +lz77_buffer.o: ../binary_search_tree.h +lz77_buffer.o: ../binary_search_tree/binary_search_tree_kernel_1.h +lz77_buffer.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +lz77_buffer.o: ../interfaces/map_pair.h ../interfaces/remover.h +lz77_buffer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +lz77_buffer.o: ../binary_search_tree/binary_search_tree_kernel_c.h +lz77_buffer.o: ../../dlib/memory_manager.h ../member_function_pointer.h +lz77_buffer.o: ../member_function_pointer/member_function_pointer_kernel_1.h +lz77_buffer.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +lz77_buffer.o: ../member_function_pointer/member_function_pointer_kernel_c.h +lz77_buffer.o: ../memory_manager.h +lz77_buffer.o: ../memory_manager/memory_manager_kernel_1.h +lz77_buffer.o: ../memory_manager/memory_manager_kernel_abstract.h +lz77_buffer.o: ../memory_manager/memory_manager_kernel_2.h +lz77_buffer.o: ../memory_manager/memory_manager_kernel_3.h +lz77_buffer.o: ../memory_manager/memory_manager_kernel_2.h +lz77_buffer.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +lz77_buffer.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +lz77_buffer.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +lz77_buffer.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h +lz77_buffer.o: ../sort.h ../set.h ../set/set_kernel_1.h +lz77_buffer.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +lz77_buffer.o: binary_search_tree.h ../../dlib/memory_manager_global.h +lz77_buffer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +lz77_buffer.o: ../memory_manager/memory_manager_kernel_abstract.h +lz77_buffer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +lz77_buffer.o: ../../dlib/memory_manager_stateless.h +lz77_buffer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +lz77_buffer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +lz77_buffer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +lz77_buffer.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +lz77_buffer.o: ../set/set_compare_abstract.h +lz77_buffer.o: ../threads/auto_mutex_extension.h +lz77_buffer.o: ../threads/auto_unlock_extension.h +lz77_buffer.o: ../threads/auto_unlock_extension_abstract.h +lz77_buffer.o: ../threads/create_new_thread_extension.h +lz77_buffer.o: ../threads/create_new_thread_extension_abstract.h +lz77_buffer.o: ../threads/multithreaded_object_extension.h +lz77_buffer.o: ../threads/multithreaded_object_extension_abstract.h +lz77_buffer.o: ../threads/rsignaler_extension.h +lz77_buffer.o: ../threads/rsignaler_extension_abstract.h ../map.h +lz77_buffer.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +lz77_buffer.o: ../threads/threaded_object_extension.h +lz77_buffer.o: ../threads/threaded_object_extension_abstract.h +lz77_buffer.o: ../threads/thread_specific_data_extension.h +lz77_buffer.o: ../threads/thread_specific_data_extension_abstract.h +lz77_buffer.o: ../threads/thread_function_extension.h +lz77_buffer.o: ../threads/thread_function_extension_abstract.h +lz77_buffer.o: ../threads/threaded_object_extension.h ../misc_api.h +lz77_buffer.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +lz77_buffer.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +lz77_buffer.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +lz77_buffer.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +lz77_buffer.o: ../smart_pointers/scoped_ptr_abstract.h +lz77_buffer.o: ../smart_pointers/shared_ptr.h +lz77_buffer.o: ../smart_pointers/shared_ptr_abstract.h +lz77_buffer.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +lz77_buffer.o: ../smart_pointers/weak_ptr_abstract.h +lz77_buffer.o: ../../dlib/logger/extra_logger_headers.h +lz77_buffer.o: ../../dlib/logger/logger_kernel_1.h +lz77_buffer.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +lz77_buffer.o: ../config_reader/config_reader_kernel_1.h +lz77_buffer.o: ../config_reader/config_reader_kernel_abstract.h +lz77_buffer.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +lz77_buffer.o: ../../dlib/map/map_kernel_abstract.h +lz77_buffer.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +lz77_buffer.o: ../tokenizer/tokenizer_kernel_1.h +lz77_buffer.o: ../tokenizer/tokenizer_kernel_abstract.h +lz77_buffer.o: ../tokenizer/tokenizer_kernel_c.h +lz77_buffer.o: ../config_reader/config_reader_thread_safe_1.h +lz77_buffer.o: ../config_reader/config_reader_thread_safe_abstract.h +lz77_buffer.o: ../../dlib/assert.h ../../dlib/algs.h +map.o: ../../dlib/map.h tester.h ../../dlib/logger.h +map.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +map.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +map.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +map.o: /usr/include/pthread.h /usr/include/features.h +map.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +map.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +map.o: /usr/include/sched.h /usr/include/bits/types.h +map.o: /usr/include/bits/typesizes.h /usr/include/time.h +map.o: /usr/include/bits/sched.h /usr/include/signal.h +map.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +map.o: /usr/include/bits/setjmp.h /usr/include/errno.h +map.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +map.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +map.o: /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h +map.o: /usr/include/sys/time.h /usr/include/bits/time.h +map.o: /usr/include/sys/select.h /usr/include/bits/select.h ../algs.h +map.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +map.o: ../threads/threads_kernel_shared.h ../threads/auto_mutex_extension.h +map.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +map.o: ../threads/rmutex_extension_abstract.h +map.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +map.o: ../binary_search_tree/binary_search_tree_kernel_1.h +map.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +map.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +map.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +map.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +map.o: ../binary_search_tree/binary_search_tree_kernel_2.h +map.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +map.o: ../../dlib/memory_manager.h ../member_function_pointer.h +map.o: ../member_function_pointer/member_function_pointer_kernel_1.h +map.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +map.o: ../member_function_pointer/member_function_pointer_kernel_c.h +map.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +map.o: ../memory_manager/memory_manager_kernel_abstract.h +map.o: ../memory_manager/memory_manager_kernel_2.h +map.o: ../memory_manager/memory_manager_kernel_3.h +map.o: ../memory_manager/memory_manager_kernel_2.h +map.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +map.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +map.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +map.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +map.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +map.o: ../set/set_kernel_c.h binary_search_tree.h +map.o: ../../dlib/memory_manager_global.h +map.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +map.o: ../memory_manager/memory_manager_kernel_abstract.h +map.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +map.o: ../../dlib/memory_manager_stateless.h +map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +map.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +map.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +map.o: ../threads/auto_unlock_extension.h +map.o: ../threads/auto_unlock_extension_abstract.h +map.o: ../threads/create_new_thread_extension.h +map.o: ../threads/create_new_thread_extension_abstract.h +map.o: ../threads/multithreaded_object_extension.h +map.o: ../threads/multithreaded_object_extension_abstract.h +map.o: ../threads/rsignaler_extension.h +map.o: ../threads/rsignaler_extension_abstract.h ../map.h +map.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +map.o: ../threads/threaded_object_extension.h +map.o: ../threads/threaded_object_extension_abstract.h +map.o: ../threads/thread_specific_data_extension.h +map.o: ../threads/thread_specific_data_extension_abstract.h +map.o: ../threads/thread_function_extension.h +map.o: ../threads/thread_function_extension_abstract.h +map.o: ../threads/threaded_object_extension.h ../misc_api.h +map.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +map.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +map.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +map.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +map.o: ../smart_pointers/scoped_ptr_abstract.h ../smart_pointers/shared_ptr.h +map.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +map.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +map.o: ../../dlib/logger/extra_logger_headers.h +map.o: ../../dlib/logger/logger_kernel_1.h +map.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +map.o: ../config_reader/config_reader_kernel_1.h +map.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +map.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +map.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +map.o: ../tokenizer/tokenizer_kernel_1.h +map.o: ../tokenizer/tokenizer_kernel_abstract.h +map.o: ../tokenizer/tokenizer_kernel_c.h +map.o: ../config_reader/config_reader_thread_safe_1.h +map.o: ../config_reader/config_reader_thread_safe_abstract.h +map.o: ../../dlib/assert.h ../../dlib/algs.h +matrix.o: ../../dlib/matrix.h ../matrix/matrix.h ../matrix/matrix_abstract.h +matrix.o: ../algs.h ../platform.h ../assert.h ../error.h ../noncopyable.h +matrix.o: ../serialize.h ../algs.h ../uintn.h ../interfaces/enumerable.h +matrix.o: ../interfaces/map_pair.h ../enable_if.h ../enable_if.h +matrix.o: ../matrix/matrix_utilities.h ../matrix/matrix_utilities_abstract.h +matrix.o: ../matrix/matrix.h ../pixel.h ../serialize.h +matrix.o: ../matrix/matrix_math_functions.h ../matrix/matrix_utilities.h +matrix.o: tester.h ../../dlib/map.h ../../dlib/logger.h +matrix.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +matrix.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +matrix.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +matrix.o: /usr/include/pthread.h /usr/include/features.h +matrix.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +matrix.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +matrix.o: /usr/include/sched.h /usr/include/bits/types.h +matrix.o: /usr/include/bits/typesizes.h /usr/include/time.h +matrix.o: /usr/include/bits/sched.h /usr/include/signal.h +matrix.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +matrix.o: /usr/include/bits/setjmp.h /usr/include/errno.h +matrix.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +matrix.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +matrix.o: /usr/include/asm-generic/errno.h +matrix.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +matrix.o: /usr/include/bits/time.h /usr/include/sys/select.h +matrix.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +matrix.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +matrix.o: ../threads/rmutex_extension.h +matrix.o: ../threads/rmutex_extension_abstract.h +matrix.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +matrix.o: ../binary_search_tree/binary_search_tree_kernel_1.h +matrix.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +matrix.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +matrix.o: ../interfaces/remover.h +matrix.o: ../binary_search_tree/binary_search_tree_kernel_2.h +matrix.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +matrix.o: ../../dlib/memory_manager.h ../member_function_pointer.h +matrix.o: ../member_function_pointer/member_function_pointer_kernel_1.h +matrix.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +matrix.o: ../member_function_pointer/member_function_pointer_kernel_c.h +matrix.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +matrix.o: ../memory_manager/memory_manager_kernel_abstract.h +matrix.o: ../memory_manager/memory_manager_kernel_2.h +matrix.o: ../memory_manager/memory_manager_kernel_3.h +matrix.o: ../memory_manager/memory_manager_kernel_2.h +matrix.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +matrix.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +matrix.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +matrix.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +matrix.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +matrix.o: ../set/set_kernel_c.h binary_search_tree.h +matrix.o: ../../dlib/memory_manager_global.h +matrix.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +matrix.o: ../memory_manager/memory_manager_kernel_abstract.h +matrix.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +matrix.o: ../../dlib/memory_manager_stateless.h +matrix.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +matrix.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +matrix.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +matrix.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +matrix.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +matrix.o: ../threads/auto_unlock_extension.h +matrix.o: ../threads/auto_unlock_extension_abstract.h +matrix.o: ../threads/create_new_thread_extension.h +matrix.o: ../threads/create_new_thread_extension_abstract.h +matrix.o: ../threads/multithreaded_object_extension.h +matrix.o: ../threads/multithreaded_object_extension_abstract.h +matrix.o: ../threads/rsignaler_extension.h +matrix.o: ../threads/rsignaler_extension_abstract.h ../map.h +matrix.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +matrix.o: ../threads/threaded_object_extension.h +matrix.o: ../threads/threaded_object_extension_abstract.h +matrix.o: ../threads/thread_specific_data_extension.h +matrix.o: ../threads/thread_specific_data_extension_abstract.h +matrix.o: ../threads/thread_function_extension.h +matrix.o: ../threads/thread_function_extension_abstract.h +matrix.o: ../threads/threaded_object_extension.h ../misc_api.h +matrix.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +matrix.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +matrix.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +matrix.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +matrix.o: ../smart_pointers/scoped_ptr_abstract.h +matrix.o: ../smart_pointers/shared_ptr.h +matrix.o: ../smart_pointers/shared_ptr_abstract.h +matrix.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +matrix.o: ../smart_pointers/weak_ptr_abstract.h +matrix.o: ../../dlib/logger/extra_logger_headers.h +matrix.o: ../../dlib/logger/logger_kernel_1.h +matrix.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +matrix.o: ../config_reader/config_reader_kernel_1.h +matrix.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +matrix.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +matrix.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +matrix.o: ../tokenizer/tokenizer_kernel_1.h +matrix.o: ../tokenizer/tokenizer_kernel_abstract.h +matrix.o: ../tokenizer/tokenizer_kernel_c.h +matrix.o: ../config_reader/config_reader_thread_safe_1.h +matrix.o: ../config_reader/config_reader_thread_safe_abstract.h +matrix.o: ../../dlib/assert.h ../../dlib/algs.h +md5.o: ../../dlib/md5.h ../../dlib/md5/md5_kernel_1.h +md5.o: ../md5/md5_kernel_abstract.h ../algs.h ../platform.h ../assert.h +md5.o: ../error.h ../noncopyable.h tester.h ../../dlib/map.h +md5.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../threads.h +md5.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +md5.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +md5.o: /usr/include/pthread.h /usr/include/features.h +md5.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +md5.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +md5.o: /usr/include/sched.h /usr/include/bits/types.h +md5.o: /usr/include/bits/typesizes.h /usr/include/time.h +md5.o: /usr/include/bits/sched.h /usr/include/signal.h +md5.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +md5.o: /usr/include/bits/setjmp.h /usr/include/errno.h +md5.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +md5.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +md5.o: /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h +md5.o: /usr/include/sys/time.h /usr/include/bits/time.h +md5.o: /usr/include/sys/select.h /usr/include/bits/select.h +md5.o: ../threads/threads_kernel_shared.h ../threads/auto_mutex_extension.h +md5.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +md5.o: ../threads/rmutex_extension_abstract.h +md5.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +md5.o: ../binary_search_tree/binary_search_tree_kernel_1.h +md5.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +md5.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +md5.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +md5.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +md5.o: ../binary_search_tree/binary_search_tree_kernel_2.h +md5.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +md5.o: ../../dlib/memory_manager.h ../member_function_pointer.h +md5.o: ../member_function_pointer/member_function_pointer_kernel_1.h +md5.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +md5.o: ../member_function_pointer/member_function_pointer_kernel_c.h +md5.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +md5.o: ../memory_manager/memory_manager_kernel_abstract.h +md5.o: ../memory_manager/memory_manager_kernel_2.h +md5.o: ../memory_manager/memory_manager_kernel_3.h +md5.o: ../memory_manager/memory_manager_kernel_2.h +md5.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +md5.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +md5.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +md5.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +md5.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +md5.o: ../set/set_kernel_c.h binary_search_tree.h +md5.o: ../../dlib/memory_manager_global.h +md5.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +md5.o: ../memory_manager/memory_manager_kernel_abstract.h +md5.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +md5.o: ../../dlib/memory_manager_stateless.h +md5.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +md5.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +md5.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +md5.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +md5.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +md5.o: ../threads/auto_unlock_extension.h +md5.o: ../threads/auto_unlock_extension_abstract.h +md5.o: ../threads/create_new_thread_extension.h +md5.o: ../threads/create_new_thread_extension_abstract.h +md5.o: ../threads/multithreaded_object_extension.h +md5.o: ../threads/multithreaded_object_extension_abstract.h +md5.o: ../threads/rsignaler_extension.h +md5.o: ../threads/rsignaler_extension_abstract.h ../map.h +md5.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +md5.o: ../threads/threaded_object_extension.h +md5.o: ../threads/threaded_object_extension_abstract.h +md5.o: ../threads/thread_specific_data_extension.h +md5.o: ../threads/thread_specific_data_extension_abstract.h +md5.o: ../threads/thread_function_extension.h +md5.o: ../threads/thread_function_extension_abstract.h +md5.o: ../threads/threaded_object_extension.h ../misc_api.h +md5.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +md5.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +md5.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +md5.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +md5.o: ../smart_pointers/scoped_ptr_abstract.h ../smart_pointers/shared_ptr.h +md5.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +md5.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +md5.o: ../../dlib/logger/extra_logger_headers.h +md5.o: ../../dlib/logger/logger_kernel_1.h +md5.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +md5.o: ../config_reader/config_reader_kernel_1.h +md5.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +md5.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +md5.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +md5.o: ../tokenizer/tokenizer_kernel_1.h +md5.o: ../tokenizer/tokenizer_kernel_abstract.h +md5.o: ../tokenizer/tokenizer_kernel_c.h +md5.o: ../config_reader/config_reader_thread_safe_1.h +md5.o: ../config_reader/config_reader_thread_safe_abstract.h +md5.o: ../../dlib/assert.h ../../dlib/algs.h +member_function_pointer.o: ../../dlib/member_function_pointer.h +member_function_pointer.o: ../member_function_pointer/member_function_pointer_kernel_1.h +member_function_pointer.o: ../algs.h ../platform.h ../assert.h ../error.h +member_function_pointer.o: ../noncopyable.h +member_function_pointer.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +member_function_pointer.o: ../member_function_pointer/member_function_pointer_kernel_c.h +member_function_pointer.o: ../assert.h tester.h ../../dlib/map.h +member_function_pointer.o: ../../dlib/logger.h +member_function_pointer.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +member_function_pointer.o: ../threads/threads_kernel.h ../platform.h +member_function_pointer.o: ../threads/posix.h ../threads/threads_kernel_2.h +member_function_pointer.o: ../threads/threads_kernel_abstract.h +member_function_pointer.o: /usr/include/pthread.h /usr/include/features.h +member_function_pointer.o: /usr/include/sys/cdefs.h +member_function_pointer.o: /usr/include/bits/wordsize.h +member_function_pointer.o: /usr/include/gnu/stubs.h +member_function_pointer.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +member_function_pointer.o: /usr/include/bits/types.h +member_function_pointer.o: /usr/include/bits/typesizes.h /usr/include/time.h +member_function_pointer.o: /usr/include/bits/sched.h /usr/include/signal.h +member_function_pointer.o: /usr/include/bits/sigset.h +member_function_pointer.o: /usr/include/bits/pthreadtypes.h +member_function_pointer.o: /usr/include/bits/setjmp.h /usr/include/errno.h +member_function_pointer.o: /usr/include/bits/errno.h +member_function_pointer.o: /usr/include/linux/errno.h +member_function_pointer.o: /usr/include/asm/errno.h +member_function_pointer.o: /usr/include/asm-i386/errno.h +member_function_pointer.o: /usr/include/asm-generic/errno.h +member_function_pointer.o: /usr/include/asm-generic/errno-base.h +member_function_pointer.o: /usr/include/sys/time.h /usr/include/bits/time.h +member_function_pointer.o: /usr/include/sys/select.h +member_function_pointer.o: /usr/include/bits/select.h +member_function_pointer.o: ../threads/threads_kernel_shared.h +member_function_pointer.o: ../threads/auto_mutex_extension.h +member_function_pointer.o: ../threads/threads_kernel.h +member_function_pointer.o: ../threads/rmutex_extension.h +member_function_pointer.o: ../threads/rmutex_extension_abstract.h +member_function_pointer.o: ../threads/auto_mutex_extension_abstract.h +member_function_pointer.o: ../binary_search_tree.h +member_function_pointer.o: ../binary_search_tree/binary_search_tree_kernel_1.h +member_function_pointer.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +member_function_pointer.o: ../interfaces/map_pair.h +member_function_pointer.o: ../interfaces/enumerable.h ../interfaces/remover.h +member_function_pointer.o: ../serialize.h ../algs.h ../uintn.h +member_function_pointer.o: ../interfaces/enumerable.h +member_function_pointer.o: ../interfaces/map_pair.h ../enable_if.h +member_function_pointer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +member_function_pointer.o: ../binary_search_tree/binary_search_tree_kernel_c.h +member_function_pointer.o: ../../dlib/memory_manager.h +member_function_pointer.o: ../member_function_pointer.h ../memory_manager.h +member_function_pointer.o: ../memory_manager/memory_manager_kernel_1.h +member_function_pointer.o: ../memory_manager/memory_manager_kernel_abstract.h +member_function_pointer.o: ../memory_manager/memory_manager_kernel_2.h +member_function_pointer.o: ../memory_manager/memory_manager_kernel_3.h +member_function_pointer.o: ../memory_manager/memory_manager_kernel_2.h +member_function_pointer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +member_function_pointer.o: ../queue.h ../queue/queue_kernel_1.h +member_function_pointer.o: ../queue/queue_kernel_abstract.h +member_function_pointer.o: ../queue/queue_kernel_2.h +member_function_pointer.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +member_function_pointer.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +member_function_pointer.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +member_function_pointer.o: ../set/set_kernel_c.h binary_search_tree.h +member_function_pointer.o: ../../dlib/memory_manager_global.h +member_function_pointer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +member_function_pointer.o: ../memory_manager/memory_manager_kernel_abstract.h +member_function_pointer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +member_function_pointer.o: ../../dlib/memory_manager_stateless.h +member_function_pointer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +member_function_pointer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +member_function_pointer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +member_function_pointer.o: ../../dlib/binary_search_tree.h +member_function_pointer.o: ../set/set_compare_1.h +member_function_pointer.o: ../set/set_compare_abstract.h +member_function_pointer.o: ../threads/auto_mutex_extension.h +member_function_pointer.o: ../threads/auto_unlock_extension.h +member_function_pointer.o: ../threads/auto_unlock_extension_abstract.h +member_function_pointer.o: ../threads/create_new_thread_extension.h +member_function_pointer.o: ../threads/create_new_thread_extension_abstract.h +member_function_pointer.o: ../threads/multithreaded_object_extension.h +member_function_pointer.o: ../threads/multithreaded_object_extension_abstract.h +member_function_pointer.o: ../threads/rsignaler_extension.h +member_function_pointer.o: ../threads/rsignaler_extension_abstract.h ../map.h +member_function_pointer.o: ../threads/rmutex_extension.h +member_function_pointer.o: ../threads/rsignaler_extension.h +member_function_pointer.o: ../threads/threaded_object_extension.h +member_function_pointer.o: ../threads/threaded_object_extension_abstract.h +member_function_pointer.o: ../threads/thread_specific_data_extension.h +member_function_pointer.o: ../threads/thread_specific_data_extension_abstract.h +member_function_pointer.o: ../threads/thread_function_extension.h +member_function_pointer.o: ../threads/thread_function_extension_abstract.h +member_function_pointer.o: ../threads/threaded_object_extension.h +member_function_pointer.o: ../misc_api.h ../misc_api/posix.h +member_function_pointer.o: ../misc_api/misc_api_kernel_2.h +member_function_pointer.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +member_function_pointer.o: ../../dlib/logger/logger_kernel_abstract.h +member_function_pointer.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +member_function_pointer.o: ../noncopyable.h +member_function_pointer.o: ../smart_pointers/scoped_ptr_abstract.h +member_function_pointer.o: ../smart_pointers/shared_ptr.h +member_function_pointer.o: ../smart_pointers/shared_ptr_abstract.h +member_function_pointer.o: ../smart_pointers/weak_ptr.h +member_function_pointer.o: ../smart_pointers/shared_ptr.h +member_function_pointer.o: ../smart_pointers/weak_ptr_abstract.h +member_function_pointer.o: ../../dlib/logger/extra_logger_headers.h +member_function_pointer.o: ../../dlib/logger/logger_kernel_1.h +member_function_pointer.o: ../../dlib/logger/logger_config_file.h +member_function_pointer.o: ../config_reader.h +member_function_pointer.o: ../config_reader/config_reader_kernel_1.h +member_function_pointer.o: ../config_reader/config_reader_kernel_abstract.h +member_function_pointer.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +member_function_pointer.o: ../../dlib/map/map_kernel_abstract.h +member_function_pointer.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +member_function_pointer.o: ../tokenizer/tokenizer_kernel_1.h +member_function_pointer.o: ../tokenizer/tokenizer_kernel_abstract.h +member_function_pointer.o: ../tokenizer/tokenizer_kernel_c.h +member_function_pointer.o: ../config_reader/config_reader_thread_safe_1.h +member_function_pointer.o: ../config_reader/config_reader_thread_safe_abstract.h +member_function_pointer.o: ../../dlib/assert.h ../../dlib/algs.h +metaprogramming.o: ../../dlib/algs.h tester.h ../../dlib/map.h +metaprogramming.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +metaprogramming.o: ../threads.h ../threads/threads_kernel.h ../platform.h +metaprogramming.o: ../threads/posix.h ../threads/threads_kernel_2.h +metaprogramming.o: ../threads/threads_kernel_abstract.h +metaprogramming.o: /usr/include/pthread.h /usr/include/features.h +metaprogramming.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +metaprogramming.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +metaprogramming.o: /usr/include/sched.h /usr/include/bits/types.h +metaprogramming.o: /usr/include/bits/typesizes.h /usr/include/time.h +metaprogramming.o: /usr/include/bits/sched.h /usr/include/signal.h +metaprogramming.o: /usr/include/bits/sigset.h +metaprogramming.o: /usr/include/bits/pthreadtypes.h +metaprogramming.o: /usr/include/bits/setjmp.h /usr/include/errno.h +metaprogramming.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +metaprogramming.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +metaprogramming.o: /usr/include/asm-generic/errno.h +metaprogramming.o: /usr/include/asm-generic/errno-base.h +metaprogramming.o: /usr/include/sys/time.h /usr/include/bits/time.h +metaprogramming.o: /usr/include/sys/select.h /usr/include/bits/select.h +metaprogramming.o: ../algs.h ../platform.h ../assert.h ../error.h +metaprogramming.o: ../noncopyable.h ../threads/threads_kernel_shared.h +metaprogramming.o: ../threads/auto_mutex_extension.h +metaprogramming.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +metaprogramming.o: ../threads/rmutex_extension_abstract.h +metaprogramming.o: ../threads/auto_mutex_extension_abstract.h +metaprogramming.o: ../binary_search_tree.h +metaprogramming.o: ../binary_search_tree/binary_search_tree_kernel_1.h +metaprogramming.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +metaprogramming.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +metaprogramming.o: ../interfaces/remover.h ../serialize.h ../algs.h +metaprogramming.o: ../uintn.h ../interfaces/enumerable.h +metaprogramming.o: ../interfaces/map_pair.h ../enable_if.h +metaprogramming.o: ../binary_search_tree/binary_search_tree_kernel_2.h +metaprogramming.o: ../binary_search_tree/binary_search_tree_kernel_c.h +metaprogramming.o: ../assert.h ../../dlib/memory_manager.h +metaprogramming.o: ../member_function_pointer.h +metaprogramming.o: ../member_function_pointer/member_function_pointer_kernel_1.h +metaprogramming.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +metaprogramming.o: ../member_function_pointer/member_function_pointer_kernel_c.h +metaprogramming.o: ../memory_manager.h +metaprogramming.o: ../memory_manager/memory_manager_kernel_1.h +metaprogramming.o: ../memory_manager/memory_manager_kernel_abstract.h +metaprogramming.o: ../memory_manager/memory_manager_kernel_2.h +metaprogramming.o: ../memory_manager/memory_manager_kernel_3.h +metaprogramming.o: ../memory_manager/memory_manager_kernel_2.h +metaprogramming.o: ../binary_search_tree/binary_search_tree_kernel_2.h +metaprogramming.o: ../queue.h ../queue/queue_kernel_1.h +metaprogramming.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +metaprogramming.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +metaprogramming.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +metaprogramming.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +metaprogramming.o: ../set/set_kernel_c.h binary_search_tree.h +metaprogramming.o: ../../dlib/memory_manager_global.h +metaprogramming.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +metaprogramming.o: ../memory_manager/memory_manager_kernel_abstract.h +metaprogramming.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +metaprogramming.o: ../../dlib/memory_manager_stateless.h +metaprogramming.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +metaprogramming.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +metaprogramming.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +metaprogramming.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +metaprogramming.o: ../set/set_compare_abstract.h +metaprogramming.o: ../threads/auto_mutex_extension.h +metaprogramming.o: ../threads/auto_unlock_extension.h +metaprogramming.o: ../threads/auto_unlock_extension_abstract.h +metaprogramming.o: ../threads/create_new_thread_extension.h +metaprogramming.o: ../threads/create_new_thread_extension_abstract.h +metaprogramming.o: ../threads/multithreaded_object_extension.h +metaprogramming.o: ../threads/multithreaded_object_extension_abstract.h +metaprogramming.o: ../threads/rsignaler_extension.h +metaprogramming.o: ../threads/rsignaler_extension_abstract.h ../map.h +metaprogramming.o: ../threads/rmutex_extension.h +metaprogramming.o: ../threads/rsignaler_extension.h +metaprogramming.o: ../threads/threaded_object_extension.h +metaprogramming.o: ../threads/threaded_object_extension_abstract.h +metaprogramming.o: ../threads/thread_specific_data_extension.h +metaprogramming.o: ../threads/thread_specific_data_extension_abstract.h +metaprogramming.o: ../threads/thread_function_extension.h +metaprogramming.o: ../threads/thread_function_extension_abstract.h +metaprogramming.o: ../threads/threaded_object_extension.h ../misc_api.h +metaprogramming.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +metaprogramming.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +metaprogramming.o: ../../dlib/logger/logger_kernel_abstract.h +metaprogramming.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +metaprogramming.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +metaprogramming.o: ../smart_pointers/shared_ptr.h +metaprogramming.o: ../smart_pointers/shared_ptr_abstract.h +metaprogramming.o: ../smart_pointers/weak_ptr.h +metaprogramming.o: ../smart_pointers/shared_ptr.h +metaprogramming.o: ../smart_pointers/weak_ptr_abstract.h +metaprogramming.o: ../../dlib/logger/extra_logger_headers.h +metaprogramming.o: ../../dlib/logger/logger_kernel_1.h +metaprogramming.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +metaprogramming.o: ../config_reader/config_reader_kernel_1.h +metaprogramming.o: ../config_reader/config_reader_kernel_abstract.h +metaprogramming.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +metaprogramming.o: ../../dlib/map/map_kernel_abstract.h +metaprogramming.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +metaprogramming.o: ../tokenizer/tokenizer_kernel_1.h +metaprogramming.o: ../tokenizer/tokenizer_kernel_abstract.h +metaprogramming.o: ../tokenizer/tokenizer_kernel_c.h +metaprogramming.o: ../config_reader/config_reader_thread_safe_1.h +metaprogramming.o: ../config_reader/config_reader_thread_safe_abstract.h +metaprogramming.o: ../../dlib/assert.h +multithreaded_object.o: ../../dlib/threads.h tester.h ../../dlib/map.h +multithreaded_object.o: ../../dlib/logger.h +multithreaded_object.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +multithreaded_object.o: ../threads/threads_kernel.h ../platform.h +multithreaded_object.o: ../threads/posix.h ../threads/threads_kernel_2.h +multithreaded_object.o: ../threads/threads_kernel_abstract.h +multithreaded_object.o: /usr/include/pthread.h /usr/include/features.h +multithreaded_object.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +multithreaded_object.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +multithreaded_object.o: /usr/include/sched.h /usr/include/bits/types.h +multithreaded_object.o: /usr/include/bits/typesizes.h /usr/include/time.h +multithreaded_object.o: /usr/include/bits/sched.h /usr/include/signal.h +multithreaded_object.o: /usr/include/bits/sigset.h +multithreaded_object.o: /usr/include/bits/pthreadtypes.h +multithreaded_object.o: /usr/include/bits/setjmp.h /usr/include/errno.h +multithreaded_object.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +multithreaded_object.o: /usr/include/asm/errno.h +multithreaded_object.o: /usr/include/asm-i386/errno.h +multithreaded_object.o: /usr/include/asm-generic/errno.h +multithreaded_object.o: /usr/include/asm-generic/errno-base.h +multithreaded_object.o: /usr/include/sys/time.h /usr/include/bits/time.h +multithreaded_object.o: /usr/include/sys/select.h /usr/include/bits/select.h +multithreaded_object.o: ../algs.h ../platform.h ../assert.h ../error.h +multithreaded_object.o: ../noncopyable.h ../threads/threads_kernel_shared.h +multithreaded_object.o: ../threads/auto_mutex_extension.h +multithreaded_object.o: ../threads/threads_kernel.h +multithreaded_object.o: ../threads/rmutex_extension.h +multithreaded_object.o: ../threads/rmutex_extension_abstract.h +multithreaded_object.o: ../threads/auto_mutex_extension_abstract.h +multithreaded_object.o: ../binary_search_tree.h +multithreaded_object.o: ../binary_search_tree/binary_search_tree_kernel_1.h +multithreaded_object.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +multithreaded_object.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +multithreaded_object.o: ../interfaces/remover.h ../serialize.h ../algs.h +multithreaded_object.o: ../uintn.h ../interfaces/enumerable.h +multithreaded_object.o: ../interfaces/map_pair.h ../enable_if.h +multithreaded_object.o: ../binary_search_tree/binary_search_tree_kernel_2.h +multithreaded_object.o: ../binary_search_tree/binary_search_tree_kernel_c.h +multithreaded_object.o: ../assert.h ../../dlib/memory_manager.h +multithreaded_object.o: ../member_function_pointer.h +multithreaded_object.o: ../member_function_pointer/member_function_pointer_kernel_1.h +multithreaded_object.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +multithreaded_object.o: ../member_function_pointer/member_function_pointer_kernel_c.h +multithreaded_object.o: ../memory_manager.h +multithreaded_object.o: ../memory_manager/memory_manager_kernel_1.h +multithreaded_object.o: ../memory_manager/memory_manager_kernel_abstract.h +multithreaded_object.o: ../memory_manager/memory_manager_kernel_2.h +multithreaded_object.o: ../memory_manager/memory_manager_kernel_3.h +multithreaded_object.o: ../memory_manager/memory_manager_kernel_2.h +multithreaded_object.o: ../binary_search_tree/binary_search_tree_kernel_2.h +multithreaded_object.o: ../queue.h ../queue/queue_kernel_1.h +multithreaded_object.o: ../queue/queue_kernel_abstract.h +multithreaded_object.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +multithreaded_object.o: ../queue/queue_sort_1.h +multithreaded_object.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +multithreaded_object.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +multithreaded_object.o: ../set/set_kernel_c.h binary_search_tree.h +multithreaded_object.o: ../../dlib/memory_manager_global.h +multithreaded_object.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +multithreaded_object.o: ../memory_manager/memory_manager_kernel_abstract.h +multithreaded_object.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +multithreaded_object.o: ../../dlib/memory_manager_stateless.h +multithreaded_object.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +multithreaded_object.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +multithreaded_object.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +multithreaded_object.o: ../../dlib/binary_search_tree.h +multithreaded_object.o: ../set/set_compare_1.h ../set/set_compare_abstract.h +multithreaded_object.o: ../threads/auto_mutex_extension.h +multithreaded_object.o: ../threads/auto_unlock_extension.h +multithreaded_object.o: ../threads/auto_unlock_extension_abstract.h +multithreaded_object.o: ../threads/create_new_thread_extension.h +multithreaded_object.o: ../threads/create_new_thread_extension_abstract.h +multithreaded_object.o: ../threads/multithreaded_object_extension.h +multithreaded_object.o: ../threads/multithreaded_object_extension_abstract.h +multithreaded_object.o: ../threads/rsignaler_extension.h +multithreaded_object.o: ../threads/rsignaler_extension_abstract.h ../map.h +multithreaded_object.o: ../threads/rmutex_extension.h +multithreaded_object.o: ../threads/rsignaler_extension.h +multithreaded_object.o: ../threads/threaded_object_extension.h +multithreaded_object.o: ../threads/threaded_object_extension_abstract.h +multithreaded_object.o: ../threads/thread_specific_data_extension.h +multithreaded_object.o: ../threads/thread_specific_data_extension_abstract.h +multithreaded_object.o: ../threads/thread_function_extension.h +multithreaded_object.o: ../threads/thread_function_extension_abstract.h +multithreaded_object.o: ../threads/threaded_object_extension.h ../misc_api.h +multithreaded_object.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +multithreaded_object.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +multithreaded_object.o: ../../dlib/logger/logger_kernel_abstract.h +multithreaded_object.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +multithreaded_object.o: ../noncopyable.h +multithreaded_object.o: ../smart_pointers/scoped_ptr_abstract.h +multithreaded_object.o: ../smart_pointers/shared_ptr.h +multithreaded_object.o: ../smart_pointers/shared_ptr_abstract.h +multithreaded_object.o: ../smart_pointers/weak_ptr.h +multithreaded_object.o: ../smart_pointers/shared_ptr.h +multithreaded_object.o: ../smart_pointers/weak_ptr_abstract.h +multithreaded_object.o: ../../dlib/logger/extra_logger_headers.h +multithreaded_object.o: ../../dlib/logger/logger_kernel_1.h +multithreaded_object.o: ../../dlib/logger/logger_config_file.h +multithreaded_object.o: ../config_reader.h +multithreaded_object.o: ../config_reader/config_reader_kernel_1.h +multithreaded_object.o: ../config_reader/config_reader_kernel_abstract.h +multithreaded_object.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +multithreaded_object.o: ../../dlib/map/map_kernel_abstract.h +multithreaded_object.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +multithreaded_object.o: ../tokenizer/tokenizer_kernel_1.h +multithreaded_object.o: ../tokenizer/tokenizer_kernel_abstract.h +multithreaded_object.o: ../tokenizer/tokenizer_kernel_c.h +multithreaded_object.o: ../config_reader/config_reader_thread_safe_1.h +multithreaded_object.o: ../config_reader/config_reader_thread_safe_abstract.h +multithreaded_object.o: ../../dlib/assert.h ../../dlib/algs.h +pipe.o: ../../dlib/misc_api.h ../platform.h ../misc_api/posix.h +pipe.o: ../misc_api/misc_api_kernel_2.h +pipe.o: ../misc_api/misc_api_kernel_abstract.h ../algs.h ../assert.h +pipe.o: ../error.h ../noncopyable.h ../uintn.h ../../dlib/pipe.h +pipe.o: ../../dlib/pipe/pipe_kernel_1.h ../threads.h +pipe.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +pipe.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +pipe.o: /usr/include/pthread.h /usr/include/features.h +pipe.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +pipe.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +pipe.o: /usr/include/sched.h /usr/include/bits/types.h +pipe.o: /usr/include/bits/typesizes.h /usr/include/time.h +pipe.o: /usr/include/bits/sched.h /usr/include/signal.h +pipe.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +pipe.o: /usr/include/bits/setjmp.h /usr/include/errno.h +pipe.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +pipe.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +pipe.o: /usr/include/asm-generic/errno.h +pipe.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +pipe.o: /usr/include/bits/time.h /usr/include/sys/select.h +pipe.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +pipe.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +pipe.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +pipe.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +pipe.o: ../binary_search_tree/binary_search_tree_kernel_1.h +pipe.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +pipe.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +pipe.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +pipe.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +pipe.o: ../binary_search_tree/binary_search_tree_kernel_2.h +pipe.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +pipe.o: ../../dlib/memory_manager.h ../member_function_pointer.h +pipe.o: ../member_function_pointer/member_function_pointer_kernel_1.h +pipe.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +pipe.o: ../member_function_pointer/member_function_pointer_kernel_c.h +pipe.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +pipe.o: ../memory_manager/memory_manager_kernel_abstract.h +pipe.o: ../memory_manager/memory_manager_kernel_2.h +pipe.o: ../memory_manager/memory_manager_kernel_3.h +pipe.o: ../memory_manager/memory_manager_kernel_2.h +pipe.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +pipe.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +pipe.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +pipe.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +pipe.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +pipe.o: ../set/set_kernel_c.h binary_search_tree.h +pipe.o: ../../dlib/memory_manager_global.h +pipe.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +pipe.o: ../memory_manager/memory_manager_kernel_abstract.h +pipe.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +pipe.o: ../../dlib/memory_manager_stateless.h +pipe.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +pipe.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +pipe.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +pipe.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +pipe.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../misc_api.h +pipe.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +pipe.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h ../noncopyable.h +pipe.o: ../smart_pointers/scoped_ptr_abstract.h +pipe.o: ../smart_pointers/shared_ptr.h +pipe.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +pipe.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +pipe.o: ../../dlib/logger/extra_logger_headers.h +pipe.o: ../../dlib/logger/logger_kernel_1.h +pipe.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +pipe.o: ../config_reader/config_reader_kernel_1.h +pipe.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +pipe.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +pipe.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +pipe.o: ../tokenizer/tokenizer_kernel_1.h +pipe.o: ../tokenizer/tokenizer_kernel_abstract.h +pipe.o: ../tokenizer/tokenizer_kernel_c.h +pipe.o: ../config_reader/config_reader_thread_safe_1.h +pipe.o: ../config_reader/config_reader_thread_safe_abstract.h +pipe.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +pipe.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +pipe.o: ../threads/auto_unlock_extension.h +pipe.o: ../threads/auto_unlock_extension_abstract.h +pipe.o: ../threads/create_new_thread_extension.h +pipe.o: ../threads/create_new_thread_extension_abstract.h +pipe.o: ../threads/multithreaded_object_extension.h +pipe.o: ../threads/multithreaded_object_extension_abstract.h +pipe.o: ../threads/rsignaler_extension.h +pipe.o: ../threads/rsignaler_extension_abstract.h +pipe.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +pipe.o: ../threads/threaded_object_extension.h +pipe.o: ../threads/threaded_object_extension_abstract.h +pipe.o: ../threads/thread_specific_data_extension.h +pipe.o: ../threads/thread_specific_data_extension_abstract.h +pipe.o: ../threads/thread_function_extension.h +pipe.o: ../threads/thread_function_extension_abstract.h +pipe.o: ../threads/threaded_object_extension.h +pipe.o: ../../dlib/pipe/pipe_kernel_abstract.h +pixel.o: ../../dlib/pixel.h ../serialize.h ../algs.h ../uintn.h +pixel.o: ../enable_if.h ../../dlib/matrix.h ../matrix/matrix.h +pixel.o: ../matrix/matrix_abstract.h ../algs.h ../platform.h ../assert.h +pixel.o: ../error.h ../noncopyable.h ../serialize.h +pixel.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +pixel.o: ../matrix/matrix_utilities.h ../matrix/matrix_utilities_abstract.h +pixel.o: ../matrix/matrix.h ../pixel.h ../matrix/matrix_math_functions.h +pixel.o: ../matrix/matrix_utilities.h tester.h ../../dlib/map.h +pixel.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../threads.h +pixel.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +pixel.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +pixel.o: /usr/include/pthread.h /usr/include/features.h +pixel.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +pixel.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +pixel.o: /usr/include/sched.h /usr/include/bits/types.h +pixel.o: /usr/include/bits/typesizes.h /usr/include/time.h +pixel.o: /usr/include/bits/sched.h /usr/include/signal.h +pixel.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +pixel.o: /usr/include/bits/setjmp.h /usr/include/errno.h +pixel.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +pixel.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +pixel.o: /usr/include/asm-generic/errno.h +pixel.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +pixel.o: /usr/include/bits/time.h /usr/include/sys/select.h +pixel.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +pixel.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +pixel.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +pixel.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +pixel.o: ../binary_search_tree/binary_search_tree_kernel_1.h +pixel.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +pixel.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +pixel.o: ../interfaces/remover.h +pixel.o: ../binary_search_tree/binary_search_tree_kernel_2.h +pixel.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +pixel.o: ../../dlib/memory_manager.h ../member_function_pointer.h +pixel.o: ../member_function_pointer/member_function_pointer_kernel_1.h +pixel.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +pixel.o: ../member_function_pointer/member_function_pointer_kernel_c.h +pixel.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +pixel.o: ../memory_manager/memory_manager_kernel_abstract.h +pixel.o: ../memory_manager/memory_manager_kernel_2.h +pixel.o: ../memory_manager/memory_manager_kernel_3.h +pixel.o: ../memory_manager/memory_manager_kernel_2.h +pixel.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +pixel.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +pixel.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +pixel.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +pixel.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +pixel.o: ../set/set_kernel_c.h binary_search_tree.h +pixel.o: ../../dlib/memory_manager_global.h +pixel.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +pixel.o: ../memory_manager/memory_manager_kernel_abstract.h +pixel.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +pixel.o: ../../dlib/memory_manager_stateless.h +pixel.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +pixel.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +pixel.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +pixel.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +pixel.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +pixel.o: ../threads/auto_unlock_extension.h +pixel.o: ../threads/auto_unlock_extension_abstract.h +pixel.o: ../threads/create_new_thread_extension.h +pixel.o: ../threads/create_new_thread_extension_abstract.h +pixel.o: ../threads/multithreaded_object_extension.h +pixel.o: ../threads/multithreaded_object_extension_abstract.h +pixel.o: ../threads/rsignaler_extension.h +pixel.o: ../threads/rsignaler_extension_abstract.h ../map.h +pixel.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +pixel.o: ../threads/threaded_object_extension.h +pixel.o: ../threads/threaded_object_extension_abstract.h +pixel.o: ../threads/thread_specific_data_extension.h +pixel.o: ../threads/thread_specific_data_extension_abstract.h +pixel.o: ../threads/thread_function_extension.h +pixel.o: ../threads/thread_function_extension_abstract.h +pixel.o: ../threads/threaded_object_extension.h ../misc_api.h +pixel.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +pixel.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +pixel.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +pixel.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +pixel.o: ../smart_pointers/scoped_ptr_abstract.h +pixel.o: ../smart_pointers/shared_ptr.h +pixel.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +pixel.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +pixel.o: ../../dlib/logger/extra_logger_headers.h +pixel.o: ../../dlib/logger/logger_kernel_1.h +pixel.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +pixel.o: ../config_reader/config_reader_kernel_1.h +pixel.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +pixel.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +pixel.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +pixel.o: ../tokenizer/tokenizer_kernel_1.h +pixel.o: ../tokenizer/tokenizer_kernel_abstract.h +pixel.o: ../tokenizer/tokenizer_kernel_c.h +pixel.o: ../config_reader/config_reader_thread_safe_1.h +pixel.o: ../config_reader/config_reader_thread_safe_abstract.h +pixel.o: ../../dlib/assert.h ../../dlib/algs.h +queue.o: ../../dlib/queue.h ../queue/queue_kernel_1.h +queue.o: ../queue/queue_kernel_abstract.h ../algs.h ../platform.h ../assert.h +queue.o: ../error.h ../noncopyable.h ../interfaces/enumerable.h +queue.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +queue.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +queue.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +queue.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +queue.o: ../memory_manager/memory_manager_kernel_2.h +queue.o: ../memory_manager/memory_manager_kernel_3.h +queue.o: ../memory_manager/memory_manager_kernel_2.h +queue.o: ../binary_search_tree/binary_search_tree_kernel_2.h +queue.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +queue.o: ../interfaces/map_pair.h ../queue/queue_kernel_2.h +queue.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +queue.o: ../queue/queue_sort_abstract.h ../sort.h ../../dlib/memory_manager.h +queue.o: ../../dlib/memory_manager_global.h +queue.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +queue.o: ../memory_manager/memory_manager_kernel_abstract.h +queue.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +queue.o: tester.h ../../dlib/map.h ../../dlib/logger.h +queue.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +queue.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +queue.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +queue.o: /usr/include/pthread.h /usr/include/features.h +queue.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +queue.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +queue.o: /usr/include/sched.h /usr/include/bits/types.h +queue.o: /usr/include/bits/typesizes.h /usr/include/time.h +queue.o: /usr/include/bits/sched.h /usr/include/signal.h +queue.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +queue.o: /usr/include/bits/setjmp.h /usr/include/errno.h +queue.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +queue.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +queue.o: /usr/include/asm-generic/errno.h +queue.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +queue.o: /usr/include/bits/time.h /usr/include/sys/select.h +queue.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +queue.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +queue.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +queue.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +queue.o: ../binary_search_tree/binary_search_tree_kernel_1.h +queue.o: ../binary_search_tree/binary_search_tree_kernel_2.h +queue.o: ../binary_search_tree/binary_search_tree_kernel_c.h +queue.o: ../member_function_pointer.h +queue.o: ../member_function_pointer/member_function_pointer_kernel_1.h +queue.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +queue.o: ../member_function_pointer/member_function_pointer_kernel_c.h +queue.o: ../queue.h ../set.h ../set/set_kernel_1.h +queue.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +queue.o: binary_search_tree.h ../../dlib/memory_manager_stateless.h +queue.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +queue.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +queue.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +queue.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +queue.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +queue.o: ../threads/auto_unlock_extension.h +queue.o: ../threads/auto_unlock_extension_abstract.h +queue.o: ../threads/create_new_thread_extension.h +queue.o: ../threads/create_new_thread_extension_abstract.h +queue.o: ../threads/multithreaded_object_extension.h +queue.o: ../threads/multithreaded_object_extension_abstract.h +queue.o: ../threads/rsignaler_extension.h +queue.o: ../threads/rsignaler_extension_abstract.h ../map.h +queue.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +queue.o: ../threads/threaded_object_extension.h +queue.o: ../threads/threaded_object_extension_abstract.h +queue.o: ../threads/thread_specific_data_extension.h +queue.o: ../threads/thread_specific_data_extension_abstract.h +queue.o: ../threads/thread_function_extension.h +queue.o: ../threads/thread_function_extension_abstract.h +queue.o: ../threads/threaded_object_extension.h ../misc_api.h +queue.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +queue.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +queue.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +queue.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +queue.o: ../smart_pointers/scoped_ptr_abstract.h +queue.o: ../smart_pointers/shared_ptr.h +queue.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +queue.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +queue.o: ../../dlib/logger/extra_logger_headers.h +queue.o: ../../dlib/logger/logger_kernel_1.h +queue.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +queue.o: ../config_reader/config_reader_kernel_1.h +queue.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +queue.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +queue.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +queue.o: ../tokenizer/tokenizer_kernel_1.h +queue.o: ../tokenizer/tokenizer_kernel_abstract.h +queue.o: ../tokenizer/tokenizer_kernel_c.h +queue.o: ../config_reader/config_reader_thread_safe_1.h +queue.o: ../config_reader/config_reader_thread_safe_abstract.h +queue.o: ../../dlib/assert.h ../../dlib/algs.h +rand.o: ../../dlib/rand.h ../rand/rand_kernel_1.h ../algs.h ../platform.h +rand.o: ../assert.h ../error.h ../noncopyable.h +rand.o: ../rand/rand_kernel_abstract.h ../rand/mersenne_twister.h ../uintn.h +rand.o: ../rand/rand_float_1.h ../rand/rand_float_abstract.h ../algs.h +rand.o: ../../dlib/compress_stream.h +rand.o: ../../dlib/compress_stream/compress_stream_kernel_1.h +rand.o: ../../dlib/compress_stream/compress_stream_kernel_abstract.h +rand.o: ../../dlib/compress_stream/compress_stream_kernel_2.h +rand.o: ../../dlib/compress_stream/compress_stream_kernel_3.h ../assert.h +rand.o: conditioning_class.h ../../dlib/conditioning_class.h +rand.o: ../../dlib/conditioning_class/conditioning_class_kernel_1.h +rand.o: ../../dlib/conditioning_class/conditioning_class_kernel_abstract.h +rand.o: ../../dlib/conditioning_class/conditioning_class_kernel_2.h +rand.o: ../../dlib/conditioning_class/conditioning_class_kernel_3.h +rand.o: ../../dlib/conditioning_class/conditioning_class_kernel_4.h +rand.o: ../../dlib/conditioning_class/conditioning_class_kernel_c.h +rand.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +rand.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../threads.h +rand.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +rand.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +rand.o: /usr/include/pthread.h /usr/include/features.h +rand.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +rand.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +rand.o: /usr/include/sched.h /usr/include/bits/types.h +rand.o: /usr/include/bits/typesizes.h /usr/include/time.h +rand.o: /usr/include/bits/sched.h /usr/include/signal.h +rand.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +rand.o: /usr/include/bits/setjmp.h /usr/include/errno.h +rand.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +rand.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +rand.o: /usr/include/asm-generic/errno.h +rand.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +rand.o: /usr/include/bits/time.h /usr/include/sys/select.h +rand.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +rand.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +rand.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +rand.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +rand.o: ../binary_search_tree/binary_search_tree_kernel_1.h +rand.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +rand.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +rand.o: ../interfaces/remover.h ../serialize.h ../uintn.h +rand.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +rand.o: ../binary_search_tree/binary_search_tree_kernel_2.h +rand.o: ../binary_search_tree/binary_search_tree_kernel_c.h +rand.o: ../member_function_pointer.h +rand.o: ../member_function_pointer/member_function_pointer_kernel_1.h +rand.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +rand.o: ../member_function_pointer/member_function_pointer_kernel_c.h +rand.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +rand.o: ../memory_manager/memory_manager_kernel_abstract.h +rand.o: ../memory_manager/memory_manager_kernel_2.h +rand.o: ../memory_manager/memory_manager_kernel_3.h +rand.o: ../memory_manager/memory_manager_kernel_2.h +rand.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +rand.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +rand.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +rand.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +rand.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +rand.o: ../set/set_kernel_c.h binary_search_tree.h +rand.o: ../../dlib/memory_manager_global.h +rand.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +rand.o: ../memory_manager/memory_manager_kernel_abstract.h +rand.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +rand.o: ../../dlib/memory_manager_stateless.h +rand.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +rand.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +rand.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +rand.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +rand.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +rand.o: ../threads/auto_unlock_extension.h +rand.o: ../threads/auto_unlock_extension_abstract.h +rand.o: ../threads/create_new_thread_extension.h +rand.o: ../threads/create_new_thread_extension_abstract.h +rand.o: ../threads/multithreaded_object_extension.h +rand.o: ../threads/multithreaded_object_extension_abstract.h +rand.o: ../threads/rsignaler_extension.h +rand.o: ../threads/rsignaler_extension_abstract.h ../map.h +rand.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +rand.o: ../threads/threaded_object_extension.h +rand.o: ../threads/threaded_object_extension_abstract.h +rand.o: ../threads/thread_specific_data_extension.h +rand.o: ../threads/thread_specific_data_extension_abstract.h +rand.o: ../threads/thread_function_extension.h +rand.o: ../threads/thread_function_extension_abstract.h +rand.o: ../threads/threaded_object_extension.h ../misc_api.h +rand.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +rand.o: ../misc_api/misc_api_kernel_abstract.h +rand.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +rand.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +rand.o: ../smart_pointers/scoped_ptr_abstract.h +rand.o: ../smart_pointers/shared_ptr.h +rand.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +rand.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +rand.o: ../../dlib/logger/extra_logger_headers.h +rand.o: ../../dlib/logger/logger_kernel_1.h +rand.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +rand.o: ../config_reader/config_reader_kernel_1.h +rand.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +rand.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +rand.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +rand.o: ../tokenizer/tokenizer_kernel_1.h +rand.o: ../tokenizer/tokenizer_kernel_abstract.h +rand.o: ../tokenizer/tokenizer_kernel_c.h +rand.o: ../config_reader/config_reader_thread_safe_1.h +rand.o: ../config_reader/config_reader_thread_safe_abstract.h +rand.o: ../../dlib/assert.h ../../dlib/algs.h ../../dlib/entropy_encoder.h +rand.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_1.h +rand.o: ../entropy_encoder/entropy_encoder_kernel_abstract.h +rand.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_2.h +rand.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_c.h +rand.o: ../../dlib/entropy_decoder.h +rand.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_1.h +rand.o: ../entropy_decoder/entropy_decoder_kernel_abstract.h +rand.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_2.h +rand.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_c.h +rand.o: ../../dlib/entropy_encoder_model.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h +rand.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h +rand.o: ../../dlib/sliding_buffer.h +rand.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_1.h +rand.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_abstract.h +rand.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_c.h +rand.o: ../../dlib/entropy_decoder_model.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h +rand.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h +rand.o: ../../dlib/lz77_buffer.h +rand.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_1.h +rand.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_abstract.h +rand.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_2.h +rand.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_c.h ../../dlib/lzp_buffer.h +rand.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_1.h +rand.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_abstract.h +rand.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_2.h +rand.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_c.h ../../dlib/crc32.h +rand.o: ../../dlib/crc32/crc32_kernel_1.h +rand.o: ../../dlib/crc32/crc32_kernel_abstract.h +reference_counter.o: ../../dlib/reference_counter.h +reference_counter.o: ../../dlib/reference_counter/reference_counter_kernel_1.h +reference_counter.o: ../../dlib/reference_counter/reference_counter_kernel_abstract.h +reference_counter.o: ../algs.h ../platform.h ../assert.h ../error.h +reference_counter.o: ../noncopyable.h ../algs.h tester.h ../../dlib/map.h +reference_counter.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +reference_counter.o: ../threads.h ../threads/threads_kernel.h ../platform.h +reference_counter.o: ../threads/posix.h ../threads/threads_kernel_2.h +reference_counter.o: ../threads/threads_kernel_abstract.h +reference_counter.o: /usr/include/pthread.h /usr/include/features.h +reference_counter.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +reference_counter.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +reference_counter.o: /usr/include/sched.h /usr/include/bits/types.h +reference_counter.o: /usr/include/bits/typesizes.h /usr/include/time.h +reference_counter.o: /usr/include/bits/sched.h /usr/include/signal.h +reference_counter.o: /usr/include/bits/sigset.h +reference_counter.o: /usr/include/bits/pthreadtypes.h +reference_counter.o: /usr/include/bits/setjmp.h /usr/include/errno.h +reference_counter.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +reference_counter.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +reference_counter.o: /usr/include/asm-generic/errno.h +reference_counter.o: /usr/include/asm-generic/errno-base.h +reference_counter.o: /usr/include/sys/time.h /usr/include/bits/time.h +reference_counter.o: /usr/include/sys/select.h /usr/include/bits/select.h +reference_counter.o: ../threads/threads_kernel_shared.h +reference_counter.o: ../threads/auto_mutex_extension.h +reference_counter.o: ../threads/threads_kernel.h +reference_counter.o: ../threads/rmutex_extension.h +reference_counter.o: ../threads/rmutex_extension_abstract.h +reference_counter.o: ../threads/auto_mutex_extension_abstract.h +reference_counter.o: ../binary_search_tree.h +reference_counter.o: ../binary_search_tree/binary_search_tree_kernel_1.h +reference_counter.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +reference_counter.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +reference_counter.o: ../interfaces/remover.h ../serialize.h ../uintn.h +reference_counter.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +reference_counter.o: ../enable_if.h +reference_counter.o: ../binary_search_tree/binary_search_tree_kernel_2.h +reference_counter.o: ../binary_search_tree/binary_search_tree_kernel_c.h +reference_counter.o: ../assert.h ../../dlib/memory_manager.h +reference_counter.o: ../member_function_pointer.h +reference_counter.o: ../member_function_pointer/member_function_pointer_kernel_1.h +reference_counter.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +reference_counter.o: ../member_function_pointer/member_function_pointer_kernel_c.h +reference_counter.o: ../memory_manager.h +reference_counter.o: ../memory_manager/memory_manager_kernel_1.h +reference_counter.o: ../memory_manager/memory_manager_kernel_abstract.h +reference_counter.o: ../memory_manager/memory_manager_kernel_2.h +reference_counter.o: ../memory_manager/memory_manager_kernel_3.h +reference_counter.o: ../memory_manager/memory_manager_kernel_2.h +reference_counter.o: ../binary_search_tree/binary_search_tree_kernel_2.h +reference_counter.o: ../queue.h ../queue/queue_kernel_1.h +reference_counter.o: ../queue/queue_kernel_abstract.h +reference_counter.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +reference_counter.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h +reference_counter.o: ../sort.h ../set.h ../set/set_kernel_1.h +reference_counter.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +reference_counter.o: binary_search_tree.h ../../dlib/memory_manager_global.h +reference_counter.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +reference_counter.o: ../memory_manager/memory_manager_kernel_abstract.h +reference_counter.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +reference_counter.o: ../../dlib/memory_manager_stateless.h +reference_counter.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +reference_counter.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +reference_counter.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +reference_counter.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +reference_counter.o: ../set/set_compare_abstract.h +reference_counter.o: ../threads/auto_mutex_extension.h +reference_counter.o: ../threads/auto_unlock_extension.h +reference_counter.o: ../threads/auto_unlock_extension_abstract.h +reference_counter.o: ../threads/create_new_thread_extension.h +reference_counter.o: ../threads/create_new_thread_extension_abstract.h +reference_counter.o: ../threads/multithreaded_object_extension.h +reference_counter.o: ../threads/multithreaded_object_extension_abstract.h +reference_counter.o: ../threads/rsignaler_extension.h +reference_counter.o: ../threads/rsignaler_extension_abstract.h ../map.h +reference_counter.o: ../threads/rmutex_extension.h +reference_counter.o: ../threads/rsignaler_extension.h +reference_counter.o: ../threads/threaded_object_extension.h +reference_counter.o: ../threads/threaded_object_extension_abstract.h +reference_counter.o: ../threads/thread_specific_data_extension.h +reference_counter.o: ../threads/thread_specific_data_extension_abstract.h +reference_counter.o: ../threads/thread_function_extension.h +reference_counter.o: ../threads/thread_function_extension_abstract.h +reference_counter.o: ../threads/threaded_object_extension.h ../misc_api.h +reference_counter.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +reference_counter.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +reference_counter.o: ../../dlib/logger/logger_kernel_abstract.h +reference_counter.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +reference_counter.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +reference_counter.o: ../smart_pointers/shared_ptr.h +reference_counter.o: ../smart_pointers/shared_ptr_abstract.h +reference_counter.o: ../smart_pointers/weak_ptr.h +reference_counter.o: ../smart_pointers/shared_ptr.h +reference_counter.o: ../smart_pointers/weak_ptr_abstract.h +reference_counter.o: ../../dlib/logger/extra_logger_headers.h +reference_counter.o: ../../dlib/logger/logger_kernel_1.h +reference_counter.o: ../../dlib/logger/logger_config_file.h +reference_counter.o: ../config_reader.h +reference_counter.o: ../config_reader/config_reader_kernel_1.h +reference_counter.o: ../config_reader/config_reader_kernel_abstract.h +reference_counter.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +reference_counter.o: ../../dlib/map/map_kernel_abstract.h +reference_counter.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +reference_counter.o: ../tokenizer/tokenizer_kernel_1.h +reference_counter.o: ../tokenizer/tokenizer_kernel_abstract.h +reference_counter.o: ../tokenizer/tokenizer_kernel_c.h +reference_counter.o: ../config_reader/config_reader_thread_safe_1.h +reference_counter.o: ../config_reader/config_reader_thread_safe_abstract.h +reference_counter.o: ../../dlib/assert.h ../../dlib/algs.h +sequence.o: ../../dlib/sequence.h ../../dlib/sequence/sequence_kernel_1.h +sequence.o: ../../dlib/sequence/sequence_kernel_abstract.h ../algs.h +sequence.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +sequence.o: ../interfaces/enumerable.h ../interfaces/remover.h ../serialize.h +sequence.o: ../algs.h ../uintn.h ../interfaces/enumerable.h +sequence.o: ../interfaces/map_pair.h ../enable_if.h ../memory_manager.h +sequence.o: ../memory_manager/memory_manager_kernel_1.h +sequence.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +sequence.o: ../memory_manager/memory_manager_kernel_2.h +sequence.o: ../memory_manager/memory_manager_kernel_3.h +sequence.o: ../memory_manager/memory_manager_kernel_2.h +sequence.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sequence.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +sequence.o: ../interfaces/map_pair.h ../../dlib/sequence/sequence_kernel_2.h +sequence.o: ../../dlib/sequence/sequence_kernel_c.h +sequence.o: ../../dlib/sequence/sequence_compare_1.h +sequence.o: ../../dlib/sequence/sequence_compare_abstract.h +sequence.o: ../../dlib/sequence/sequence_sort_1.h +sequence.o: ../../dlib/sequence/sequence_sort_abstract.h +sequence.o: ../../dlib/sequence/sequence_sort_2.h ../sort.h +sequence.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +sequence.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +sequence.o: ../threads.h ../threads/threads_kernel.h ../platform.h +sequence.o: ../threads/posix.h ../threads/threads_kernel_2.h +sequence.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +sequence.o: /usr/include/features.h /usr/include/sys/cdefs.h +sequence.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +sequence.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +sequence.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +sequence.o: /usr/include/time.h /usr/include/bits/sched.h +sequence.o: /usr/include/signal.h /usr/include/bits/sigset.h +sequence.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +sequence.o: /usr/include/errno.h /usr/include/bits/errno.h +sequence.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +sequence.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +sequence.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +sequence.o: /usr/include/bits/time.h /usr/include/sys/select.h +sequence.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +sequence.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +sequence.o: ../threads/rmutex_extension.h +sequence.o: ../threads/rmutex_extension_abstract.h +sequence.o: ../threads/auto_mutex_extension_abstract.h +sequence.o: ../binary_search_tree.h +sequence.o: ../binary_search_tree/binary_search_tree_kernel_1.h +sequence.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sequence.o: ../binary_search_tree/binary_search_tree_kernel_c.h +sequence.o: ../member_function_pointer.h +sequence.o: ../member_function_pointer/member_function_pointer_kernel_1.h +sequence.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +sequence.o: ../member_function_pointer/member_function_pointer_kernel_c.h +sequence.o: ../queue.h ../queue/queue_kernel_1.h +sequence.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +sequence.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +sequence.o: ../queue/queue_sort_abstract.h ../set.h ../set/set_kernel_1.h +sequence.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +sequence.o: binary_search_tree.h ../../dlib/memory_manager_global.h +sequence.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +sequence.o: ../memory_manager/memory_manager_kernel_abstract.h +sequence.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +sequence.o: ../../dlib/memory_manager_stateless.h +sequence.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +sequence.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +sequence.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +sequence.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +sequence.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +sequence.o: ../threads/auto_unlock_extension.h +sequence.o: ../threads/auto_unlock_extension_abstract.h +sequence.o: ../threads/create_new_thread_extension.h +sequence.o: ../threads/create_new_thread_extension_abstract.h +sequence.o: ../threads/multithreaded_object_extension.h +sequence.o: ../threads/multithreaded_object_extension_abstract.h +sequence.o: ../threads/rsignaler_extension.h +sequence.o: ../threads/rsignaler_extension_abstract.h ../map.h +sequence.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +sequence.o: ../threads/threaded_object_extension.h +sequence.o: ../threads/threaded_object_extension_abstract.h +sequence.o: ../threads/thread_specific_data_extension.h +sequence.o: ../threads/thread_specific_data_extension_abstract.h +sequence.o: ../threads/thread_function_extension.h +sequence.o: ../threads/thread_function_extension_abstract.h +sequence.o: ../threads/threaded_object_extension.h ../misc_api.h +sequence.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +sequence.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +sequence.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +sequence.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +sequence.o: ../smart_pointers/scoped_ptr_abstract.h +sequence.o: ../smart_pointers/shared_ptr.h +sequence.o: ../smart_pointers/shared_ptr_abstract.h +sequence.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +sequence.o: ../smart_pointers/weak_ptr_abstract.h +sequence.o: ../../dlib/logger/extra_logger_headers.h +sequence.o: ../../dlib/logger/logger_kernel_1.h +sequence.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +sequence.o: ../config_reader/config_reader_kernel_1.h +sequence.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +sequence.o: ../../dlib/map/map_kernel_1.h +sequence.o: ../../dlib/map/map_kernel_abstract.h +sequence.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +sequence.o: ../tokenizer/tokenizer_kernel_1.h +sequence.o: ../tokenizer/tokenizer_kernel_abstract.h +sequence.o: ../tokenizer/tokenizer_kernel_c.h +sequence.o: ../config_reader/config_reader_thread_safe_1.h +sequence.o: ../config_reader/config_reader_thread_safe_abstract.h +sequence.o: ../../dlib/assert.h ../../dlib/algs.h +serialize.o: ../../dlib/compress_stream.h +serialize.o: ../../dlib/compress_stream/compress_stream_kernel_1.h ../algs.h +serialize.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +serialize.o: ../../dlib/compress_stream/compress_stream_kernel_abstract.h +serialize.o: ../../dlib/compress_stream/compress_stream_kernel_2.h +serialize.o: ../../dlib/compress_stream/compress_stream_kernel_3.h +serialize.o: ../assert.h conditioning_class.h ../../dlib/conditioning_class.h +serialize.o: ../../dlib/conditioning_class/conditioning_class_kernel_1.h +serialize.o: ../../dlib/conditioning_class/conditioning_class_kernel_abstract.h +serialize.o: ../../dlib/conditioning_class/conditioning_class_kernel_2.h +serialize.o: ../../dlib/conditioning_class/conditioning_class_kernel_3.h +serialize.o: ../../dlib/conditioning_class/conditioning_class_kernel_4.h +serialize.o: ../../dlib/conditioning_class/conditioning_class_kernel_c.h +serialize.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +serialize.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +serialize.o: ../threads.h ../threads/threads_kernel.h ../platform.h +serialize.o: ../threads/posix.h ../threads/threads_kernel_2.h +serialize.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +serialize.o: /usr/include/features.h /usr/include/sys/cdefs.h +serialize.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +serialize.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +serialize.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +serialize.o: /usr/include/time.h /usr/include/bits/sched.h +serialize.o: /usr/include/signal.h /usr/include/bits/sigset.h +serialize.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +serialize.o: /usr/include/errno.h /usr/include/bits/errno.h +serialize.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +serialize.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +serialize.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +serialize.o: /usr/include/bits/time.h /usr/include/sys/select.h +serialize.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +serialize.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +serialize.o: ../threads/rmutex_extension.h +serialize.o: ../threads/rmutex_extension_abstract.h +serialize.o: ../threads/auto_mutex_extension_abstract.h +serialize.o: ../binary_search_tree.h +serialize.o: ../binary_search_tree/binary_search_tree_kernel_1.h +serialize.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +serialize.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +serialize.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +serialize.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +serialize.o: ../enable_if.h +serialize.o: ../binary_search_tree/binary_search_tree_kernel_2.h +serialize.o: ../binary_search_tree/binary_search_tree_kernel_c.h +serialize.o: ../member_function_pointer.h +serialize.o: ../member_function_pointer/member_function_pointer_kernel_1.h +serialize.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +serialize.o: ../member_function_pointer/member_function_pointer_kernel_c.h +serialize.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +serialize.o: ../memory_manager/memory_manager_kernel_abstract.h +serialize.o: ../memory_manager/memory_manager_kernel_2.h +serialize.o: ../memory_manager/memory_manager_kernel_3.h +serialize.o: ../memory_manager/memory_manager_kernel_2.h +serialize.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +serialize.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +serialize.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +serialize.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +serialize.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +serialize.o: ../set/set_kernel_c.h binary_search_tree.h +serialize.o: ../../dlib/memory_manager_global.h +serialize.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +serialize.o: ../memory_manager/memory_manager_kernel_abstract.h +serialize.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +serialize.o: ../../dlib/memory_manager_stateless.h +serialize.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +serialize.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +serialize.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +serialize.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +serialize.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +serialize.o: ../threads/auto_unlock_extension.h +serialize.o: ../threads/auto_unlock_extension_abstract.h +serialize.o: ../threads/create_new_thread_extension.h +serialize.o: ../threads/create_new_thread_extension_abstract.h +serialize.o: ../threads/multithreaded_object_extension.h +serialize.o: ../threads/multithreaded_object_extension_abstract.h +serialize.o: ../threads/rsignaler_extension.h +serialize.o: ../threads/rsignaler_extension_abstract.h ../map.h +serialize.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +serialize.o: ../threads/threaded_object_extension.h +serialize.o: ../threads/threaded_object_extension_abstract.h +serialize.o: ../threads/thread_specific_data_extension.h +serialize.o: ../threads/thread_specific_data_extension_abstract.h +serialize.o: ../threads/thread_function_extension.h +serialize.o: ../threads/thread_function_extension_abstract.h +serialize.o: ../threads/threaded_object_extension.h ../misc_api.h +serialize.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +serialize.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +serialize.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +serialize.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +serialize.o: ../smart_pointers/scoped_ptr_abstract.h +serialize.o: ../smart_pointers/shared_ptr.h +serialize.o: ../smart_pointers/shared_ptr_abstract.h +serialize.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +serialize.o: ../smart_pointers/weak_ptr_abstract.h +serialize.o: ../../dlib/logger/extra_logger_headers.h +serialize.o: ../../dlib/logger/logger_kernel_1.h +serialize.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +serialize.o: ../config_reader/config_reader_kernel_1.h +serialize.o: ../config_reader/config_reader_kernel_abstract.h +serialize.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +serialize.o: ../../dlib/map/map_kernel_abstract.h +serialize.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +serialize.o: ../tokenizer/tokenizer_kernel_1.h +serialize.o: ../tokenizer/tokenizer_kernel_abstract.h +serialize.o: ../tokenizer/tokenizer_kernel_c.h +serialize.o: ../config_reader/config_reader_thread_safe_1.h +serialize.o: ../config_reader/config_reader_thread_safe_abstract.h +serialize.o: ../../dlib/assert.h ../../dlib/algs.h +serialize.o: ../../dlib/entropy_encoder.h +serialize.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_1.h +serialize.o: ../entropy_encoder/entropy_encoder_kernel_abstract.h +serialize.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_2.h +serialize.o: ../../dlib/entropy_encoder/entropy_encoder_kernel_c.h +serialize.o: ../../dlib/entropy_decoder.h +serialize.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_1.h +serialize.o: ../entropy_decoder/entropy_decoder_kernel_abstract.h +serialize.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_2.h +serialize.o: ../../dlib/entropy_decoder/entropy_decoder_kernel_c.h +serialize.o: ../../dlib/entropy_encoder_model.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h +serialize.o: ../../dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h +serialize.o: ../../dlib/sliding_buffer.h +serialize.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_1.h +serialize.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_abstract.h +serialize.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_c.h +serialize.o: ../../dlib/entropy_decoder_model.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h +serialize.o: ../../dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h +serialize.o: ../../dlib/lz77_buffer.h +serialize.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_1.h +serialize.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_abstract.h +serialize.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_2.h +serialize.o: ../../dlib/lz77_buffer/lz77_buffer_kernel_c.h +serialize.o: ../../dlib/lzp_buffer.h +serialize.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_1.h +serialize.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_abstract.h +serialize.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_2.h +serialize.o: ../../dlib/lzp_buffer/lzp_buffer_kernel_c.h ../../dlib/crc32.h +serialize.o: ../../dlib/crc32/crc32_kernel_1.h +serialize.o: ../../dlib/crc32/crc32_kernel_abstract.h ../../dlib/base64.h +serialize.o: ../../dlib/base64/base64_kernel_1.h ../../dlib/serialize.h +set.o: ../../dlib/set.h tester.h ../../dlib/map.h ../../dlib/logger.h +set.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +set.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +set.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +set.o: /usr/include/pthread.h /usr/include/features.h +set.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +set.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +set.o: /usr/include/sched.h /usr/include/bits/types.h +set.o: /usr/include/bits/typesizes.h /usr/include/time.h +set.o: /usr/include/bits/sched.h /usr/include/signal.h +set.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +set.o: /usr/include/bits/setjmp.h /usr/include/errno.h +set.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +set.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +set.o: /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h +set.o: /usr/include/sys/time.h /usr/include/bits/time.h +set.o: /usr/include/sys/select.h /usr/include/bits/select.h ../algs.h +set.o: ../platform.h ../assert.h ../error.h ../noncopyable.h +set.o: ../threads/threads_kernel_shared.h ../threads/auto_mutex_extension.h +set.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +set.o: ../threads/rmutex_extension_abstract.h +set.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +set.o: ../binary_search_tree/binary_search_tree_kernel_1.h +set.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +set.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +set.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +set.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +set.o: ../binary_search_tree/binary_search_tree_kernel_2.h +set.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +set.o: ../../dlib/memory_manager.h ../member_function_pointer.h +set.o: ../member_function_pointer/member_function_pointer_kernel_1.h +set.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +set.o: ../member_function_pointer/member_function_pointer_kernel_c.h +set.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +set.o: ../memory_manager/memory_manager_kernel_abstract.h +set.o: ../memory_manager/memory_manager_kernel_2.h +set.o: ../memory_manager/memory_manager_kernel_3.h +set.o: ../memory_manager/memory_manager_kernel_2.h +set.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +set.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +set.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +set.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +set.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +set.o: ../set/set_kernel_c.h binary_search_tree.h +set.o: ../../dlib/memory_manager_global.h +set.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +set.o: ../memory_manager/memory_manager_kernel_abstract.h +set.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +set.o: ../../dlib/memory_manager_stateless.h +set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +set.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +set.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +set.o: ../threads/auto_unlock_extension.h +set.o: ../threads/auto_unlock_extension_abstract.h +set.o: ../threads/create_new_thread_extension.h +set.o: ../threads/create_new_thread_extension_abstract.h +set.o: ../threads/multithreaded_object_extension.h +set.o: ../threads/multithreaded_object_extension_abstract.h +set.o: ../threads/rsignaler_extension.h +set.o: ../threads/rsignaler_extension_abstract.h ../map.h +set.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +set.o: ../threads/threaded_object_extension.h +set.o: ../threads/threaded_object_extension_abstract.h +set.o: ../threads/thread_specific_data_extension.h +set.o: ../threads/thread_specific_data_extension_abstract.h +set.o: ../threads/thread_function_extension.h +set.o: ../threads/thread_function_extension_abstract.h +set.o: ../threads/threaded_object_extension.h ../misc_api.h +set.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +set.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +set.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +set.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +set.o: ../smart_pointers/scoped_ptr_abstract.h ../smart_pointers/shared_ptr.h +set.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +set.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +set.o: ../../dlib/logger/extra_logger_headers.h +set.o: ../../dlib/logger/logger_kernel_1.h +set.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +set.o: ../config_reader/config_reader_kernel_1.h +set.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +set.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +set.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +set.o: ../tokenizer/tokenizer_kernel_1.h +set.o: ../tokenizer/tokenizer_kernel_abstract.h +set.o: ../tokenizer/tokenizer_kernel_c.h +set.o: ../config_reader/config_reader_thread_safe_1.h +set.o: ../config_reader/config_reader_thread_safe_abstract.h +set.o: ../../dlib/assert.h ../../dlib/algs.h +sliding_buffer.o: ../../dlib/sliding_buffer.h +sliding_buffer.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_1.h +sliding_buffer.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_abstract.h +sliding_buffer.o: ../algs.h ../platform.h ../assert.h ../error.h +sliding_buffer.o: ../noncopyable.h ../interfaces/enumerable.h ../serialize.h +sliding_buffer.o: ../algs.h ../uintn.h ../interfaces/enumerable.h +sliding_buffer.o: ../interfaces/map_pair.h ../enable_if.h +sliding_buffer.o: ../../dlib/sliding_buffer/sliding_buffer_kernel_c.h +sliding_buffer.o: ../assert.h tester.h ../../dlib/map.h ../../dlib/logger.h +sliding_buffer.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +sliding_buffer.o: ../threads/threads_kernel.h ../platform.h +sliding_buffer.o: ../threads/posix.h ../threads/threads_kernel_2.h +sliding_buffer.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +sliding_buffer.o: /usr/include/features.h /usr/include/sys/cdefs.h +sliding_buffer.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +sliding_buffer.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +sliding_buffer.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +sliding_buffer.o: /usr/include/time.h /usr/include/bits/sched.h +sliding_buffer.o: /usr/include/signal.h /usr/include/bits/sigset.h +sliding_buffer.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +sliding_buffer.o: /usr/include/errno.h /usr/include/bits/errno.h +sliding_buffer.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +sliding_buffer.o: /usr/include/asm-i386/errno.h +sliding_buffer.o: /usr/include/asm-generic/errno.h +sliding_buffer.o: /usr/include/asm-generic/errno-base.h +sliding_buffer.o: /usr/include/sys/time.h /usr/include/bits/time.h +sliding_buffer.o: /usr/include/sys/select.h /usr/include/bits/select.h +sliding_buffer.o: ../threads/threads_kernel_shared.h +sliding_buffer.o: ../threads/auto_mutex_extension.h +sliding_buffer.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +sliding_buffer.o: ../threads/rmutex_extension_abstract.h +sliding_buffer.o: ../threads/auto_mutex_extension_abstract.h +sliding_buffer.o: ../binary_search_tree.h +sliding_buffer.o: ../binary_search_tree/binary_search_tree_kernel_1.h +sliding_buffer.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +sliding_buffer.o: ../interfaces/map_pair.h ../interfaces/remover.h +sliding_buffer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sliding_buffer.o: ../binary_search_tree/binary_search_tree_kernel_c.h +sliding_buffer.o: ../../dlib/memory_manager.h ../member_function_pointer.h +sliding_buffer.o: ../member_function_pointer/member_function_pointer_kernel_1.h +sliding_buffer.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +sliding_buffer.o: ../member_function_pointer/member_function_pointer_kernel_c.h +sliding_buffer.o: ../memory_manager.h +sliding_buffer.o: ../memory_manager/memory_manager_kernel_1.h +sliding_buffer.o: ../memory_manager/memory_manager_kernel_abstract.h +sliding_buffer.o: ../memory_manager/memory_manager_kernel_2.h +sliding_buffer.o: ../memory_manager/memory_manager_kernel_3.h +sliding_buffer.o: ../memory_manager/memory_manager_kernel_2.h +sliding_buffer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sliding_buffer.o: ../queue.h ../queue/queue_kernel_1.h +sliding_buffer.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +sliding_buffer.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +sliding_buffer.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +sliding_buffer.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +sliding_buffer.o: ../set/set_kernel_c.h binary_search_tree.h +sliding_buffer.o: ../../dlib/memory_manager_global.h +sliding_buffer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +sliding_buffer.o: ../memory_manager/memory_manager_kernel_abstract.h +sliding_buffer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +sliding_buffer.o: ../../dlib/memory_manager_stateless.h +sliding_buffer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +sliding_buffer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +sliding_buffer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +sliding_buffer.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +sliding_buffer.o: ../set/set_compare_abstract.h +sliding_buffer.o: ../threads/auto_mutex_extension.h +sliding_buffer.o: ../threads/auto_unlock_extension.h +sliding_buffer.o: ../threads/auto_unlock_extension_abstract.h +sliding_buffer.o: ../threads/create_new_thread_extension.h +sliding_buffer.o: ../threads/create_new_thread_extension_abstract.h +sliding_buffer.o: ../threads/multithreaded_object_extension.h +sliding_buffer.o: ../threads/multithreaded_object_extension_abstract.h +sliding_buffer.o: ../threads/rsignaler_extension.h +sliding_buffer.o: ../threads/rsignaler_extension_abstract.h ../map.h +sliding_buffer.o: ../threads/rmutex_extension.h +sliding_buffer.o: ../threads/rsignaler_extension.h +sliding_buffer.o: ../threads/threaded_object_extension.h +sliding_buffer.o: ../threads/threaded_object_extension_abstract.h +sliding_buffer.o: ../threads/thread_specific_data_extension.h +sliding_buffer.o: ../threads/thread_specific_data_extension_abstract.h +sliding_buffer.o: ../threads/thread_function_extension.h +sliding_buffer.o: ../threads/thread_function_extension_abstract.h +sliding_buffer.o: ../threads/threaded_object_extension.h ../misc_api.h +sliding_buffer.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +sliding_buffer.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +sliding_buffer.o: ../../dlib/logger/logger_kernel_abstract.h +sliding_buffer.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +sliding_buffer.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +sliding_buffer.o: ../smart_pointers/shared_ptr.h +sliding_buffer.o: ../smart_pointers/shared_ptr_abstract.h +sliding_buffer.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +sliding_buffer.o: ../smart_pointers/weak_ptr_abstract.h +sliding_buffer.o: ../../dlib/logger/extra_logger_headers.h +sliding_buffer.o: ../../dlib/logger/logger_kernel_1.h +sliding_buffer.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +sliding_buffer.o: ../config_reader/config_reader_kernel_1.h +sliding_buffer.o: ../config_reader/config_reader_kernel_abstract.h +sliding_buffer.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +sliding_buffer.o: ../../dlib/map/map_kernel_abstract.h +sliding_buffer.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +sliding_buffer.o: ../tokenizer/tokenizer_kernel_1.h +sliding_buffer.o: ../tokenizer/tokenizer_kernel_abstract.h +sliding_buffer.o: ../tokenizer/tokenizer_kernel_c.h +sliding_buffer.o: ../config_reader/config_reader_thread_safe_1.h +sliding_buffer.o: ../config_reader/config_reader_thread_safe_abstract.h +sliding_buffer.o: ../../dlib/assert.h ../../dlib/algs.h +smart_pointers.o: ../../dlib/smart_pointers.h ../smart_pointers/scoped_ptr.h +smart_pointers.o: ../noncopyable.h ../algs.h ../platform.h ../assert.h +smart_pointers.o: ../error.h ../noncopyable.h +smart_pointers.o: ../smart_pointers/scoped_ptr_abstract.h +smart_pointers.o: ../smart_pointers/shared_ptr.h +smart_pointers.o: ../smart_pointers/shared_ptr_abstract.h +smart_pointers.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +smart_pointers.o: ../smart_pointers/weak_ptr_abstract.h tester.h +smart_pointers.o: ../../dlib/map.h ../../dlib/logger.h +smart_pointers.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +smart_pointers.o: ../threads/threads_kernel.h ../platform.h +smart_pointers.o: ../threads/posix.h ../threads/threads_kernel_2.h +smart_pointers.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +smart_pointers.o: /usr/include/features.h /usr/include/sys/cdefs.h +smart_pointers.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +smart_pointers.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +smart_pointers.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +smart_pointers.o: /usr/include/time.h /usr/include/bits/sched.h +smart_pointers.o: /usr/include/signal.h /usr/include/bits/sigset.h +smart_pointers.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +smart_pointers.o: /usr/include/errno.h /usr/include/bits/errno.h +smart_pointers.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +smart_pointers.o: /usr/include/asm-i386/errno.h +smart_pointers.o: /usr/include/asm-generic/errno.h +smart_pointers.o: /usr/include/asm-generic/errno-base.h +smart_pointers.o: /usr/include/sys/time.h /usr/include/bits/time.h +smart_pointers.o: /usr/include/sys/select.h /usr/include/bits/select.h +smart_pointers.o: ../threads/threads_kernel_shared.h +smart_pointers.o: ../threads/auto_mutex_extension.h +smart_pointers.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +smart_pointers.o: ../threads/rmutex_extension_abstract.h +smart_pointers.o: ../threads/auto_mutex_extension_abstract.h +smart_pointers.o: ../binary_search_tree.h +smart_pointers.o: ../binary_search_tree/binary_search_tree_kernel_1.h +smart_pointers.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +smart_pointers.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +smart_pointers.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +smart_pointers.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +smart_pointers.o: ../enable_if.h +smart_pointers.o: ../binary_search_tree/binary_search_tree_kernel_2.h +smart_pointers.o: ../binary_search_tree/binary_search_tree_kernel_c.h +smart_pointers.o: ../assert.h ../../dlib/memory_manager.h +smart_pointers.o: ../member_function_pointer.h +smart_pointers.o: ../member_function_pointer/member_function_pointer_kernel_1.h +smart_pointers.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +smart_pointers.o: ../member_function_pointer/member_function_pointer_kernel_c.h +smart_pointers.o: ../memory_manager.h +smart_pointers.o: ../memory_manager/memory_manager_kernel_1.h +smart_pointers.o: ../memory_manager/memory_manager_kernel_abstract.h +smart_pointers.o: ../memory_manager/memory_manager_kernel_2.h +smart_pointers.o: ../memory_manager/memory_manager_kernel_3.h +smart_pointers.o: ../memory_manager/memory_manager_kernel_2.h +smart_pointers.o: ../binary_search_tree/binary_search_tree_kernel_2.h +smart_pointers.o: ../queue.h ../queue/queue_kernel_1.h +smart_pointers.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +smart_pointers.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +smart_pointers.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +smart_pointers.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +smart_pointers.o: ../set/set_kernel_c.h binary_search_tree.h +smart_pointers.o: ../../dlib/memory_manager_global.h +smart_pointers.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +smart_pointers.o: ../memory_manager/memory_manager_kernel_abstract.h +smart_pointers.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +smart_pointers.o: ../../dlib/memory_manager_stateless.h +smart_pointers.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +smart_pointers.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +smart_pointers.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +smart_pointers.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +smart_pointers.o: ../set/set_compare_abstract.h +smart_pointers.o: ../threads/auto_mutex_extension.h +smart_pointers.o: ../threads/auto_unlock_extension.h +smart_pointers.o: ../threads/auto_unlock_extension_abstract.h +smart_pointers.o: ../threads/create_new_thread_extension.h +smart_pointers.o: ../threads/create_new_thread_extension_abstract.h +smart_pointers.o: ../threads/multithreaded_object_extension.h +smart_pointers.o: ../threads/multithreaded_object_extension_abstract.h +smart_pointers.o: ../threads/rsignaler_extension.h +smart_pointers.o: ../threads/rsignaler_extension_abstract.h ../map.h +smart_pointers.o: ../threads/rmutex_extension.h +smart_pointers.o: ../threads/rsignaler_extension.h +smart_pointers.o: ../threads/threaded_object_extension.h +smart_pointers.o: ../threads/threaded_object_extension_abstract.h +smart_pointers.o: ../threads/thread_specific_data_extension.h +smart_pointers.o: ../threads/thread_specific_data_extension_abstract.h +smart_pointers.o: ../threads/thread_function_extension.h +smart_pointers.o: ../threads/thread_function_extension_abstract.h +smart_pointers.o: ../threads/threaded_object_extension.h ../misc_api.h +smart_pointers.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +smart_pointers.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +smart_pointers.o: ../../dlib/logger/logger_kernel_abstract.h +smart_pointers.o: ../smart_pointers.h +smart_pointers.o: ../../dlib/logger/extra_logger_headers.h +smart_pointers.o: ../../dlib/logger/logger_kernel_1.h +smart_pointers.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +smart_pointers.o: ../config_reader/config_reader_kernel_1.h +smart_pointers.o: ../config_reader/config_reader_kernel_abstract.h +smart_pointers.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +smart_pointers.o: ../../dlib/map/map_kernel_abstract.h +smart_pointers.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +smart_pointers.o: ../tokenizer/tokenizer_kernel_1.h +smart_pointers.o: ../tokenizer/tokenizer_kernel_abstract.h +smart_pointers.o: ../tokenizer/tokenizer_kernel_c.h +smart_pointers.o: ../config_reader/config_reader_thread_safe_1.h +smart_pointers.o: ../config_reader/config_reader_thread_safe_abstract.h +smart_pointers.o: ../../dlib/assert.h ../../dlib/algs.h +sockets.o: ../../dlib/sockets.h ../platform.h ../sockets/posix.h +sockets.o: ../sockets/sockets_kernel_2.h ../platform.h +sockets.o: ../sockets/sockets_kernel_abstract.h /usr/include/sys/types.h +sockets.o: /usr/include/features.h /usr/include/sys/cdefs.h +sockets.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +sockets.o: /usr/include/gnu/stubs-32.h /usr/include/bits/types.h +sockets.o: /usr/include/bits/typesizes.h /usr/include/time.h +sockets.o: /usr/include/endian.h /usr/include/bits/endian.h +sockets.o: /usr/include/sys/select.h /usr/include/bits/select.h +sockets.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +sockets.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +sockets.o: /usr/include/sys/socket.h /usr/include/sys/uio.h +sockets.o: /usr/include/bits/uio.h /usr/include/bits/socket.h +sockets.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h +sockets.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h +sockets.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h +sockets.o: /usr/include/asm/socket.h /usr/include/asm-i386/socket.h +sockets.o: /usr/include/asm/sockios.h /usr/include/asm-i386/sockios.h +sockets.o: /usr/include/errno.h /usr/include/bits/errno.h +sockets.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +sockets.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +sockets.o: /usr/include/asm-generic/errno-base.h /usr/include/arpa/inet.h +sockets.o: /usr/include/netinet/in.h /usr/include/stdint.h +sockets.o: /usr/include/bits/wchar.h /usr/include/bits/in.h +sockets.o: /usr/include/bits/byteswap.h /usr/include/signal.h +sockets.o: /usr/include/inttypes.h /usr/include/netdb.h +sockets.o: /usr/include/rpc/netdb.h /usr/include/bits/netdb.h +sockets.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +sockets.o: /usr/include/bits/confname.h /usr/include/getopt.h +sockets.o: /usr/include/sys/param.h /usr/include/linux/param.h +sockets.o: /usr/include/asm/param.h /usr/include/asm-i386/param.h +sockets.o: ../threads.h ../threads/threads_kernel.h ../threads/posix.h +sockets.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +sockets.o: /usr/include/pthread.h /usr/include/sched.h +sockets.o: /usr/include/bits/sched.h /usr/include/bits/setjmp.h +sockets.o: /usr/include/sys/time.h ../algs.h ../assert.h ../error.h +sockets.o: ../noncopyable.h ../threads/threads_kernel_shared.h +sockets.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +sockets.o: ../threads/rmutex_extension.h +sockets.o: ../threads/rmutex_extension_abstract.h +sockets.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +sockets.o: ../binary_search_tree/binary_search_tree_kernel_1.h +sockets.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +sockets.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +sockets.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +sockets.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +sockets.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sockets.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +sockets.o: ../../dlib/memory_manager.h ../member_function_pointer.h +sockets.o: ../member_function_pointer/member_function_pointer_kernel_1.h +sockets.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +sockets.o: ../member_function_pointer/member_function_pointer_kernel_c.h +sockets.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +sockets.o: ../memory_manager/memory_manager_kernel_abstract.h +sockets.o: ../memory_manager/memory_manager_kernel_2.h +sockets.o: ../memory_manager/memory_manager_kernel_3.h +sockets.o: ../memory_manager/memory_manager_kernel_2.h +sockets.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +sockets.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +sockets.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +sockets.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +sockets.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +sockets.o: ../set/set_kernel_c.h binary_search_tree.h +sockets.o: ../../dlib/memory_manager_global.h +sockets.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +sockets.o: ../memory_manager/memory_manager_kernel_abstract.h +sockets.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +sockets.o: ../../dlib/memory_manager_stateless.h +sockets.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +sockets.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +sockets.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +sockets.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +sockets.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +sockets.o: ../misc_api.h ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +sockets.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +sockets.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +sockets.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +sockets.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +sockets.o: ../smart_pointers/shared_ptr.h +sockets.o: ../smart_pointers/shared_ptr_abstract.h +sockets.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +sockets.o: ../smart_pointers/weak_ptr_abstract.h +sockets.o: ../../dlib/logger/extra_logger_headers.h +sockets.o: ../../dlib/logger/logger_kernel_1.h +sockets.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +sockets.o: ../config_reader/config_reader_kernel_1.h +sockets.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +sockets.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +sockets.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +sockets.o: ../tokenizer/tokenizer_kernel_1.h +sockets.o: ../tokenizer/tokenizer_kernel_abstract.h +sockets.o: ../tokenizer/tokenizer_kernel_c.h +sockets.o: ../config_reader/config_reader_thread_safe_1.h +sockets.o: ../config_reader/config_reader_thread_safe_abstract.h +sockets.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +sockets.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +sockets.o: ../threads/auto_unlock_extension.h +sockets.o: ../threads/auto_unlock_extension_abstract.h +sockets.o: ../threads/create_new_thread_extension.h +sockets.o: ../threads/create_new_thread_extension_abstract.h +sockets.o: ../threads/multithreaded_object_extension.h +sockets.o: ../threads/multithreaded_object_extension_abstract.h +sockets.o: ../threads/rsignaler_extension.h +sockets.o: ../threads/rsignaler_extension_abstract.h +sockets.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +sockets.o: ../threads/threaded_object_extension.h +sockets.o: ../threads/threaded_object_extension_abstract.h +sockets.o: ../threads/thread_specific_data_extension.h +sockets.o: ../threads/thread_specific_data_extension_abstract.h +sockets.o: ../threads/thread_function_extension.h +sockets.o: ../threads/thread_function_extension_abstract.h +sockets.o: ../threads/threaded_object_extension.h +sockets.o: ../sockets/sockets_extensions.h ../sockets.h +sockets.o: ../sockets/sockets_extensions_abstract.h ../../dlib/server.h +sockets.o: ../../dlib/server/server_kernel_1.h +sockets.o: ../../dlib/server/server_kernel_abstract.h ../logger.h +sockets.o: ../../dlib/server/server_kernel_c.h +sockets.o: ../../dlib/server/server_iostream_1.h +sockets.o: ../../dlib/server/server_iostream_abstract.h +sockets.o: ../../dlib/server/server_http_1.h +sockets.o: ../../dlib/server/server_http_abstract.h ../../dlib/set.h +sockets.o: ../../dlib/sockstreambuf.h +sockets.o: ../../dlib/sockstreambuf/sockstreambuf_kernel_1.h +sockets.o: ../sockstreambuf/sockstreambuf_kernel_abstract.h +sockets.o: ../../dlib/sockstreambuf/sockstreambuf_kernel_2.h +sockets.o: ../../dlib/queue.h ../../dlib/misc_api.h +sockstreambuf.o: ../../dlib/sockets.h ../platform.h ../sockets/posix.h +sockstreambuf.o: ../sockets/sockets_kernel_2.h ../platform.h +sockstreambuf.o: ../sockets/sockets_kernel_abstract.h +sockstreambuf.o: /usr/include/sys/types.h /usr/include/features.h +sockstreambuf.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +sockstreambuf.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +sockstreambuf.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +sockstreambuf.o: /usr/include/time.h /usr/include/endian.h +sockstreambuf.o: /usr/include/bits/endian.h /usr/include/sys/select.h +sockstreambuf.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +sockstreambuf.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +sockstreambuf.o: /usr/include/bits/pthreadtypes.h /usr/include/sys/socket.h +sockstreambuf.o: /usr/include/sys/uio.h /usr/include/bits/uio.h +sockstreambuf.o: /usr/include/bits/socket.h /usr/include/limits.h +sockstreambuf.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h +sockstreambuf.o: /usr/include/linux/limits.h /usr/include/bits/posix2_lim.h +sockstreambuf.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h +sockstreambuf.o: /usr/include/asm-i386/socket.h /usr/include/asm/sockios.h +sockstreambuf.o: /usr/include/asm-i386/sockios.h /usr/include/errno.h +sockstreambuf.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +sockstreambuf.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +sockstreambuf.o: /usr/include/asm-generic/errno.h +sockstreambuf.o: /usr/include/asm-generic/errno-base.h +sockstreambuf.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +sockstreambuf.o: /usr/include/stdint.h /usr/include/bits/wchar.h +sockstreambuf.o: /usr/include/bits/in.h /usr/include/bits/byteswap.h +sockstreambuf.o: /usr/include/signal.h /usr/include/inttypes.h +sockstreambuf.o: /usr/include/netdb.h /usr/include/rpc/netdb.h +sockstreambuf.o: /usr/include/bits/netdb.h /usr/include/unistd.h +sockstreambuf.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h +sockstreambuf.o: /usr/include/getopt.h /usr/include/sys/param.h +sockstreambuf.o: /usr/include/linux/param.h /usr/include/asm/param.h +sockstreambuf.o: /usr/include/asm-i386/param.h ../threads.h +sockstreambuf.o: ../threads/threads_kernel.h ../threads/posix.h +sockstreambuf.o: ../threads/threads_kernel_2.h +sockstreambuf.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +sockstreambuf.o: /usr/include/sched.h /usr/include/bits/sched.h +sockstreambuf.o: /usr/include/bits/setjmp.h /usr/include/sys/time.h ../algs.h +sockstreambuf.o: ../assert.h ../error.h ../noncopyable.h +sockstreambuf.o: ../threads/threads_kernel_shared.h +sockstreambuf.o: ../threads/auto_mutex_extension.h +sockstreambuf.o: ../threads/threads_kernel.h ../threads/rmutex_extension.h +sockstreambuf.o: ../threads/rmutex_extension_abstract.h +sockstreambuf.o: ../threads/auto_mutex_extension_abstract.h +sockstreambuf.o: ../binary_search_tree.h +sockstreambuf.o: ../binary_search_tree/binary_search_tree_kernel_1.h +sockstreambuf.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +sockstreambuf.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +sockstreambuf.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +sockstreambuf.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +sockstreambuf.o: ../enable_if.h +sockstreambuf.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sockstreambuf.o: ../binary_search_tree/binary_search_tree_kernel_c.h +sockstreambuf.o: ../assert.h ../../dlib/memory_manager.h +sockstreambuf.o: ../member_function_pointer.h +sockstreambuf.o: ../member_function_pointer/member_function_pointer_kernel_1.h +sockstreambuf.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +sockstreambuf.o: ../member_function_pointer/member_function_pointer_kernel_c.h +sockstreambuf.o: ../memory_manager.h +sockstreambuf.o: ../memory_manager/memory_manager_kernel_1.h +sockstreambuf.o: ../memory_manager/memory_manager_kernel_abstract.h +sockstreambuf.o: ../memory_manager/memory_manager_kernel_2.h +sockstreambuf.o: ../memory_manager/memory_manager_kernel_3.h +sockstreambuf.o: ../memory_manager/memory_manager_kernel_2.h +sockstreambuf.o: ../binary_search_tree/binary_search_tree_kernel_2.h +sockstreambuf.o: ../queue.h ../queue/queue_kernel_1.h +sockstreambuf.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +sockstreambuf.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +sockstreambuf.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +sockstreambuf.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +sockstreambuf.o: ../set/set_kernel_c.h binary_search_tree.h +sockstreambuf.o: ../../dlib/memory_manager_global.h +sockstreambuf.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +sockstreambuf.o: ../memory_manager/memory_manager_kernel_abstract.h +sockstreambuf.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +sockstreambuf.o: ../../dlib/memory_manager_stateless.h +sockstreambuf.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +sockstreambuf.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +sockstreambuf.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +sockstreambuf.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +sockstreambuf.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +sockstreambuf.o: ../misc_api.h ../misc_api/posix.h +sockstreambuf.o: ../misc_api/misc_api_kernel_2.h +sockstreambuf.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +sockstreambuf.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +sockstreambuf.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h +sockstreambuf.o: ../noncopyable.h ../smart_pointers/scoped_ptr_abstract.h +sockstreambuf.o: ../smart_pointers/shared_ptr.h +sockstreambuf.o: ../smart_pointers/shared_ptr_abstract.h +sockstreambuf.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +sockstreambuf.o: ../smart_pointers/weak_ptr_abstract.h +sockstreambuf.o: ../../dlib/logger/extra_logger_headers.h +sockstreambuf.o: ../../dlib/logger/logger_kernel_1.h +sockstreambuf.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +sockstreambuf.o: ../config_reader/config_reader_kernel_1.h +sockstreambuf.o: ../config_reader/config_reader_kernel_abstract.h +sockstreambuf.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +sockstreambuf.o: ../../dlib/map/map_kernel_abstract.h +sockstreambuf.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +sockstreambuf.o: ../tokenizer/tokenizer_kernel_1.h +sockstreambuf.o: ../tokenizer/tokenizer_kernel_abstract.h +sockstreambuf.o: ../tokenizer/tokenizer_kernel_c.h +sockstreambuf.o: ../config_reader/config_reader_thread_safe_1.h +sockstreambuf.o: ../config_reader/config_reader_thread_safe_abstract.h +sockstreambuf.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +sockstreambuf.o: ../set/set_compare_abstract.h +sockstreambuf.o: ../threads/auto_mutex_extension.h +sockstreambuf.o: ../threads/auto_unlock_extension.h +sockstreambuf.o: ../threads/auto_unlock_extension_abstract.h +sockstreambuf.o: ../threads/create_new_thread_extension.h +sockstreambuf.o: ../threads/create_new_thread_extension_abstract.h +sockstreambuf.o: ../threads/multithreaded_object_extension.h +sockstreambuf.o: ../threads/multithreaded_object_extension_abstract.h +sockstreambuf.o: ../threads/rsignaler_extension.h +sockstreambuf.o: ../threads/rsignaler_extension_abstract.h +sockstreambuf.o: ../threads/rmutex_extension.h +sockstreambuf.o: ../threads/rsignaler_extension.h +sockstreambuf.o: ../threads/threaded_object_extension.h +sockstreambuf.o: ../threads/threaded_object_extension_abstract.h +sockstreambuf.o: ../threads/thread_specific_data_extension.h +sockstreambuf.o: ../threads/thread_specific_data_extension_abstract.h +sockstreambuf.o: ../threads/thread_function_extension.h +sockstreambuf.o: ../threads/thread_function_extension_abstract.h +sockstreambuf.o: ../threads/threaded_object_extension.h +sockstreambuf.o: ../sockets/sockets_extensions.h ../sockets.h +sockstreambuf.o: ../sockets/sockets_extensions_abstract.h +sockstreambuf.o: ../../dlib/misc_api.h ../../dlib/sockstreambuf.h +sockstreambuf.o: ../../dlib/sockstreambuf/sockstreambuf_kernel_1.h +sockstreambuf.o: ../sockstreambuf/sockstreambuf_kernel_abstract.h +sockstreambuf.o: ../../dlib/sockstreambuf/sockstreambuf_kernel_2.h +sockstreambuf.o: ../../dlib/smart_pointers.h +stack.o: ../../dlib/stack.h ../../dlib/stack/stack_kernel_1.h +stack.o: ../../dlib/stack/stack_kernel_abstract.h ../algs.h ../platform.h +stack.o: ../assert.h ../error.h ../noncopyable.h ../interfaces/enumerable.h +stack.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +stack.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +stack.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +stack.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +stack.o: ../memory_manager/memory_manager_kernel_2.h +stack.o: ../memory_manager/memory_manager_kernel_3.h +stack.o: ../memory_manager/memory_manager_kernel_2.h +stack.o: ../binary_search_tree/binary_search_tree_kernel_2.h +stack.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +stack.o: ../interfaces/map_pair.h ../../dlib/stack/stack_kernel_c.h +stack.o: ../../dlib/memory_manager.h tester.h ../../dlib/map.h +stack.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../threads.h +stack.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +stack.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +stack.o: /usr/include/pthread.h /usr/include/features.h +stack.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +stack.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +stack.o: /usr/include/sched.h /usr/include/bits/types.h +stack.o: /usr/include/bits/typesizes.h /usr/include/time.h +stack.o: /usr/include/bits/sched.h /usr/include/signal.h +stack.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +stack.o: /usr/include/bits/setjmp.h /usr/include/errno.h +stack.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +stack.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +stack.o: /usr/include/asm-generic/errno.h +stack.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +stack.o: /usr/include/bits/time.h /usr/include/sys/select.h +stack.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +stack.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +stack.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +stack.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +stack.o: ../binary_search_tree/binary_search_tree_kernel_1.h +stack.o: ../binary_search_tree/binary_search_tree_kernel_2.h +stack.o: ../binary_search_tree/binary_search_tree_kernel_c.h +stack.o: ../member_function_pointer.h +stack.o: ../member_function_pointer/member_function_pointer_kernel_1.h +stack.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +stack.o: ../member_function_pointer/member_function_pointer_kernel_c.h +stack.o: ../queue.h ../queue/queue_kernel_1.h +stack.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +stack.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +stack.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +stack.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +stack.o: ../set/set_kernel_c.h binary_search_tree.h +stack.o: ../../dlib/memory_manager_global.h +stack.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +stack.o: ../memory_manager/memory_manager_kernel_abstract.h +stack.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +stack.o: ../../dlib/memory_manager_stateless.h +stack.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +stack.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +stack.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +stack.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +stack.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +stack.o: ../threads/auto_unlock_extension.h +stack.o: ../threads/auto_unlock_extension_abstract.h +stack.o: ../threads/create_new_thread_extension.h +stack.o: ../threads/create_new_thread_extension_abstract.h +stack.o: ../threads/multithreaded_object_extension.h +stack.o: ../threads/multithreaded_object_extension_abstract.h +stack.o: ../threads/rsignaler_extension.h +stack.o: ../threads/rsignaler_extension_abstract.h ../map.h +stack.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +stack.o: ../threads/threaded_object_extension.h +stack.o: ../threads/threaded_object_extension_abstract.h +stack.o: ../threads/thread_specific_data_extension.h +stack.o: ../threads/thread_specific_data_extension_abstract.h +stack.o: ../threads/thread_function_extension.h +stack.o: ../threads/thread_function_extension_abstract.h +stack.o: ../threads/threaded_object_extension.h ../misc_api.h +stack.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +stack.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +stack.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +stack.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +stack.o: ../smart_pointers/scoped_ptr_abstract.h +stack.o: ../smart_pointers/shared_ptr.h +stack.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +stack.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +stack.o: ../../dlib/logger/extra_logger_headers.h +stack.o: ../../dlib/logger/logger_kernel_1.h +stack.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +stack.o: ../config_reader/config_reader_kernel_1.h +stack.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +stack.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +stack.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +stack.o: ../tokenizer/tokenizer_kernel_1.h +stack.o: ../tokenizer/tokenizer_kernel_abstract.h +stack.o: ../tokenizer/tokenizer_kernel_c.h +stack.o: ../config_reader/config_reader_thread_safe_1.h +stack.o: ../config_reader/config_reader_thread_safe_abstract.h +stack.o: ../../dlib/assert.h ../../dlib/algs.h +static_map.o: ../../dlib/hash_table.h +static_map.o: ../../dlib/hash_table/hash_table_kernel_1.h +static_map.o: ../../dlib/hash_table/hash_table_kernel_abstract.h +static_map.o: ../general_hash/general_hash.h ../algs.h ../platform.h +static_map.o: ../assert.h ../error.h ../noncopyable.h +static_map.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +static_map.o: ../interfaces/remover.h ../assert.h ../serialize.h ../algs.h +static_map.o: ../uintn.h ../interfaces/enumerable.h ../interfaces/map_pair.h +static_map.o: ../enable_if.h ../memory_manager.h +static_map.o: ../memory_manager/memory_manager_kernel_1.h +static_map.o: ../memory_manager/memory_manager_kernel_abstract.h +static_map.o: ../memory_manager/memory_manager_kernel_2.h +static_map.o: ../memory_manager/memory_manager_kernel_3.h +static_map.o: ../memory_manager/memory_manager_kernel_2.h +static_map.o: ../binary_search_tree/binary_search_tree_kernel_2.h +static_map.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +static_map.o: ../../dlib/hash_table/hash_table_kernel_2.h +static_map.o: ../../dlib/hash_table/hash_table_kernel_c.h +static_map.o: ../../dlib/memory_manager.h binary_search_tree.h +static_map.o: ../../dlib/memory_manager_global.h +static_map.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +static_map.o: ../memory_manager/memory_manager_kernel_abstract.h +static_map.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +static_map.o: ../../dlib/memory_manager_stateless.h +static_map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +static_map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +static_map.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +static_map.o: ../threads.h ../threads/threads_kernel.h ../platform.h +static_map.o: ../threads/posix.h ../threads/threads_kernel_2.h +static_map.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +static_map.o: /usr/include/features.h /usr/include/sys/cdefs.h +static_map.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +static_map.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +static_map.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +static_map.o: /usr/include/time.h /usr/include/bits/sched.h +static_map.o: /usr/include/signal.h /usr/include/bits/sigset.h +static_map.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +static_map.o: /usr/include/errno.h /usr/include/bits/errno.h +static_map.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +static_map.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +static_map.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +static_map.o: /usr/include/bits/time.h /usr/include/sys/select.h +static_map.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +static_map.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +static_map.o: ../threads/rmutex_extension.h +static_map.o: ../threads/rmutex_extension_abstract.h +static_map.o: ../threads/auto_mutex_extension_abstract.h +static_map.o: ../binary_search_tree.h +static_map.o: ../binary_search_tree/binary_search_tree_kernel_1.h +static_map.o: ../binary_search_tree/binary_search_tree_kernel_2.h +static_map.o: ../binary_search_tree/binary_search_tree_kernel_c.h +static_map.o: ../member_function_pointer.h +static_map.o: ../member_function_pointer/member_function_pointer_kernel_1.h +static_map.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +static_map.o: ../member_function_pointer/member_function_pointer_kernel_c.h +static_map.o: ../queue.h ../queue/queue_kernel_1.h +static_map.o: ../queue/queue_kernel_abstract.h ../queue/queue_kernel_2.h +static_map.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +static_map.o: ../queue/queue_sort_abstract.h ../sort.h ../set.h +static_map.o: ../set/set_kernel_1.h ../set/set_kernel_abstract.h +static_map.o: ../set/set_kernel_c.h ../set/set_compare_1.h +static_map.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +static_map.o: ../threads/auto_unlock_extension.h +static_map.o: ../threads/auto_unlock_extension_abstract.h +static_map.o: ../threads/create_new_thread_extension.h +static_map.o: ../threads/create_new_thread_extension_abstract.h +static_map.o: ../threads/multithreaded_object_extension.h +static_map.o: ../threads/multithreaded_object_extension_abstract.h +static_map.o: ../threads/rsignaler_extension.h +static_map.o: ../threads/rsignaler_extension_abstract.h ../map.h +static_map.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +static_map.o: ../threads/threaded_object_extension.h +static_map.o: ../threads/threaded_object_extension_abstract.h +static_map.o: ../threads/thread_specific_data_extension.h +static_map.o: ../threads/thread_specific_data_extension_abstract.h +static_map.o: ../threads/thread_function_extension.h +static_map.o: ../threads/thread_function_extension_abstract.h +static_map.o: ../threads/threaded_object_extension.h +static_map.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +static_map.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +static_map.o: ../misc_api.h ../misc_api/posix.h +static_map.o: ../misc_api/misc_api_kernel_2.h +static_map.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +static_map.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +static_map.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +static_map.o: ../smart_pointers/scoped_ptr_abstract.h +static_map.o: ../smart_pointers/shared_ptr.h +static_map.o: ../smart_pointers/shared_ptr_abstract.h +static_map.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +static_map.o: ../smart_pointers/weak_ptr_abstract.h +static_map.o: ../../dlib/logger/extra_logger_headers.h +static_map.o: ../../dlib/logger/logger_kernel_1.h +static_map.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +static_map.o: ../config_reader/config_reader_kernel_1.h +static_map.o: ../config_reader/config_reader_kernel_abstract.h +static_map.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +static_map.o: ../../dlib/map/map_kernel_abstract.h +static_map.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +static_map.o: ../tokenizer/tokenizer_kernel_1.h +static_map.o: ../tokenizer/tokenizer_kernel_abstract.h +static_map.o: ../tokenizer/tokenizer_kernel_c.h +static_map.o: ../config_reader/config_reader_thread_safe_1.h +static_map.o: ../config_reader/config_reader_thread_safe_abstract.h +static_map.o: ../../dlib/assert.h ../../dlib/algs.h ../../dlib/static_map.h +static_map.o: ../../dlib/static_map/static_map_kernel_1.h +static_map.o: ../../dlib/static_map/static_map_kernel_abstract.h +static_map.o: ../../dlib/static_map/static_map_kernel_c.h +static_set.o: ../../dlib/queue.h ../queue/queue_kernel_1.h +static_set.o: ../queue/queue_kernel_abstract.h ../algs.h ../platform.h +static_set.o: ../assert.h ../error.h ../noncopyable.h +static_set.o: ../interfaces/enumerable.h ../interfaces/remover.h +static_set.o: ../serialize.h ../algs.h ../uintn.h ../interfaces/enumerable.h +static_set.o: ../interfaces/map_pair.h ../enable_if.h ../memory_manager.h +static_set.o: ../memory_manager/memory_manager_kernel_1.h +static_set.o: ../memory_manager/memory_manager_kernel_abstract.h ../assert.h +static_set.o: ../memory_manager/memory_manager_kernel_2.h +static_set.o: ../memory_manager/memory_manager_kernel_3.h +static_set.o: ../memory_manager/memory_manager_kernel_2.h +static_set.o: ../binary_search_tree/binary_search_tree_kernel_2.h +static_set.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +static_set.o: ../interfaces/map_pair.h ../queue/queue_kernel_2.h +static_set.o: ../queue/queue_kernel_c.h ../queue/queue_sort_1.h +static_set.o: ../queue/queue_sort_abstract.h ../sort.h +static_set.o: ../../dlib/memory_manager.h ../../dlib/static_set.h +static_set.o: ../../dlib/static_set/static_set_kernel_1.h +static_set.o: ../../dlib/static_set/static_set_kernel_abstract.h +static_set.o: ../../dlib/static_set/static_set_kernel_c.h +static_set.o: ../../dlib/static_set/static_set_compare_1.h +static_set.o: ../../dlib/static_set/static_set_compare_abstract.h +static_set.o: ../../dlib/set.h tester.h ../../dlib/map.h ../../dlib/logger.h +static_set.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +static_set.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +static_set.o: ../threads/threads_kernel_2.h +static_set.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +static_set.o: /usr/include/features.h /usr/include/sys/cdefs.h +static_set.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +static_set.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +static_set.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +static_set.o: /usr/include/time.h /usr/include/bits/sched.h +static_set.o: /usr/include/signal.h /usr/include/bits/sigset.h +static_set.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +static_set.o: /usr/include/errno.h /usr/include/bits/errno.h +static_set.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +static_set.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +static_set.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +static_set.o: /usr/include/bits/time.h /usr/include/sys/select.h +static_set.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +static_set.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +static_set.o: ../threads/rmutex_extension.h +static_set.o: ../threads/rmutex_extension_abstract.h +static_set.o: ../threads/auto_mutex_extension_abstract.h +static_set.o: ../binary_search_tree.h +static_set.o: ../binary_search_tree/binary_search_tree_kernel_1.h +static_set.o: ../binary_search_tree/binary_search_tree_kernel_2.h +static_set.o: ../binary_search_tree/binary_search_tree_kernel_c.h +static_set.o: ../member_function_pointer.h +static_set.o: ../member_function_pointer/member_function_pointer_kernel_1.h +static_set.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +static_set.o: ../member_function_pointer/member_function_pointer_kernel_c.h +static_set.o: ../queue.h ../set.h ../set/set_kernel_1.h +static_set.o: ../set/set_kernel_abstract.h ../set/set_kernel_c.h +static_set.o: binary_search_tree.h ../../dlib/memory_manager_global.h +static_set.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +static_set.o: ../memory_manager/memory_manager_kernel_abstract.h +static_set.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +static_set.o: ../../dlib/memory_manager_stateless.h +static_set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +static_set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +static_set.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +static_set.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +static_set.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +static_set.o: ../threads/auto_unlock_extension.h +static_set.o: ../threads/auto_unlock_extension_abstract.h +static_set.o: ../threads/create_new_thread_extension.h +static_set.o: ../threads/create_new_thread_extension_abstract.h +static_set.o: ../threads/multithreaded_object_extension.h +static_set.o: ../threads/multithreaded_object_extension_abstract.h +static_set.o: ../threads/rsignaler_extension.h +static_set.o: ../threads/rsignaler_extension_abstract.h ../map.h +static_set.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +static_set.o: ../threads/threaded_object_extension.h +static_set.o: ../threads/threaded_object_extension_abstract.h +static_set.o: ../threads/thread_specific_data_extension.h +static_set.o: ../threads/thread_specific_data_extension_abstract.h +static_set.o: ../threads/thread_function_extension.h +static_set.o: ../threads/thread_function_extension_abstract.h +static_set.o: ../threads/threaded_object_extension.h ../misc_api.h +static_set.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +static_set.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +static_set.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +static_set.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +static_set.o: ../smart_pointers/scoped_ptr_abstract.h +static_set.o: ../smart_pointers/shared_ptr.h +static_set.o: ../smart_pointers/shared_ptr_abstract.h +static_set.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +static_set.o: ../smart_pointers/weak_ptr_abstract.h +static_set.o: ../../dlib/logger/extra_logger_headers.h +static_set.o: ../../dlib/logger/logger_kernel_1.h +static_set.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +static_set.o: ../config_reader/config_reader_kernel_1.h +static_set.o: ../config_reader/config_reader_kernel_abstract.h +static_set.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +static_set.o: ../../dlib/map/map_kernel_abstract.h +static_set.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +static_set.o: ../tokenizer/tokenizer_kernel_1.h +static_set.o: ../tokenizer/tokenizer_kernel_abstract.h +static_set.o: ../tokenizer/tokenizer_kernel_c.h +static_set.o: ../config_reader/config_reader_thread_safe_1.h +static_set.o: ../config_reader/config_reader_thread_safe_abstract.h +static_set.o: ../../dlib/assert.h ../../dlib/algs.h +string.o: ../../dlib/string.h tester.h ../../dlib/map.h ../../dlib/logger.h +string.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +string.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +string.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +string.o: /usr/include/pthread.h /usr/include/features.h +string.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +string.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +string.o: /usr/include/sched.h /usr/include/bits/types.h +string.o: /usr/include/bits/typesizes.h /usr/include/time.h +string.o: /usr/include/bits/sched.h /usr/include/signal.h +string.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +string.o: /usr/include/bits/setjmp.h /usr/include/errno.h +string.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +string.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +string.o: /usr/include/asm-generic/errno.h +string.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +string.o: /usr/include/bits/time.h /usr/include/sys/select.h +string.o: /usr/include/bits/select.h ../algs.h ../platform.h ../assert.h +string.o: ../error.h ../noncopyable.h ../threads/threads_kernel_shared.h +string.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +string.o: ../threads/rmutex_extension.h +string.o: ../threads/rmutex_extension_abstract.h +string.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +string.o: ../binary_search_tree/binary_search_tree_kernel_1.h +string.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +string.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +string.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +string.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +string.o: ../binary_search_tree/binary_search_tree_kernel_2.h +string.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +string.o: ../../dlib/memory_manager.h ../member_function_pointer.h +string.o: ../member_function_pointer/member_function_pointer_kernel_1.h +string.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +string.o: ../member_function_pointer/member_function_pointer_kernel_c.h +string.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +string.o: ../memory_manager/memory_manager_kernel_abstract.h +string.o: ../memory_manager/memory_manager_kernel_2.h +string.o: ../memory_manager/memory_manager_kernel_3.h +string.o: ../memory_manager/memory_manager_kernel_2.h +string.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +string.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +string.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +string.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +string.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +string.o: ../set/set_kernel_c.h binary_search_tree.h +string.o: ../../dlib/memory_manager_global.h +string.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +string.o: ../memory_manager/memory_manager_kernel_abstract.h +string.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +string.o: ../../dlib/memory_manager_stateless.h +string.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +string.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +string.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +string.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +string.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +string.o: ../threads/auto_unlock_extension.h +string.o: ../threads/auto_unlock_extension_abstract.h +string.o: ../threads/create_new_thread_extension.h +string.o: ../threads/create_new_thread_extension_abstract.h +string.o: ../threads/multithreaded_object_extension.h +string.o: ../threads/multithreaded_object_extension_abstract.h +string.o: ../threads/rsignaler_extension.h +string.o: ../threads/rsignaler_extension_abstract.h ../map.h +string.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +string.o: ../threads/threaded_object_extension.h +string.o: ../threads/threaded_object_extension_abstract.h +string.o: ../threads/thread_specific_data_extension.h +string.o: ../threads/thread_specific_data_extension_abstract.h +string.o: ../threads/thread_function_extension.h +string.o: ../threads/thread_function_extension_abstract.h +string.o: ../threads/threaded_object_extension.h ../misc_api.h +string.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +string.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +string.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +string.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +string.o: ../smart_pointers/scoped_ptr_abstract.h +string.o: ../smart_pointers/shared_ptr.h +string.o: ../smart_pointers/shared_ptr_abstract.h +string.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +string.o: ../smart_pointers/weak_ptr_abstract.h +string.o: ../../dlib/logger/extra_logger_headers.h +string.o: ../../dlib/logger/logger_kernel_1.h +string.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +string.o: ../config_reader/config_reader_kernel_1.h +string.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +string.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +string.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +string.o: ../tokenizer/tokenizer_kernel_1.h +string.o: ../tokenizer/tokenizer_kernel_abstract.h +string.o: ../tokenizer/tokenizer_kernel_c.h +string.o: ../config_reader/config_reader_thread_safe_1.h +string.o: ../config_reader/config_reader_thread_safe_abstract.h +string.o: ../../dlib/assert.h ../../dlib/algs.h +threads.o: ../../dlib/misc_api.h ../platform.h ../misc_api/posix.h +threads.o: ../misc_api/misc_api_kernel_2.h +threads.o: ../misc_api/misc_api_kernel_abstract.h ../algs.h ../assert.h +threads.o: ../error.h ../noncopyable.h ../uintn.h ../../dlib/threads.h +threads.o: tester.h ../../dlib/map.h ../../dlib/logger.h +threads.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +threads.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +threads.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +threads.o: /usr/include/pthread.h /usr/include/features.h +threads.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +threads.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +threads.o: /usr/include/sched.h /usr/include/bits/types.h +threads.o: /usr/include/bits/typesizes.h /usr/include/time.h +threads.o: /usr/include/bits/sched.h /usr/include/signal.h +threads.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +threads.o: /usr/include/bits/setjmp.h /usr/include/errno.h +threads.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +threads.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +threads.o: /usr/include/asm-generic/errno.h +threads.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +threads.o: /usr/include/bits/time.h /usr/include/sys/select.h +threads.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +threads.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +threads.o: ../threads/rmutex_extension.h +threads.o: ../threads/rmutex_extension_abstract.h +threads.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +threads.o: ../binary_search_tree/binary_search_tree_kernel_1.h +threads.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +threads.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +threads.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +threads.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +threads.o: ../binary_search_tree/binary_search_tree_kernel_2.h +threads.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +threads.o: ../../dlib/memory_manager.h ../member_function_pointer.h +threads.o: ../member_function_pointer/member_function_pointer_kernel_1.h +threads.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +threads.o: ../member_function_pointer/member_function_pointer_kernel_c.h +threads.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +threads.o: ../memory_manager/memory_manager_kernel_abstract.h +threads.o: ../memory_manager/memory_manager_kernel_2.h +threads.o: ../memory_manager/memory_manager_kernel_3.h +threads.o: ../memory_manager/memory_manager_kernel_2.h +threads.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +threads.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +threads.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +threads.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +threads.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +threads.o: ../set/set_kernel_c.h binary_search_tree.h +threads.o: ../../dlib/memory_manager_global.h +threads.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +threads.o: ../memory_manager/memory_manager_kernel_abstract.h +threads.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +threads.o: ../../dlib/memory_manager_stateless.h +threads.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +threads.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +threads.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +threads.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +threads.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +threads.o: ../threads/auto_unlock_extension.h +threads.o: ../threads/auto_unlock_extension_abstract.h +threads.o: ../threads/create_new_thread_extension.h +threads.o: ../threads/create_new_thread_extension_abstract.h +threads.o: ../threads/multithreaded_object_extension.h +threads.o: ../threads/multithreaded_object_extension_abstract.h +threads.o: ../threads/rsignaler_extension.h +threads.o: ../threads/rsignaler_extension_abstract.h ../map.h +threads.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +threads.o: ../threads/threaded_object_extension.h +threads.o: ../threads/threaded_object_extension_abstract.h +threads.o: ../threads/thread_specific_data_extension.h +threads.o: ../threads/thread_specific_data_extension_abstract.h +threads.o: ../threads/thread_function_extension.h +threads.o: ../threads/thread_function_extension_abstract.h +threads.o: ../threads/threaded_object_extension.h ../misc_api.h +threads.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +threads.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +threads.o: ../smart_pointers/scoped_ptr_abstract.h +threads.o: ../smart_pointers/shared_ptr.h +threads.o: ../smart_pointers/shared_ptr_abstract.h +threads.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +threads.o: ../smart_pointers/weak_ptr_abstract.h +threads.o: ../../dlib/logger/extra_logger_headers.h +threads.o: ../../dlib/logger/logger_kernel_1.h +threads.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +threads.o: ../config_reader/config_reader_kernel_1.h +threads.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +threads.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +threads.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +threads.o: ../tokenizer/tokenizer_kernel_1.h +threads.o: ../tokenizer/tokenizer_kernel_abstract.h +threads.o: ../tokenizer/tokenizer_kernel_c.h +threads.o: ../config_reader/config_reader_thread_safe_1.h +threads.o: ../config_reader/config_reader_thread_safe_abstract.h +threads.o: ../../dlib/assert.h ../../dlib/algs.h +timer.o: ../../dlib/timer.h ../timer/timer_kernel_1.h ../threads.h +timer.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +timer.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +timer.o: /usr/include/pthread.h /usr/include/features.h +timer.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +timer.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +timer.o: /usr/include/sched.h /usr/include/bits/types.h +timer.o: /usr/include/bits/typesizes.h /usr/include/time.h +timer.o: /usr/include/bits/sched.h /usr/include/signal.h +timer.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +timer.o: /usr/include/bits/setjmp.h /usr/include/errno.h +timer.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +timer.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +timer.o: /usr/include/asm-generic/errno.h +timer.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +timer.o: /usr/include/bits/time.h /usr/include/sys/select.h +timer.o: /usr/include/bits/select.h ../algs.h ../platform.h ../assert.h +timer.o: ../error.h ../noncopyable.h ../threads/threads_kernel_shared.h +timer.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +timer.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +timer.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +timer.o: ../binary_search_tree/binary_search_tree_kernel_1.h +timer.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +timer.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +timer.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +timer.o: ../interfaces/enumerable.h ../interfaces/map_pair.h ../enable_if.h +timer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +timer.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +timer.o: ../../dlib/memory_manager.h ../member_function_pointer.h +timer.o: ../member_function_pointer/member_function_pointer_kernel_1.h +timer.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +timer.o: ../member_function_pointer/member_function_pointer_kernel_c.h +timer.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +timer.o: ../memory_manager/memory_manager_kernel_abstract.h +timer.o: ../memory_manager/memory_manager_kernel_2.h +timer.o: ../memory_manager/memory_manager_kernel_3.h +timer.o: ../memory_manager/memory_manager_kernel_2.h +timer.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +timer.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +timer.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +timer.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +timer.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +timer.o: ../set/set_kernel_c.h binary_search_tree.h +timer.o: ../../dlib/memory_manager_global.h +timer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +timer.o: ../memory_manager/memory_manager_kernel_abstract.h +timer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +timer.o: ../../dlib/memory_manager_stateless.h +timer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +timer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +timer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +timer.o: ../../dlib/binary_search_tree.h tester.h ../../dlib/map.h +timer.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h +timer.o: ../misc_api.h ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +timer.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +timer.o: ../../dlib/logger/logger_kernel_abstract.h ../map.h +timer.o: ../smart_pointers.h ../smart_pointers/scoped_ptr.h ../noncopyable.h +timer.o: ../smart_pointers/scoped_ptr_abstract.h +timer.o: ../smart_pointers/shared_ptr.h +timer.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +timer.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +timer.o: ../../dlib/logger/extra_logger_headers.h +timer.o: ../../dlib/logger/logger_kernel_1.h +timer.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +timer.o: ../config_reader/config_reader_kernel_1.h +timer.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +timer.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +timer.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +timer.o: ../tokenizer/tokenizer_kernel_1.h +timer.o: ../tokenizer/tokenizer_kernel_abstract.h +timer.o: ../tokenizer/tokenizer_kernel_c.h +timer.o: ../config_reader/config_reader_thread_safe_1.h +timer.o: ../config_reader/config_reader_thread_safe_abstract.h +timer.o: ../../dlib/assert.h ../../dlib/algs.h ../set/set_compare_1.h +timer.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +timer.o: ../threads/auto_unlock_extension.h +timer.o: ../threads/auto_unlock_extension_abstract.h +timer.o: ../threads/create_new_thread_extension.h +timer.o: ../threads/create_new_thread_extension_abstract.h +timer.o: ../threads/multithreaded_object_extension.h +timer.o: ../threads/multithreaded_object_extension_abstract.h +timer.o: ../threads/rsignaler_extension.h +timer.o: ../threads/rsignaler_extension_abstract.h +timer.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +timer.o: ../threads/threaded_object_extension.h +timer.o: ../threads/threaded_object_extension_abstract.h +timer.o: ../threads/thread_specific_data_extension.h +timer.o: ../threads/thread_specific_data_extension_abstract.h +timer.o: ../threads/thread_function_extension.h +timer.o: ../threads/thread_function_extension_abstract.h +timer.o: ../threads/threaded_object_extension.h +timer.o: ../timer/timer_kernel_abstract.h ../timer/timer_kernel_2.h +timer.o: ../../dlib/timeout.h ../timeout/timeout_kernel_1.h +timer.o: ../timeout/timeout_kernel_abstract.h ../timer.h +tokenizer.o: ../../dlib/tokenizer.h ../tokenizer/tokenizer_kernel_1.h +tokenizer.o: ../algs.h ../platform.h ../assert.h ../error.h ../noncopyable.h +tokenizer.o: ../tokenizer/tokenizer_kernel_abstract.h +tokenizer.o: ../tokenizer/tokenizer_kernel_c.h ../assert.h tester.h +tokenizer.o: ../../dlib/map.h ../../dlib/logger.h +tokenizer.o: ../../dlib/logger/logger_kernel_1.h ../threads.h +tokenizer.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +tokenizer.o: ../threads/threads_kernel_2.h +tokenizer.o: ../threads/threads_kernel_abstract.h /usr/include/pthread.h +tokenizer.o: /usr/include/features.h /usr/include/sys/cdefs.h +tokenizer.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h +tokenizer.o: /usr/include/gnu/stubs-32.h /usr/include/sched.h +tokenizer.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +tokenizer.o: /usr/include/time.h /usr/include/bits/sched.h +tokenizer.o: /usr/include/signal.h /usr/include/bits/sigset.h +tokenizer.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/setjmp.h +tokenizer.o: /usr/include/errno.h /usr/include/bits/errno.h +tokenizer.o: /usr/include/linux/errno.h /usr/include/asm/errno.h +tokenizer.o: /usr/include/asm-i386/errno.h /usr/include/asm-generic/errno.h +tokenizer.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +tokenizer.o: /usr/include/bits/time.h /usr/include/sys/select.h +tokenizer.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +tokenizer.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +tokenizer.o: ../threads/rmutex_extension.h +tokenizer.o: ../threads/rmutex_extension_abstract.h +tokenizer.o: ../threads/auto_mutex_extension_abstract.h +tokenizer.o: ../binary_search_tree.h +tokenizer.o: ../binary_search_tree/binary_search_tree_kernel_1.h +tokenizer.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +tokenizer.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +tokenizer.o: ../interfaces/remover.h ../serialize.h ../algs.h ../uintn.h +tokenizer.o: ../interfaces/enumerable.h ../interfaces/map_pair.h +tokenizer.o: ../enable_if.h +tokenizer.o: ../binary_search_tree/binary_search_tree_kernel_2.h +tokenizer.o: ../binary_search_tree/binary_search_tree_kernel_c.h +tokenizer.o: ../../dlib/memory_manager.h ../member_function_pointer.h +tokenizer.o: ../member_function_pointer/member_function_pointer_kernel_1.h +tokenizer.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +tokenizer.o: ../member_function_pointer/member_function_pointer_kernel_c.h +tokenizer.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +tokenizer.o: ../memory_manager/memory_manager_kernel_abstract.h +tokenizer.o: ../memory_manager/memory_manager_kernel_2.h +tokenizer.o: ../memory_manager/memory_manager_kernel_3.h +tokenizer.o: ../memory_manager/memory_manager_kernel_2.h +tokenizer.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +tokenizer.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +tokenizer.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +tokenizer.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +tokenizer.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +tokenizer.o: ../set/set_kernel_c.h binary_search_tree.h +tokenizer.o: ../../dlib/memory_manager_global.h +tokenizer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +tokenizer.o: ../memory_manager/memory_manager_kernel_abstract.h +tokenizer.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +tokenizer.o: ../../dlib/memory_manager_stateless.h +tokenizer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +tokenizer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +tokenizer.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +tokenizer.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +tokenizer.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +tokenizer.o: ../threads/auto_unlock_extension.h +tokenizer.o: ../threads/auto_unlock_extension_abstract.h +tokenizer.o: ../threads/create_new_thread_extension.h +tokenizer.o: ../threads/create_new_thread_extension_abstract.h +tokenizer.o: ../threads/multithreaded_object_extension.h +tokenizer.o: ../threads/multithreaded_object_extension_abstract.h +tokenizer.o: ../threads/rsignaler_extension.h +tokenizer.o: ../threads/rsignaler_extension_abstract.h ../map.h +tokenizer.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +tokenizer.o: ../threads/threaded_object_extension.h +tokenizer.o: ../threads/threaded_object_extension_abstract.h +tokenizer.o: ../threads/thread_specific_data_extension.h +tokenizer.o: ../threads/thread_specific_data_extension_abstract.h +tokenizer.o: ../threads/thread_function_extension.h +tokenizer.o: ../threads/thread_function_extension_abstract.h +tokenizer.o: ../threads/threaded_object_extension.h ../misc_api.h +tokenizer.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +tokenizer.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +tokenizer.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +tokenizer.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +tokenizer.o: ../smart_pointers/scoped_ptr_abstract.h +tokenizer.o: ../smart_pointers/shared_ptr.h +tokenizer.o: ../smart_pointers/shared_ptr_abstract.h +tokenizer.o: ../smart_pointers/weak_ptr.h ../smart_pointers/shared_ptr.h +tokenizer.o: ../smart_pointers/weak_ptr_abstract.h +tokenizer.o: ../../dlib/logger/extra_logger_headers.h +tokenizer.o: ../../dlib/logger/logger_kernel_1.h +tokenizer.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +tokenizer.o: ../config_reader/config_reader_kernel_1.h +tokenizer.o: ../config_reader/config_reader_kernel_abstract.h +tokenizer.o: ../../dlib/map.h ../../dlib/map/map_kernel_1.h +tokenizer.o: ../../dlib/map/map_kernel_abstract.h +tokenizer.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +tokenizer.o: ../config_reader/config_reader_thread_safe_1.h +tokenizer.o: ../config_reader/config_reader_thread_safe_abstract.h +tokenizer.o: ../../dlib/assert.h ../../dlib/algs.h +tuple.o: ../../dlib/tuple.h ../../dlib/tuple/tuple.h ../enable_if.h ../algs.h +tuple.o: ../platform.h ../assert.h ../error.h ../noncopyable.h ../serialize.h +tuple.o: ../algs.h ../uintn.h ../interfaces/enumerable.h +tuple.o: ../interfaces/map_pair.h ../enable_if.h +tuple.o: ../../dlib/tuple/tuple_abstract.h tester.h ../../dlib/map.h +tuple.o: ../../dlib/logger.h ../../dlib/logger/logger_kernel_1.h ../threads.h +tuple.o: ../threads/threads_kernel.h ../platform.h ../threads/posix.h +tuple.o: ../threads/threads_kernel_2.h ../threads/threads_kernel_abstract.h +tuple.o: /usr/include/pthread.h /usr/include/features.h +tuple.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h +tuple.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-32.h +tuple.o: /usr/include/sched.h /usr/include/bits/types.h +tuple.o: /usr/include/bits/typesizes.h /usr/include/time.h +tuple.o: /usr/include/bits/sched.h /usr/include/signal.h +tuple.o: /usr/include/bits/sigset.h /usr/include/bits/pthreadtypes.h +tuple.o: /usr/include/bits/setjmp.h /usr/include/errno.h +tuple.o: /usr/include/bits/errno.h /usr/include/linux/errno.h +tuple.o: /usr/include/asm/errno.h /usr/include/asm-i386/errno.h +tuple.o: /usr/include/asm-generic/errno.h +tuple.o: /usr/include/asm-generic/errno-base.h /usr/include/sys/time.h +tuple.o: /usr/include/bits/time.h /usr/include/sys/select.h +tuple.o: /usr/include/bits/select.h ../threads/threads_kernel_shared.h +tuple.o: ../threads/auto_mutex_extension.h ../threads/threads_kernel.h +tuple.o: ../threads/rmutex_extension.h ../threads/rmutex_extension_abstract.h +tuple.o: ../threads/auto_mutex_extension_abstract.h ../binary_search_tree.h +tuple.o: ../binary_search_tree/binary_search_tree_kernel_1.h +tuple.o: ../binary_search_tree/binary_search_tree_kernel_abstract.h +tuple.o: ../interfaces/map_pair.h ../interfaces/enumerable.h +tuple.o: ../interfaces/remover.h +tuple.o: ../binary_search_tree/binary_search_tree_kernel_2.h +tuple.o: ../binary_search_tree/binary_search_tree_kernel_c.h ../assert.h +tuple.o: ../../dlib/memory_manager.h ../member_function_pointer.h +tuple.o: ../member_function_pointer/member_function_pointer_kernel_1.h +tuple.o: ../member_function_pointer/member_function_pointer_kernel_abstract.h +tuple.o: ../member_function_pointer/member_function_pointer_kernel_c.h +tuple.o: ../memory_manager.h ../memory_manager/memory_manager_kernel_1.h +tuple.o: ../memory_manager/memory_manager_kernel_abstract.h +tuple.o: ../memory_manager/memory_manager_kernel_2.h +tuple.o: ../memory_manager/memory_manager_kernel_3.h +tuple.o: ../memory_manager/memory_manager_kernel_2.h +tuple.o: ../binary_search_tree/binary_search_tree_kernel_2.h ../queue.h +tuple.o: ../queue/queue_kernel_1.h ../queue/queue_kernel_abstract.h +tuple.o: ../queue/queue_kernel_2.h ../queue/queue_kernel_c.h +tuple.o: ../queue/queue_sort_1.h ../queue/queue_sort_abstract.h ../sort.h +tuple.o: ../set.h ../set/set_kernel_1.h ../set/set_kernel_abstract.h +tuple.o: ../set/set_kernel_c.h binary_search_tree.h +tuple.o: ../../dlib/memory_manager_global.h +tuple.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_1.h +tuple.o: ../memory_manager/memory_manager_kernel_abstract.h +tuple.o: ../../dlib/memory_manager_global/memory_manager_global_kernel_abstract.h +tuple.o: ../../dlib/memory_manager_stateless.h +tuple.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h +tuple.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h +tuple.o: ../../dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h +tuple.o: ../../dlib/binary_search_tree.h ../set/set_compare_1.h +tuple.o: ../set/set_compare_abstract.h ../threads/auto_mutex_extension.h +tuple.o: ../threads/auto_unlock_extension.h +tuple.o: ../threads/auto_unlock_extension_abstract.h +tuple.o: ../threads/create_new_thread_extension.h +tuple.o: ../threads/create_new_thread_extension_abstract.h +tuple.o: ../threads/multithreaded_object_extension.h +tuple.o: ../threads/multithreaded_object_extension_abstract.h +tuple.o: ../threads/rsignaler_extension.h +tuple.o: ../threads/rsignaler_extension_abstract.h ../map.h +tuple.o: ../threads/rmutex_extension.h ../threads/rsignaler_extension.h +tuple.o: ../threads/threaded_object_extension.h +tuple.o: ../threads/threaded_object_extension_abstract.h +tuple.o: ../threads/thread_specific_data_extension.h +tuple.o: ../threads/thread_specific_data_extension_abstract.h +tuple.o: ../threads/thread_function_extension.h +tuple.o: ../threads/thread_function_extension_abstract.h +tuple.o: ../threads/threaded_object_extension.h ../misc_api.h +tuple.o: ../misc_api/posix.h ../misc_api/misc_api_kernel_2.h +tuple.o: ../misc_api/misc_api_kernel_abstract.h ../uintn.h +tuple.o: ../../dlib/logger/logger_kernel_abstract.h ../smart_pointers.h +tuple.o: ../smart_pointers/scoped_ptr.h ../noncopyable.h +tuple.o: ../smart_pointers/scoped_ptr_abstract.h +tuple.o: ../smart_pointers/shared_ptr.h +tuple.o: ../smart_pointers/shared_ptr_abstract.h ../smart_pointers/weak_ptr.h +tuple.o: ../smart_pointers/shared_ptr.h ../smart_pointers/weak_ptr_abstract.h +tuple.o: ../../dlib/logger/extra_logger_headers.h +tuple.o: ../../dlib/logger/logger_kernel_1.h +tuple.o: ../../dlib/logger/logger_config_file.h ../config_reader.h +tuple.o: ../config_reader/config_reader_kernel_1.h +tuple.o: ../config_reader/config_reader_kernel_abstract.h ../../dlib/map.h +tuple.o: ../../dlib/map/map_kernel_1.h ../../dlib/map/map_kernel_abstract.h +tuple.o: ../../dlib/map/map_kernel_c.h ../tokenizer.h +tuple.o: ../tokenizer/tokenizer_kernel_1.h +tuple.o: ../tokenizer/tokenizer_kernel_abstract.h +tuple.o: ../tokenizer/tokenizer_kernel_c.h +tuple.o: ../config_reader/config_reader_thread_safe_1.h +tuple.o: ../config_reader/config_reader_thread_safe_abstract.h +tuple.o: ../../dlib/assert.h ../../dlib/algs.h diff --git a/dlib/test/map.cpp b/dlib/test/map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62a38b74c00ce5e50e5c8a225fec160f0f26151f --- /dev/null +++ b/dlib/test/map.cpp @@ -0,0 +1,441 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.map"); + + template < + typename map + > + void map_kernel_test ( + ) + /*! + requires + - map is an implementation of map/map_kernel_abstract.h and + is instantiated to map int to int + ensures + - runs tests on map for compliance with the specs + !*/ + { + + print_spinner(); + + srand(static_cast(time(0))); + + + + map test, test2; + + enumerable >& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + for (int j = 0; j < 4; ++j) + { + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + + + int a,b; + a = 8; + b = 94; + test.add(a,b); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(test.is_in_domain(8) == true,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + DLIB_CASSERT(test[8] == 94,""); + a = 53; + b = 4; + test.add(a,b); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test.is_in_domain(53) == true,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + DLIB_CASSERT(test[53] == 4,""); + + + swap(test,test2); + + + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(test2.is_in_domain(8) == true,""); + DLIB_CASSERT(test2.is_in_domain(5) == false,""); + DLIB_CASSERT(test2.is_in_domain(0) == false,""); + DLIB_CASSERT(test2.is_in_domain(-999) == false,""); + DLIB_CASSERT(test2.is_in_domain(4999) == false,""); + DLIB_CASSERT(test2[8] == 94,""); + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(test2.is_in_domain(53) == true,""); + DLIB_CASSERT(test2.is_in_domain(5) == false,""); + DLIB_CASSERT(test2.is_in_domain(0) == false,""); + DLIB_CASSERT(test2.is_in_domain(-999) == false,""); + DLIB_CASSERT(test2.is_in_domain(4999) == false,""); + DLIB_CASSERT(test2[53] == 4,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_in_domain(8) == false,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_in_domain(53) == false,""); + DLIB_CASSERT(test.is_in_domain(5) == false,""); + DLIB_CASSERT(test.is_in_domain(0) == false,""); + DLIB_CASSERT(test.is_in_domain(-999) == false,""); + DLIB_CASSERT(test.is_in_domain(4999) == false,""); + + + test.clear(); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + DLIB_CASSERT(test.size() == 10000,""); + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + DLIB_CASSERT(test.size() == 10000,""); + + int count = 0; + a = -1; + while (test.move_next()) + { + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.element().value() == test.element().value(),""); + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.element().value() == test.element().value(),""); + + + DLIB_CASSERT(a < test.element().key(),""); + a = test.element().key(); + ++count; + } + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + DLIB_CASSERT(count == 10000,""); + + test.swap(test2); + + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test2.size() == 10000,""); + count = 0; + a = -1; + test2.reset(); + + test2.move_next(); + test2.element().value() = 99; + DLIB_CASSERT(test2[test2.element().key()] == 99,""); + DLIB_CASSERT(test2.element().value() == 99,""); + + test2.reset(); + + while (test2.move_next()) + { + DLIB_CASSERT(test2[test2.element().key()] == test2.element().value(),""); + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(test2.element().value() == test2.element().value(),""); + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(test2.element().value() == test2.element().value(),""); + DLIB_CASSERT(a < test2.element().key(),""); + a = test2.element().key(); + ++count; + } + DLIB_CASSERT(test2.size() == 10000,""); + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + + + test2.clear(); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.at_start() == true,""); + + while (test.size() < 20000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + // serialize the state of test, then clear test, then + // load the state back into test. + ostringstream sout; + serialize(test,sout); + istringstream sin(sout.str()); + test.clear(); + deserialize(test,sin); + + DLIB_CASSERT(test.at_start() == true,""); + + { + int* array1 = new int[test.size()]; + int* array2 = new int[test.size()]; + + int* tmp1 = array1; + int* tmp2 = array2; + + count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.element().value() == test.element().value(),""); + DLIB_CASSERT(test.element().key() == test.element().key(),""); + DLIB_CASSERT(test.current_element_valid() == true,""); + *tmp1 = test.element().key(); + *tmp2 = test.element().value(); + ++tmp1; + ++tmp2; + ++count; + } + DLIB_CASSERT(count == 20000,""); + + tmp1 = array1; + tmp2 = array2; + for (int i = 0; i < 20000; ++i) + { + DLIB_CASSERT(test.is_in_domain(*tmp1) == true,""); + DLIB_CASSERT(test[*tmp1] == *tmp2,""); + ++tmp1; + ++tmp2; + } + + DLIB_CASSERT(test.size() == 20000,""); + + tmp1 = array1; + tmp2 = array2; + count = 0; + while (test.size() > 10000) + { + test.remove(*tmp1,a,b); + DLIB_CASSERT(*tmp1 == a,""); + DLIB_CASSERT(*tmp2 == b,""); + ++tmp1; + ++tmp2; + ++count; + } + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.move_next()) + { + DLIB_CASSERT(test.element().key() == *tmp1,""); + DLIB_CASSERT(test.element().key() == *tmp1,""); + DLIB_CASSERT(test.element().key() == *tmp1,""); + DLIB_CASSERT(test.element().value() == *tmp2,""); + DLIB_CASSERT(test.element().value() == *tmp2,""); + DLIB_CASSERT(test.element().value() == *tmp2,""); + ++tmp1; + ++tmp2; + ++count; + } + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.size() < 20000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + test2.swap(test); + + count = 0; + a = -1; + while (test2.move_next()) + { + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(test2.element().value() == test2.element().value(),""); + DLIB_CASSERT(test2.element().key() == test2.element().key(),""); + DLIB_CASSERT(a < test2.element().key(),""); + a = test2.element().key(); + ++count; + } + + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test2.size() == 20000,""); + + a = -1; + int c = 0; + while (test2.size()>0) + { + test2.remove_any(b,c); + DLIB_CASSERT( a < b,""); + a = b; + } + + DLIB_CASSERT(test2.size() == 0,""); + delete [] array1; + delete [] array2; + } + + test.clear(); + test2.clear(); + while (test.size() < 10000) + { + a = ::rand(); + b = ::rand(); + if (!test.is_in_domain(a)) + test.add(a,b); + } + + count = 0; + a = -1; + while (test.move_next()) + { + DLIB_CASSERT(a < test.element().key(),""); + DLIB_CASSERT(test[test.element().key()] == test.element().value(),""); + a = test.element().key(); + ++count; + if (count == 5000) + break; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + test.reset(); + + count = 0; + a = -1; + while (test.move_next()) + { + DLIB_CASSERT(a < test.element().key(),""); + a = test.element().key(); + ++count; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + DLIB_CASSERT(count == 10000,""); + + + test.clear(); + test2.clear(); + } + + + { + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + int a = 5; + int b = 6; + test.add(a,b); + a = 7; + b = 8; + test.add(a,b); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test[7] == 8,""); + DLIB_CASSERT(test[5] == 6,""); + DLIB_CASSERT(test.is_in_domain(7),""); + DLIB_CASSERT(test.is_in_domain(5),""); + test.destroy(7); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(!test.is_in_domain(7),""); + DLIB_CASSERT(test.is_in_domain(5),""); + test.destroy(5); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(!test.is_in_domain(7),""); + DLIB_CASSERT(!test.is_in_domain(5),""); + } + + } + + + + + class map_tester : public tester + { + public: + map_tester ( + ) : + tester ("test_map", + "Runs tests on the map component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + map_kernel_test::kernel_1a> (); + dlog << LINFO << "testing kernel_1a_c"; + map_kernel_test::kernel_1a_c>(); + dlog << LINFO << "testing kernel_1b"; + map_kernel_test::kernel_1b> (); + dlog << LINFO << "testing kernel_1b_c"; + map_kernel_test::kernel_1b_c>(); + } + } a; + +} + diff --git a/dlib/test/matrix.cpp b/dlib/test/matrix.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da920d19796de34fdf22edaf277bad0bcf0828d4 --- /dev/null +++ b/dlib/test/matrix.cpp @@ -0,0 +1,1206 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include "../stl_checked.h" +#include "../array.h" + +#include "tester.h" +#include +#include + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.matrix"); + + void matrix_test ( + ) + /*! + ensures + - runs tests on the matrix stuff compliance with the specs + !*/ + { + typedef memory_manager_stateless::kernel_2_2a MM; + print_spinner(); + + const double ident[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 }; + + const double uniform3[] = { + 3, 3, 3, 3, + 3, 3, 3, 3, + 3, 3, 3, 3, + 3, 3, 3, 3 + }; + + const double uniform1[] = { + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1 + }; + + const double uniform0[] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + + const int array[] = { + 42, 58, 9, 1, + 9, 5, 8, 2, + 98, 28, 4, 77, + 9, 2, 44, 88 }; + + const int array2[] = { + 1, 22, 3, + 4, 52, 6, + 7, 8, 9 }; + + const int array2_r[] = { + 52, 6, 4, + 8, 9, 7, + 22, 3, 1 + }; + + const double array_f[] = { + -0.99, + 0.99}; + + + matrix fm(array_f); + + DLIB_CASSERT(fm.size() == 2,""); + matrix dfm(fm); + DLIB_CASSERT(round(fm)(0) == -1,""); + DLIB_CASSERT(round(fm)(1) == 1,""); + DLIB_CASSERT(round(dfm)(0) == -1,""); + DLIB_CASSERT(round(dfm)(1) == 1,""); + DLIB_CASSERT(round(dfm).size() == dfm.size(),""); + + + const int array3[] = { 1, 2, 3, 4 }; + + matrix m3(array2); + matrix dm3; + DLIB_CASSERT(dm3.size() == 0,""); + DLIB_CASSERT(dm3.nr() == 0,""); + DLIB_CASSERT(dm3.nc() == 0,""); + dm3.set_size(3,4); + DLIB_CASSERT(dm3.nr() == 3,""); + DLIB_CASSERT(dm3.nc() == 4,""); + DLIB_CASSERT(dm3.size() == 3*4,""); + dm3.set_size(3,3); + DLIB_CASSERT(dm3.nr() == 3,""); + DLIB_CASSERT(dm3.nc() == 3,""); + dm3 = m3; + dm3(0,0)++; + DLIB_CASSERT( dm3 != m3,""); + dm3 = m3; + DLIB_CASSERT( dm3 == m3,""); + DLIB_CASSERT( abs(sum(squared(normalize(dm3))) - 1.0) < 1e-10,""); + + matrix mrc; + mrc.set_size(3,4); + + set_all_elements(mrc,1); + matrix mrc2; + set_all_elements(mrc2,1); + DLIB_CASSERT((removerc<1,1>(mrc) == mrc2),""); + + matrix m4, m5, m6; + set_all_elements(m4, 4); + set_all_elements(m5, 4); + set_all_elements(m6, 1); + + DLIB_CASSERT(squared(m4) == pointwise_multiply(m4,m4),""); + DLIB_CASSERT(cubed(m4) == pointwise_multiply(m4,m4,m4),""); + DLIB_CASSERT(pow(matrix_cast(m4),2) == squared(matrix_cast(m4)),""); + DLIB_CASSERT(pow(matrix_cast(m4),3) == cubed(matrix_cast(m4)),""); + + matrix dm4; + matrix::kernel_2_2a> dm5; + dm4 = dm4; + dm4 = dm5; + DLIB_CASSERT(dm4.nr() == 0,""); + dm4 = m4; + dm5 = m5; + DLIB_CASSERT(dm4 == dm5,""); + + + DLIB_CASSERT(m4 == m5,""); + DLIB_CASSERT(m6 != m5,""); + m4.swap(m6); + DLIB_CASSERT(m6 == m5,""); + DLIB_CASSERT(m4 != m5,""); + + DLIB_CASSERT(m3.nr() == 3,""); + DLIB_CASSERT(m3.nc() == 3,""); + + matrix v(array3), v2; + DLIB_CASSERT(v.nr() == 4,""); + DLIB_CASSERT(v.nc() == 1,""); + + std::vector stdv(4); + std_vector_c stdv_c(4); + dlib::array::expand_1a_c arr; + arr.expand(4); + for (long i = 0; i < 4; ++i) + stdv[i] = stdv_c[i] = arr[i] = i+1; + + DLIB_CASSERT(vector_to_matrix(stdv)(0) == 1,""); + DLIB_CASSERT(vector_to_matrix(stdv)(1) == 2,""); + DLIB_CASSERT(vector_to_matrix(stdv)(2) == 3,""); + DLIB_CASSERT(vector_to_matrix(stdv)(3) == 4,""); + DLIB_CASSERT(vector_to_matrix(stdv).nr() == 4,""); + DLIB_CASSERT(vector_to_matrix(stdv).nc() == 1,""); + DLIB_CASSERT(vector_to_matrix(stdv).size() == 4,""); + DLIB_CASSERT(equal(trans(vector_to_matrix(stdv))*vector_to_matrix(stdv), trans(v)*v), ""); + + DLIB_CASSERT(vector_to_matrix(stdv_c)(0) == 1,""); + DLIB_CASSERT(vector_to_matrix(stdv_c)(1) == 2,""); + DLIB_CASSERT(vector_to_matrix(stdv_c)(2) == 3,""); + DLIB_CASSERT(vector_to_matrix(stdv_c)(3) == 4,""); + DLIB_CASSERT(vector_to_matrix(stdv_c).nr() == 4,""); + DLIB_CASSERT(vector_to_matrix(stdv_c).nc() == 1,""); + DLIB_CASSERT(vector_to_matrix(stdv_c).size() == 4,""); + DLIB_CASSERT(equal(trans(vector_to_matrix(stdv_c))*vector_to_matrix(stdv_c), trans(v)*v), ""); + + DLIB_CASSERT(vector_to_matrix(arr)(0) == 1,""); + DLIB_CASSERT(vector_to_matrix(arr)(1) == 2,""); + DLIB_CASSERT(vector_to_matrix(arr)(2) == 3,""); + DLIB_CASSERT(vector_to_matrix(arr)(3) == 4,""); + DLIB_CASSERT(vector_to_matrix(arr).nr() == 4,""); + DLIB_CASSERT(vector_to_matrix(arr).nc() == 1,""); + DLIB_CASSERT(vector_to_matrix(arr).size() == 4,""); + DLIB_CASSERT(equal(trans(vector_to_matrix(arr))*vector_to_matrix(arr), trans(v)*v), ""); + + DLIB_CASSERT(v(0) == 1,""); + DLIB_CASSERT(v(1) == 2,""); + DLIB_CASSERT(v(2) == 3,""); + DLIB_CASSERT(v(3) == 4,""); + matrix dv = v; + DLIB_CASSERT((trans(v)*v).size() == 1,""); + DLIB_CASSERT((trans(v)*v).nr() == 1,""); + DLIB_CASSERT((trans(v)*dv).nr() == 1,""); + DLIB_CASSERT((trans(dv)*dv).nr() == 1,""); + DLIB_CASSERT((trans(dv)*v).nr() == 1,""); + DLIB_CASSERT((trans(v)*v).nc() == 1,""); + DLIB_CASSERT((trans(v)*dv).nc() == 1,""); + DLIB_CASSERT((trans(dv)*dv).nc() == 1,""); + DLIB_CASSERT((trans(dv)*v).nc() == 1,""); + DLIB_CASSERT((trans(v)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4,""); + DLIB_CASSERT((trans(dv)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4,""); + DLIB_CASSERT((trans(dv)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4,""); + DLIB_CASSERT((trans(v)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4,""); + + dv = trans(dv)*v; + DLIB_CASSERT(dv.nr() == 1,""); + DLIB_CASSERT(dv.nc() == 1,""); + + dm3 = m3; + DLIB_CASSERT(floor(det(m3)+0.01) == -444,""); + DLIB_CASSERT(floor(det(dm3)+0.01) == -444,""); + DLIB_CASSERT(min(m3) == 1,""); + DLIB_CASSERT(min(dm3) == 1,""); + DLIB_CASSERT(max(m3) == 52,""); + DLIB_CASSERT(max(dm3) == 52,""); + DLIB_CASSERT(sum(m3) == 112,""); + DLIB_CASSERT(sum(dm3) == 112,""); + DLIB_CASSERT(prod(m3) == 41513472,""); + DLIB_CASSERT(prod(dm3) == 41513472,""); + DLIB_CASSERT(prod(diag(m3)) == 1*52*9,""); + DLIB_CASSERT(prod(diag(dm3)) == 1*52*9,""); + DLIB_CASSERT(sum(diag(m3)) == 1+52+9,""); + DLIB_CASSERT(sum(diag(dm3)) == 1+52+9,""); + DLIB_CASSERT((round(10000*m3*inv(m3))/10000 == identity_matrix()),""); + DLIB_CASSERT((round(10000*dm3*inv(m3))/10000 == identity_matrix()),""); + DLIB_CASSERT((round(10000*dm3*inv(dm3))/10000 == identity_matrix()),""); + DLIB_CASSERT((round(10000*m3*inv(dm3))/10000 == identity_matrix()),""); + DLIB_CASSERT(-1*m3 == -m3,""); + DLIB_CASSERT(-1*dm3 == -m3,""); + DLIB_CASSERT(-1*m3 == -dm3,""); + DLIB_CASSERT(-1*dm3 == -dm3,""); + + DLIB_CASSERT(m3 == dm3,""); + m3(1,1) = 99; + DLIB_CASSERT(m3 != dm3,""); + m3 = dm3; + DLIB_CASSERT(m3 == dm3,""); + + matrix mident(ident); + matrix muniform0(uniform0); + matrix muniform1(uniform1); + matrix muniform3(uniform3); + matrix m1(array), m2; + DLIB_CASSERT(m1.nr() == 4,""); + DLIB_CASSERT(m1.nc() == 4,""); + + DLIB_CASSERT(muniform1 + muniform1 + muniform1 == muniform3,""); + DLIB_CASSERT(muniform1*2 + muniform1 + muniform1 - muniform1 == muniform3,""); + DLIB_CASSERT(2*muniform1 + muniform1 + muniform1 - muniform1 == muniform3,""); + DLIB_CASSERT(muniform1 + muniform1 + muniform1 - muniform3 == muniform0,""); + DLIB_CASSERT(muniform3/3 == muniform1,""); + DLIB_CASSERT(v != m1,""); + DLIB_CASSERT(v == v,""); + DLIB_CASSERT(m1 == m1,""); + + muniform0.swap(muniform1); + DLIB_CASSERT((muniform1 == matrix_cast(uniform_matrix())),""); + DLIB_CASSERT((muniform0 == matrix_cast(uniform_matrix())),""); + DLIB_CASSERT((muniform1 == matrix_cast(uniform_matrix(4,4,0))),""); + DLIB_CASSERT((muniform0 == matrix_cast(uniform_matrix(4,4,1))),""); + swap(muniform0,muniform1); + + DLIB_CASSERT((mident == identity_matrix()),""); + DLIB_CASSERT((muniform0 == matrix_cast(uniform_matrix())),""); + DLIB_CASSERT((muniform1 == matrix_cast(uniform_matrix())),""); + DLIB_CASSERT((muniform3 == matrix_cast(uniform_matrix())),""); + DLIB_CASSERT((muniform1*8 == matrix_cast(uniform_matrix())),""); + + set_all_elements(m2,7); + DLIB_CASSERT(m2 == muniform1*7,""); + m2 = array; + DLIB_CASSERT(m2 == m1,""); + + const double m1inv[] = { + -0.00946427624, 0.0593272941, 0.00970564379, -0.00973323731, + 0.0249312057, -0.0590122427, -0.00583102756, 0.00616002729, + -0.00575431149, 0.110081189, -0.00806792253, 0.00462297692, + 0.00327847478, -0.0597669712, 0.00317386196, 0.00990759201 + }; + + m2 = m1inv; + DLIB_CASSERT((round(m2*m1) == identity_matrix()),""); + + DLIB_CASSERT(round(m2*10000) == round(inv(m1)*10000),""); + DLIB_CASSERT(m1 == abs(-1*m1),""); + DLIB_CASSERT(abs(m2) == abs(-1*m2),""); + + DLIB_CASSERT(floor(det(m1)+0.01) == 3297875,"\nm1: \n" << m1 << "\ndet(m1): " << det(m1)); + + + ostringstream sout; + m1 = m2; + serialize(m1,sout); + set_all_elements(m1,0); + istringstream sin(sout.str()); + deserialize(m1,sin); + DLIB_CASSERT(round(100000*m1) == round(100000*m2),"m1: \n" << m1 << endl << "m2: \n" << m2); + + + set_all_elements(v,2); + v2 = pointwise_multiply(v, v*2); + set_all_elements(v,8); + DLIB_CASSERT(v == v2,""); + DLIB_CASSERT(v == tmp(v2),""); + DLIB_CASSERT((v == rotate<2,0>(v)),""); + + m4 = array2; + m5 = array2_r; + DLIB_CASSERT((m5 == rotate<1,1>(m4)),""); + + m5 = array2; + DLIB_CASSERT((m5*2 == pointwise_multiply(m5,uniform_matrix())),""); + DLIB_CASSERT((tmp(m5*2) == tmp(pointwise_multiply(m5,uniform_matrix()))),""); + + v = tmp(v); + + + + + matrix dm10(10,5); + DLIB_CASSERT(dm10.nr() == 10,""); + DLIB_CASSERT(dm10.nc() == 5,""); + set_all_elements(dm10,4); + DLIB_CASSERT(dm10.nr() == 10,""); + DLIB_CASSERT(dm10.nc() == 5,""); + matrix m10; + DLIB_CASSERT(m10.nr() == 10,""); + DLIB_CASSERT(m10.nc() == 5,""); + set_all_elements(m10,4); + DLIB_CASSERT(dm10 == m10,""); + DLIB_CASSERT((clamp<0,3>(dm10) == clamp<0,3>(m10)),""); + DLIB_CASSERT((clamp<0,3>(dm10)(0,2) == 3),""); + + set_all_elements(dm10,1); + set_all_elements(m10,4); + DLIB_CASSERT(4*dm10 == m10,""); + DLIB_CASSERT(5*dm10 - dm10 == m10,""); + DLIB_CASSERT((16*dm10)/4 == m10,""); + DLIB_CASSERT(dm10+dm10+2*dm10 == m10,""); + DLIB_CASSERT(dm10+tmp(dm10+2*dm10) == m10,""); + set_all_elements(dm10,4); + DLIB_CASSERT(dm10 == m10,""); + DLIB_CASSERT(sum(abs(sigmoid(dm10) -sigmoid(m10))) < 1e-10,sum(abs(sigmoid(dm10) -sigmoid(m10))) ); + + + matrix m7; + matrix dm7(7,7); + for (long r= 0; r< dm7.nr(); ++r) + { + for (long c = 0; c < dm7.nc(); ++c) + { + dm7(r,c) = r*c/3.3; + } + } + m7 = dm7; + + DLIB_CASSERT(inv(dm7) == inv(m7),""); + DLIB_CASSERT(det(dm7) == det(m7),""); + DLIB_CASSERT(min(dm7) == min(m7),""); + DLIB_CASSERT(max(dm7) == max(m7),""); + DLIB_CASSERT(abs(sum(dm7) - sum(m7)) < 1e-14,sum(dm7) - sum(m7)); + DLIB_CASSERT(prod(dm7) == prod(m7),""); + DLIB_CASSERT(diag(dm7) == diag(m7),""); + DLIB_CASSERT(trans(dm7) == trans(m7),""); + DLIB_CASSERT(abs(dm7) == abs(m7),""); + DLIB_CASSERT(round(dm7) == round(m7),""); + DLIB_CASSERT(matrix_cast(dm7) == matrix_cast(m7),""); + DLIB_CASSERT((rotate<2,3>(dm7) == rotate<2,3>(m7)),""); + DLIB_CASSERT((sum(pointwise_multiply(dm7,dm7) - pointwise_multiply(m7,m7))) < 1e-10,""); + DLIB_CASSERT((sum(pointwise_multiply(dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7))) < 1e-10,""); + DLIB_CASSERT((sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7))) < 1e-10, + (sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7))) + ); + + + matrix temp(5,5); + matrix dsm(5,5); + matrix sm; + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,1); + + dsm += dsm; + sm += sm; + DLIB_CASSERT(dsm == 2*temp,""); + DLIB_CASSERT(sm == 2*temp,""); + temp = dsm*sm + dsm; + dsm += dsm*sm; + DLIB_CASSERT(temp == dsm,temp - dsm); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,1); + + dsm += dsm; + sm += sm; + DLIB_CASSERT(dsm == 2*temp,""); + DLIB_CASSERT(sm == 2*temp,""); + temp = dsm*sm + dsm; + sm += dsm*sm; + DLIB_CASSERT(temp == sm,temp - sm); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,1); + + dsm += dsm; + sm += sm; + DLIB_CASSERT(dsm == 2*temp,""); + DLIB_CASSERT(sm == 2*temp,""); + temp = sm - dsm*sm ; + sm -= dsm*sm; + DLIB_CASSERT(temp == sm,temp - sm); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,1); + + dsm += dsm; + sm += sm; + DLIB_CASSERT(dsm == 2*temp,""); + DLIB_CASSERT(sm == 2*temp,""); + temp = dsm - dsm*sm ; + dsm -= dsm*sm; + DLIB_CASSERT(temp == dsm,temp - dsm); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,2); + + dsm *= 2; + sm *= 2; + DLIB_CASSERT(dsm == temp,""); + DLIB_CASSERT(sm == temp,""); + dsm /= 2; + sm /= 2; + DLIB_CASSERT(dsm == temp/2,""); + DLIB_CASSERT(sm == temp/2,""); + + dsm += dsm; + sm += sm; + DLIB_CASSERT(dsm == temp,""); + DLIB_CASSERT(sm == temp,""); + dsm += sm; + sm += dsm; + DLIB_CASSERT(dsm == 2*temp,""); + DLIB_CASSERT(sm == temp*3,""); + dsm -= sm; + sm -= dsm; + DLIB_CASSERT(dsm == -temp,""); + DLIB_CASSERT(sm == 4*temp,""); + sm -= sm; + dsm -= dsm; + DLIB_CASSERT(dsm == 0*temp,""); + DLIB_CASSERT(sm == 0*temp,""); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,3); + dsm += sm+sm; + DLIB_CASSERT(dsm == temp,""); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,-1); + dsm -= sm+sm; + DLIB_CASSERT(dsm == temp,""); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,-1); + sm -= dsm+dsm; + DLIB_CASSERT(sm == temp,""); + + set_all_elements(dsm,1); + set_all_elements(sm,1); + set_all_elements(temp,3); + sm += dsm+dsm; + DLIB_CASSERT(sm == temp,""); + + + + // test the implicit conversion to bool stuff + { + matrix bt1(3,1); + matrix bt2; + set_all_elements(bt1,2); + set_all_elements(bt2,3); + + DLIB_CASSERT(trans(bt1)*bt2 == 18,""); + } + { + matrix bt1; + matrix bt2(3,1); + set_all_elements(bt1,2); + set_all_elements(bt2,3); + + DLIB_CASSERT(trans(bt1)*bt2 == 18,""); + } + { + matrix bt1(3,1); + matrix bt2(3,1); + set_all_elements(bt1,2); + set_all_elements(bt2,3); + + DLIB_CASSERT(trans(bt1)*bt2 == 18,""); + } + { + matrix bt1; + matrix bt2; + set_all_elements(bt1,2); + set_all_elements(bt2,3); + + DLIB_CASSERT(trans(bt1)*bt2 == 18,""); + } + + + + { + srand(423452); + const long M = 10; + const long N = 7; + + matrix a(M,N); + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = 10*((double)rand())/RAND_MAX; + } + } + + matrix u(M,N); + matrix w; + matrix v(N,N); + + matrix a2; + a2 = tmp(a/2); + + + svd(a2+a2,u,w,v); + + DLIB_CASSERT( sum(round(1e10*(a - u*w*trans(v)))) == 0,""); + DLIB_CASSERT((round(1e10*trans(u)*u) == 1e10*identity_matrix()),""); + DLIB_CASSERT((round(1e10*trans(v)*v) == 1e10*identity_matrix()),""); + } + + { + srand(423452); + const long M = 1; + const long N = 1; + + matrix a(M,N); + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = 10*((double)rand())/RAND_MAX; + } + } + + matrix u; + matrix w; + matrix v; + + matrix a2; + a2 = tmp(a/2); + + + svd(a2+a2,u,w,v); + + DLIB_CASSERT( sum(round(1e10*(a - u*w*trans(v)))) == 0,""); + DLIB_CASSERT((round(1e10*trans(u)*u) == 1e10*identity_matrix()),""); + DLIB_CASSERT((round(1e10*trans(v)*v) == 1e10*identity_matrix()),""); + } + + + { + srand(53434); + const long M = 5; + const long N = 5; + + matrix a(M,N); + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = 10*((double)rand())/RAND_MAX; + } + } + + matrix u(M,N); + matrix w; + matrix v; + + svd(a,u,w,v); + + DLIB_CASSERT( sum(round(1e10*(a - u*w*trans(v)))) == 0,""); + DLIB_CASSERT((round(1e10*trans(u)*u) == 1e10*identity_matrix()),""); + DLIB_CASSERT((round(1e10*trans(v)*v) == 1e10*identity_matrix()),""); + } + + + { + srand(11234); + const long M = 9; + const long N = 4; + + matrix a(M,N); + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = 10*((double)rand())/RAND_MAX; + } + } + + matrix u; + matrix w; + matrix v; + + svd(a,u,w,v); + + DLIB_CASSERT( sum(round(1e10*(a - u*w*trans(v)))) == 0,""); + DLIB_CASSERT((round(1e10*trans(u)*u) == 1e10*identity_matrix()),""); + DLIB_CASSERT((round(1e10*trans(v)*v) == 1e10*identity_matrix()),""); + } + + + + { + srand(53934); + const long M = 2; + const long N = 4; + + matrix a(M,N); + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = 10*((double)rand())/RAND_MAX; + } + } + + matrix u; + matrix w; + matrix v; + + svd(a,u,w,v); + + DLIB_CASSERT( sum(round(1e10*(a - u*w*trans(v)))) == 0,""); + } + + + { + srand(53234); + const long M = 9; + const long N = 40; + + matrix a(M,N); + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = 10*((double)rand())/RAND_MAX; + } + } + + matrix u; + matrix w; + matrix v; + + svd(a,u,w,v); + + DLIB_CASSERT( sum(round(1e10*(a - u*w*trans(v)))) == 0,""); + } + + + { + matrix a(3,3); + matrix b; + set_all_elements(a,0); + + a(0,0) = 1; + a(1,1) = 2; + a(2,2) = 3; + b = a; + + DLIB_CASSERT(diag(a)(0) == 1,""); + DLIB_CASSERT(diag(a)(1) == 2,""); + DLIB_CASSERT(diag(a)(2) == 3,""); + DLIB_CASSERT(diag(a).nr() == 3,""); + DLIB_CASSERT(diag(a).nc() == 1,""); + + DLIB_CASSERT(diag(b)(0) == 1,""); + DLIB_CASSERT(diag(b)(1) == 2,""); + DLIB_CASSERT(diag(b)(2) == 3,""); + DLIB_CASSERT(diag(b).nr() == 3,""); + DLIB_CASSERT(diag(b).nc() == 1,""); + + DLIB_CASSERT(pointwise_multiply(a,b)(0,0) == 1,""); + DLIB_CASSERT(pointwise_multiply(a,b)(1,1) == 4,""); + DLIB_CASSERT(pointwise_multiply(a,b)(2,2) == 9,""); + DLIB_CASSERT(pointwise_multiply(a,b)(1,0) == 0,""); + DLIB_CASSERT(pointwise_multiply(a,b,a)(1,0) == 0,""); + DLIB_CASSERT(pointwise_multiply(a,b,a,b)(1,0) == 0,""); + + + DLIB_CASSERT(complex_matrix(a,b)(0,0) == std::complex(1,1),""); + DLIB_CASSERT(complex_matrix(a,b)(2,2) == std::complex(3,3),""); + DLIB_CASSERT(complex_matrix(a,b)(2,1) == std::complex(0,0),""); + } + + { + matrix m1, m2; + set_all_elements(m1,2.0); + set_all_elements(m2,1.0/2.0); + DLIB_CASSERT(reciprocal(m1) == m2,""); + DLIB_CASSERT((reciprocal(uniform_matrix(2.0)) == m2),""); + DLIB_CASSERT((round_zeros(uniform_matrix(1e-8f)) == uniform_matrix(0)) ,""); + set_all_elements(m1,2.0); + m2 = m1; + m1(1,0) = static_cast(1e-8); + m2(1,0) = 0; + DLIB_CASSERT(round_zeros(m1) == m2,""); + m1 = round_zeros(m1); + DLIB_CASSERT(m1 == m2,""); + } + + { + matrix > m; + m.set_size(3,3); + set_all_elements(m,uniform_matrix(1)); + DLIB_CASSERT((sum(m) == uniform_matrix(9)),""); + DLIB_CASSERT((round_zeros(sqrt(sum(m)) - uniform_matrix(3)) == uniform_matrix(0)),""); + } + + { + matrix m1; + matrix m2; + m2.set_size(2,2); + + set_all_elements(m1,2); + m2 = uniform_matrix(2); + + m1 = m1 + m2; + DLIB_CASSERT((m1 == uniform_matrix(4)),""); + + set_all_elements(m1,2); + set_all_elements(m2,2); + m1 = m1*m1; + DLIB_CASSERT((m1 == uniform_matrix(8)),""); + + m1(1,0) = 1; + set_all_elements(m2,8); + m2(0,1) = 1; + m1 = trans(m1); + DLIB_CASSERT(m1 == m2,""); + } + + { + matrix m; + matrix m2(2,3); + + set_all_elements(m,1); + DLIB_CASSERT(mean(m) == 1,""); + set_all_elements(m,2); + DLIB_CASSERT(mean(m) == 2,""); + m(0,0) = 1; + m(0,1) = 1; + m(0,2) = 1; + DLIB_CASSERT(abs(mean(m) - 1.5) < 1e-10,""); + DLIB_CASSERT(abs(variance(m) - 0.3) < 1e-10,""); + + set_all_elements(m2,1); + DLIB_CASSERT(mean(m2) == 1,""); + set_all_elements(m2,2); + DLIB_CASSERT(mean(m2) == 2,""); + m2(0,0) = 1; + m2(0,1) = 1; + m2(0,2) = 1; + DLIB_CASSERT(abs(mean(m2) - 1.5) < 1e-10,""); + DLIB_CASSERT(abs(variance(m2) - 0.3) < 1e-10,""); + + set_all_elements(m,0); + DLIB_CASSERT(abs(variance(m)) < 1e-10,""); + set_all_elements(m,1); + DLIB_CASSERT(abs(variance(m)) < 1e-10,""); + set_all_elements(m,23.4); + DLIB_CASSERT(abs(variance(m)) < 1e-10,""); + } + + { + matrix,2,2,MM> m; + set_all_elements(m,uniform_matrix(1)); + DLIB_CASSERT((round_zeros(variance(m)) == uniform_matrix(0)),""); + DLIB_CASSERT((round_zeros(mean(m)) == uniform_matrix(1)),""); + m(0,0) = uniform_matrix(9); + DLIB_CASSERT((round_zeros(variance(m)) == uniform_matrix(16)),""); + DLIB_CASSERT((round_zeros(mean(m)) == uniform_matrix(3)),""); + } + + { + matrix,2,2,MM> m; + set_all_elements(m,complex(1,2)); + DLIB_CASSERT((conj(m) == uniform_matrix,2,2>(conj(m(0,0)))),""); + DLIB_CASSERT((real(m) == uniform_matrix(1)),""); + DLIB_CASSERT((imag(m) == uniform_matrix(2)),""); + DLIB_CASSERT((sum(abs(norm(m) - uniform_matrix(5))) < 1e-10 ),norm(m)); + + } + + { + matrix m(5,5); + + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m(r,c) = r*c; + } + } + + m = cos(exp(m)); + + + matrix mi = pinv(m ); + DLIB_CASSERT(mi.nr() == m.nc(),""); + DLIB_CASSERT(mi.nc() == m.nr(),""); + DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix())),""); + DLIB_CASSERT((equal(round_zeros(m*mi,0.000001) , identity_matrix())),""); + } + { + matrix m(5,5); + + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m(r,c) = r*c; + } + } + + m = cos(exp(m)); + + + matrix mi = pinv(m ); + DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix())),""); + } + + { + matrix m(5,5); + + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m(r,c) = r*c; + } + } + + m = cos(exp(m)); + + + matrix mi = pinv(m ); + DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix())),""); + } + + + { + matrix m(5,5); + + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m(r,c) = r*c; + } + } + + m = cos(exp(m)); + + + matrix mi = pinv(m ); + DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix())),""); + } + + + { + matrix m(5,2); + + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m(r,c) = r*c; + } + } + + m = cos(exp(m)); + + + matrix mi = pinv(m ); + DLIB_CASSERT(mi.nr() == m.nc(),""); + DLIB_CASSERT(mi.nc() == m.nr(),""); + } + + { + matrix a1(5,1); + matrix a2(1,5); + matrix b1(5,1); + matrix b2(1,5); + matrix c1(5,1); + matrix c2(1,5); + matrix d1(5,1); + matrix d2(1,5); + + for (long i = 0; i < 5; ++i) + { + a1(i) = i; + a2(i) = i; + b1(i) = i; + b2(i) = i; + c1(i) = i; + c2(i) = i; + d1(i) = i; + d2(i) = i; + } + + DLIB_CASSERT(a1 == trans(a2),""); + DLIB_CASSERT(a1 == trans(b2),""); + DLIB_CASSERT(a1 == trans(c2),""); + DLIB_CASSERT(a1 == trans(d2),""); + + DLIB_CASSERT(a1 == b1,""); + DLIB_CASSERT(a1 == c1,""); + DLIB_CASSERT(a1 == d1,""); + + DLIB_CASSERT(trans(a1) == c2,""); + DLIB_CASSERT(trans(b1) == c2,""); + DLIB_CASSERT(trans(c1) == c2,""); + DLIB_CASSERT(trans(d1) == c2,""); + + DLIB_CASSERT(sum(a1) == 10,""); + DLIB_CASSERT(sum(a2) == 10,""); + DLIB_CASSERT(sum(b1) == 10,""); + DLIB_CASSERT(sum(b2) == 10,""); + DLIB_CASSERT(sum(c1) == 10,""); + DLIB_CASSERT(sum(c2) == 10,""); + DLIB_CASSERT(sum(d1) == 10,""); + DLIB_CASSERT(sum(d2) == 10,""); + + const matrix orig1 = a1; + const matrix orig2 = a2; + + ostringstream sout; + serialize(a1,sout); + serialize(a2,sout); + serialize(b1,sout); + serialize(b2,sout); + serialize(c1,sout); + serialize(c2,sout); + serialize(d1,sout); + serialize(d2,sout); + + DLIB_CASSERT(a1 == orig1,""); + DLIB_CASSERT(a2 == orig2,""); + DLIB_CASSERT(b1 == orig1,""); + DLIB_CASSERT(b2 == orig2,""); + DLIB_CASSERT(c1 == orig1,""); + DLIB_CASSERT(c2 == orig2,""); + DLIB_CASSERT(d1 == orig1,""); + DLIB_CASSERT(d2 == orig2,""); + + set_all_elements(a1,99); + set_all_elements(a2,99); + set_all_elements(b1,99); + set_all_elements(b2,99); + set_all_elements(c1,99); + set_all_elements(c2,99); + set_all_elements(d1,99); + set_all_elements(d2,99); + + DLIB_CASSERT(a1 != orig1,""); + DLIB_CASSERT(a2 != orig2,""); + DLIB_CASSERT(b1 != orig1,""); + DLIB_CASSERT(b2 != orig2,""); + DLIB_CASSERT(c1 != orig1,""); + DLIB_CASSERT(c2 != orig2,""); + DLIB_CASSERT(d1 != orig1,""); + DLIB_CASSERT(d2 != orig2,""); + + istringstream sin(sout.str()); + + deserialize(a1,sin); + deserialize(a2,sin); + deserialize(b1,sin); + deserialize(b2,sin); + deserialize(c1,sin); + deserialize(c2,sin); + deserialize(d1,sin); + deserialize(d2,sin); + + DLIB_CASSERT(a1 == orig1,""); + DLIB_CASSERT(a2 == orig2,""); + DLIB_CASSERT(b1 == orig1,""); + DLIB_CASSERT(b2 == orig2,""); + DLIB_CASSERT(c1 == orig1,""); + DLIB_CASSERT(c2 == orig2,""); + DLIB_CASSERT(d1 == orig1,""); + DLIB_CASSERT(d2 == orig2,""); + + + } + + { + matrix a(5); + matrix b(5); + matrix c(5); + matrix d(5); + DLIB_CASSERT(a.nr() == 1,""); + DLIB_CASSERT(a.nc() == 5,""); + DLIB_CASSERT(c.nr() == 1,""); + DLIB_CASSERT(c.nc() == 5,""); + + DLIB_CASSERT(b.nc() == 1,""); + DLIB_CASSERT(b.nr() == 5,""); + DLIB_CASSERT(d.nc() == 1,""); + DLIB_CASSERT(d.nr() == 5,""); + } + + { + matrix a; + matrix b; + matrix c; + matrix d; + + a.set_size(5); + b.set_size(5); + c.set_size(5); + d.set_size(5); + + DLIB_CASSERT(a.nr() == 1,""); + DLIB_CASSERT(a.nc() == 5,""); + DLIB_CASSERT(c.nr() == 1,""); + DLIB_CASSERT(c.nc() == 5,""); + + DLIB_CASSERT(b.nc() == 1,""); + DLIB_CASSERT(b.nr() == 5,""); + DLIB_CASSERT(d.nc() == 1,""); + DLIB_CASSERT(d.nr() == 5,""); + } + + { + matrix a(1,5); + matrix b(5,1); + + set_all_elements(a,1); + set_all_elements(b,1); + + + a = a*b; + + DLIB_CASSERT(a(0) == 5,""); + } + + { + matrix a(6,7); + + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a(r,c) = r*a.nc() + c; + } + } + + + + DLIB_CASSERT(rowm(a,1).nr() == 1,""); + DLIB_CASSERT(rowm(a,1).nc() == a.nc(),""); + DLIB_CASSERT(colm(a,1).nr() == a.nr(),""); + DLIB_CASSERT(colm(a,1).nc() == 1,""); + + for (long c = 0; c < a.nc(); ++c) + { + DLIB_CASSERT( rowm(a,1)(c) == 1*a.nc() + c,""); + } + + for (long r = 0; r < a.nr(); ++r) + { + DLIB_CASSERT( colm(a,1)(r) == r*a.nc() + 1,""); + } + + rectangle rect(2, 1, 3+2-1, 2+1-1); + DLIB_CASSERT(get_rect(a).contains(get_rect(a)), ""); + DLIB_CASSERT(get_rect(a).contains(rect), ""); + for (long r = 0; r < 2; ++r) + { + for (long c = 0; c < 3; ++c) + { + DLIB_CASSERT(subm(a,1,2,2,3)(r,c) == (r+1)*a.nc() + c+2,""); + DLIB_CASSERT(subm(a,1,2,2,3) == subm(a,rect),""); + } + } + + DLIB_CASSERT(subm(a,rectangle()).nr() == 0,""); + DLIB_CASSERT(subm(a,rectangle()).nc() == 0,""); + + } + + { + array2d::kernel_1a_c a; + a.set_size(6,7); + + + for (long r = 0; r < a.nr(); ++r) + { + for (long c = 0; c < a.nc(); ++c) + { + a[r][c] = r*a.nc() + c; + } + } + + + + DLIB_CASSERT(rowm(array_to_matrix(a),1).nr() == 1,""); + DLIB_CASSERT(rowm(array_to_matrix(a),1).nc() == a.nc(),""); + DLIB_CASSERT(colm(array_to_matrix(a),1).nr() == a.nr(),""); + DLIB_CASSERT(colm(array_to_matrix(a),1).nc() == 1,""); + + for (long c = 0; c < a.nc(); ++c) + { + DLIB_CASSERT( rowm(array_to_matrix(a),1)(c) == 1*a.nc() + c,""); + } + + for (long r = 0; r < a.nr(); ++r) + { + DLIB_CASSERT( colm(array_to_matrix(a),1)(r) == r*a.nc() + 1,""); + } + + for (long r = 0; r < 2; ++r) + { + for (long c = 0; c < 3; ++c) + { + DLIB_CASSERT(subm(array_to_matrix(a),1,2,2,3)(r,c) == (r+1)*a.nc() + c+2,""); + } + } + + + } + + { + array2d::kernel_1a_c m; + m.set_size(5,5); + + for (long r = 0; r < m.nr(); ++r) + { + for (long c = 0; c < m.nc(); ++c) + { + m[r][c] = r*c; + } + } + + + matrix mi = pinv(cos(exp(array_to_matrix(m))) ); + DLIB_CASSERT(mi.nr() == m.nc(),""); + DLIB_CASSERT(mi.nc() == m.nr(),""); + DLIB_CASSERT((equal(round_zeros(mi*cos(exp(array_to_matrix(m))),0.000001) , identity_matrix())),""); + DLIB_CASSERT((equal(round_zeros(cos(exp(array_to_matrix(m)))*mi,0.000001) , identity_matrix())),""); + } + + } + + + + + + + class matrix_tester : public tester + { + public: + matrix_tester ( + ) : + tester ("test_matrix", + "Runs tests on the matrix component.") + {} + + void perform_test ( + ) + { + matrix_test(); + } + } a; + +} + + diff --git a/dlib/test/md5.cpp b/dlib/test/md5.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa09e94a7f6534103c0ca6242e592df8faa7a06f --- /dev/null +++ b/dlib/test/md5.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.md5"); + + void md5_test ( + ) + /*! + ensures + - runs tests on the md5 stuff compliance with the specs + !*/ + { + + DLIB_CASSERT(md5 ("") == "d41d8cd98f00b204e9800998ecf8427e",""); + DLIB_CASSERT(md5 ("a") == "0cc175b9c0f1b6a831c399e269772661",""); + DLIB_CASSERT(md5 ("abc") == "900150983cd24fb0d6963f7d28e17f72",""); + DLIB_CASSERT(md5 ("message digest") == "f96b697d7cb7938d525a2f31aaf161d0",""); + DLIB_CASSERT(md5 ("abcdefghijklmnopqrstuvwxyz") == "c3fcd3d76192e4007dfb496cca67e13b",""); + DLIB_CASSERT(md5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") == "d174ab98d277d9f5a5611c2c9f419d9f",""); + DLIB_CASSERT(md5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") == "57edf4a22be3c955ac49da2e2107b67a",""); + + + } + + + class md5_tester : public tester + { + public: + md5_tester ( + ) : + tester ("test_md5", + "Runs tests on the md5 component.") + {} + + void perform_test ( + ) + { + md5_test(); + } + } a; + +} + + + diff --git a/dlib/test/member_function_pointer.cpp b/dlib/test/member_function_pointer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..843c06e7c8d198692df8bc5af28542a479779e1c --- /dev/null +++ b/dlib/test/member_function_pointer.cpp @@ -0,0 +1,402 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.member_function_pointer"); + + class mfp_test_helper + { + public: + mfp_test_helper ( + ): i(-1) {} + + + int i; + + + void go0 ( + ) { i = 0; } + void go1 ( + int + ) { i = 1; } + void go2 ( + int,int + ) { i = 2; } + void go3 ( + int,int,int + ) { i = 3; } + void go4 ( + int,int,int,int + ) { i = 4; } + }; + + template < + template class mfp + > + void member_function_pointer_kernel_test ( + ) + /*! + requires + - mfp is an implementation of member_function_pointer/member_function_pointer_kernel_abstract.h + ensures + - runs tests on mfp for compliance with the specs + !*/ + { + + + mfp_test_helper helper; + + mfp<> a0, b0; + mfp a1, b1; + mfp a2, b2; + mfp a3, b3; + mfp a4, b4; + + member_function_pointer_kernel_c > a0c, b0c; + member_function_pointer_kernel_c > a1c, b1c; + member_function_pointer_kernel_c > a2c, b2c; + member_function_pointer_kernel_c > a3c, b3c; + member_function_pointer_kernel_c > a4c, b4c; + + DLIB_CASSERT(a0c == b0c, ""); + DLIB_CASSERT(a1c == b1c, ""); + DLIB_CASSERT(a2c == b2c, ""); + DLIB_CASSERT(a3c == b3c, ""); + DLIB_CASSERT(a4c == b4c, ""); + DLIB_CASSERT((a0c != b0c) == false, ""); + DLIB_CASSERT((a1c != b1c) == false, ""); + DLIB_CASSERT((a2c != b2c) == false, ""); + DLIB_CASSERT((a3c != b3c) == false, ""); + DLIB_CASSERT((a4c != b4c) == false, ""); + + DLIB_CASSERT(a0.is_set() == false,""); + DLIB_CASSERT(b0.is_set() == false,""); + DLIB_CASSERT(a0c.is_set() == false,""); + DLIB_CASSERT(b0c.is_set() == false,""); + + DLIB_CASSERT(a1.is_set() == false,""); + DLIB_CASSERT(b1.is_set() == false,""); + DLIB_CASSERT(a1c.is_set() == false,""); + DLIB_CASSERT(b1c.is_set() == false,""); + + DLIB_CASSERT(a2.is_set() == false,""); + DLIB_CASSERT(b2.is_set() == false,""); + DLIB_CASSERT(a2c.is_set() == false,""); + DLIB_CASSERT(b2c.is_set() == false,""); + + DLIB_CASSERT(a3.is_set() == false,""); + DLIB_CASSERT(b3.is_set() == false,""); + DLIB_CASSERT(a3c.is_set() == false,""); + DLIB_CASSERT(b3c.is_set() == false,""); + + DLIB_CASSERT(a4.is_set() == false,""); + DLIB_CASSERT(b4.is_set() == false,""); + DLIB_CASSERT(a4c.is_set() == false,""); + DLIB_CASSERT(b4c.is_set() == false,""); + + a0.set(helper,&mfp_test_helper::go0); + a0c.set(helper,&mfp_test_helper::go0); + DLIB_CASSERT(a0.is_set() == true,""); + DLIB_CASSERT(a0c.is_set() == true,""); + DLIB_CASSERT(b0.is_set() == false,""); + DLIB_CASSERT(b0c.is_set() == false,""); + + a0 = a0; + DLIB_CASSERT(a0 == a0, ""); + DLIB_CASSERT(!(a0 != a0),""); + DLIB_CASSERT(a0.is_set() == true,""); + DLIB_CASSERT(a0c.is_set() == true,""); + DLIB_CASSERT(b0.is_set() == false,""); + DLIB_CASSERT(b0c.is_set() == false,""); + + swap(a0,b0); + swap(a0c,b0c); + DLIB_CASSERT(a0.is_set() == false,""); + DLIB_CASSERT(a0c.is_set() == false,""); + DLIB_CASSERT(b0.is_set() == true,""); + DLIB_CASSERT(b0c.is_set() == true,""); + + a0 = b0; + DLIB_CASSERT(a0 == a0, ""); + DLIB_CASSERT(a0 == b0, ""); + DLIB_CASSERT(!(a0 != b0),""); + DLIB_CASSERT(a0.is_set() == true,""); + DLIB_CASSERT(a0c.is_set() == false,""); + DLIB_CASSERT(b0.is_set() == true,""); + DLIB_CASSERT(b0c.is_set() == true,""); + + + a0.clear(); + a0c.clear(); + b0.clear(); + b0c.clear(); + DLIB_CASSERT(a0.is_set() == false,""); + DLIB_CASSERT(a0c.is_set() == false,""); + DLIB_CASSERT(b0.is_set() == false,""); + DLIB_CASSERT(b0c.is_set() == false,""); + + + a1.set(helper,&mfp_test_helper::go1); + a1c.set(helper,&mfp_test_helper::go1); + DLIB_CASSERT(a1.is_set() == true,""); + DLIB_CASSERT(a1c.is_set() == true,""); + DLIB_CASSERT(b1.is_set() == false,""); + DLIB_CASSERT(b1c.is_set() == false,""); + swap(a1,b1); + swap(a1c,b1c); + DLIB_CASSERT(a1.is_set() == false,""); + DLIB_CASSERT(a1c.is_set() == false,""); + DLIB_CASSERT(b1.is_set() == true,""); + DLIB_CASSERT(b1c.is_set() == true,""); + + + a1 = b1; + DLIB_CASSERT(a1 == a1, ""); + DLIB_CASSERT(a1 == b1, ""); + DLIB_CASSERT(!(a1 != b1),""); + DLIB_CASSERT(a1.is_set() == true,""); + DLIB_CASSERT(a1c.is_set() == false,""); + DLIB_CASSERT(b1.is_set() == true,""); + DLIB_CASSERT(b1c.is_set() == true,""); + + + a1.clear(); + a1c.clear(); + b1.clear(); + b1c.clear(); + DLIB_CASSERT(a1.is_set() == false,""); + DLIB_CASSERT(a1c.is_set() == false,""); + DLIB_CASSERT(b1.is_set() == false,""); + DLIB_CASSERT(b1c.is_set() == false,""); + + + a2.set(helper,&mfp_test_helper::go2); + a2c.set(helper,&mfp_test_helper::go2); + DLIB_CASSERT(a2.is_set() == true,""); + DLIB_CASSERT(a2c.is_set() == true,""); + DLIB_CASSERT(b2.is_set() == false,""); + DLIB_CASSERT(b2c.is_set() == false,""); + swap(a2,b2); + swap(a2c,b2c); + DLIB_CASSERT(a2.is_set() == false,""); + DLIB_CASSERT(a2c.is_set() == false,""); + DLIB_CASSERT(b2.is_set() == true,""); + DLIB_CASSERT(b2c.is_set() == true,""); + + a2 = b2; + DLIB_CASSERT(a2 == a2, ""); + DLIB_CASSERT(a2 == b2, ""); + DLIB_CASSERT(!(a2 != b2),""); + DLIB_CASSERT(a2.is_set() == true,""); + DLIB_CASSERT(a2c.is_set() == false,""); + DLIB_CASSERT(b2.is_set() == true,""); + DLIB_CASSERT(b2c.is_set() == true,""); + + a2.clear(); + a2c.clear(); + b2.clear(); + b2c.clear(); + DLIB_CASSERT(a2.is_set() == false,""); + DLIB_CASSERT(a2c.is_set() == false,""); + DLIB_CASSERT(b2.is_set() == false,""); + DLIB_CASSERT(b2c.is_set() == false,""); + + + a3.set(helper,&mfp_test_helper::go3); + a3c.set(helper,&mfp_test_helper::go3); + DLIB_CASSERT(a3.is_set() == true,""); + DLIB_CASSERT(a3c.is_set() == true,""); + DLIB_CASSERT(b3.is_set() == false,""); + DLIB_CASSERT(b3c.is_set() == false,""); + swap(a3,b3); + swap(a3c,b3c); + DLIB_CASSERT(a3.is_set() == false,""); + DLIB_CASSERT(a3c.is_set() == false,""); + DLIB_CASSERT(b3.is_set() == true,""); + DLIB_CASSERT(b3c.is_set() == true,""); + + a3 = b3; + DLIB_CASSERT(a3 == a3, ""); + DLIB_CASSERT(a3 == b3, ""); + DLIB_CASSERT(!(a3 != b3),""); + DLIB_CASSERT(a3.is_set() == true,""); + DLIB_CASSERT(a3c.is_set() == false,""); + DLIB_CASSERT(b3.is_set() == true,""); + DLIB_CASSERT(b3c.is_set() == true,""); + + + a3.clear(); + a3c.clear(); + b3.clear(); + b3c.clear(); + DLIB_CASSERT(a3.is_set() == false,""); + DLIB_CASSERT(a3c.is_set() == false,""); + DLIB_CASSERT(b3.is_set() == false,""); + DLIB_CASSERT(b3c.is_set() == false,""); + + + a4.set(helper,&mfp_test_helper::go4); + a4c.set(helper,&mfp_test_helper::go4); + DLIB_CASSERT(a4.is_set() == true,""); + DLIB_CASSERT(a4c.is_set() == true,""); + DLIB_CASSERT(b4.is_set() == false,""); + DLIB_CASSERT(b4c.is_set() == false,""); + swap(a4,b4); + swap(a4c,b4c); + DLIB_CASSERT(a4.is_set() == false,""); + DLIB_CASSERT(a4c.is_set() == false,""); + DLIB_CASSERT(b4.is_set() == true,""); + DLIB_CASSERT(b4c.is_set() == true,""); + + a4 = b4; + a4 = b4; + a4 = b4; + a4 = b4; + DLIB_CASSERT(a4 == a4, ""); + DLIB_CASSERT(a4 == b4, ""); + DLIB_CASSERT(!(a4 != b4),""); + DLIB_CASSERT(a4.is_set() == true,""); + DLIB_CASSERT(a4c.is_set() == false,""); + DLIB_CASSERT(b4.is_set() == true,""); + DLIB_CASSERT(b4c.is_set() == true,""); + + + a4.clear(); + a4c.clear(); + b4.clear(); + b4c.clear(); + DLIB_CASSERT(a4.is_set() == false,""); + DLIB_CASSERT(a4c.is_set() == false,""); + DLIB_CASSERT(b4.is_set() == false,""); + DLIB_CASSERT(b4c.is_set() == false,""); + + + a0.set(helper,&mfp_test_helper::go0); + a0c.set(helper,&mfp_test_helper::go0); + b0 = a0; + b0c = a0c; + helper.i = -1; + a0(); + DLIB_CASSERT(helper.i == 0,""); + helper.i = -1; + b0(); + DLIB_CASSERT(helper.i == 0,""); + helper.i = -1; + a0c(); + DLIB_CASSERT(helper.i == 0,""); + helper.i = -1; + b0c(); + DLIB_CASSERT(helper.i == 0,""); + + + a1.set(helper,&mfp_test_helper::go1); + a1c.set(helper,&mfp_test_helper::go1); + b1 = a1; + b1c = a1c; + helper.i = -1; + a1(0); + DLIB_CASSERT(helper.i == 1,""); + helper.i = -1; + b1(0); + DLIB_CASSERT(helper.i == 1,""); + helper.i = -1; + a1c(0); + DLIB_CASSERT(helper.i == 1,""); + helper.i = -1; + b1c(0); + DLIB_CASSERT(helper.i == 1,""); + + + a2.set(helper,&mfp_test_helper::go2); + a2c.set(helper,&mfp_test_helper::go2); + b2 = a2; + b2c = a2c; + helper.i = -1; + a2(0,0); + DLIB_CASSERT(helper.i == 2,""); + helper.i = -1; + b2(0,0); + DLIB_CASSERT(helper.i == 2,""); + helper.i = -1; + a2c(0,0); + DLIB_CASSERT(helper.i == 2,""); + helper.i = -1; + b2c(0,0); + DLIB_CASSERT(helper.i == 2,""); + + + a3.set(helper,&mfp_test_helper::go3); + a3c.set(helper,&mfp_test_helper::go3); + b3 = a3; + b3c = a3c; + helper.i = -1; + a3(0,0,0); + DLIB_CASSERT(helper.i == 3,""); + helper.i = -1; + b3(0,0,0); + DLIB_CASSERT(helper.i == 3,""); + helper.i = -1; + a3c(0,0,0); + DLIB_CASSERT(helper.i == 3,""); + helper.i = -1; + b3c(0,0,0); + DLIB_CASSERT(helper.i == 3,""); + + + a4.set(helper,&mfp_test_helper::go4); + a4c.set(helper,&mfp_test_helper::go4); + b4 = a4; + b4c = a4c; + helper.i = -1; + a4(0,0,0,0); + DLIB_CASSERT(helper.i == 4,""); + helper.i = -1; + b4(0,0,0,0); + DLIB_CASSERT(helper.i == 4,""); + helper.i = -1; + a4c(0,0,0,0); + DLIB_CASSERT(helper.i == 4,""); + helper.i = -1; + b4c(0,0,0,0); + DLIB_CASSERT(helper.i == 4,""); + + + + } + + + + class member_function_pointer_tester : public tester + { + public: + member_function_pointer_tester ( + ) : + tester ("test_member_function_pointer", + "Runs tests on the member_function_pointer component.") + {} + + void perform_test ( + ) + { + member_function_pointer_kernel_test(); + } + } a; + +} + + diff --git a/dlib/test/metaprogramming.cpp b/dlib/test/metaprogramming.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9078a52ad3bba2d6cb8a758abcf25bda2585e2fb --- /dev/null +++ b/dlib/test/metaprogramming.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.metaprogramming"); + + + void metaprogramming_test ( + ) + /*! + ensures + - runs tests on template metaprogramming objects and functions for compliance with the specs + !*/ + { + + print_spinner(); + + DLIB_CASSERT(is_signed_type::value == true,""); + DLIB_CASSERT(is_signed_type::value == true,""); + DLIB_CASSERT(is_signed_type::value == true,""); + DLIB_CASSERT(is_signed_type::value == true,""); + DLIB_CASSERT(is_unsigned_type::value == false,""); + DLIB_CASSERT(is_unsigned_type::value == false,""); + DLIB_CASSERT(is_unsigned_type::value == false,""); + DLIB_CASSERT(is_unsigned_type::value == false,""); + + DLIB_CASSERT(is_unsigned_type::value == true,""); + DLIB_CASSERT(is_unsigned_type::value == true,""); + DLIB_CASSERT(is_unsigned_type::value == true,""); + DLIB_CASSERT(is_unsigned_type::value == true,""); + DLIB_CASSERT(is_signed_type::value == false,""); + DLIB_CASSERT(is_signed_type::value == false,""); + DLIB_CASSERT(is_signed_type::value == false,""); + DLIB_CASSERT(is_signed_type::value == false,""); + + + COMPILE_TIME_ASSERT(is_signed_type::value == true); + COMPILE_TIME_ASSERT(is_signed_type::value == true); + COMPILE_TIME_ASSERT(is_signed_type::value == true); + COMPILE_TIME_ASSERT(is_signed_type::value == true); + COMPILE_TIME_ASSERT(is_unsigned_type::value == false); + COMPILE_TIME_ASSERT(is_unsigned_type::value == false); + COMPILE_TIME_ASSERT(is_unsigned_type::value == false); + COMPILE_TIME_ASSERT(is_unsigned_type::value == false); + + COMPILE_TIME_ASSERT(is_unsigned_type::value == true); + COMPILE_TIME_ASSERT(is_unsigned_type::value == true); + COMPILE_TIME_ASSERT(is_unsigned_type::value == true); + COMPILE_TIME_ASSERT(is_unsigned_type::value == true); + COMPILE_TIME_ASSERT(is_signed_type::value == false); + COMPILE_TIME_ASSERT(is_signed_type::value == false); + COMPILE_TIME_ASSERT(is_signed_type::value == false); + COMPILE_TIME_ASSERT(is_signed_type::value == false); + + + } + + + + + class metaprogramming_tester : public tester + { + public: + metaprogramming_tester ( + ) : + tester ("test_metaprogramming", + "Runs tests on the metaprogramming objects and functions.") + {} + + void perform_test ( + ) + { + metaprogramming_test(); + } + } a; + +} + + + diff --git a/dlib/test/multithreaded_object.cpp b/dlib/test/multithreaded_object.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e27125a40ab5f9f9b47eca5430f0344c31517a7d --- /dev/null +++ b/dlib/test/multithreaded_object.cpp @@ -0,0 +1,311 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include + +#include +#include "tester.h" + +namespace +{ + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.multithreaded_object"); + + dlib::mutex cm; + int count; + + class test1 : multithreaded_object + { + public: + test1 () + { + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + clear(); + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + } + + ~test1 () + { + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + stop(); + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + wait(); + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + } + + private: + }; + + class test2 : private multithreaded_object + { + public: + test2() + { + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + register_thread(*this,&test2::thread); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + clear(); + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + register_thread(*this,&test2::thread); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + } + + ~test2() + { + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + stop(); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + wait(); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + } + + private: + + void thread() + { + auto_mutex M(cm); + ++count; + } + + }; + + class test3_c1 : private multithreaded_object + { + public: + test3_c1() + { + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + register_thread(*this,&test3_c1::thread); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + start(); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(is_running() == true,""); + } + + ~test3_c1() + { + DLIB_CASSERT(number_of_threads_registered() == 1,""); + stop(); + DLIB_CASSERT(is_running() == false,""); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + wait(); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + } + + private: + + void thread() + { + cm.lock(); + ++count; + cm.unlock(); + // wait until we are supposed to stop + while (!should_stop()) + dlib::sleep(1); + } + + }; + + class test4_c2 : private multithreaded_object + { + public: + test4_c2() + { + DLIB_CASSERT(number_of_threads_registered() == 0,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + register_thread(*this,&test4_c2::thread); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + start(); + DLIB_CASSERT(number_of_threads_registered() == 1,""); + DLIB_CASSERT(number_of_threads_alive() == 1,""); + DLIB_CASSERT(is_running() == true,""); + register_thread(*this,&test4_c2::thread); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == true,""); + start(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == true,""); + start(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == true,""); + start(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == true,""); + start(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == true,""); + pause(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == false,""); + } + + ~test4_c2() + { + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 2,""); + DLIB_CASSERT(is_running() == false,"is_running(): " << is_running()); + stop(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(is_running() == false,""); + wait(); + DLIB_CASSERT(number_of_threads_registered() == 2,""); + DLIB_CASSERT(number_of_threads_alive() == 0,""); + DLIB_CASSERT(is_running() == false,""); + } + + private: + + void thread() + { + auto_mutex M(cm); + ++count; + while (!should_stop()) + dlib::sleep(10); + } + + }; + + + class test5 : private multithreaded_object + { + public: + test5() + { + register_thread(*this,&test5::thread1); + register_thread(*this,&test5::thread2); + register_thread(*this,&test5::thread3); + register_thread(*this,&test5::thread3); + start(); + } + + ~test5() + { + stop(); + wait(); + } + + private: + + void thread1() + { + while (!should_stop()) + dlib::sleep(10); + } + + void thread2() + { + while (!should_stop()) + dlib::sleep(10); + } + + void thread3() + { + while (!should_stop()) + dlib::sleep(10); + } + + }; + + + void multithreaded_object_test ( + ) + /*! + ensures + - runs tests on dlib::multithreaded_object for compliance with the specs + !*/ + { + + count = 0; + + for (int i = 0; i < 5; ++i) + { + { + test1 a1; + test2 a2; + test3_c1 a3; + test4_c2 a4; + test5 a5; + } + DLIB_CASSERT(count == (i+1)*3,""); + } + count = 0; + + for (int i = 0; i < 5; ++i) + { + { + test1 a1; + test2 a2; + test3_c1 a3; + test4_c2 a4; + test5 a5; + dlib::sleep(50); + } + DLIB_CASSERT(count == (i+1)*3,""); + } + } + + + class multithreaded_object_tester : public tester + { + public: + multithreaded_object_tester ( + ) : + tester ("test_multithreaded_object", + "Runs tests on the multithreaded_object component.") + {} + + void perform_test ( + ) + { + multithreaded_object_test(); + } + } a; + +} + + + diff --git a/dlib/test/pipe.cpp b/dlib/test/pipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..699ae9796a69dde53c2ceb329b728a814ef09f05 --- /dev/null +++ b/dlib/test/pipe.cpp @@ -0,0 +1,541 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.pipe"); + + namespace pipe_kernel_test_helpers + { + const unsigned long proc1_count = 10000; + mutex m; + signaler s(m); + unsigned long threads_running = 0; + bool found_error; + + inline void add_running_thread ( + ) + { + auto_mutex M(m); + ++threads_running; + } + + inline void remove_running_thread ( + ) + { + auto_mutex M(m); + --threads_running; + s.broadcast(); + } + + inline void wait_for_threads ( + ) + { + auto_mutex M(m); + while (threads_running > 0) + s.wait(); + } + + template < + typename pipe + > + void threadproc1 ( + void* param + ) + { + add_running_thread(); + pipe& p = *reinterpret_cast(param); + try + { + + int last = -1; + for (unsigned long i = 0; i < proc1_count; ++i) + { + int cur; + DLIB_CASSERT(p.dequeue(cur) == true,""); + DLIB_CASSERT(last + 1 == cur,""); + last = cur; + } + DLIB_CASSERT(p.size() == 0,""); + } + catch(exception& e) + { + auto_mutex M(m); + found_error = true; + cout << "\n\nERRORS FOUND" << endl; + cout << e.what() << endl; + dlog << LWARN << "ERRORS FOUND"; + dlog << LWARN << e.what(); + p.disable(); + } + + remove_running_thread(); + } + + + template < + typename pipe + > + void threadproc2 ( + void* param + ) + { + add_running_thread(); + pipe& p = *reinterpret_cast(param); + try + { + + int last = -1; + int cur; + while (p.dequeue(cur)) + { + DLIB_CASSERT(last < cur,""); + last = cur; + } + auto_mutex M(m); + } + catch(exception& e) + { + auto_mutex M(m); + found_error = true; + cout << "\n\nERRORS FOUND" << endl; + cout << e.what() << endl; + dlog << LWARN << "ERRORS FOUND"; + dlog << LWARN << e.what(); + p.disable(); + } + remove_running_thread(); + } + + + + template < + typename pipe + > + void threadproc3 ( + void* param + ) + { + add_running_thread(); + pipe& p = *reinterpret_cast(param); + try + { + + int last = -1; + int cur; + while (p.dequeue_or_timeout(cur,100000)) + { + DLIB_CASSERT(last < cur,""); + last = cur; + } + auto_mutex M(m); + } + catch(exception& e) + { + auto_mutex M(m); + found_error = true; + cout << "\n\nERRORS FOUND" << endl; + cout << e.what() << endl; + dlog << LWARN << "ERRORS FOUND"; + dlog << LWARN << e.what(); + p.disable(); + } + remove_running_thread(); + } + + + } + + + + template < + typename pipe + > + void pipe_kernel_test ( + ) + /*! + requires + - pipe is an implementation of pipe/pipe_kernel_abstract.h and + is instantiated with int + ensures + - runs tests on pipe for compliance with the specs + !*/ + { + using namespace pipe_kernel_test_helpers; + found_error = false; + + + print_spinner(); + pipe test(10), test2(100); + pipe test_0(0), test2_0(0); + pipe test_1(1), test2_1(1); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test_0.size() == 0,""); + DLIB_CASSERT(test2_0.size() == 0,""); + DLIB_CASSERT(test_1.size() == 0,""); + DLIB_CASSERT(test2_1.size() == 0,""); + + test.empty(); + test2.empty(); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test2.size() == 0,""); + + test_0.empty(); + test2_0.empty(); + DLIB_CASSERT(test_0.size() == 0,""); + DLIB_CASSERT(test2_0.size() == 0,""); + + test_1.empty(); + test2_1.empty(); + DLIB_CASSERT(test_1.size() == 0,""); + DLIB_CASSERT(test2_1.size() == 0,""); + + + + int a; + a = 3; + test.enqueue(a); + DLIB_CASSERT(test.size() == 1,""); + a = 5; + test.enqueue(a); + DLIB_CASSERT(test.size() == 2,""); + + a = 0; + test.dequeue(a); + DLIB_CASSERT(a == 3,""); + DLIB_CASSERT(test.size() == 1,""); + + a = 0; + test.dequeue(a); + DLIB_CASSERT(a == 5,""); + DLIB_CASSERT(test.size() == 0,""); + + + print_spinner(); + { + dlog << LINFO << "starting normal length pipe tests"; + create_new_thread(&threadproc1,&test); + create_new_thread(&threadproc2,&test2); + create_new_thread(&threadproc2,&test2); + create_new_thread(&threadproc2,&test2); + + for (unsigned long i = 0; i < proc1_count; ++i) + { + a = i; + test.enqueue(a); + } + DLIB_CASSERT(test.is_enqueue_enabled() == true,""); + test.disable_enqueue(); + DLIB_CASSERT(test.is_enqueue_enabled() == false,""); + for (unsigned long i = 0; i < proc1_count; ++i) + { + a = i; + test.enqueue(a); + } + + for (unsigned long i = 0; i < 100000; ++i) + { + a = i; + if (i%2 == 0) + test2.enqueue(a); + else + test2.enqueue_or_timeout(a,100000); + } + + test2.wait_for_num_blocked_dequeues(3); + DLIB_CASSERT(test2.size() == 0,""); + test2.disable(); + + wait_for_threads(); + DLIB_CASSERT(test2.size() == 0,""); + + test2.enable(); + + print_spinner(); + + create_new_thread(&threadproc3,&test2); + create_new_thread(&threadproc3,&test2); + + + for (unsigned long i = 0; i < 100000; ++i) + { + a = i; + if (i%2 == 0) + test2.enqueue(a); + else + test2.enqueue_or_timeout(a,100000); + } + + test2.wait_for_num_blocked_dequeues(2); + DLIB_CASSERT(test2.size() == 0,""); + test2.disable(); + + wait_for_threads(); + DLIB_CASSERT(test2.size() == 0,""); + + } + + + print_spinner(); + { + dlog << LINFO << "starting 0 length pipe tests"; + create_new_thread(&threadproc1,&test_0); + create_new_thread(&threadproc2,&test2_0); + create_new_thread(&threadproc2,&test2_0); + create_new_thread(&threadproc2,&test2_0); + dlog << LTRACE << "0: 1"; + + for (unsigned long i = 0; i < proc1_count; ++i) + { + a = i; + test_0.enqueue(a); + } + + dlog << LTRACE << "0: 2"; + DLIB_CASSERT(test_0.is_enqueue_enabled() == true,""); + test_0.disable_enqueue(); + DLIB_CASSERT(test_0.is_enqueue_enabled() == false,""); + for (unsigned long i = 0; i < proc1_count; ++i) + { + a = i; + test_0.enqueue(a); + } + + dlog << LTRACE << "0: 3"; + for (unsigned long i = 0; i < 100000; ++i) + { + a = i; + if (i%2 == 0) + test2_0.enqueue(a); + else + test2_0.enqueue_or_timeout(a,100000); + } + + print_spinner(); + dlog << LTRACE << "0: 4"; + test2_0.wait_for_num_blocked_dequeues(3); + DLIB_CASSERT(test2_0.size() == 0,""); + test2_0.disable(); + + wait_for_threads(); + DLIB_CASSERT(test2_0.size() == 0,""); + + dlog << LTRACE << "0: 5"; + test2_0.enable(); + + + create_new_thread(&threadproc3,&test2_0); + create_new_thread(&threadproc3,&test2_0); + + + for (unsigned long i = 0; i < 20000; ++i) + { + if ((i%100) == 0) + print_spinner(); + + a = i; + if (i%2 == 0) + test2_0.enqueue(a); + else + test2_0.enqueue_or_timeout(a,100000); + } + + dlog << LTRACE << "0: 6"; + test2_0.wait_for_num_blocked_dequeues(2); + DLIB_CASSERT(test2_0.size() == 0,""); + test2_0.disable(); + + wait_for_threads(); + DLIB_CASSERT(test2_0.size() == 0,""); + + dlog << LTRACE << "0: 7"; + } + + print_spinner(); + { + dlog << LINFO << "starting 1 length pipe tests"; + create_new_thread(&threadproc1,&test_1); + create_new_thread(&threadproc2,&test2_1); + create_new_thread(&threadproc2,&test2_1); + create_new_thread(&threadproc2,&test2_1); + + for (unsigned long i = 0; i < proc1_count; ++i) + { + a = i; + test_1.enqueue(a); + } + DLIB_CASSERT(test_1.is_enqueue_enabled() == true,""); + test_1.disable_enqueue(); + DLIB_CASSERT(test_1.is_enqueue_enabled() == false,""); + for (unsigned long i = 0; i < proc1_count; ++i) + { + a = i; + test_1.enqueue(a); + } + print_spinner(); + + for (unsigned long i = 0; i < 100000; ++i) + { + a = i; + if (i%2 == 0) + test2_1.enqueue(a); + else + test2_1.enqueue_or_timeout(a,100000); + } + + test2_1.wait_for_num_blocked_dequeues(3); + DLIB_CASSERT(test2_1.size() == 0,""); + test2_1.disable(); + + wait_for_threads(); + DLIB_CASSERT(test2_1.size() == 0,""); + + test2_1.enable(); + + + create_new_thread(&threadproc3,&test2_1); + create_new_thread(&threadproc3,&test2_1); + + + for (unsigned long i = 0; i < 100000; ++i) + { + a = i; + if (i%2 == 0) + test2_1.enqueue(a); + else + test2_1.enqueue_or_timeout(a,100000); + } + + test2_1.wait_for_num_blocked_dequeues(2); + DLIB_CASSERT(test2_1.size() == 0,""); + test2_1.disable(); + + wait_for_threads(); + DLIB_CASSERT(test2_1.size() == 0,""); + + } + + test.enable_enqueue(); + test_0.enable_enqueue(); + test_1.enable_enqueue(); + + DLIB_CASSERT(test.is_enabled(),""); + DLIB_CASSERT(test.is_enqueue_enabled(),""); + DLIB_CASSERT(test_0.is_enabled(),""); + DLIB_CASSERT(test_0.is_enqueue_enabled(),""); + DLIB_CASSERT(test_1.is_enabled(),""); + DLIB_CASSERT(test_1.is_enqueue_enabled(),""); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test_0.size() == 0,""); + DLIB_CASSERT(test_1.size() == 0,""); + DLIB_CASSERT(test.max_size() == 10,""); + DLIB_CASSERT(test_0.max_size() == 0,""); + DLIB_CASSERT(test_1.max_size() == 1,""); + + + for (int i = 0; i < 100; ++i) + { + a = 1; + test.enqueue_or_timeout(a,0); + a = 1; + test_0.enqueue_or_timeout(a,0); + a = 1; + test_1.enqueue_or_timeout(a,0); + } + + DLIB_CASSERT(test.size() == 10,"size: " << test.size() ); + DLIB_CASSERT(test_0.size() == 0,"size: " << test.size() ); + DLIB_CASSERT(test_1.size() == 1,"size: " << test.size() ); + + for (int i = 0; i < 10; ++i) + { + a = 0; + DLIB_CASSERT(test.enqueue_or_timeout(a,10) == false,""); + a = 0; + DLIB_CASSERT(test_0.enqueue_or_timeout(a,10) == false,""); + a = 0; + DLIB_CASSERT(test_1.enqueue_or_timeout(a,10) == false,""); + } + + DLIB_CASSERT(test.size() == 10,"size: " << test.size() ); + DLIB_CASSERT(test_0.size() == 0,"size: " << test.size() ); + DLIB_CASSERT(test_1.size() == 1,"size: " << test.size() ); + + for (int i = 0; i < 10; ++i) + { + a = 0; + DLIB_CASSERT(test.dequeue_or_timeout(a,0) == true,""); + DLIB_CASSERT(a == 1,""); + } + + DLIB_CASSERT(test.max_size() == 10,""); + DLIB_CASSERT(test_0.max_size() == 0,""); + DLIB_CASSERT(test_1.max_size() == 1,""); + + a = 0; + DLIB_CASSERT(test_1.dequeue_or_timeout(a,0) == true,""); + + DLIB_CASSERT(test.max_size() == 10,""); + DLIB_CASSERT(test_0.max_size() == 0,""); + DLIB_CASSERT(test_1.max_size() == 1,""); + + + DLIB_CASSERT(a == 1,"a: " << a); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test_0.size() == 0,""); + DLIB_CASSERT(test_1.size() == 0,""); + + DLIB_CASSERT(test.dequeue_or_timeout(a,0) == false,""); + DLIB_CASSERT(test_0.dequeue_or_timeout(a,0) == false,""); + DLIB_CASSERT(test_1.dequeue_or_timeout(a,0) == false,""); + DLIB_CASSERT(test.dequeue_or_timeout(a,10) == false,""); + DLIB_CASSERT(test_0.dequeue_or_timeout(a,10) == false,""); + DLIB_CASSERT(test_1.dequeue_or_timeout(a,10) == false,""); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test_0.size() == 0,""); + DLIB_CASSERT(test_1.size() == 0,""); + + DLIB_CASSERT(found_error == false,""); + } + + + + + class pipe_tester : public tester + { + public: + pipe_tester ( + ) : + tester ("test_pipe", + "Runs tests on the pipe component.") + {} + + void perform_test ( + ) + { + pipe_kernel_test::kernel_1a>(); + } + } a; + +} + + diff --git a/dlib/test/pixel.cpp b/dlib/test/pixel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b342b1189d299f472c2b75e70fa6f28a8ca32e03 --- /dev/null +++ b/dlib/test/pixel.cpp @@ -0,0 +1,305 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.pixel"); + + + void pixel_test ( + ) + /*! + ensures + - runs tests on pixel objects and functions for compliance with the specs + !*/ + { + + print_spinner(); + + unsigned char p_gray; + unsigned short p_gray16; + rgb_pixel p_rgb; + hsi_pixel p_hsi, p_hsi2; + rgb_alpha_pixel p_rgba; + + + assign_pixel(p_gray,0); + assign_pixel(p_rgb,0); + assign_pixel(p_hsi,0); + assign_pixel(p_rgba,0); + assign_pixel(p_gray16,0); + + DLIB_CASSERT(p_gray == 0,""); + DLIB_CASSERT(p_gray16 == 0,""); + + DLIB_CASSERT(p_rgb.red == 0,""); + DLIB_CASSERT(p_rgb.green == 0,""); + DLIB_CASSERT(p_rgb.blue == 0,""); + + DLIB_CASSERT(p_rgba.red == 0,""); + DLIB_CASSERT(p_rgba.green == 0,""); + DLIB_CASSERT(p_rgba.blue == 0,""); + DLIB_CASSERT(p_rgba.alpha == 255,""); + + DLIB_CASSERT(p_hsi.h == 0,""); + DLIB_CASSERT(p_hsi.s == 0,""); + DLIB_CASSERT(p_hsi.i == 0,""); + + assign_pixel(p_gray,10); + assign_pixel(p_gray16,10); + assign_pixel(p_rgb,10); + assign_pixel(p_hsi,10); + assign_pixel(p_rgba,10); + + DLIB_CASSERT(p_gray == 10,""); + DLIB_CASSERT(p_gray16 == 10,""); + + DLIB_CASSERT(p_rgb.red == 10,""); + DLIB_CASSERT(p_rgb.green == 10,""); + DLIB_CASSERT(p_rgb.blue == 10,""); + + DLIB_CASSERT(p_rgba.red == 10,""); + DLIB_CASSERT(p_rgba.green == 10,""); + DLIB_CASSERT(p_rgba.blue == 10,""); + DLIB_CASSERT(p_rgba.alpha == 255,""); + + DLIB_CASSERT(p_hsi.h == 0,""); + DLIB_CASSERT(p_hsi.s == 0,""); + DLIB_CASSERT(p_hsi.i == 10,""); + + assign_pixel(p_gray16,12345); + DLIB_CASSERT(p_gray16 == 12345,""); + + p_rgb.red = 255; + p_rgb.green = 100; + p_rgb.blue = 50; + + p_rgba.alpha = 4; + assign_pixel(p_gray,p_rgb); + assign_pixel(p_rgb,p_rgb); + assign_pixel(p_rgba,p_rgb); + assign_pixel(p_hsi,p_rgb); + + DLIB_CASSERT(p_gray == (255+100+50)/3,""); + + DLIB_CASSERT(p_rgb.red == 255,""); + DLIB_CASSERT(p_rgb.green == 100,""); + DLIB_CASSERT(p_rgb.blue == 50,""); + + DLIB_CASSERT(p_rgba.red == 255,""); + DLIB_CASSERT(p_rgba.green == 100,""); + DLIB_CASSERT(p_rgba.blue == 50,""); + DLIB_CASSERT(p_rgba.alpha == 255,""); + + DLIB_CASSERT(p_hsi.i > 0,""); + DLIB_CASSERT(p_hsi.s > 0,""); + DLIB_CASSERT(p_hsi.h > 0,""); + + assign_pixel(p_rgb,0); + DLIB_CASSERT(p_rgb.red == 0,""); + DLIB_CASSERT(p_rgb.green == 0,""); + DLIB_CASSERT(p_rgb.blue == 0,""); + assign_pixel(p_rgb, p_hsi); + + DLIB_CASSERT(p_rgb.red > 251 ,(int)p_rgb.green); + DLIB_CASSERT(p_rgb.green > 96 && p_rgb.green < 104,(int)p_rgb.green); + DLIB_CASSERT(p_rgb.blue > 47 && p_rgb.blue < 53,(int)p_rgb.green); + + assign_pixel(p_hsi2, p_hsi); + DLIB_CASSERT(p_hsi.h == p_hsi2.h,""); + DLIB_CASSERT(p_hsi.s == p_hsi2.s,""); + DLIB_CASSERT(p_hsi.i == p_hsi2.i,""); + assign_pixel(p_hsi,0); + DLIB_CASSERT(p_hsi.h == 0,""); + DLIB_CASSERT(p_hsi.s == 0,""); + DLIB_CASSERT(p_hsi.i == 0,""); + assign_pixel(p_hsi, p_rgba); + + DLIB_CASSERT(p_hsi.h == p_hsi2.h,""); + DLIB_CASSERT(p_hsi.s == p_hsi2.s,""); + DLIB_CASSERT(p_hsi.i == p_hsi2.i,""); + + assign_pixel(p_rgba, 100); + assign_pixel(p_gray, 10); + assign_pixel(p_rgb, 10); + assign_pixel(p_hsi, 10); + + p_rgba.alpha = 0; + assign_pixel(p_gray, p_rgba); + DLIB_CASSERT(p_gray == 10,""); + assign_pixel(p_rgb, p_rgba); + DLIB_CASSERT(p_rgb.red == 10,""); + DLIB_CASSERT(p_rgb.green == 10,""); + DLIB_CASSERT(p_rgb.blue == 10,""); + + assign_pixel(p_hsi, p_rgba); + assign_pixel(p_hsi2, p_rgb); + DLIB_CASSERT(p_hsi.h == 0,""); + DLIB_CASSERT(p_hsi.s == 0,""); + DLIB_CASSERT(p_hsi.i < p_hsi2.i+2 && p_hsi.i > p_hsi2.i -2,(int)p_hsi.i << " " << (int)p_hsi2.i); + + assign_pixel(p_rgba, 100); + assign_pixel(p_gray, 10); + assign_pixel(p_rgb, 10); + p_rgba.alpha = 128; + assign_pixel(p_gray, p_rgba); + assign_pixel(p_rgb, p_rgba); + DLIB_CASSERT(p_gray == (100 + 10)/2,""); + DLIB_CASSERT(p_rgb.red == (100 + 10)/2,""); + DLIB_CASSERT(p_rgb.green == (100 + 10)/2,""); + DLIB_CASSERT(p_rgb.blue == (100 + 10)/2,""); + + assign_pixel(p_rgba, 100); + assign_pixel(p_gray, 10); + assign_pixel(p_rgb, 10); + DLIB_CASSERT(p_rgba.alpha == 255,""); + assign_pixel(p_gray, p_rgba); + assign_pixel(p_rgb, p_rgba); + DLIB_CASSERT(p_gray == 100,""); + DLIB_CASSERT(p_rgb.red == 100,""); + DLIB_CASSERT(p_rgb.green == 100,""); + DLIB_CASSERT(p_rgb.blue == 100,""); + + + p_rgb.red = 1; + p_rgb.green = 2; + p_rgb.blue = 3; + + p_rgba.red = 4; + p_rgba.green = 5; + p_rgba.blue = 6; + p_rgba.alpha = 7; + + p_gray = 8; + + p_hsi.h = 9; + p_hsi.s = 10; + p_hsi.i = 11; + + ostringstream sout; + serialize(p_rgb,sout); + serialize(p_rgba,sout); + serialize(p_gray,sout); + serialize(p_hsi,sout); + + assign_pixel(p_rgb,0); + assign_pixel(p_rgba,0); + assign_pixel(p_gray,0); + assign_pixel(p_hsi,0); + + istringstream sin(sout.str()); + + deserialize(p_rgb,sin); + deserialize(p_rgba,sin); + deserialize(p_gray,sin); + deserialize(p_hsi,sin); + + DLIB_CASSERT(p_rgb.red == 1,""); + DLIB_CASSERT(p_rgb.green == 2,""); + DLIB_CASSERT(p_rgb.blue == 3,""); + + DLIB_CASSERT(p_rgba.red == 4,""); + DLIB_CASSERT(p_rgba.green == 5,""); + DLIB_CASSERT(p_rgba.blue == 6,""); + DLIB_CASSERT(p_rgba.alpha == 7,""); + + DLIB_CASSERT(p_gray == 8,""); + + DLIB_CASSERT(p_hsi.h == 9,""); + DLIB_CASSERT(p_hsi.s == 10,""); + DLIB_CASSERT(p_hsi.i == 11,""); + + { + matrix m_gray; + matrix m_rgb, m_hsi; + + m_gray = pixel_to_vector(p_gray); + m_hsi = pixel_to_vector(p_hsi); + m_rgb = pixel_to_vector(p_rgb); + + DLIB_CASSERT(m_gray(0) == p_gray,""); + DLIB_CASSERT(m_rgb(0) == p_rgb.red,""); + DLIB_CASSERT(m_rgb(1) == p_rgb.green,""); + DLIB_CASSERT(m_rgb(2) == p_rgb.blue,""); + DLIB_CASSERT(m_hsi(0) == p_hsi.h,""); + DLIB_CASSERT(m_hsi(1) == p_hsi.s,""); + DLIB_CASSERT(m_hsi(2) == p_hsi.i,""); + + DLIB_CASSERT(p_rgb.red == 1,""); + DLIB_CASSERT(p_rgb.green == 2,""); + DLIB_CASSERT(p_rgb.blue == 3,""); + + DLIB_CASSERT(p_rgba.red == 4,""); + DLIB_CASSERT(p_rgba.green == 5,""); + DLIB_CASSERT(p_rgba.blue == 6,""); + DLIB_CASSERT(p_rgba.alpha == 7,""); + + DLIB_CASSERT(p_gray == 8,""); + + DLIB_CASSERT(p_hsi.h == 9,""); + DLIB_CASSERT(p_hsi.s == 10,""); + DLIB_CASSERT(p_hsi.i == 11,""); + + assign_pixel(p_gray,0); + assign_pixel(p_hsi,0); + assign_pixel(p_rgb,0); + + vector_to_pixel(p_gray, m_gray); + vector_to_pixel(p_hsi, m_hsi); + vector_to_pixel(p_rgb, m_rgb); + + DLIB_CASSERT(p_rgb.red == 1,""); + DLIB_CASSERT(p_rgb.green == 2,""); + DLIB_CASSERT(p_rgb.blue == 3,""); + + DLIB_CASSERT(p_rgba.red == 4,""); + DLIB_CASSERT(p_rgba.green == 5,""); + DLIB_CASSERT(p_rgba.blue == 6,""); + DLIB_CASSERT(p_rgba.alpha == 7,""); + + DLIB_CASSERT(p_gray == 8,""); + + DLIB_CASSERT(p_hsi.h == 9,""); + DLIB_CASSERT(p_hsi.s == 10,""); + DLIB_CASSERT(p_hsi.i == 11,""); + } + + } + + + + + class pixel_tester : public tester + { + public: + pixel_tester ( + ) : + tester ("test_pixel", + "Runs tests on the pixel objects and functions.") + {} + + void perform_test ( + ) + { + pixel_test(); + } + } a; + +} + + + diff --git a/dlib/test/queue.cpp b/dlib/test/queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c3d46d4a2450b451ce45c50adec3412f9813ca6 --- /dev/null +++ b/dlib/test/queue.cpp @@ -0,0 +1,426 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +// This is called an unnamed-namespace and it has the effect of making everything inside this file "private" +// so that everything you declare will have static linkage. Thus we won't have any multiply +// defined symbol errors coming out of the linker when we try to compile the test suite. +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + // Declare the logger we will use in this test. The name of the tester + // should start with "test." + logger dlog("test.queue"); + + template < + typename queue + > + void queue_sort_test ( + ) + /*! + requires + - queue is an implementation of queue/queue_sort_abstract.h + is instantiated with int + ensures + - runs tests on queue for compliance with the specs + !*/ + { + + print_spinner(); + srand(static_cast(time(0))); + + queue q,q2; + + enumerable& e = q; + + // I will use these DLIB_CASSERT macros to assert that conditions are true. If they are + // false then it means we have detected an error in the queue object. CASSERT + // will then throw an exception which we will catch at the end of this function and + // report as an error/failed test. + DLIB_CASSERT(e.at_start() == true,""); + + int a; + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q.at_start() == true,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + + q.sort(); + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q.at_start() == true,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + + DLIB_CASSERT (q.move_next() == false,""); + DLIB_CASSERT (q.move_next() == false,""); + DLIB_CASSERT (q.move_next() == false,""); + DLIB_CASSERT (q.move_next() == false,""); + DLIB_CASSERT (q.move_next() == false,""); + DLIB_CASSERT (q.move_next() == false,""); + + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q.at_start() == false,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + + + q.reset(); + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q.at_start() == true,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + + + + + + + + + + + + q.clear(); + q2.clear(); + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q2.size() == 0,""); + + for (int i = 0; i < 10000; ++i) + { + int a = i; + q.enqueue(a); + } + + q2.cat(q); + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q2.size() == 10000,""); + + int g = 0; + while (q2.move_next()) + { + DLIB_CASSERT(q2.element() == g,g); + ++g; + } + + for (int i = 0;i < 10000; ++i) + { + int a = 0; + q2.dequeue(a); + DLIB_CASSERT(a == i,""); + } + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q2.size() == 0,""); + q.clear(); + q2.clear(); + + + + + print_spinner(); + + + dlog << LTRACE << "creating big pre-sorted queue"; + q.clear(); + DLIB_CASSERT(q.size() == 0,""); + + for (int i = 0; i < 10000; ++i) + { + int a = i; + q.enqueue(a); + } + + dlog << LTRACE << "sorting already sorted queue"; + q.sort(); + + + dlog << LTRACE << "done sorting, checking the results"; + for (int i = 0; i < 10000; ++i) + { + q.dequeue(a); + DLIB_CASSERT(a == i,""); + } + + + q.clear(); + dlog << LTRACE << "done with the big pre-sorted queue test"; + + + + + + + + + + + + + + + + q.clear(); + q2.clear(); + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q2.size() == 0,""); + + for (int i = 0; i < 1; ++i) + { + int a = i; + q.enqueue(a); + } + + q2.cat(q); + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q2.size() == 1,""); + + + + g = 0; + while (q2.move_next()) + { + DLIB_CASSERT(q2.element() == g,g); + ++g; + } + + for (int i = 0;i < 1; ++i) + { + int a = 0; + q2.dequeue(a); + DLIB_CASSERT(a == i,""); + } + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q2.size() == 0,""); + q.clear(); + q2.clear(); + + + + + + + + print_spinner(); + + + + + + + + + + + + for (int j = 0; j < 3; ++j) + { + for (int i = 0; i < 10000; ++i) + { + a = ::rand(); + q.enqueue(a); + } + + while (q.move_next()); + + DLIB_CASSERT(q.at_start() == false,""); + + q.sort(); + + DLIB_CASSERT(q.at_start() == true,""); + + // serialize the state of q, then clear q, then + // load the state back into q. + ostringstream sout; + serialize(q,sout); + DLIB_CASSERT(q.at_start() == true,""); + istringstream sin(sout.str()); + q.clear(); + deserialize(q,sin); + + + DLIB_CASSERT(q.at_start() == true,""); + + a = 0; + int last = 0; + while (q.move_next()) + { + ++a; + DLIB_CASSERT(last <= q.element(),"items weren't actually sorted"); + last = q.element(); + DLIB_CASSERT(q.current_element_valid() == true,""); + DLIB_CASSERT(q.at_start() == false,""); + DLIB_CASSERT(q.current_element_valid() == true,""); + + + } + DLIB_CASSERT(a == 10000,"some items were lost between the sorting and iterating"); + + + DLIB_CASSERT(q.size() == 10000,""); + swap(q,q2); + DLIB_CASSERT(q2.at_start() == false,""); + DLIB_CASSERT(q2.current_element_valid() == false, ""); + + DLIB_CASSERT (q2.move_next() == false,""); + DLIB_CASSERT (q2.move_next() == false,""); + DLIB_CASSERT (q2.move_next() == false,""); + DLIB_CASSERT (q2.move_next() == false,""); + DLIB_CASSERT (q2.move_next() == false,""); + DLIB_CASSERT (q2.move_next() == false,""); + + + DLIB_CASSERT(q2.size() == 10000,""); + DLIB_CASSERT(q2.at_start() == false,""); + DLIB_CASSERT(q2.current_element_valid() == false, ""); + + q2.clear(); + + q.swap(q2); + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q.at_start() == true,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + } + + + + print_spinner(); + + + + // try the above code but this time with just one element + // in the queue + for (int j = 0; j < 3; ++j) + { + for (int i = 0; i < 1; ++i) + { + a = ::rand(); + q.enqueue(a); + } + + q.sort(); + + a = 0; + int last = 0; + while (q.move_next()) + { + ++a; + DLIB_CASSERT(last <= q.element(),"items weren't actually sorted"); + DLIB_CASSERT(q.current_element_valid() == true,""); + + } + DLIB_CASSERT(a == 1,"some items were lost between the sorting and iterating"); + + + DLIB_CASSERT(q.size() == 1,""); + DLIB_CASSERT(q.at_start() == false,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + + q.clear(); + + DLIB_CASSERT(q.size() == 0,""); + DLIB_CASSERT(q.at_start() == true,""); + DLIB_CASSERT(q.current_element_valid() == false, ""); + } + + + print_spinner(); + + { + q.clear(); + remover& go = q; + for (int i = 0; i < 100; ++i) + { + int a = 3; + q.enqueue(a); + } + DLIB_CASSERT(go.size() == 100,""); + for (int i = 0; i < 100; ++i) + { + int a = 9; + go.remove_any(a); + DLIB_CASSERT(a == 3,""); + } + DLIB_CASSERT(go.size() == 0,""); + } + + } + + + struct factory + { + template + struct return_type { + typedef typename memory_manager::kernel_3c type; + }; + + template + static typename return_type::type* get_instance ( + ) + { + static typename return_type::type a; + return &a; + } + }; + + + + + class queue_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a test for the queue object. When it is constructed + it adds itself into the testing framework. The command line switch is + specified as test_queue by passing that string to the tester constructor. + !*/ + public: + queue_tester ( + ) : + tester ("test_queue", + "Runs tests on the queue component.") + {} + + void perform_test ( + ) + { + // There are multiple implementations of the queue object so use + // the templated function defined above to test them all and report + // a failed test if any of them don't pass. + + typedef dlib::memory_manager_global::kernel_1a mm; + + + dlog << LINFO << "testing sort_1a_c"; + queue_sort_test::sort_1a_c> (); + dlog << LINFO << "testing sort_1a"; + queue_sort_test::sort_1a>(); + dlog << LINFO << "testing sort_1b"; + queue_sort_test::sort_1b> (); + dlog << LINFO << "testing sort_1b_c"; + queue_sort_test::sort_1b_c>(); + dlog << LINFO << "testing sort_1c"; + queue_sort_test::sort_1c> (); + dlog << LINFO << "testing sort_1c_c"; + queue_sort_test::sort_1c_c>(); + } + } a; + +} + diff --git a/dlib/test/rand.cpp b/dlib/test/rand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f0ee4becfac060dce53d99a87b66ab3b0bf86ce --- /dev/null +++ b/dlib/test/rand.cpp @@ -0,0 +1,182 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.rand"); + + void check_bpp ( + const std::string str + ) + { + istringstream rdata; + ostringstream sout; + rdata.str(str); + double compressed_size; + compress_stream::kernel_1a cs1; + compress_stream::kernel_2a cs2; + + compress_stream_kernel_1< + entropy_encoder_model_kernel_5<257,entropy_encoder::kernel_1a,4000000,4>, + entropy_decoder_model_kernel_5<257,entropy_decoder::kernel_1a,4000000,4>, + crc32::kernel_1a + > cs3; + + + print_spinner(); + + rdata.clear(); + rdata.seekg(0); + sout.clear(); + sout.str(""); + cs1.compress(rdata,sout); + compressed_size = sout.str().size(); + compressed_size *= 8; + compressed_size /= str.size(); + DLIB_CASSERT(compressed_size >= 8, "order 0 bps: " << compressed_size); + dlog << LINFO << "order 0: " << compressed_size; + + print_spinner(); + + rdata.clear(); + rdata.seekg(0); + sout.clear(); + sout.str(""); + cs2.compress(rdata,sout); + compressed_size = sout.str().size(); + compressed_size *= 8; + compressed_size /= str.size(); + DLIB_CASSERT(compressed_size >= 8, "order 1 bps: " << compressed_size); + dlog << LINFO << "order 1: " << compressed_size; + + print_spinner(); + + rdata.clear(); + rdata.seekg(0); + sout.clear(); + sout.str(""); + cs3.compress(rdata,sout); + compressed_size = sout.str().size(); + compressed_size *= 8; + compressed_size /= str.size(); + DLIB_CASSERT(compressed_size >= 8, "order 4 bps: " << compressed_size); + dlog << LINFO << "order 4: " << compressed_size; + + } + + template < + typename rand + > + void rand_test ( + ) + /*! + requires + - rand is an implementation of rand/rand_kernel_abstract.h + is instantiated with int + ensures + - runs tests on rand for compliance with the specs + !*/ + { + + ostringstream seed; + seed << (unsigned int)time(0); + + ostringstream sout; + + + rand r, r2; + DLIB_CASSERT(r.get_seed() == "",""); + r.set_seed(seed.str()); + + DLIB_CASSERT(r.get_seed() == seed.str(),""); + r.clear(); + DLIB_CASSERT(r.get_seed() == "",""); + swap(r,r2); + DLIB_CASSERT(r.get_seed() == "",""); + r.set_seed(seed.str()); + DLIB_CASSERT(r.get_seed() == seed.str(),""); + swap(r,r2); + DLIB_CASSERT(r2.get_seed() == seed.str(),""); + DLIB_CASSERT(r.get_seed() == "",""); + swap(r,r2); + DLIB_CASSERT(r.get_seed() == seed.str(),""); + DLIB_CASSERT(r2.get_seed() == "",""); + + print_spinner(); + unsigned long size = 100000; + for (unsigned long i = 0; i < size; ++i) + { + uint32 ch = r.get_random_32bit_number(); + sout.write((char*)&ch,4); + } + + check_bpp(sout.str()); + sout.clear(); + sout.str(""); + + print_spinner(); + for (unsigned long i = 0; i < size; ++i) + { + uint16 ch = r.get_random_16bit_number(); + sout.write((char*)&ch,2); + } + + check_bpp(sout.str()); + sout.clear(); + sout.str(""); + + print_spinner(); + for (unsigned long i = 0; i < size; ++i) + { + unsigned char ch = r.get_random_8bit_number(); + sout.write((char*)&ch,1); + } + + check_bpp(sout.str()); + sout.clear(); + sout.str(""); + + + } + + + + + + + class rand_tester : public tester + { + public: + rand_tester ( + ) : + tester ("test_rand", + "Runs tests on the rand component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + rand_test(); + } + } a; + +} + + diff --git a/dlib/test/reference_counter.cpp b/dlib/test/reference_counter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99c86e490bbe9d8e1603ce13d79df6993faf8f17 --- /dev/null +++ b/dlib/test/reference_counter.cpp @@ -0,0 +1,122 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.reference_counter"); + + template < + typename ref_counter + > + void reference_counter_test ( + ) + /*! + requires + - ref_counter is an implementation of reference_counter/reference_counter_kernel_abstract.h + and is instantiated to contain an int + ensures + - runs tests on reference_counter for compliance with the specs + !*/ + { + + ref_counter a, b, c; + + for (long i = 0; i < 10; ++i) + { + print_spinner(); + for (long j = 0; j < 10000; ++j) + { + a.modify() = j; + b.modify() = j+1; + c.modify() = j+2; + DLIB_ASSERT(a.access() == j,""); + DLIB_ASSERT(b.access() == j+1,""); + DLIB_ASSERT(c.access() == j+2,""); + DLIB_ASSERT(a.modify() == j,""); + DLIB_ASSERT(b.modify() == j+1,""); + DLIB_ASSERT(c.modify() == j+2,""); + DLIB_ASSERT(a.access() == j,""); + DLIB_ASSERT(b.access() == j+1,""); + DLIB_ASSERT(c.access() == j+2,""); + DLIB_ASSERT(a.modify() == j,""); + DLIB_ASSERT(b.modify() == j+1,""); + DLIB_ASSERT(c.modify() == j+2,""); + a = c; + DLIB_ASSERT(a.access() == j+2,""); + DLIB_ASSERT(b.access() == j+1,""); + DLIB_ASSERT(c.access() == j+2,""); + DLIB_ASSERT(a.modify() == j+2,""); + DLIB_ASSERT(b.modify() == j+1,""); + DLIB_ASSERT(c.modify() == j+2,""); + DLIB_ASSERT(a.access() == j+2,""); + DLIB_ASSERT(b.access() == j+1,""); + DLIB_ASSERT(c.access() == j+2,""); + DLIB_ASSERT(a.modify() == j+2,""); + DLIB_ASSERT(b.modify() == j+1,""); + DLIB_ASSERT(c.modify() == j+2,""); + + a = b = c; + DLIB_ASSERT(a.access() == b.access(),""); + DLIB_ASSERT(a.access() == c.access(),""); + DLIB_ASSERT(c.access() == b.access(),""); + a.modify() = j; + DLIB_ASSERT(a.access() == j,""); + DLIB_ASSERT(a.access() != b.access(),""); + DLIB_ASSERT(a.access() != c.access(),""); + DLIB_ASSERT(c.access() == b.access(),""); + DLIB_ASSERT(c.access() == j+2,""); + DLIB_ASSERT(b.access() == j+2,""); + + DLIB_ASSERT(a.access() == j,""); + a = a; + DLIB_ASSERT(a.access() == j,""); + c = c; + DLIB_ASSERT(c.access() == j+2,""); + DLIB_ASSERT(b.access() == j+2,""); + swap(a,c); + DLIB_ASSERT(a.access() == j+2,""); + DLIB_ASSERT(c.access() == j,""); + DLIB_ASSERT(b.access() == j+2,""); + } + } + + } + + + + + + class reference_counter_tester : public tester + { + public: + reference_counter_tester ( + ) : + tester ("test_reference_counter", + "Runs tests on the reference_counter component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + reference_counter_test::kernel_1a> (); + } + } a; + +} + + diff --git a/dlib/test/sequence.cpp b/dlib/test/sequence.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6bfb405dcf538a9b8bcd362d2cff09606206c795 --- /dev/null +++ b/dlib/test/sequence.cpp @@ -0,0 +1,312 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.sequence"); + + template < + typename seq + > + void sequence_sort_test ( + ) + /*! + requires + - seq is an implementation of sequence/sequence_sort_aseqract.h is instantiated + with int + ensures + - runs tests on seq for compliance with the specs + !*/ + { + + + srand(static_cast(time(0))); + + + print_spinner(); + + + + + + { + // this test is to make sure that jumping around via + // operator[] doesn't corrupt the object + + seq a; + + for (int i = 0; i < 100; ++i) + { + int x = i; + a.add(a.size(),x); + } + + + int x; + + for (int i = 0; i < (int)a.size(); ++i) + { + DLIB_CASSERT(a[i] >= i,"1"); + // cout << a[i] << endl; + } + + for (unsigned long i = 0; i < a.size(); ++i) + { + for (unsigned long j = i+1; j < a.size(); ++j) + { + if ((a[j]+a[i])%3 ==0) + { + a.remove(j,x); + --j; + } + } + } + + //cout << endl; + + for (int i = 0; i < (int)a.size(); ++i) + { + // cout << a[i] << endl; + DLIB_CASSERT(a[i] >= i,"2"); + } + + } + + + + + + + + seq test, test2; + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + enumerable& e = test; + + DLIB_CASSERT(e.at_start() == true,""); + DLIB_CASSERT(e.current_element_valid() == false,""); + + + for (int g = 0; g < 5; ++g) + { + test.clear(); + test2.clear(); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(e.at_start() == true,""); + DLIB_CASSERT(e.current_element_valid() == false,""); + + DLIB_CASSERT(e.move_next() == false,""); + DLIB_CASSERT(e.current_element_valid() == false,""); + DLIB_CASSERT(e.at_start() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + swap(test,test2); + DLIB_CASSERT(test.at_start() == true,""); + test.clear(); + test2.clear(); + + int a; + + + for (int i = 0; i < 100; ++i) + { + a = i; + test.add(i,a); + } + + DLIB_CASSERT(test.size() == 100,""); + + for (int i = 0; i < static_cast(test.size()); ++i) + { + DLIB_CASSERT(test[i] == i,""); + } + + swap(test,test2); + + a = 0; + DLIB_CASSERT(test2.at_start() == true,""); + while(test2.move_next()) + { + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.element() == a,""); + ++a; + } + + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + test2.reset(); + + DLIB_CASSERT(test2.at_start() == true,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + a = 0; + while(test2.move_next()) + { + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == true,""); + DLIB_CASSERT(test2.element() == a,""); + ++a; + } + + + + + + for (int i = 0; i < 1000; ++i) + { + a = ::rand(); + test.add(0,a); + } + DLIB_CASSERT(test.size() == 1000,""); + + test.sort(); + + + for (unsigned long i = 0; i < test.size()-1; ++i) + { + DLIB_CASSERT(test[i] <= test[i+1],""); + } + + a = 0; + while(test.move_next()) + { + DLIB_CASSERT(a <= test.element(),""); + a = test.element(); + } + + + test.clear(); + test2.clear(); + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test2.size() == 0,""); + + for (int i = 0; i < 100; ++i) + { + a = i; + test.add(i,a); + } + + for (int i = 100; i < 200; ++i) + { + a = i; + test.add(i,a); + } + + test.cat(test2); + DLIB_CASSERT(test.size() == 200,""); + DLIB_CASSERT(test2.size() == 0,""); + + + // serialize the state of test, then clear test, then + // load the state back into test. + ostringstream sout; + serialize(test,sout); + DLIB_CASSERT(test.at_start() == true,""); + istringstream sin(sout.str()); + test.clear(); + deserialize(test,sin); + + + for (int i = 0; i < 200; ++i) + { + DLIB_CASSERT(test[i] == i,""); + } + + a = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element() == a,""); + DLIB_CASSERT(test[0]==0,""); + ++a; + } + + DLIB_CASSERT(a == 200,""); + + DLIB_CASSERT(test[9] == 9,""); + test.remove(9,a); + DLIB_CASSERT(a == 9,""); + DLIB_CASSERT(test[9] == 10,""); + DLIB_CASSERT(test.size() == 199,""); + + test.remove(0,a); + DLIB_CASSERT(test[0] == 1,""); + DLIB_CASSERT(test.size() == 198,""); + DLIB_CASSERT(a == 0,""); + DLIB_CASSERT(test[9] == 11,""); + DLIB_CASSERT(test[20] == 22,""); + + + + + } + + { + test.clear(); + for (int i = 0; i < 100; ++i) + { + int a = 3; + test.add(0,a); + } + DLIB_CASSERT(test.size() == 100,""); + remover& go = test; + for (int i = 0; i < 100; ++i) + { + int a = 9; + go.remove_any(a); + DLIB_CASSERT(a == 3,""); + } + DLIB_CASSERT(go.size() == 0,""); + } + + + } + + + + + class sequence_tester : public tester + { + public: + sequence_tester ( + ) : + tester ("test_sequence", + "Runs tests on the sequence component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing sort_1a"; + sequence_sort_test::sort_1a> (); + dlog << LINFO << "testing sort_1a_c"; + sequence_sort_test::sort_1a_c>(); + dlog << LINFO << "testing sort_2a"; + sequence_sort_test::sort_2a> (); + dlog << LINFO << "testing sort_2a_c"; + sequence_sort_test::sort_2a_c>(); + } + } a; + +} + diff --git a/dlib/test/serialize.cpp b/dlib/test/serialize.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b22edb80762ab66cff1bbb69197a616d1302fbf1 --- /dev/null +++ b/dlib/test/serialize.cpp @@ -0,0 +1,521 @@ +// Copyright (C) 2008 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + +// ---------------------------------------------------------------------------------------- + + using namespace test; + using namespace dlib; + using namespace std; + + struct test_object + { + signed char i1; + signed short i2; + signed long i3; + unsigned char i4; + unsigned short i5; + unsigned long i6; + uint64 i7; + + signed char i1_0; + signed short i2_0; + signed long i3_0; + unsigned char i4_0; + unsigned short i5_0; + unsigned long i6_0; + uint64 i7_0; + + signed char i1_n; + signed short i2_n; + signed long i3_n; + + + float f1; + double f2; + long double f3; + float f1_inf; + double f2_inf; + long double f3_inf; + float f1_ninf; + double f2_ninf; + long double f3_ninf; + float f1_qnan; + double f2_qnan; + long double f3_qnan; + float f1_snan; + double f2_snan; + long double f3_snan; + + std::string s1; + std::wstring s2; + + int array[10]; + + bool b_true; + bool b_false; + + + void set_state_1( + ) + { + i1 = 1; + i2 = 2; + i3 = 3; + i4 = 4; + i5 = 5; + i6 = 6; + i7 = 7; + + i1_0 = 0; + i2_0 = 0; + i3_0 = 0; + i4_0 = 0; + i5_0 = 0; + i6_0 = 0; + i7_0 = 0; + + i1_n = -1; + i2_n = -2; + i3_n = -3; + + f1 = 123.456f; + f2 = 543.341; + f3 = 5234234.23; + + f1_inf = numeric_limits::infinity(); + f2_inf = numeric_limits::infinity(); + f3_inf = numeric_limits::infinity(); + f1_ninf = -numeric_limits::infinity(); + f2_ninf = -numeric_limits::infinity(); + f3_ninf = -numeric_limits::infinity(); + f1_qnan = numeric_limits::quiet_NaN(); + f2_qnan = numeric_limits::quiet_NaN(); + f3_qnan = numeric_limits::quiet_NaN(); + f1_snan = numeric_limits::signaling_NaN(); + f2_snan = numeric_limits::signaling_NaN(); + f3_snan = numeric_limits::signaling_NaN(); + + s1 = "davis"; + s2 = L"yo yo yo"; + + for (int i = 0; i < 10; ++i) + array[i] = i; + + b_true = true; + b_false = false; + } + + void set_state_2( + ) + { + i1 = 10; + i2 = 20; + i3 = 30; + i4 = 40; + i5 = 50; + i6 = 60; + i7 = 70; + + i1_0 = 5; + i2_0 = 6; + i3_0 = 7; + i4_0 = 8; + i5_0 = 9; + i6_0 = 10; + i7_0 = 11; + + i1_n = -13; + i2_n = -25; + i3_n = -12; + + f1 = 45.3f; + f2 = 0.001; + f3 = 2.332; + + f1_inf = f1; + f2_inf = f2; + f3_inf = f3; + f1_ninf = f1; + f2_ninf = f2; + f3_ninf = f3; + f1_qnan = f1; + f2_qnan = f2; + f3_qnan = f3; + f1_snan = f1; + f2_snan = f2; + f3_snan = f3; + + s1 = ""; + s2 = L""; + + for (int i = 0; i < 10; ++i) + array[i] = 10-i; + + b_true = false; + b_false = true; + } + + void assert_in_state_1 ( + ) + { + DLIB_CASSERT (i1 == 1,""); + DLIB_CASSERT (i2 == 2,""); + DLIB_CASSERT (i3 == 3,""); + DLIB_CASSERT (i4 == 4,""); + DLIB_CASSERT (i5 == 5,""); + DLIB_CASSERT (i6 == 6,""); + DLIB_CASSERT (i7 == 7,""); + + DLIB_CASSERT (i1_0 == 0,""); + DLIB_CASSERT (i2_0 == 0,""); + DLIB_CASSERT (i3_0 == 0,""); + DLIB_CASSERT (i4_0 == 0,""); + DLIB_CASSERT (i5_0 == 0,""); + DLIB_CASSERT (i6_0 == 0,""); + DLIB_CASSERT (i7_0 == 0,""); + + DLIB_CASSERT (i1_n == -1,""); + DLIB_CASSERT (i2_n == -2,""); + DLIB_CASSERT (i3_n == -3,""); + + DLIB_CASSERT (abs(f1 -123.456) < 1e-5,""); + DLIB_CASSERT (abs(f2 - 543.341) < 1e-10,""); + DLIB_CASSERT (abs(f3 - 5234234.23) < 1e-10,""); + + DLIB_CASSERT (f1_inf == numeric_limits::infinity(),""); + DLIB_CASSERT (f2_inf == numeric_limits::infinity(),""); + DLIB_CASSERT (f3_inf == numeric_limits::infinity(),""); + DLIB_CASSERT (f1_ninf == -numeric_limits::infinity(),""); + DLIB_CASSERT (f2_ninf == -numeric_limits::infinity(),""); + DLIB_CASSERT (f3_ninf == -numeric_limits::infinity(),""); + DLIB_CASSERT (!(f1_qnan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() ),""); + DLIB_CASSERT (!(f2_qnan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() ),""); + DLIB_CASSERT (!(f3_qnan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() ),""); + DLIB_CASSERT (!(f1_snan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() ),""); + DLIB_CASSERT (!(f2_snan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() ),""); + DLIB_CASSERT (!(f3_snan <= numeric_limits::infinity() && f1_qnan >= -numeric_limits::infinity() ),""); + + DLIB_CASSERT (s1 == "davis",""); + DLIB_CASSERT (s2 == L"yo yo yo",""); + + for (int i = 0; i < 10; ++i) + { + DLIB_CASSERT (array[i] == i,""); + } + + DLIB_CASSERT (b_true == true,""); + DLIB_CASSERT (b_false == false,""); + + } + + void assert_in_state_2 ( + ) + { + DLIB_CASSERT (i1 == 10,""); + DLIB_CASSERT (i2 == 20,""); + DLIB_CASSERT (i3 == 30,""); + DLIB_CASSERT (i4 == 40,""); + DLIB_CASSERT (i5 == 50,""); + DLIB_CASSERT (i6 == 60,""); + DLIB_CASSERT (i7 == 70,""); + + DLIB_CASSERT (i1_0 == 5,""); + DLIB_CASSERT (i2_0 == 6,""); + DLIB_CASSERT (i3_0 == 7,""); + DLIB_CASSERT (i4_0 == 8,""); + DLIB_CASSERT (i5_0 == 9,""); + DLIB_CASSERT (i6_0 == 10,""); + DLIB_CASSERT (i7_0 == 11,""); + + DLIB_CASSERT (i1_n == -13,""); + DLIB_CASSERT (i2_n == -25,""); + DLIB_CASSERT (i3_n == -12,""); + + DLIB_CASSERT (abs(f1 - 45.3) < 1e-5,""); + DLIB_CASSERT (abs(f2 - 0.001) < 1e-10,""); + DLIB_CASSERT (abs(f3 - 2.332) < 1e-10,""); + DLIB_CASSERT (abs(f1_inf - 45.3) < 1e-5,""); + DLIB_CASSERT (abs(f2_inf - 0.001) < 1e-10,""); + DLIB_CASSERT (abs(f3_inf - 2.332) < 1e-10,""); + DLIB_CASSERT (abs(f1_ninf - 45.3) < 1e-5,""); + DLIB_CASSERT (abs(f2_ninf - 0.001) < 1e-10,""); + DLIB_CASSERT (abs(f3_ninf - 2.332) < 1e-10,""); + DLIB_CASSERT (abs(f1_qnan - 45.3) < 1e-5,""); + DLIB_CASSERT (abs(f2_qnan - 0.001) < 1e-10,""); + DLIB_CASSERT (abs(f3_qnan - 2.332) < 1e-10,""); + DLIB_CASSERT (abs(f1_snan - 45.3) < 1e-5,""); + DLIB_CASSERT (abs(f2_snan - 0.001) < 1e-10,""); + DLIB_CASSERT (abs(f3_snan - 2.332) < 1e-10,""); + + DLIB_CASSERT (s1 == "",""); + DLIB_CASSERT (s2 == L"",""); + + for (int i = 0; i < 10; ++i) + { + DLIB_CASSERT (array[i] == 10-i,""); + } + + DLIB_CASSERT (b_true == false,""); + DLIB_CASSERT (b_false == true,""); + + } + + }; + +// ---------------------------------------------------------------------------------------- + + void serialize ( + const test_object& item, + std::ostream& out + ) + { + dlib::serialize(item.i1,out); + dlib::serialize(item.i2,out); + dlib::serialize(item.i3,out); + dlib::serialize(item.i4,out); + dlib::serialize(item.i5,out); + dlib::serialize(item.i6,out); + dlib::serialize(item.i7,out); + + dlib::serialize(item.i1_0,out); + dlib::serialize(item.i2_0,out); + dlib::serialize(item.i3_0,out); + dlib::serialize(item.i4_0,out); + dlib::serialize(item.i5_0,out); + dlib::serialize(item.i6_0,out); + dlib::serialize(item.i7_0,out); + + dlib::serialize(item.i1_n,out); + dlib::serialize(item.i2_n,out); + dlib::serialize(item.i3_n,out); + + + dlib::serialize(item.f1,out); + dlib::serialize(item.f2,out); + dlib::serialize(item.f3,out); + + dlib::serialize(item.f1_inf,out); + dlib::serialize(item.f2_inf,out); + dlib::serialize(item.f3_inf,out); + dlib::serialize(item.f1_ninf,out); + dlib::serialize(item.f2_ninf,out); + dlib::serialize(item.f3_ninf,out); + dlib::serialize(item.f1_qnan,out); + dlib::serialize(item.f2_qnan,out); + dlib::serialize(item.f3_qnan,out); + dlib::serialize(item.f1_snan,out); + dlib::serialize(item.f2_snan,out); + dlib::serialize(item.f3_snan,out); + + dlib::serialize(item.s1,out); + dlib::serialize(item.s2,out); + + dlib::serialize(item.array,out); + + dlib::serialize(item.b_true,out); + dlib::serialize(item.b_false,out); + } + +// ---------------------------------------------------------------------------------------- + + void deserialize ( + test_object& item, + std::istream& in + ) + { + dlib::deserialize(item.i1,in); + dlib::deserialize(item.i2,in); + dlib::deserialize(item.i3,in); + dlib::deserialize(item.i4,in); + dlib::deserialize(item.i5,in); + dlib::deserialize(item.i6,in); + dlib::deserialize(item.i7,in); + + dlib::deserialize(item.i1_0,in); + dlib::deserialize(item.i2_0,in); + dlib::deserialize(item.i3_0,in); + dlib::deserialize(item.i4_0,in); + dlib::deserialize(item.i5_0,in); + dlib::deserialize(item.i6_0,in); + dlib::deserialize(item.i7_0,in); + + dlib::deserialize(item.i1_n,in); + dlib::deserialize(item.i2_n,in); + dlib::deserialize(item.i3_n,in); + + + dlib::deserialize(item.f1,in); + dlib::deserialize(item.f2,in); + dlib::deserialize(item.f3,in); + + dlib::deserialize(item.f1_inf,in); + dlib::deserialize(item.f2_inf,in); + dlib::deserialize(item.f3_inf,in); + dlib::deserialize(item.f1_ninf,in); + dlib::deserialize(item.f2_ninf,in); + dlib::deserialize(item.f3_ninf,in); + dlib::deserialize(item.f1_qnan,in); + dlib::deserialize(item.f2_qnan,in); + dlib::deserialize(item.f3_qnan,in); + dlib::deserialize(item.f1_snan,in); + dlib::deserialize(item.f2_snan,in); + dlib::deserialize(item.f3_snan,in); + + dlib::deserialize(item.s1,in); + dlib::deserialize(item.s2,in); + + dlib::deserialize(item.array,in); + + dlib::deserialize(item.b_true,in); + dlib::deserialize(item.b_false,in); + } + +// ---------------------------------------------------------------------------------------- + + // This function returns the contents of the file 'stuff.bin' + const std::string get_decoded_string() + { + dlib::base64::kernel_1a base64_coder; + dlib::compress_stream::kernel_1ea compressor; + std::ostringstream sout; + std::istringstream sin; + + + // The base64 encoded data from the file 'stuff.bin' we want to decode and return. + sout << "AVaifX9zEbXbpgarAlucU9BNkSZXOyTKOGxr7taGvaQqrWOaCnaFVnAkSoI4sZ3Va8+I4DqkUa10"; + sout << "6im2LoQqVlfhtRzCgI93x19uWen15Lk+zylZTc34P6aBwSuYMo957IjLhCcBsxIqIbXnWN/7zQSv"; + sout << "c7Anq5STW+yvKzSohWor56pGXDTtZrm9bFTsaztlavtnauYvgn7RZkp4a9MrbgnDzdzmzAnE7+w1"; + sout << "hl94IKktATHIBtMUJsrENvx+np3m01ygEPIftRmEa4KpW1JkZORjqUR/j211oUweh+LYIMR+s4cX"; + sout << "0L7bwPBmULwA"; + + + // Put the data into the istream sin + sin.str(sout.str()); + sout.str(""); + + // Decode the base64 text into its compressed binary form + base64_coder.decode(sin,sout); + sin.clear(); + sin.str(sout.str()); + sout.str(""); + + // Decompress the data into its original form + compressor.decompress(sin,sout); + + // Return the decoded and decompressed data + return sout.str(); + } + +// ---------------------------------------------------------------------------------------- + + // Declare the logger we will use in this test. The name of the tester + // should start with "test." + logger dlog("test.serialize"); + + void serialize_test ( + ) + /*! + ensures + - runs tests on the serialization code for compliance with the specs + !*/ + { + + + print_spinner(); + + ostringstream sout; + test_object obj; + + obj.set_state_1(); + obj.assert_in_state_1(); + serialize(obj, sout); + obj.assert_in_state_1(); + + obj.set_state_2(); + obj.assert_in_state_2(); + serialize(obj, sout); + obj.assert_in_state_2(); + + + istringstream sin(sout.str()); + + deserialize(obj,sin); + obj.assert_in_state_1(); + deserialize(obj,sin); + obj.assert_in_state_2(); + + + // now do the same thing as above but deserialize from some stored binary + // data to make sure the serialized values are portable between different + // machines + + sin.clear(); + sin.str(get_decoded_string()); + + deserialize(obj,sin); + obj.assert_in_state_1(); + deserialize(obj,sin); + obj.assert_in_state_2(); + + /* + // This is the code that produced the encoded data stored in the get_decoded_string() function + ofstream fout("stuff.bin",ios::binary); + obj.set_state_1(); + obj.assert_in_state_1(); + serialize(obj, fout); + obj.assert_in_state_1(); + + obj.set_state_2(); + obj.assert_in_state_2(); + serialize(obj, fout); + obj.assert_in_state_2(); + */ + + } + + + + + + class serialize_tester : public tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a test for the serialization . When it is constructed + it adds itself into the testing framework. The command line switch is + specified as test_serialize by passing that string to the tester constructor. + !*/ + public: + serialize_tester ( + ) : + tester ("test_serialize", + "Runs tests on the serialization code.") + {} + + void perform_test ( + ) + { + serialize_test(); + } + } a; + + +} + + diff --git a/dlib/test/set.cpp b/dlib/test/set.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0218b7b5bd0fa3e07b0d70f310972a3160fcfa7 --- /dev/null +++ b/dlib/test/set.cpp @@ -0,0 +1,464 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.set"); + + template < + typename set + > + void set_compare_test ( + ) + /*! + requires + - set is an implementation of set/set_compare_abstract.h and + is instantiated with int + ensures + - runs tests on set for compliance with the specs + !*/ + { + + + srand(static_cast(time(0))); + + + + set test, test2; + + enumerable& e = test; + DLIB_CASSERT(e.at_start() == true,""); + + for (int j = 0; j < 4; ++j) + { + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + + + int a,b = 0; + a = 8; + test.add(a); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(test.is_member(8) == true,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + a = 53; + test.add(a); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test.is_member(53) == true,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + + + swap(test,test2); + + + + DLIB_CASSERT(test2.is_member(8) == true,""); + DLIB_CASSERT(test2.is_member(5) == false,""); + DLIB_CASSERT(test2.is_member(0) == false,""); + DLIB_CASSERT(test2.is_member(-999) == false,""); + DLIB_CASSERT(test2.is_member(4999) == false,""); + DLIB_CASSERT(test2.size() == 2,""); + DLIB_CASSERT(test2.is_member(53) == true,""); + DLIB_CASSERT(test2.is_member(5) == false,""); + DLIB_CASSERT(test2.is_member(0) == false,""); + DLIB_CASSERT(test2.is_member(-999) == false,""); + DLIB_CASSERT(test2.is_member(4999) == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_member(8) == false,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.is_member(53) == false,""); + DLIB_CASSERT(test.is_member(5) == false,""); + DLIB_CASSERT(test.is_member(0) == false,""); + DLIB_CASSERT(test.is_member(-999) == false,""); + DLIB_CASSERT(test.is_member(4999) == false,""); + + + test.clear(); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + DLIB_CASSERT(test.size() == 10000,""); + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + + while (test.size() < 10000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + DLIB_CASSERT(test.size() == 10000,""); + + int count = 0; + a = 0; + while (test.move_next()) + { + enumerable& gogo = test; + gogo.element(); + + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + + DLIB_CASSERT(a <= test.element(),""); + a = test.element(); + ++count; + } + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + + DLIB_CASSERT(count == 10000,""); + + test.swap(test2); + + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test2.size() == 10000,""); + count = 0; + a = -1; + test2.reset(); + while (test2.move_next()) + { + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(a < test2.element(),""); + a = test2.element(); + ++count; + } + DLIB_CASSERT(test2.size() == 10000,""); + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + + + + test2.clear(); + DLIB_CASSERT(test2.size() == 0,""); + DLIB_CASSERT(test2.at_start() == true,""); + + while (test.size() < 20000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + DLIB_CASSERT(test.at_start() == true,""); + + { + int* array = new int[test.size()]; + int* tmp = array; + + count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + DLIB_CASSERT(test.element() == test.element(),""); + *tmp = test.element(); + ++tmp; + ++count; + } + DLIB_CASSERT(count == 20000,""); + + // serialize the state of test, then clear test, then + // load the state back into test. + ostringstream sout; + serialize(test,sout); + DLIB_CASSERT(test.at_start() == true,""); + istringstream sin(sout.str()); + test.clear(); + deserialize(test,sin); + + + + tmp = array; + for (int i = 0; i < 20000; ++i) + { + DLIB_CASSERT(test.is_member(*tmp) == true,""); + ++tmp; + } + + DLIB_CASSERT(test.size() == 20000,""); + + tmp = array; + count = 0; + while (test.size() > 10000) + { + test.remove(*tmp,a); + DLIB_CASSERT(*tmp == a,""); + ++tmp; + ++count; + } + DLIB_CASSERT(count == 10000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.move_next()) + { + DLIB_CASSERT(test.element() == *tmp,""); + DLIB_CASSERT(test.element() == *tmp,""); + DLIB_CASSERT(test.element() == *tmp,""); + ++tmp; + ++count; + } + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test.size() == 10000,""); + + while (test.size() < 20000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + test2.swap(test); + + count = 0; + a = 0; + while (test2.move_next()) + { + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(test2.element() == test2.element(),""); + DLIB_CASSERT(a <= test2.element(),""); + a = test2.element(); + ++count; + } + + DLIB_CASSERT(count == 20000,""); + DLIB_CASSERT(test2.size() == 20000,""); + + a = -1; + while (test2.size()>0) + { + test2.remove_any(b); + DLIB_CASSERT( a < b,""); + a = b; + } + + DLIB_CASSERT(test2.size() == 0,""); + delete [] array; + } + + test.clear(); + test2.clear(); + while (test.size() < 10000) + { + a = ::rand(); + if (!test.is_member(a)) + test.add(a); + } + + count = 0; + a = -1; + while (test.move_next()) + { + DLIB_CASSERT(a < test.element(),""); + a = test.element(); + ++count; + if (count == 5000) + break; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + test.reset(); + + count = 0; + a = -1; + while (test.move_next()) + { + DLIB_CASSERT(a < test.element(),""); + a = test.element(); + ++count; + DLIB_CASSERT(test.current_element_valid() == true,""); + } + + DLIB_CASSERT(count == 10000,""); + + + test.clear(); + test2.clear(); + } + + + + { + DLIB_CASSERT(test == test2,""); + DLIB_CASSERT(test < test2 == false,""); + DLIB_CASSERT(test2 < test == false,""); + + int a = 3, b = 3; + test.add(a); + test2.add(b); + test.move_next(); + DLIB_CASSERT(test == test2,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test.move_next(); + DLIB_CASSERT(test < test2 == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test.move_next(); + DLIB_CASSERT(test2 < test == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + + a = 2; b = 5; + test.add(a); + test2.add(b); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT((test == test2) == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT(test < test2 == true,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT(test2 < test == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + + + a = 8; + test.add(a); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT((test == test2) == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT(test < test2 == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT(test2 < test == true,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + + test.clear(); + + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT((test == test2) == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT(test < test2 == true,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + test2.move_next(); + DLIB_CASSERT(test2 < test == false,""); + DLIB_CASSERT(test.at_start() && test2.at_start(),""); + + + } + + + { + test.clear(); + DLIB_CASSERT(test.size() == 0,""); + int a = 5; + test.add(a); + a = 7; + test.add(a); + DLIB_CASSERT(test.size() == 2,""); + DLIB_CASSERT(test.is_member(7),""); + DLIB_CASSERT(test.is_member(5),""); + test.destroy(7); + DLIB_CASSERT(test.size() == 1,""); + DLIB_CASSERT(!test.is_member(7),""); + DLIB_CASSERT(test.is_member(5),""); + test.destroy(5); + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(!test.is_member(7),""); + DLIB_CASSERT(!test.is_member(5),""); + } + + + } + + + + + class set_tester : public tester + { + public: + set_tester ( + ) : + tester ("test_set", + "Runs tests on the set component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing compare_1a"; + set_compare_test::compare_1a> (); + dlog << LINFO << "testing compare_1a_c"; + set_compare_test::compare_1a_c>(); + dlog << LINFO << "testing compare_1b"; + set_compare_test::compare_1b> (); + dlog << LINFO << "testing compare_1b_c"; + set_compare_test::compare_1b_c>(); + } + } a; + +} + diff --git a/dlib/test/sliding_buffer.cpp b/dlib/test/sliding_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8e03ae146ca60b75c8652278166012973cc566c --- /dev/null +++ b/dlib/test/sliding_buffer.cpp @@ -0,0 +1,330 @@ +// Copyright (C) 2004 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.sliding_buffer"); + + template < + typename buf + > + void sliding_buffer_kernel_test ( + ) + /*! + requires + - buf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h + - buf is instantiated with T=unsigned char + ensures + - runs tests on buf for compliance with the specs + !*/ + { + + print_spinner(); + + buf test; + + DLIB_CASSERT(test.size() == 0,""); + + test.set_size(3); + buf test2; + + DLIB_CASSERT(test.size() == 8,""); + + for (int g = 0; g < 2; ++g) + { + + test.clear(); + + DLIB_CASSERT(test.size() == 0,""); + test.set_size(2); + + DLIB_CASSERT(test.size() == 4,""); + + + + test[0] = 'a'; + test[1] = 's'; + test[2] = 'd'; + test[3] = 'f'; + + unsigned long id = test.get_element_id(2); + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + + + DLIB_CASSERT(test[0] == 'a',""); + DLIB_CASSERT(test[1] == 's',""); + DLIB_CASSERT(test[2] == 'd',""); + DLIB_CASSERT(test[3] == 'f',""); + + DLIB_CASSERT(test2.size() == 0,""); + swap(test,test2); + DLIB_CASSERT(test2.size() == 4,""); + + DLIB_CASSERT(test2[0] == 'a',""); + DLIB_CASSERT(test2[1] == 's',""); + DLIB_CASSERT(test2[2] == 'd',""); + DLIB_CASSERT(test2[3] == 'f',""); + + swap(test,test2); + + test.rotate_left(4); + + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + + DLIB_CASSERT(test[0] == 'a',""); + DLIB_CASSERT(test[1] == 's',""); + DLIB_CASSERT(test[2] == 'd',""); + DLIB_CASSERT(test[3] == 'f',""); + + test.rotate_right(1); + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + + DLIB_CASSERT(test[0] == 's',""); + DLIB_CASSERT(test[1] == 'd',""); + DLIB_CASSERT(test[2] == 'f',""); + DLIB_CASSERT(test[3] == 'a',""); + + + test.rotate_left(1); + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + DLIB_CASSERT(test[0] == 'a',""); + DLIB_CASSERT(test[1] == 's',""); + DLIB_CASSERT(test[2] == 'd',""); + DLIB_CASSERT(test[3] == 'f',""); + + + test.rotate_left(16); + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + DLIB_CASSERT(test[0] == 'a',""); + DLIB_CASSERT(test[1] == 's',""); + DLIB_CASSERT(test[2] == 'd',""); + DLIB_CASSERT(test[3] == 'f',""); + + + test.rotate_left(2); + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + + DLIB_CASSERT(test[0] == 'd',""); + DLIB_CASSERT(test[1] == 'f',""); + DLIB_CASSERT(test[2] == 'a',""); + DLIB_CASSERT(test[3] == 's',""); + + test.rotate_left(1); + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + DLIB_CASSERT(test[0] == 's',""); + DLIB_CASSERT(test[1] == 'd',""); + DLIB_CASSERT(test[2] == 'f',""); + DLIB_CASSERT(test[3] == 'a',""); + + test.rotate_left(1); + + DLIB_CASSERT(test[test.get_element_index(id)] == 'd',""); + DLIB_CASSERT(test[0] == 'a',""); + DLIB_CASSERT(test[1] == 's',""); + DLIB_CASSERT(test[2] == 'd',""); + DLIB_CASSERT(test[3] == 'f',""); + + DLIB_CASSERT(test.size() == 4,""); + + test[0] = 'x'; + + DLIB_CASSERT(test[0] == 'x',""); + DLIB_CASSERT(test[1] == 's',""); + DLIB_CASSERT(test[2] == 'd',""); + DLIB_CASSERT(test[3] == 'f',""); + + test.rotate_left(1); + + DLIB_CASSERT(test[0] == 'f',test[0]); + DLIB_CASSERT(test[1] == 'x',""); + DLIB_CASSERT(test[2] == 's',""); + DLIB_CASSERT(test[3] == 'd',""); + + + test[0] = 'x'; + + DLIB_CASSERT(test[0] == 'x',""); + DLIB_CASSERT(test[1] == 'x',""); + DLIB_CASSERT(test[2] == 's',""); + DLIB_CASSERT(test[3] == 'd',""); + + + test.rotate_left(1); + + + DLIB_CASSERT(test[0] == 'd',""); + DLIB_CASSERT(test[1] == 'x',""); + DLIB_CASSERT(test[2] == 'x',""); + DLIB_CASSERT(test[3] == 's',""); + + + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + + test.clear(); + test2.clear(); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + + swap(test,test2); + + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + DLIB_CASSERT(test2.move_next() == false,""); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test2.current_element_valid() == false,""); + + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + test.set_size(3); + DLIB_CASSERT(test.size() == 8,""); + + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + test.reset(); + DLIB_CASSERT(test.size() == 8,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + + + test.rotate_right(1); + DLIB_CASSERT(test.size() == 8,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + + test.rotate_left(1); + DLIB_CASSERT(test.size() == 8,""); + DLIB_CASSERT(test.at_start() == true,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == true,""); + DLIB_CASSERT(test.at_start() == false,""); + DLIB_CASSERT(test.current_element_valid() == true,""); + test.reset(); + + + for (unsigned long i = 0; i < test.size(); ++i) + { + test[i] = static_cast(i); + } + + unsigned long count = 0; + while (test.move_next()) + { + DLIB_CASSERT(test.element() == count,""); + ++count; + } + + DLIB_CASSERT(count == test.size(),""); + + + test2.clear(); + ostringstream sout; + istringstream sin; + + serialize(test,sout); + sin.str(sout.str()); + deserialize(test2,sin); + + char ch; + sin >> ch; + DLIB_CASSERT( !sin, ""); + + DLIB_CASSERT(test2.size() == test.size(),""); + + + for (unsigned long i = 0; i < test.size(); ++i) + { + DLIB_CASSERT(test[i] == test2[i], + "\ni: " << i << + "\ntest[i]: " << test[i] << + "\ntest2[i]: " << test2[i]); + } + + count = 0; + while (test.move_next() && test2.move_next()) + { + DLIB_CASSERT(test.element() == count,""); + DLIB_CASSERT(test2.element() == count,""); + ++count; + } + + DLIB_CASSERT(test2.size() == count,""); + DLIB_CASSERT(test.size() == count,""); + + test2.clear(); + + + } // for (int g = 0; g < 2; ++g) + + + } + + + + + + + class sliding_buffer_tester : public tester + { + public: + sliding_buffer_tester ( + ) : + tester ("test_sliding_buffer", + "Runs tests on the sliding_buffer component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + sliding_buffer_kernel_test::kernel_1a> (); + dlog << LINFO << "testing kernel_1a_c"; + sliding_buffer_kernel_test::kernel_1a_c>(); + } + } a; + +} + diff --git a/dlib/test/smart_pointers.cpp b/dlib/test/smart_pointers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fd0d971c26bad115df098e265ee2ad885e5d307 --- /dev/null +++ b/dlib/test/smart_pointers.cpp @@ -0,0 +1,393 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.smart_pointers"); + + int counter = 0; + struct base + { + int num; + virtual ~base() {} + }; + + struct derived : public base + { + derived() { ++counter; } + ~derived() { --counter; } + }; + + int deleter_called = 0; + void deleter ( derived* p) { ++deleter_called; delete p; } + void deleter_base ( base* p) { ++deleter_called; delete p; } + typedef void (*D)(derived*); + typedef void (*Db)(base*); + + void smart_pointers_test ( + ) + /*! + ensures + - runs tests on the smart pointers for compliance with the specs + !*/ + { + counter = 0; + deleter_called = 0; + + { + DLIB_CASSERT(counter == 0,counter); + scoped_ptr p1(new derived); + scoped_ptr p2(new derived); + scoped_ptr p3; + DLIB_CASSERT(counter == 2,counter); + DLIB_CASSERT(!p3,""); + + p1->num = 1; + p2->num = 2; + DLIB_CASSERT(p1->num == 1,""); + DLIB_CASSERT(p2->num == 2,""); + + (*p1).num = 3; + (*p2).num = 4; + DLIB_CASSERT(p1->num == 3,""); + DLIB_CASSERT(p2->num == 4,""); + + DLIB_CASSERT(counter == 2,counter); + + DLIB_CASSERT(p1,""); + DLIB_CASSERT(p2,""); + + DLIB_CASSERT(counter == 2,counter); + p1.reset(); + DLIB_CASSERT(counter == 1,counter); + DLIB_CASSERT(!p1,""); + DLIB_CASSERT(p2,""); + p1.reset(new derived); + DLIB_CASSERT(counter == 2,counter); + DLIB_CASSERT(p1,""); + + + DLIB_CASSERT(counter == 2,counter); + p2.reset(); + DLIB_CASSERT(counter == 1,counter); + DLIB_CASSERT(!p2,""); + derived* d = new derived; + p2.reset(d); + DLIB_CASSERT(p2.get() == d,""); + DLIB_CASSERT(counter == 2,counter); + DLIB_CASSERT(p2,""); + DLIB_CASSERT(!p3,""); + p2->num = 9; + swap(p2,p3); + DLIB_CASSERT(!p2,""); + DLIB_CASSERT(p3,""); + DLIB_CASSERT(p3->num == 9,""); + p2.swap(p3); + DLIB_CASSERT(p2,""); + DLIB_CASSERT(!p3,""); + DLIB_CASSERT(p2->num == 9,""); + + + DLIB_CASSERT(counter == 2,counter); + + } + DLIB_CASSERT(counter == 0,counter); + + { + base* realp1 = new derived; + derived* realp2 = new derived; + shared_ptr p1(realp1); + shared_ptr p2(realp2,&deleter); + shared_ptr p3; + shared_ptr p4; + DLIB_CASSERT(p4.get() == 0,""); + DLIB_CASSERT(p1,""); + DLIB_CASSERT(p2,""); + DLIB_CASSERT(!p3,""); + DLIB_CASSERT(!p4,""); + DLIB_CASSERT(p1.get() == realp1,""); + DLIB_CASSERT(p2.get() == realp2,""); + p1->num = 1; + p2->num = 2; + DLIB_CASSERT((*p1).num == 1,""); + DLIB_CASSERT((*p2).num == 2,""); + + p1.swap(p3); + DLIB_CASSERT(!p1,""); + DLIB_CASSERT(p3,""); + DLIB_CASSERT((*p3).num == 1,""); + DLIB_CASSERT(p3->num == 1,""); + swap(p1,p3); + DLIB_CASSERT(p1,""); + DLIB_CASSERT(!p3,""); + DLIB_CASSERT((*p1).num == 1,""); + DLIB_CASSERT(p1->num == 1,""); + DLIB_CASSERT(counter == 2,counter); + + DLIB_CASSERT(p1.unique(),""); + DLIB_CASSERT(p2.unique(),""); + DLIB_CASSERT(!p3.unique(),""); + DLIB_CASSERT(!p4.unique(),""); + + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(p2.use_count() == 1,""); + DLIB_CASSERT(p3.use_count() == 0,""); + DLIB_CASSERT(p4.use_count() == 0,""); + + shared_ptr p11(p1); + + DLIB_CASSERT(!p1.unique(),""); + DLIB_CASSERT(p2.unique(),""); + DLIB_CASSERT(!p3.unique(),""); + DLIB_CASSERT(!p4.unique(),""); + + DLIB_CASSERT(p1.use_count() == 2,""); + DLIB_CASSERT(p2.use_count() == 1,""); + DLIB_CASSERT(p3.use_count() == 0,""); + DLIB_CASSERT(p4.use_count() == 0,""); + + shared_ptr p22(p2); + + DLIB_CASSERT(!p1.unique(),""); + DLIB_CASSERT(!p2.unique(),""); + DLIB_CASSERT(!p3.unique(),""); + DLIB_CASSERT(!p4.unique(),""); + + DLIB_CASSERT(p1.use_count() == 2,""); + DLIB_CASSERT(p2.use_count() == 2,""); + DLIB_CASSERT(p3.use_count() == 0,""); + DLIB_CASSERT(p4.use_count() == 0,""); + + DLIB_CASSERT(p11.get() == realp1,""); + DLIB_CASSERT(p11 == p1,""); + DLIB_CASSERT(p22 == p2,""); + DLIB_CASSERT(p3 == p4,""); + DLIB_CASSERT(p11 != p22,""); + DLIB_CASSERT(p1 != p2,""); + DLIB_CASSERT(p3 != p1,""); + DLIB_CASSERT(p3 != p11,""); + DLIB_CASSERT(p3 != p2,""); + + + p1 = p1 = p1; + DLIB_CASSERT(p1.use_count() == 2,""); + DLIB_CASSERT(p1->num == 1,""); + DLIB_CASSERT(p11.use_count() == 2,""); + p1.reset(); + DLIB_CASSERT(p1.get() == 0,""); + DLIB_CASSERT(p1.use_count() == 0,""); + DLIB_CASSERT(p1.unique() == false,""); + DLIB_CASSERT(p11.use_count() == 1,""); + p11 = p2; + DLIB_CASSERT(p1.use_count() == 0,""); + DLIB_CASSERT(p1.unique() == false,""); + DLIB_CASSERT(p11.use_count() == 3,""); + DLIB_CASSERT(p11.unique() == false,""); + + // now p11, p2, and p22 all reference the same thing and the rest are null + DLIB_CASSERT((p11 < p2) == false,"") + DLIB_CASSERT((p2 < p11) == false,"") + + DLIB_CASSERT(get_deleter(p4) == 0,""); + p4 = p2; + DLIB_CASSERT(get_deleter(p4) != 0,""); + DLIB_CASSERT(get_deleter(p4) == get_deleter(p2),""); + DLIB_CASSERT(get_deleter(p4) == get_deleter(p11),""); + DLIB_CASSERT(get_deleter(p4) == 0,""); + + realp1 = new derived; + p1.reset(realp1, &deleter_base); + DLIB_CASSERT(p1.get() == realp1,""); + DLIB_CASSERT(p1.unique(),""); + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(*get_deleter(p1) == &deleter_base,""); + DLIB_CASSERT(p1 != p4,""); + p4 = dynamic_pointer_cast(p1); + DLIB_CASSERT(!p1.unique(),""); + DLIB_CASSERT(p1.use_count() == 2,""); + DLIB_CASSERT(p1 == p4,""); + + realp1 = new derived; + p1.reset(realp1); + DLIB_CASSERT(p1.get() == realp1,""); + DLIB_CASSERT(p1.unique(),""); + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(get_deleter(p1) == 0,""); + + + auto_ptr ap1(new derived); + auto_ptr ap2(new derived); + ap1->num = 35; + ap2->num = 36; + + DLIB_CASSERT(ap1.get() != 0,""); + DLIB_CASSERT(ap2.get() != 0,""); + p1 = ap2; + p2 = ap1; + + DLIB_CASSERT(ap1.get() == 0,""); + DLIB_CASSERT(p1.unique(),""); + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(ap2.get() == 0,""); + DLIB_CASSERT(p2.unique(),""); + DLIB_CASSERT(p2.use_count() == 1,""); + DLIB_CASSERT(p1->num == 36,""); + DLIB_CASSERT(p2->num == 35,""); + + } + + DLIB_CASSERT(counter == 0,counter); + DLIB_CASSERT(deleter_called == 2,counter); + + weak_ptr wp4; + { + shared_ptr p1(new derived, &deleter_base); + shared_ptr p2; + shared_ptr p3; + + weak_ptr wp1; + weak_ptr wp2; + weak_ptr wp3; + + weak_ptr wp1c(p1); + weak_ptr wp2c(p1); + weak_ptr wp3c(p2); + + DLIB_CASSERT(wp1c.use_count() == 1,""); + DLIB_CASSERT(wp1c.lock() == p1,""); + DLIB_CASSERT(wp1c.expired() == false,""); + + DLIB_CASSERT(wp2c.use_count() == 1,""); + DLIB_CASSERT(wp2c.lock() == p1,""); + DLIB_CASSERT(wp2c.expired() == false,""); + + DLIB_CASSERT(wp3c.use_count() == 0,""); + DLIB_CASSERT(wp3c.lock() == shared_ptr(),""); + DLIB_CASSERT(wp3c.expired() == true,""); + + DLIB_CASSERT(wp2.use_count() == 0,""); + DLIB_CASSERT(wp2.expired() == true,""); + DLIB_CASSERT(wp2.lock().use_count() == 0,""); + DLIB_CASSERT(wp2.lock().unique() == false,""); + + wp1 = p1; + wp2 = wp1; + wp3 = p1; + + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(p1.unique(),""); + DLIB_CASSERT(wp1.use_count() == 1,""); + DLIB_CASSERT(wp2.use_count() == 1,""); + DLIB_CASSERT(wp3.use_count() == 1,""); + DLIB_CASSERT(wp1.expired() == false,""); + DLIB_CASSERT(wp2.expired() == false,""); + DLIB_CASSERT(wp3.expired() == false,""); + DLIB_CASSERT(wp1.lock() == p1,""); + DLIB_CASSERT(wp2.lock() == p1,""); + DLIB_CASSERT(wp3.lock() == p1,""); + + wp3.reset(); + + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(p1.unique(),""); + DLIB_CASSERT(wp1.use_count() == 1,""); + DLIB_CASSERT(wp2.use_count() == 1,""); + DLIB_CASSERT(wp3.use_count() == 0,""); + DLIB_CASSERT(wp1.expired() == false,""); + DLIB_CASSERT(wp2.expired() == false,""); + DLIB_CASSERT(wp3.expired() == true,""); + DLIB_CASSERT(wp1.lock() == p1,""); + DLIB_CASSERT(wp2.lock() == p1,""); + DLIB_CASSERT(wp3.lock() == shared_ptr(),""); + + + p1.reset(); + + DLIB_CASSERT(p1.use_count() == 0,""); + DLIB_CASSERT(p1.unique() == false,""); + DLIB_CASSERT(wp1.use_count() == 0,""); + DLIB_CASSERT(wp2.use_count() == 0,""); + DLIB_CASSERT(wp3.use_count() == 0,""); + DLIB_CASSERT(wp1.expired() == true,""); + DLIB_CASSERT(wp2.expired() == true,""); + DLIB_CASSERT(wp3.expired() == true,""); + DLIB_CASSERT(wp1.lock() == shared_ptr(),""); + DLIB_CASSERT(wp2.lock() == shared_ptr(),""); + DLIB_CASSERT(wp3.lock() == shared_ptr(),""); + + p1.reset(new derived); + + DLIB_CASSERT(p1.use_count() == 1,""); + DLIB_CASSERT(p1.unique() == true,""); + DLIB_CASSERT(wp1.use_count() == 0,""); + DLIB_CASSERT(wp2.use_count() == 0,""); + DLIB_CASSERT(wp3.use_count() == 0,""); + DLIB_CASSERT(wp1.expired() == true,""); + DLIB_CASSERT(wp2.expired() == true,""); + DLIB_CASSERT(wp3.expired() == true,""); + DLIB_CASSERT(wp1.lock() == shared_ptr(),""); + DLIB_CASSERT(wp2.lock() == shared_ptr(),""); + DLIB_CASSERT(wp3.lock() == shared_ptr(),""); + + DLIB_CASSERT(wp4.expired() == true,""); + DLIB_CASSERT(wp4.lock() == shared_ptr(),""); + wp4 = p1; + p3 = p1; + DLIB_CASSERT(wp4.expired() == false,""); + DLIB_CASSERT(wp4.lock() == p3,""); + + + bool ok = false; + try { + shared_ptr bad_ptr(wp1); + } catch (bad_weak_ptr&) + { + ok = true; + } + DLIB_CASSERT(ok,""); + } + DLIB_CASSERT(wp4.expired() == true,""); + DLIB_CASSERT(wp4.lock() == shared_ptr(),""); + + + DLIB_CASSERT(counter == 0,counter); + DLIB_CASSERT(deleter_called == 3,counter); + + } + + + + class smart_pointers_tester : public tester + { + public: + smart_pointers_tester ( + ) : + tester ("test_smart_pointers", + "Runs tests on the smart pointers.") + {} + + void perform_test ( + ) + { + smart_pointers_test(); + } + } a; + +} + + + diff --git a/dlib/test/sockets.cpp b/dlib/test/sockets.cpp new file mode 100644 index 0000000000000000000000000000000000000000..264f0cf6ebf1845c62544f85b78a2bcf23e23774 --- /dev/null +++ b/dlib/test/sockets.cpp @@ -0,0 +1,231 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + dlib::mutex m; + dlib::signaler s(m); + const char magic_num = 42; + const int min_bytes_sent = 10000; + int thread_count; + int thread_count2; + int assigned_port; + + logger dlog("test.sockets"); + +// ---------------------------------------------------------------------------------------- + + class serv : public server::kernel_1a_c + { + public: + serv ( + ) : + error_occurred (false) + {} + + void on_listening_port_assigned ( + ) + { + auto_mutex M(m); + assigned_port = get_listening_port(); + s.broadcast(); + } + + + void on_connect ( + connection& con + ) + { + dlog << LINFO << "in serv::on_connect(): got new connection"; + int status; + int count = 0; + char buf[100]; + while ((status = con.read(buf,sizeof(buf))) > 0) + { + for (int i = 0; i < status; ++i) + { + if (buf[i] != magic_num) + { + tag = 4.0; + error_occurred = true; + } + } + count += status; + } + if (count != min_bytes_sent) + { + tag = 5.0; + error_occurred = true; + } + dlog << LINFO << "in serv::on_connect(): on_connect ending"; + } + + bool error_occurred; + double tag; + }; + +// ---------------------------------------------------------------------------------------- + + void thread_proc ( + void* param + ) + { + serv& srv = *reinterpret_cast(param); + try + { + dlog << LTRACE << "enter thread"; + { + auto_mutex M(m); + while (assigned_port == 0) + s.wait(); + } + + int status; + connection* con; + string hostname; + string ip; + status = get_local_hostname(hostname); + if (status) + { + srv.tag = 1.0; + srv.error_occurred = true; + srv.clear(); + dlog << LWARN << "leaving thread, line: " << __LINE__; + return; + } + + status = hostname_to_ip(hostname,ip); + if (status) + { + srv.tag = 2.0; + srv.error_occurred = true; + srv.clear(); + dlog << LWARN << "leaving thread, line: " << __LINE__; + return; + } + + dlog << LTRACE << "try to connect to the server at port " << srv.get_listening_port(); + status = create_connection(con,srv.get_listening_port(),ip); + if (status) + { + srv.tag = 3.0; + srv.error_occurred = true; + srv.clear(); + dlog << LWARN << "leaving thread, line: " << __LINE__; + return; + } + + dlog << LTRACE << "sending magic_num to server"; + int i; + for (i = 0; i < min_bytes_sent; ++i) + { + con->write(&magic_num,1); + } + + dlog << LTRACE << "shutting down connection to server"; + close_gracefully(con); + dlog << LTRACE << "finished calling close_gracefully() on the connection"; + + auto_mutex M(m); + --thread_count; + s.broadcast(); + while (thread_count > 0) + s.wait(); + + srv.clear(); + + --thread_count2; + s.broadcast(); + } + catch (exception& e) + { + srv.error_occurred = true; + dlog << LERROR << "exception thrown in thread_proc(): " << e.what(); + cout << "exception thrown in thread_proc(): " << e.what(); + } + dlog << LTRACE << "exit thread"; + } + + void sockets_test ( + ) + /*! + requires + - sockets is an implementation of sockets/sockets_kernel_abstract.h + is instantiated with int + ensures + - runs tests on sockets for compliance with the specs + !*/ + { + + dlog << LTRACE << "starting test"; + serv srv; + + thread_count = 10; + assigned_port = 0; + thread_count2 = thread_count; + + + dlog << LTRACE << "spawning threads"; + int num = thread_count; + for (int i = 0; i < num; ++i) + { + create_new_thread(thread_proc,&srv); + } + + + + dlog << LTRACE << "calling srv.start()"; + srv.start(); + dlog << LTRACE << "srv.start() just ended."; + + { + auto_mutex M(m); + while (thread_count2 > 0) + s.wait(); + } + if (srv.error_occurred) + { + dlog << LDEBUG << "tag: " << srv.tag; + } + + dlog << LTRACE << "ending successful test"; + DLIB_CASSERT( !srv.error_occurred,""); + } + +// ---------------------------------------------------------------------------------------- + + + class sockets_tester : public tester + { + public: + sockets_tester ( + ) : + tester ("test_sockets", + "Runs tests on the sockets component.") + {} + + void perform_test ( + ) + { + sockets_test(); + } + } a; + +} + diff --git a/dlib/test/sockstreambuf.cpp b/dlib/test/sockstreambuf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..115f2e6a2ef4e31c2a9f377b8dc83f0dbc2118a3 --- /dev/null +++ b/dlib/test/sockstreambuf.cpp @@ -0,0 +1,250 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + dlib::mutex m; + dlib::signaler s(m); + bool thread_running; + + logger dlog("test.sockstreambuf"); + +// ---------------------------------------------------------------------------------------- + + template + void thread_proc ( + void* param + ) + { + + listener& list = *reinterpret_cast(param); + connection* con; + list.accept(con); + + ssb buf(con); + ostream out(&buf); + + + char ch; + char* bigbuf = new char[1000000]; + + + for (int i = 'a'; i < 'z'; ++i) + { + ch = i; + out << ch << " "; + } + + out.put('A'); + + for (int i = 0; i < 256; ++i) + { + ch = i; + out.write(&ch,1); + } + + for (int i = -100; i < 25600; ++i) + { + out << i << " "; + } + + out.put('A'); + + for (int i = -100; i < 25600; ++i) + { + out.write((char*)&i,sizeof(i)); + } + + for (int i = 0; i < 1000000; ++i) + { + bigbuf[i] = (i&0xFF); + } + out.write(bigbuf,1000000); + + out.put('d'); + out.put('a'); + out.put('v'); + out.put('i'); + out.put('s'); + + + string tstring = "this is a test"; + int tint = -853; + unsigned int tuint = 89; + serialize(tstring,out); + serialize(tint,out); + serialize(tuint,out); + + + out.flush(); + + + auto_mutex M(m); + thread_running = false; + s.signal(); + + dlib::sleep(300); + delete con; + delete &list; + + delete [] bigbuf; + } + + template + void sockstreambuf_test ( + ) + /*! + requires + - ssb is an implementation of sockstreambuf/sockstreambuf_kernel_abstract.h + ensures + - runs tests on ssb for compliance with the specs + !*/ + { + char ch; + vector vbuf; + vbuf.resize(1000000); + char* bigbuf = &vbuf[0]; + connection* con; + + print_spinner(); + thread_running = true; + listener* list; + if (create_listener(list,0)) + { + DLIB_CASSERT(false, "Unable to create a listener"); + } + + create_new_thread(thread_proc,list); + + if (create_connection(con,list->get_listening_port(),"127.0.0.1")) + { + DLIB_CASSERT(false, "Unable to create a connection"); + } + + // make sure con gets deleted + scoped_ptr del_con(con); + + ssb buf(con); + istream in(&buf); + + + + for (int i = 'a'; i < 'z'; ++i) + { + in >> ch; + char c = i; + DLIB_CASSERT(ch == c,"ch: " << (int)ch << " c: " << (int)c); + } + + in.get(); + DLIB_CASSERT(in.peek() == 'A', "*" << in.peek() << "*"); + in.get(); + + for (int i = 0; i < 256; ++i) + { + in.read(&ch,1); + char c = i; + DLIB_CASSERT(ch == c,"ch: " << (int)ch << " c: " << (int)c ); + } + + for (int i = -100; i < 25600; ++i) + { + int n = 0; + in >> n; + DLIB_CASSERT(n == i,"n: " << n << " i:" << i); + } + + in.get(); + DLIB_CASSERT(in.peek() == 'A', "*" << in.peek() << "*"); + in.get(); + + for (int i = -100; i < 25600; ++i) + { + int n; + in.read((char*)&n,sizeof(n)); + DLIB_CASSERT(n == i,"n: " << n << " i:" << i); + } + + in.read(bigbuf,1000000); + for (int i = 0; i < 1000000; ++i) + { + DLIB_CASSERT(bigbuf[i] == (char)(i&0xFF),""); + } + + DLIB_CASSERT(in.get() == 'd',""); + DLIB_CASSERT(in.get() == 'a',""); + DLIB_CASSERT(in.get() == 'v',""); + DLIB_CASSERT(in.get() == 'i',""); + + DLIB_CASSERT(in.peek() == 's',""); + + DLIB_CASSERT(in.get() == 's',""); + + in.putback('s'); + DLIB_CASSERT(in.peek() == 's',""); + + DLIB_CASSERT(in.get() == 's',""); + + + string tstring; + int tint; + unsigned int tuint; + deserialize(tstring,in); + deserialize(tint,in); + deserialize(tuint,in); + + DLIB_CASSERT(tstring == "this is a test",""); + DLIB_CASSERT(tint == -853,""); + DLIB_CASSERT(tuint == 89,""); + + + + auto_mutex M(m); + while (thread_running) + s.wait(); + + } + +// ---------------------------------------------------------------------------------------- + + + class sockstreambuf_tester : public tester + { + public: + sockstreambuf_tester ( + ) : + tester ("test_sockstreambuf", + "Runs tests on the sockstreambuf component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + sockstreambuf_test(); + dlog << LINFO << "testing kernel_2a"; + sockstreambuf_test(); + } + } a; + +} + + diff --git a/dlib/test/stack.cpp b/dlib/test/stack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c64feb08ad2e1ba17dd4c33699366df7a9c4786c --- /dev/null +++ b/dlib/test/stack.cpp @@ -0,0 +1,294 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.stack"); + + template < + typename stack + > + void stack_kernel_test ( + ) + /*! + requires + - stack is an implementation of stack/stack_sort_abstract.h + stack is instantiated with int + ensures + - runs tests on stack for compliance with the specs + !*/ + { + + + srand(static_cast(time(0))); + + print_spinner(); + + stack a1, a2; + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + swap(a1,a2); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.move_next() == false,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + a1.reset(); + a2.reset(); + + for (unsigned long k = 0; k < 4; ++k) + { + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + swap(a1,a2); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.move_next() == false,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + a1.clear(); + a2.clear(); + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + swap(a1,a2); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.move_next() == false,""); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a2.size() == 0,""); + + + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start(),""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.move_next() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a1.at_start() == false,""); + DLIB_CASSERT(a1.size() == 0,""); + + a1.clear(); + a2.clear(); + + + for (unsigned long i = 0; i < 100; ++i) + { + int a = (int)i; + a1.push(a); + } + + DLIB_CASSERT(a1.size() == 100,""); + + int count = 99; + while (a1.move_next()) + { + DLIB_CASSERT(a1.element() == count,a1.element() << " : " << count); + --count; + } + + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == false,""); + + a1.swap(a2); + + count = 99; + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + DLIB_CASSERT(a1.current_element_valid() == false,""); + DLIB_CASSERT(a1.at_start() == true,""); + + DLIB_CASSERT(a1.size() == 0,""); + DLIB_CASSERT(a2.size() == 100,""); + DLIB_CASSERT(a2.current() == 99,""); + + a2.reset(); + while (a2.move_next()) + { + DLIB_CASSERT(a2.element() == count--,""); + } + + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == false,""); + int b = 4; + a2.push(b); + DLIB_CASSERT(a2.current_element_valid() == false,""); + DLIB_CASSERT(a2.at_start() == true,""); + + DLIB_CASSERT(a2.current() == 4,""); + int c = 0; + a2.pop(c); + DLIB_CASSERT(c == 4,""); + + // serialize the state of a2, then clear a2, then + // load the state back into a2. + ostringstream sout; + serialize(a2,sout); + DLIB_CASSERT(a2.at_start() == true,""); + istringstream sin(sout.str()); + a2.clear(); + deserialize(a2,sin); + + + count = 99; + while (a2.size()) + { + int a = 0; + DLIB_CASSERT(a2.current() == count,""); + DLIB_CASSERT(const_cast(a2).current() == count,""); + a2.pop(a); + DLIB_CASSERT(a == count--,""); + } + + + + + + + a1.clear(); + a2.clear(); + } + + + { + a1.clear(); + remover& go = a1; + for (int i = 0; i < 100; ++i) + { + int a = 3; + a1.push(a); + } + DLIB_CASSERT(go.size() == 100,""); + for (int i = 0; i < 100; ++i) + { + int a = 9; + go.remove_any(a); + DLIB_CASSERT(a == 3,""); + } + DLIB_CASSERT(go.size() == 0,""); + } + + } + + + + + class stack_tester : public tester + { + public: + stack_tester ( + ) : + tester ("test_stack", + "Runs tests on the stack component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + stack_kernel_test::kernel_1a> (); + dlog << LINFO << "testing kernel_1a_c"; + stack_kernel_test::kernel_1a_c>(); + } + } a; + +} + diff --git a/dlib/test/static_map.cpp b/dlib/test/static_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76ed41c4995bfbe70996903298867eb14ab64f14 --- /dev/null +++ b/dlib/test/static_map.cpp @@ -0,0 +1,323 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include + +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.static_map"); + + template < + typename map + > + void static_map_kernel_test ( + ) + /*! + requires + - map is an implementation of static_map/static_map_kernel_abstract.h and + is instantiated to map int to int + ensures + - runs tests on map for compliance with the specs + !*/ + { + + print_spinner(); + srand(static_cast(time(0))); + + typedef binary_search_tree::kernel_2a_c bst; + typedef hash_table::kernel_1a_c ht; + + const unsigned long table_4_max_size = 100; + const unsigned long tree_max_size = 50000; + ht table_4(4); + ht table_8(8); + bst tree; + + ht table_4b(4); + ht table_8b(8); + bst treeb; + + + // just do the following to make sure operator[] doesn't hang + // under some instances + { + int g = 1, h = 1; + treeb.add(g,h); + map test; + map test2; + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.move_next() == false,""); + DLIB_CASSERT(test.current_element_valid() == false,""); + DLIB_CASSERT(test.at_start() == false,""); + + swap(test,test2); + DLIB_CASSERT(test2.at_start() == false,""); + DLIB_CASSERT(test.at_start() == true,""); + + swap(test,test2); + DLIB_CASSERT(test.at_start() == false,""); + + + DLIB_CASSERT(test.size() == 0,""); + DLIB_CASSERT(test[1] == 0,""); + DLIB_CASSERT(test[2] == 0,""); + DLIB_CASSERT(test[3] == 0,""); + DLIB_CASSERT(test[0] == 0,""); + + test.load(treeb); + DLIB_CASSERT(test.at_start(),""); + DLIB_CASSERT(test[1] != 0,""); + DLIB_CASSERT(test[2] == 0,""); + DLIB_CASSERT(test[3] == 0,""); + DLIB_CASSERT(test[0] == 0,""); + + test2.clear(); + swap(test2,test); + DLIB_CASSERT(test2[1] != 0,""); + DLIB_CASSERT(test2[2] == 0,""); + DLIB_CASSERT(test2[3] == 0,""); + DLIB_CASSERT(test2[0] == 0,""); + DLIB_CASSERT(test[1] == 0,""); + DLIB_CASSERT(test[2] == 0,""); + DLIB_CASSERT(test[3] == 0,""); + DLIB_CASSERT(test[0] == 0,""); + + + DLIB_CASSERT(treeb.size() == 0,""); + treeb.clear(); + } + + + for (unsigned long i = 0; i < table_4_max_size; ++i) + { + int a = ::rand()&0xFF; + int b = a + 1; + int ab = a; + int bb = b; + table_4.add(a,b); + table_4b.add(ab,bb); + } + + for (unsigned long i = 0; i < table_4_max_size; ++i) + { + int a = ::rand()&0xF; + int b = a + 1; + int ab = a; + int bb = b; + table_8.add(a,b); + table_8b.add(ab,bb); + } + + for (unsigned long i = 0; i < tree_max_size; ++i) + { + int a = ::rand()&0xFFF; + int b = a + 1; + int ab = a; + int bb = b; + tree.add(a,b); + treeb.add(ab,bb); + } + + map m_4; + m_4.load(table_4); + map m_8; + m_8.load(table_8); + map m_t; + m_t.load(tree); + map e; + e.load(table_4); + + DLIB_CASSERT(e.size() == 0,""); + DLIB_CASSERT(e.at_start() == true,""); + DLIB_CASSERT(e.current_element_valid() == false,""); + DLIB_CASSERT(e.move_next() == false,""); + DLIB_CASSERT(e.at_start() == false,""); + DLIB_CASSERT(e.current_element_valid() == false,""); + + DLIB_CASSERT(m_4.size() == table_4b.size(),""); + DLIB_CASSERT(m_8.size() == table_8b.size(),""); + DLIB_CASSERT(m_t.size() == treeb.size(),""); + + DLIB_CASSERT(m_4.at_start() == true,""); + DLIB_CASSERT(m_8.at_start() == true,""); + DLIB_CASSERT(m_t.at_start() == true,""); + DLIB_CASSERT(m_4.current_element_valid() == false,""); + DLIB_CASSERT(m_8.current_element_valid() == false,""); + DLIB_CASSERT(m_t.current_element_valid() == false,""); + + + DLIB_CASSERT(m_4.move_next() == true,""); + DLIB_CASSERT(m_4.at_start() == false,""); + DLIB_CASSERT(m_4.current_element_valid() == true,""); + DLIB_CASSERT(m_8.move_next() == true,""); + DLIB_CASSERT(m_8.at_start() == false,""); + DLIB_CASSERT(m_8.current_element_valid() == true,""); + DLIB_CASSERT(m_t.move_next() == true,""); + DLIB_CASSERT(m_t.at_start() == false,""); + DLIB_CASSERT(m_t.current_element_valid() == true,""); + + m_4.reset(); + m_8.reset(); + m_t.reset(); + + while (m_4.move_next()) + { + DLIB_CASSERT( table_4b[m_4.element().key()] != 0,""); + DLIB_CASSERT( *table_4b[m_4.element().key()] == m_4.element().value(),""); + } + + // serialize the state of m_4, then clear m_4, then + // load the state back into m_4. + ostringstream sout; + serialize(m_4,sout); + DLIB_CASSERT(m_4.at_start() == true,""); + istringstream sin(sout.str()); + m_4.clear(); + deserialize(m_4,sin); + DLIB_CASSERT(m_4.at_start() == true,""); + + + + while (table_4b.move_next()) + { + DLIB_CASSERT( m_4[table_4b.element().key()] != 0,""); + DLIB_CASSERT( *m_4[table_4b.element().key()] == table_4b.element().value(),""); + } + + // serialize the state of m_8, then clear m_8, then + // load the state back into m_8. + sout.str(""); + serialize(m_8,sout); + DLIB_CASSERT(m_8.at_start() == true,""); + sin.str(sout.str()); + m_8.clear(); + deserialize(m_8,sin); + DLIB_CASSERT(m_8.at_start() == true,""); + + while (m_8.move_next()) + { + DLIB_CASSERT( table_8b[m_8.element().key()] != 0,""); + DLIB_CASSERT( *table_8b[m_8.element().key()] == m_8.element().value(),""); + } + + while (table_8b.move_next()) + { + DLIB_CASSERT( m_8[table_8b.element().key()] != 0,""); + DLIB_CASSERT( *m_8[table_8b.element().key()] == table_8b.element().value(),""); + } + + + while (m_t.move_next()) + { + DLIB_CASSERT( treeb[m_t.element().key()] != 0,""); + DLIB_CASSERT( *treeb[m_t.element().key()] == m_t.element().value(),""); + } + + // make sure operator[] doesn't hang + for (int l = 1; l < 10000; ++l) + { + DLIB_CASSERT(m_t[l+0xFFF] == 0,""); + } + + while (treeb.move_next()) + { + DLIB_CASSERT( m_t[treeb.element().key()] != 0,""); + DLIB_CASSERT( *m_t[treeb.element().key()] == treeb.element().value(),""); + } + + + + m_4.reset(); + m_8.reset(); + m_t.reset(); + + int last = 0; + while (m_4.move_next()) + { + DLIB_CASSERT(last <= m_4.element().key(),""); + DLIB_CASSERT(m_4.element().key() + 1 == m_4.element().value(),""); + last = m_4.element().key(); + } + + last = 0; + while (m_8.move_next()) + { + DLIB_CASSERT(last <= m_8.element().key(),""); + DLIB_CASSERT(m_8.element().key() + 1 == m_8.element().value(),""); + last = m_8.element().key(); + } + + last = 0; + while (m_t.move_next()) + { + DLIB_CASSERT(last <= m_t.element().key(),""); + DLIB_CASSERT(m_t.element().key() + 1 == m_t.element().value(),""); + last = m_t.element().key(); + } + + + + + + + // this is just to test swap + m_4.swap(m_8); + m_4.reset(); + table_4b.reset(); + while (m_8.move_next()) + { + DLIB_CASSERT( table_4b[m_8.element().key()] != 0,""); + DLIB_CASSERT( *table_4b[m_8.element().key()] == m_8.element().value(),""); + } + + while (table_4b.move_next()) + { + DLIB_CASSERT( m_8[table_4b.element().key()] != 0,""); + DLIB_CASSERT( *m_8[table_4b.element().key()] == table_4b.element().value(),""); + } + + } + + + + + + class static_map_tester : public tester + { + public: + static_map_tester ( + ) : + tester ("test_static_map", + "Runs tests on the static_map component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + static_map_kernel_test::kernel_1a> (); + dlog << LINFO << "testing kernel_1a_c"; + static_map_kernel_test::kernel_1a_c>(); + } + } a; + +} + diff --git a/dlib/test/static_set.cpp b/dlib/test/static_set.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9900952262fb632dde669386efb5def9c930978c --- /dev/null +++ b/dlib/test/static_set.cpp @@ -0,0 +1,206 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.static_set"); + + template < + typename set + > + void static_set_kernel_test ( + ) + /*! + requires + - set is an implementation of static_set/static_set_kernel_abstract.h and + is instantiated to hold ints + ensures + - runs tests on set for compliance with the specs + !*/ + { + + print_spinner(); + + srand(static_cast(time(0))); + + typedef queue::kernel_2a_c queue_of_int; + typedef dlib::set::kernel_1a_c set_of_int; + + queue_of_int q, qb, qc; + set_of_int ds; + + set S; + S.load(ds); + + for (int k = 1; k < 1000; ++k) + { + q.clear(); + qb.clear(); + qc.clear(); + unsigned long num = k; + for (unsigned long i = 0; i < num; ++i) + { + int a = ::rand()&0xFF; + int b = a; + int c = a; + q.enqueue(a); + qb.enqueue(b); + qc.enqueue(c); + } + + + + set s; + + DLIB_CASSERT(s.size() == 0,""); + DLIB_CASSERT(s.at_start(),""); + DLIB_CASSERT(s.current_element_valid() == false,""); + DLIB_CASSERT(s.move_next() == false,""); + DLIB_CASSERT(s.current_element_valid() == false,""); + DLIB_CASSERT(s.at_start() == false,""); + + s.load(q); + DLIB_CASSERT(s.at_start(),""); + set se; + se.load(q); + + DLIB_CASSERT(se.size() == 0,""); + DLIB_CASSERT(se.at_start() == true,""); + DLIB_CASSERT(se.current_element_valid() == false,""); + DLIB_CASSERT(se.move_next() == false,""); + DLIB_CASSERT(se.at_start() == false,""); + DLIB_CASSERT(se.current_element_valid() == false,""); + + + DLIB_CASSERT(s.size() == qb.size(),""); + DLIB_CASSERT(s.at_start() == true,""); + DLIB_CASSERT(s.current_element_valid() == false,""); + DLIB_CASSERT(s.move_next() == true,""); + DLIB_CASSERT(s.at_start() == false,""); + DLIB_CASSERT(s.current_element_valid() == true,""); + s.reset(); + se.reset(); + + swap(se,s); + + DLIB_CASSERT(s.size() == 0,""); + DLIB_CASSERT(s.at_start() == true,""); + DLIB_CASSERT(s.current_element_valid() == false,""); + DLIB_CASSERT(s.move_next() == false,""); + DLIB_CASSERT(s.at_start() == false,""); + DLIB_CASSERT(s.current_element_valid() == false,""); + + DLIB_CASSERT(se.size() == qb.size(),""); + DLIB_CASSERT(se.at_start() == true,""); + DLIB_CASSERT(se.current_element_valid() == false,""); + DLIB_CASSERT(se.move_next() == true,""); + DLIB_CASSERT(se.at_start() == false,""); + DLIB_CASSERT(se.current_element_valid() == true,""); + s.reset(); + se.reset(); + + swap(se,s); + + + + int last = 0; + while (s.move_next()) + { + DLIB_CASSERT(last <= s.element(),""); + last = s.element(); + } + + + + while (qb.move_next()) + { + int a; + qb.dequeue(a); + DLIB_CASSERT(s.is_member(a),""); + DLIB_CASSERT(!se.is_member(a),""); + + // make sure is_member() doesn't hang + for (int l = 0; l < 100; ++l) + { + int a = ::rand(); + s.is_member(a); + } + } + + swap(s,se); + + // serialize the state of se, then clear se, then + // load the state back into se. + ostringstream sout; + serialize(se,sout); + DLIB_CASSERT(se.at_start() == true,""); + istringstream sin(sout.str()); + se.clear(); + deserialize(se,sin); + DLIB_CASSERT(se.at_start() == true,""); + + + last = 0; + while (se.move_next()) + { + DLIB_CASSERT(last <= se.element(),""); + last = se.element(); + } + + + DLIB_CASSERT(s.size() == 0,""); + DLIB_CASSERT(se.size() == qc.size(),""); + + while (qc.move_next()) + { + int a; + qc.dequeue(a); + DLIB_CASSERT(se.is_member(a),""); + DLIB_CASSERT(!s.is_member(a),""); + } + + + } + } + + + + + + class static_set_tester : public tester + { + public: + static_set_tester ( + ) : + tester ("test_static_set", + "Runs tests on the static_set component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + static_set_kernel_test::kernel_1a> (); + dlog << LINFO << "testing kernel_1a_c"; + static_set_kernel_test::kernel_1a_c>(); + } + } a; + +} + diff --git a/dlib/test/string.cpp b/dlib/test/string.cpp new file mode 100644 index 0000000000000000000000000000000000000000..437efa077bf5b4ad5d51232ae5f0477ae42eba09 --- /dev/null +++ b/dlib/test/string.cpp @@ -0,0 +1,202 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.string"); + + + void string_test ( + ) + /*! + ensures + - runs tests on string functions for compliance with the specs + !*/ + { + + print_spinner(); + + string a = " davis "; + string A = " DAVIS "; + string empty = " "; + + dlog << LTRACE << 1; + + DLIB_CASSERT(string_cast("5") == 5,string_cast("5")); + DLIB_CASSERT(string_cast("0x5") == 5,string_cast("0x5")); + DLIB_CASSERT(string_cast("0xA") == 10,string_cast("0xA")); + DLIB_CASSERT(string_cast("0.5") == 0.5,""); + DLIB_CASSERT(string_cast("0.5 !") == "0.5 !",""); + DLIB_CASSERT(string_cast("true") == true,""); + DLIB_CASSERT(string_cast("false") == false,""); + DLIB_CASSERT(string_cast("TRUE") == true,""); + DLIB_CASSERT(string_cast("FALSE") == false,""); + + dlog << LTRACE << 2; + + DLIB_CASSERT(string_cast(L"5") == 5,string_cast("5")); + dlog << LTRACE << 2.1; + DLIB_CASSERT(string_cast(L"0x5") == 5,string_cast("0x5")); + DLIB_CASSERT(string_cast(L"0xA") == 10,string_cast("0xA")); + DLIB_CASSERT(string_cast(L"0.5") == 0.5,""); + DLIB_CASSERT(string_cast(L"0.5 !") == "0.5 !",""); + DLIB_CASSERT(string_cast(L"true") == true,""); + DLIB_CASSERT(string_cast(L"false") == false,""); + DLIB_CASSERT(string_cast(L"TRUE") == true,""); + DLIB_CASSERT(string_cast(L"FALSE") == false,""); + + dlog << LTRACE << 3; + + DLIB_CASSERT(cast_to_string(5) == "5",""); + DLIB_CASSERT(cast_to_string(5.5) == "5.5",""); + + dlog << LTRACE << 4; + DLIB_CASSERT(cast_to_wstring(5) == L"5",""); + DLIB_CASSERT(cast_to_wstring(5.5) == L"5.5",""); + dlog << LTRACE << 5; + DLIB_CASSERT(toupper(a) == A,""); + DLIB_CASSERT(toupper(A) == A,""); + DLIB_CASSERT(tolower(a) == a,""); + DLIB_CASSERT(tolower(A) == a,""); + DLIB_CASSERT(trim(a) == "davis",""); + DLIB_CASSERT(ltrim(a) == "davis ",""); + DLIB_CASSERT(rtrim(a) == " davis",""); + DLIB_CASSERT(trim(string_cast(a)) == L"davis",""); + DLIB_CASSERT(ltrim(string_cast(a)) == L"davis ",""); + DLIB_CASSERT(rtrim(string_cast(a)) == L" davis",""); + DLIB_CASSERT(trim(a, " ") == "davis",""); + DLIB_CASSERT(ltrim(a, " ") == "davis ",""); + DLIB_CASSERT(rtrim(a, " ") == " davis",""); + DLIB_CASSERT(trim(empty) == "",""); + DLIB_CASSERT(ltrim(empty) == "",""); + DLIB_CASSERT(rtrim(empty) == "",""); + DLIB_CASSERT(trim(string_cast(empty)) == L"",""); + DLIB_CASSERT(ltrim(string_cast(empty)) == L"",""); + DLIB_CASSERT(rtrim(string_cast(empty)) == L"",""); + DLIB_CASSERT(trim(empty, " ") == "",""); + DLIB_CASSERT(ltrim(empty, " ") == "",""); + DLIB_CASSERT(rtrim(empty, " ") == "",""); + + + dlog << LTRACE << 6; + DLIB_CASSERT( (lpad(wstring(L"davis"), 10) == L" davis"), ""); + DLIB_CASSERT( (rpad(wstring(L"davis"), 10) == L"davis "), ""); + DLIB_CASSERT( (pad(wstring(L"davis"), 10) == L" davis "), ""); + + DLIB_CASSERT( (lpad(string("davis"), -10) == "davis"), ""); + DLIB_CASSERT( (rpad(string("davis"), -10) == "davis"), ""); + DLIB_CASSERT( (pad(string("davis"), -10) == "davis"), ""); + DLIB_CASSERT( (lpad(string("davis"), 10) == " davis"), ""); + DLIB_CASSERT( (rpad(string("davis"), 10) == "davis "), ""); + DLIB_CASSERT( (pad(string("davis"), 10) == " davis "), ""); + DLIB_CASSERT( (lpad(string("davis"), 10, string("*")) == "*****davis"), ""); + DLIB_CASSERT( (rpad(string("davis"), 10, string("*")) == "davis*****"), ""); + DLIB_CASSERT( (pad(string("davis"), 10, string("*")) == "**davis***"), ""); + DLIB_CASSERT( (lpad(string("davis"), 10, string("_-")) == "_-_-_davis"), ""); + DLIB_CASSERT( (rpad(string("davis"), 10, string("_-")) == "davis_-_-_"), ""); + DLIB_CASSERT( (pad(string("davis"), 10, string("_-")) == "_-davis_-_"), ""); + DLIB_CASSERT( (lpad(string("davis"), 10, string("willy wanka")) == "willydavis"), ""); + DLIB_CASSERT( (rpad(string("davis"), 10, string("willy wanka")) == "daviswilly"), ""); + DLIB_CASSERT( (pad(string("davis"), 10, string("willy wanka")) == "widaviswil"), ""); + DLIB_CASSERT( (lpad(string("davis"), 10, "*")) == "*****davis", ""); + DLIB_CASSERT( (rpad(string("davis"), 10, "*") == "davis*****"), ""); + DLIB_CASSERT( (pad(string("davis"), 10, "*") == "**davis***"), ""); + DLIB_CASSERT( (lpad(string("davis"), 10, "_-") == "_-_-_davis"), ""); + DLIB_CASSERT( (rpad(string("davis"), 10, "_-") == "davis_-_-_"), ""); + DLIB_CASSERT( (pad(string("davis"), 10, "_-") == "_-davis_-_"), ""); + DLIB_CASSERT( (lpad(string("davis"), 10, "willy wanka") == "willydavis"), ""); + DLIB_CASSERT( (rpad(string("davis"), 10, "willy wanka") == "daviswilly"), ""); + DLIB_CASSERT( (pad(string("davis"), 10, "willy wanka") == "widaviswil"), ""); + dlog << LTRACE << 7; + + a = "file.txt"; + DLIB_CASSERT( (left_substr(a,string(".")) == "file"), ""); + DLIB_CASSERT( (left_substr(a,".") == "file"), ""); + DLIB_CASSERT( (right_substr(a,string(".")) == "txt"), ""); + DLIB_CASSERT( (right_substr(a,".") == "txt"), ""); + + DLIB_CASSERT( (left_substr(a," ") == "file.txt"), ""); + DLIB_CASSERT( (right_substr(a," ") == ""), ""); + + DLIB_CASSERT( (left_substr(a,"") == "file.txt"), ""); + DLIB_CASSERT( (right_substr(a,"") == ""), ""); + + wstring ws = L"file.txt"; + DLIB_CASSERT( (left_substr(ws,wstring(L".")) == L"file"), ""); + DLIB_CASSERT( (left_substr(ws,L".") == L"file"), L""); + DLIB_CASSERT( (right_substr(ws,wstring(L".")) == L"txt"), ""); + DLIB_CASSERT( (right_substr(ws,L".") == L"txt"), L""); + + + dlog << LTRACE << 8; + { + ostringstream sout; + wchar_t w = 85; + char c = 4; + serialize(w,sout); + serialize(c,sout); + w = static_cast(-1); + serialize(w,sout); + c = static_cast(-1); + serialize(c,sout); + + istringstream sin(sout.str()); + w = 0; + c = 0; + deserialize(w,sin); + deserialize(c,sin); + DLIB_CASSERT(w == 85,""); + DLIB_CASSERT(c == 4,""); + deserialize(w,sin); + deserialize(c,sin); + DLIB_CASSERT(w == static_cast(-1),""); + DLIB_CASSERT(c == static_cast(-1),""); + + wstring str = L"test string"; + + sout.str(""); + serialize(str, sout); + sin.clear(); + sin.str(sout.str()); + str = L"something else"; + deserialize(str,sin); + DLIB_CASSERT(str == L"test string",""); + } + } + + + + + class string_tester : public tester + { + public: + string_tester ( + ) : + tester ("test_string", + "Runs tests on the string objects and functions.") + {} + + void perform_test ( + ) + { + string_test(); + } + } a; + +} + + + diff --git a/dlib/test/tester.cpp b/dlib/test/tester.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fd848f4cbec91894d04c093d9f800d66cbe0b57 --- /dev/null +++ b/dlib/test/tester.cpp @@ -0,0 +1,126 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#include +#include "tester.h" +#include +#include + +namespace test +{ + + static dlib::mutex spinner_mutex; + +// ----------------------------------------------------------------------------- + + map_of_testers& testers ( + ) + { + static map_of_testers t; + return t; + } + +// ----------------------------------------------------------------------------- + + tester:: + tester ( + const std::string& switch_name_, + const std::string& description__, + unsigned long num_of_args__ + ) : + switch_name(switch_name_), + description_(description__), + num_of_args_(num_of_args__) + { + using namespace std; + if (testers().is_in_domain(switch_name)) + { + cerr << "ERROR: More than one tester has been defined with the switch '" << switch_name << "'." << endl; + exit(1); + } + + string temp(switch_name); + tester* t = this; + testers().add(temp,t); + } + +// ----------------------------------------------------------------------------- + + const std::string& tester:: + cmd_line_switch ( + ) const + { + return switch_name; + } + +// ----------------------------------------------------------------------------- + + const std::string& tester:: + description ( + ) const + { + return description_; + } + +// ----------------------------------------------------------------------------- + + unsigned long tester:: + num_of_args ( + ) const + { + return num_of_args_; + } + +// ----------------------------------------------------------------------------- + + void tester:: + perform_test ( + ) + { + } + +// ----------------------------------------------------------------------------- + + void tester:: + perform_test ( + const std::string& + ) + { + } + +// ----------------------------------------------------------------------------- + + void tester:: + perform_test ( + const std::string&, + const std::string& + ) + { + } + +// ----------------------------------------------------------------------------- + + void print_spinner ( + ) + { + using namespace std; + dlib::auto_mutex M(spinner_mutex); + static int i = 0; + cout << "\b\b"; + switch (i) + { + case 0: cout << '|'; break; + case 1: cout << '/'; break; + case 2: cout << '-'; break; + case 3: cout << '\\'; break; + } + cout << " " << flush; + i = (i+1)%4; + } + +// ----------------------------------------------------------------------------- + +} + + + diff --git a/dlib/test/tester.h b/dlib/test/tester.h new file mode 100644 index 0000000000000000000000000000000000000000..ba32b009b43eae11fc68b1ced46f0910b69fbe5e --- /dev/null +++ b/dlib/test/tester.h @@ -0,0 +1,136 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TESTEr_ +#define DLIB_TESTEr_ + +#include +#include +#include +#include +#include +#include +#include + +namespace test +{ + class tester; + typedef dlib::map::kernel_1a_c map_of_testers; + + map_of_testers& testers ( + ); + +// ----------------------------------------------------------------------------- + + void print_spinner ( + ); + /*! + ensures + - reprints the spinner + !*/ + +// ----------------------------------------------------------------------------- + + class tester + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a generic regression test. + !*/ + + public: + + tester ( + const std::string& switch_name, + const std::string& description_, + unsigned long num_of_args_ = 0 + ); + /*! + requires + - testers().is_in_domain(switch_name) == false + ensures + - #cmd_line_switch() == switch_name + - #description() == description_ + - #num_of_args() == num_of_args_ + - adds this tester to the testers() map. + !*/ + + virtual ~tester ( + ){} + + const std::string& cmd_line_switch ( + ) const; + /*! + ensures + - returns the name of the command line switch for this tester. + !*/ + + const std::string& description ( + ) const; + /*! + ensures + - returns the description of what this tester tests. + !*/ + + unsigned long num_of_args ( + ) const; + /*! + ensures + - returns the number of arguments this test expects + !*/ + + virtual void perform_test ( + ); + /*! + requires + - is invoked when number_of_args() == 0 + ensures + - performs the test and throws an exception + derived from std::exception if the test fails. + !*/ + + virtual void perform_test ( + const std::string& arg + ); + /*! + requires + - is invoked when number_of_args() == 1 + ensures + - performs the test and throws an exception + derived from std::exception if the test fails. + !*/ + + virtual void perform_test ( + const std::string& arg1, + const std::string& arg2 + ); + /*! + requires + - is invoked when number_of_args() == 2 + ensures + - performs the test and throws an exception + derived from std::exception if the test fails. + !*/ + + private: + + // --------------------------------------------------------------------------- + // Implementation Details + // --------------------------------------------------------------------------- + + /*! + CONVENTION + - switch_name == cmd_line_switch() + - description_ == description() + - num_of_args_ == num_of_args() + - test::tester[switch_name] == this + !*/ + + const std::string switch_name; + const std::string description_; + const unsigned long num_of_args_; + }; + +} + +#endif // DLIB_TESTEr_ + diff --git a/dlib/test/threads.cpp b/dlib/test/threads.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5855f1fe9e5c5145fb57679dd2ca00499e0f8921 --- /dev/null +++ b/dlib/test/threads.cpp @@ -0,0 +1,125 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.threads"); + + class threads_tester : public tester + { + public: + threads_tester ( + ) : + tester ("test_threads", + "Runs tests on the threads component."), + sm(cm) + {} + + thread_specific_data tsd; + mutex cm; + signaler sm; + int count; + bool failure; + + void perform_test ( + ) + { + failure = false; + print_spinner(); + + + count = 10; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + if (!create_new_thread(*this)) failure = true; + + thread(66); + + // this should happen in the main program thread + if (is_dlib_thread()) + failure = true; + + auto_mutex M(cm); + while (count > 0 && !failure) + sm.wait(); + + + DLIB_CASSERT(!failure,""); + } + + void thread_end_handler ( + ) + { + auto_mutex M(cm); + --count; + if (count == 0) + sm.signal(); + } + + void thread1() { thread(1); } + void thread2() + { + thread(2); + if (is_dlib_thread() == false) + failure = true; + } + void thread3() { thread(3); } + void thread4() { thread(4); } + void thread5() { thread(5); } + void thread6() { thread(6); } + void thread7() { thread(7); } + void thread8() { thread(8); } + void thread9() { thread(9); } + void thread10() { thread(10); } + + void thread ( + int num + ) + { + dlog << LTRACE << "starting thread num " << num; + if (is_dlib_thread()) + register_thread_end_handler(*this,&threads_tester::thread_end_handler); + tsd.data() = num; + for (int i = 0; i < 0x3FFFF; ++i) + { + if ((i&0xFFF) == 0) + dlib::sleep(10); + // if this isn't equal to num then there is a problem with the thread specific data stuff + if (tsd.data() != num) + { + auto_mutex M(cm); + failure = true; + sm.signal(); + } + } + dlog << LTRACE << "ending of thread num " << num; + + } + } a; + + +} + + + diff --git a/dlib/test/timer.cpp b/dlib/test/timer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..439b0515e8efa05395c73330fa0b34b68a7a4e59 --- /dev/null +++ b/dlib/test/timer.cpp @@ -0,0 +1,282 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include + +#include +#include +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.timer"); + + class timer_test_helper + { + public: + mutex m; + int count; + + timer_test_helper():count(0){} + void add() + { + m.lock(); + print_spinner(); + ++count; + m.unlock(); + } + + void delayed_add() + { + dlib::sleep(1000); + add(); + } + }; + + template < + typename timer_t + > + void timer_test ( + ) + /*! + requires + - timer_t is an implementation of timer/timer_kernel_aseqract.h is instantiated + timer_test_helper + ensures + - runs tests on timer_t for compliance with the specs + !*/ + { + + print_spinner(); + for (int j = 0; j < 3; ++j) + { + timer_test_helper h; + + timer_t t1(h,&timer_test_helper::add); + timer_t t2(h,&timer_test_helper::add); + timer_t t3(h,&timer_test_helper::add); + + DLIB_CASSERT(t1.delay_time() == 1000,""); + DLIB_CASSERT(t2.delay_time() == 1000,""); + DLIB_CASSERT(t3.delay_time() == 1000,""); + DLIB_CASSERT(t1.is_running() == false,""); + DLIB_CASSERT(t2.is_running() == false,""); + DLIB_CASSERT(t3.is_running() == false,""); + DLIB_CASSERT(t1.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t2.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t3.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(&t1.action_object() == &h,""); + DLIB_CASSERT(&t2.action_object() == &h,""); + DLIB_CASSERT(&t3.action_object() == &h,""); + + t1.set_delay_time(1000); + t2.set_delay_time(500); + t3.set_delay_time(200); + + DLIB_CASSERT(t1.delay_time() == 1000,""); + DLIB_CASSERT(t2.delay_time() == 500,""); + DLIB_CASSERT(t3.delay_time() == 200,""); + DLIB_CASSERT(t1.is_running() == false,""); + DLIB_CASSERT(t2.is_running() == false,""); + DLIB_CASSERT(t3.is_running() == false,""); + DLIB_CASSERT(t1.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t2.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t3.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(&t1.action_object() == &h,""); + DLIB_CASSERT(&t2.action_object() == &h,""); + DLIB_CASSERT(&t3.action_object() == &h,""); + dlib::sleep(1100); + print_spinner(); + DLIB_CASSERT(h.count == 0,""); + + t1.stop_and_wait(); + t2.stop_and_wait(); + t3.stop_and_wait(); + + dlib::sleep(1100); + print_spinner(); + DLIB_CASSERT(h.count == 0,""); + DLIB_CASSERT(t1.delay_time() == 1000,""); + DLIB_CASSERT(t2.delay_time() == 500,""); + DLIB_CASSERT(t3.delay_time() == 200,""); + DLIB_CASSERT(t1.is_running() == false,""); + DLIB_CASSERT(t2.is_running() == false,""); + DLIB_CASSERT(t3.is_running() == false,""); + DLIB_CASSERT(t1.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t2.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t3.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(&t1.action_object() == &h,""); + DLIB_CASSERT(&t2.action_object() == &h,""); + DLIB_CASSERT(&t3.action_object() == &h,""); + + t1.start(); + t2.start(); + t3.start(); + + DLIB_CASSERT(t1.delay_time() == 1000,""); + DLIB_CASSERT(t2.delay_time() == 500,""); + DLIB_CASSERT(t3.delay_time() == 200,""); + DLIB_CASSERT(t1.is_running() == true,""); + DLIB_CASSERT(t2.is_running() == true,""); + DLIB_CASSERT(t3.is_running() == true,""); + DLIB_CASSERT(t1.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t2.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t3.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(&t1.action_object() == &h,""); + DLIB_CASSERT(&t2.action_object() == &h,""); + DLIB_CASSERT(&t3.action_object() == &h,""); + + t1.stop(); + t2.stop(); + t3.stop(); + + DLIB_CASSERT(t1.delay_time() == 1000,""); + DLIB_CASSERT(t2.delay_time() == 500,""); + DLIB_CASSERT(t3.delay_time() == 200,""); + DLIB_CASSERT(t1.is_running() == false,""); + DLIB_CASSERT(t2.is_running() == false,""); + DLIB_CASSERT(t3.is_running() == false,""); + DLIB_CASSERT(t1.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t2.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(t3.action_function() == &timer_test_helper::add,""); + DLIB_CASSERT(&t1.action_object() == &h,""); + DLIB_CASSERT(&t2.action_object() == &h,""); + DLIB_CASSERT(&t3.action_object() == &h,""); + + DLIB_CASSERT(h.count == 0,""); + dlib::sleep(1100); + print_spinner(); + DLIB_CASSERT(h.count == 0,""); + + for (int i = 1; i <= 3; ++i) + { + t1.start(); + t2.start(); + t3.start(); + + DLIB_CASSERT(t1.is_running() == true,""); + DLIB_CASSERT(t2.is_running() == true,""); + DLIB_CASSERT(t3.is_running() == true,""); + + dlib::sleep(1100); + // this should allow the timers to trigger 8 times + t1.stop(); + t2.stop(); + t3.stop(); + + DLIB_CASSERT(h.count == 8*i,"h.count: " << h.count << " i: " << i); + dlib::sleep(1100); + DLIB_CASSERT(h.count == 8*i,"h.count: " << h.count << " i: " << i); + } + + + h.count = 0; + t1.start(); + dlib::sleep(300); + DLIB_CASSERT(h.count == 0,h.count); + t1.set_delay_time(400); + dlib::sleep(200); + DLIB_CASSERT(h.count == 1,h.count); + dlib::sleep(250); + DLIB_CASSERT(h.count == 1,h.count); + dlib::sleep(100); + DLIB_CASSERT(h.count == 2,h.count); + t1.set_delay_time(2000); + DLIB_CASSERT(h.count == 2,h.count); + dlib::sleep(1000); + DLIB_CASSERT(h.count == 2,h.count); + t1.clear(); + + h.count = 0; + t3.start(); + DLIB_CASSERT(t3.is_running() == true,""); + DLIB_CASSERT(t3.delay_time() == 200,""); + DLIB_CASSERT(h.count == 0,h.count); + t3.clear(); + DLIB_CASSERT(t3.is_running() == false,""); + DLIB_CASSERT(t3.delay_time() == 1000,""); + DLIB_CASSERT(h.count == 0,h.count); + dlib::sleep(200); + DLIB_CASSERT(t3.is_running() == false,""); + DLIB_CASSERT(t3.delay_time() == 1000,""); + DLIB_CASSERT(h.count == 0,h.count); + + + { + h.count = 0; + timer_t t4(h,&timer_test_helper::delayed_add); + t4.set_delay_time(100); + t4.start(); + DLIB_CASSERT(h.count == 0,h.count); + dlib::sleep(400); + DLIB_CASSERT(h.count == 0,h.count); + t4.stop_and_wait(); + DLIB_CASSERT(h.count == 1,h.count); + DLIB_CASSERT(t4.is_running() == false,""); + } + + { + h.count = 0; + timer_t t4(h,&timer_test_helper::delayed_add); + t4.set_delay_time(100); + t4.start(); + DLIB_CASSERT(h.count == 0,h.count); + dlib::sleep(400); + DLIB_CASSERT(h.count == 0,h.count); + t4.clear(); + DLIB_CASSERT(t4.is_running() == false,""); + DLIB_CASSERT(h.count == 0,h.count); + t4.stop_and_wait(); + DLIB_CASSERT(h.count == 1,h.count); + DLIB_CASSERT(t4.is_running() == false,""); + } + + { + h.count = 0; + timer_t t5(h,&timer_test_helper::delayed_add); + t5.set_delay_time(100); + t5.start(); + DLIB_CASSERT(h.count == 0,h.count); + dlib::sleep(400); + DLIB_CASSERT(h.count == 0,h.count); + } + DLIB_CASSERT(h.count == 1,h.count); + + } + + } + + + + + class timer_tester : public tester + { + public: + timer_tester ( + ) : + tester ("test_timer", + "Runs tests on the timer component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + timer_test::kernel_1a> (); + dlog << LINFO << "testing kernel_2a"; + timer_test::kernel_2a> (); + } + } a; + +} + + diff --git a/dlib/test/tokenizer.cpp b/dlib/test/tokenizer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92c3f3e556fac908d65bd2b0f308d39a980630bd --- /dev/null +++ b/dlib/test/tokenizer.cpp @@ -0,0 +1,378 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include + +#include +#include "tester.h" + +namespace +{ + using namespace test; + using namespace std; + using namespace dlib; + + logger dlog("test.tokenizer"); + + template < + typename tok + > + void tokenizer_kernel_test ( + ) + /*! + requires + - tok is an implementation of tokenizer_kernel_abstract.h + ensures + - runs tests on tok for compliance with the specs + !*/ + { + + print_spinner(); + + tok test; + + DLIB_CASSERT(test.numbers() == "0123456789",""); + DLIB_CASSERT(test.uppercase_letters() == "ABCDEFGHIJKLMNOPQRSTUVWXYZ",""); + DLIB_CASSERT(test.lowercase_letters() == "abcdefghijklmnopqrstuvwxyz",""); + + DLIB_CASSERT(test.get_identifier_body() == "_" + test.lowercase_letters() + + test.uppercase_letters() + test.numbers(),""); + DLIB_CASSERT(test.get_identifier_head() == "_" + test.lowercase_letters() + + test.uppercase_letters(),""); + + DLIB_CASSERT(test.stream_is_set() == false,""); + test.clear(); + DLIB_CASSERT(test.stream_is_set() == false,""); + + DLIB_CASSERT(test.get_identifier_body() == "_" + test.lowercase_letters() + + test.uppercase_letters() + test.numbers(),""); + DLIB_CASSERT(test.get_identifier_head() == "_" + test.lowercase_letters() + + test.uppercase_letters(),""); + + tok test2; + + ostringstream sout; + istringstream sin; + test2.set_stream(sin); + + DLIB_CASSERT(test2.stream_is_set(),""); + DLIB_CASSERT(&test2.get_stream() == &sin,""); + + int type; + string token; + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_FILE,""); + test2.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_FILE,""); + test2.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_FILE,""); + + + sin.clear(); + sin.str(" The cat 123asdf1234 ._ \n test."); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + DLIB_CASSERT(test2.peek_type() == tok::IDENTIFIER,""); + DLIB_CASSERT(test2.peek_token() == "The",""); + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "The",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "cat",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::NUMBER,""); + DLIB_CASSERT(token == "123","token: " << token); + + DLIB_CASSERT(test2.peek_type() == tok::IDENTIFIER,""); + DLIB_CASSERT(test2.peek_token() == "asdf1234",""); + DLIB_CASSERT(test2.peek_type() == tok::IDENTIFIER,""); + DLIB_CASSERT(test2.peek_token() == "asdf1234",""); + DLIB_CASSERT(test2.peek_type() == tok::IDENTIFIER,""); + DLIB_CASSERT(test2.peek_token() == "asdf1234",""); + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "asdf1234",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == ".","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "_",""); + + DLIB_CASSERT(test2.peek_type() == tok::WHITE_SPACE,""); + DLIB_CASSERT(test2.peek_token() == " ","token: \"" << token << "\"" << + "\ntoken size: " << (unsigned int)token.size()); + + swap(test,test2); + + DLIB_CASSERT(test2.stream_is_set() == false,""); + + DLIB_CASSERT(test.peek_type() == tok::WHITE_SPACE,""); + DLIB_CASSERT(test.peek_token() == " ","token: \"" << token << "\"" << + "\ntoken size: " << (unsigned int)token.size()); + test.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: \"" << token << "\"" << + "\ntoken size: " << (unsigned int)token.size()); + + test.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_LINE,"token: " << token); + DLIB_CASSERT(token == "\n","token: " << token); + + swap(test,test2); + DLIB_CASSERT(test.stream_is_set() == false,""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "test","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == ".","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_FILE,""); + + + + + + + + + + + test2.set_identifier_token("_" + test.uppercase_letters() + + test.lowercase_letters(),test.numbers() + "_" + test.uppercase_letters() + +test.lowercase_letters()); + + + sin.clear(); + sin.str(" The cat 123asdf1234 ._ \n\r test."); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "The",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "cat",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::NUMBER,""); + DLIB_CASSERT(token == "123","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "asdf1234",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == ".","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "_",""); + + swap(test,test2); + + DLIB_CASSERT(test2.stream_is_set() == false,""); + + test.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: \"" << token << "\"" << + "\ntoken size: " << (unsigned int)token.size()); + + test.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_LINE,"token: " << token); + DLIB_CASSERT(token == "\n","token: " << token); + + swap(test,test2); + DLIB_CASSERT(test.stream_is_set() == false,""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == "\r ","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "test","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == ".","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_FILE,""); + + + + + + + + + + + + + + test2.set_identifier_token(test.uppercase_letters() + + test.lowercase_letters(),test.numbers() + test.uppercase_letters() + +test.lowercase_letters()); + + + sin.clear(); + sin.str(" The cat 123as_df1234 ._ \n test."); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "The",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "cat",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::NUMBER,""); + DLIB_CASSERT(token == "123","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "as",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == "_","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "df1234",""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == ".","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == "_",""); + + swap(test,test2); + + DLIB_CASSERT(test2.stream_is_set() == false,""); + + test.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: \"" << token << "\"" << + "\ntoken size: " << (unsigned int)token.size()); + + test.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_LINE,"token: " << token); + DLIB_CASSERT(token == "\n","token: " << token); + + swap(test,test2); + DLIB_CASSERT(test.stream_is_set() == false,""); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::WHITE_SPACE,""); + DLIB_CASSERT(token == " ","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::IDENTIFIER,""); + DLIB_CASSERT(token == "test","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::CHAR,""); + DLIB_CASSERT(token == ".","token: " << token); + + test2.get_token(type,token); + DLIB_CASSERT(type == tok::END_OF_FILE,""); + + + } + + + + + + class tokenizer_tester : public tester + { + public: + tokenizer_tester ( + ) : + tester ("test_tokenizer", + "Runs tests on the tokenizer component.") + {} + + void perform_test ( + ) + { + dlog << LINFO << "testing kernel_1a"; + tokenizer_kernel_test (); + dlog << LINFO << "testing kernel_1a_c"; + tokenizer_kernel_test(); + } + } a; + +} + + diff --git a/dlib/test/tuple.cpp b/dlib/test/tuple.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbb6b39be03ed88921673bb6076c4e7d3dd188e2 --- /dev/null +++ b/dlib/test/tuple.cpp @@ -0,0 +1,184 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.tuple"); + + struct nil + { + template + void operator() ( + const T& + ) const + { + } + }; + + + struct inc + { + template + void operator() ( + T& a + ) const + { + a += 1; + } + }; + + + template + void check_const ( + const T& t + ) + { + t.template get<0>(); + + typedef typename T::template get_type<0>::type type0; + t.template get(); + t.template index(); + } + + template + void check_nonconst ( + T& t + ) + { + t.template get<0>(); + + typedef typename T::template get_type<0>::type type0; + t.template get(); + t.template index(); + } + + void tuple_test ( + ) + /*! + ensures + - runs tests on tuple functions for compliance with the specs + !*/ + { + + print_spinner(); + + tuple<> a; + tuple b; + tuple c; + + + a.get<1>(); + a.get<2>(); + a.get<3>(); + a.get<4>(); + a.get<5>(); + + check_nonconst(b); + check_nonconst(c); + check_const(b); + check_const(c); + + COMPILE_TIME_ASSERT((is_same_type::get_type<0>::type, null_type>::value)); + COMPILE_TIME_ASSERT((is_same_type::get_type<0>::type, int>::value)); + COMPILE_TIME_ASSERT((is_same_type::get_type<0>::type, int>::value)); + COMPILE_TIME_ASSERT((is_same_type::get_type<1>::type, float>::value)); + COMPILE_TIME_ASSERT((is_same_type::get_type<2>::type, null_type>::value)); + + b.get<0>() = 8; + DLIB_CASSERT(b.get() == 8,""); + DLIB_CASSERT(b.index() == 0,""); + + c.get<0>() = 9; + DLIB_CASSERT(c.get() == 9,""); + DLIB_CASSERT(c.index() == 0,""); + c.get<1>() = 3.0; + DLIB_CASSERT(c.get() == 3.0,""); + DLIB_CASSERT(c.index() == 1,""); + + + + { + typedef tuple T; + T a, b; + a.get<0>() = 1; + a.get<1>() = 3; + a.get<2>() = 2; + + b = a; + + inc i; + nil n; + a.for_each(inc()); + a.for_each(i); + const_cast(a).for_each(nil()); + const_cast(a).for_each(n); + + DLIB_CASSERT(a.get<0>() == b.get<0>()+2,""); + DLIB_CASSERT(a.get<1>() == b.get<1>()+2,""); + DLIB_CASSERT(a.get<2>() == b.get<2>()+2,""); + + ostringstream sout; + + serialize(a,sout); + istringstream sin(sout.str()); + deserialize(b,sin); + + DLIB_CASSERT(a.get<0>() == b.get<0>(),""); + DLIB_CASSERT(a.get<1>() == b.get<1>(),""); + DLIB_CASSERT(a.get<2>() == b.get<2>(),""); + + a.for_index(i,0); + a.for_index(inc(),1); + const_cast(a).for_index(n,2); + const_cast(a).for_index(nil(),0); + + DLIB_CASSERT(a.get<0>() == b.get<0>()+1,""); + DLIB_CASSERT(a.get<1>() == b.get<1>()+1,""); + DLIB_CASSERT(a.get<2>() == b.get<2>()+0,""); + + swap(a,b); + + DLIB_CASSERT(b.get<0>() == a.get<0>()+1,""); + DLIB_CASSERT(b.get<1>() == a.get<1>()+1,""); + DLIB_CASSERT(b.get<2>() == a.get<2>()+0,""); + } + + + } + + + + + class tuple_tester : public tester + { + public: + tuple_tester ( + ) : + tester ("test_tuple", + "Runs tests on the tuple object") + {} + + void perform_test ( + ) + { + tuple_test(); + } + } a; + +} + + + diff --git a/dlib/threads.h b/dlib/threads.h new file mode 100644 index 0000000000000000000000000000000000000000..e91cb06cbb92c7c0d8c88d6660705152e9516688 --- /dev/null +++ b/dlib/threads.h @@ -0,0 +1,19 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADs_ +#define DLIB_THREADs_ + +#include "threads/threads_kernel.h" + +#include "threads/auto_mutex_extension.h" +#include "threads/auto_unlock_extension.h" +#include "threads/create_new_thread_extension.h" +#include "threads/multithreaded_object_extension.h" +#include "threads/rmutex_extension.h" +#include "threads/rsignaler_extension.h" +#include "threads/threaded_object_extension.h" +#include "threads/thread_specific_data_extension.h" +#include "threads/thread_function_extension.h" + +#endif // DLIB_THREADs_ + diff --git a/dlib/threads/auto_mutex_extension.h b/dlib/threads/auto_mutex_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..0aad959dd8a9821173223d1bdd6574e2d918b7d7 --- /dev/null +++ b/dlib/threads/auto_mutex_extension.h @@ -0,0 +1,74 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_AUTO_MUTEX_EXTENSIOn_ +#define DLIB_AUTO_MUTEX_EXTENSIOn_ + +#include "threads_kernel.h" +#include "rmutex_extension.h" +#include "auto_mutex_extension_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class auto_mutex + { + /*! + INITIAL VALUE + - if (m != 0) then + - the mutex pointed to by m is locked + - if (r != 0) then + - the mutex pointed to by r is locked + - exactly one of r or m is not 0. + + CONVENTION + - if (m != 0) then + - the mutex pointed to by m is locked + - if (r != 0) then + - the mutex pointed to by r is locked + - exactly one of r or m is not 0. + !*/ + public: + + auto_mutex ( + const mutex& m_ + ) : m(&m_), + r(0) + { + m->lock(); + } + + auto_mutex ( + const rmutex& r_ + ) : m(0), + r(&r_) + { + r->lock(); + } + + ~auto_mutex ( + ) + { + if (m != 0) + m->unlock(); + else + r->unlock(); + } + + private: + + const mutex* m; + const rmutex* r; + + // restricted functions + auto_mutex(auto_mutex&); // copy constructor + auto_mutex& operator=(auto_mutex&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_AUTO_MUTEX_EXTENSIOn_ + diff --git a/dlib/threads/auto_mutex_extension_abstract.h b/dlib/threads/auto_mutex_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..6c567f565fdd2555158f743033eda293f844bd48 --- /dev/null +++ b/dlib/threads/auto_mutex_extension_abstract.h @@ -0,0 +1,64 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_AUTO_MUTEX_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_AUTO_MUTEX_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" +#include "rmutex_extension_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class auto_mutex + { + /*! + INITIAL VALUE + The mutex given in the constructor is locked and associated with this + object. + + WHAT THIS OBJECT REPRESENTS + This object represents a mechanism for automatically locking and unlocking + a mutex object. + !*/ + public: + + auto_mutex ( + const mutex& m + ); + /*! + ensures + - #*this is properly initialized + - m will be locked + !*/ + + auto_mutex ( + const rmutex& m + ); + /*! + ensures + - #*this is properly initialized + - m will be locked + !*/ + + ~auto_mutex ( + ); + /*! + ensures + - all resources allocated by *this have been freed + - the mutex associated with *this has been unlocked + !*/ + + private: + // restricted functions + auto_mutex(auto_mutex&); // copy constructor + auto_mutex& operator=(auto_mutex&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_AUTO_MUTEX_EXTENSIOn_ABSTRACT_ + diff --git a/dlib/threads/auto_unlock_extension.h b/dlib/threads/auto_unlock_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..25944633b74f803d16fbbb2783cf9e732849cac1 --- /dev/null +++ b/dlib/threads/auto_unlock_extension.h @@ -0,0 +1,71 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_AUTO_UNLOCK_EXTENSIOn_ +#define DLIB_AUTO_UNLOCK_EXTENSIOn_ + +#include "threads_kernel.h" +#include "rmutex_extension.h" +#include "auto_unlock_extension_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class auto_unlock + { + /*! + INITIAL VALUE + - if (m != 0) then + - the mutex pointed to by m is locked + - if (r != 0) then + - the mutex pointed to by r is locked + - exactly one of r or m is not 0. + + CONVENTION + - if (m != 0) then + - the mutex pointed to by m is locked + - if (r != 0) then + - the mutex pointed to by r is locked + - exactly one of r or m is not 0. + !*/ + public: + + auto_unlock ( + const mutex& m_ + ) : m(&m_), + r(0) + {} + + auto_unlock ( + const rmutex& r_ + ) : m(0), + r(&r_) + {} + + ~auto_unlock ( + ) + { + if (m != 0) + m->unlock(); + else + r->unlock(); + } + + private: + + const mutex* m; + const rmutex* r; + + // restricted functions + auto_unlock(auto_unlock&); // copy constructor + auto_unlock& operator=(auto_unlock&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_AUTO_UNLOCK_EXTENSIOn_ + + diff --git a/dlib/threads/auto_unlock_extension_abstract.h b/dlib/threads/auto_unlock_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..d4d11df43ea65852f53952f0110845ade013d291 --- /dev/null +++ b/dlib/threads/auto_unlock_extension_abstract.h @@ -0,0 +1,66 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_AUTO_UNLOCK_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_AUTO_UNLOCK_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" +#include "rmutex_extension_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class auto_unlock + { + /*! + INITIAL VALUE + The mutex given in the constructor is associated with this object. + + WHAT THIS OBJECT REPRESENTS + This object represents a mechanism for automatically unlocking + a mutex object. It is useful when you already have a locked mutex + and want to make sure it gets unlocked even if an exception is thrown + or you quit the function at a weird spot. + !*/ + public: + + auto_unlock ( + const mutex& m + ); + /*! + ensures + - #*this is properly initialized + - does not modify m in any way + !*/ + + auto_unlock ( + const rmutex& m + ); + /*! + ensures + - #*this is properly initialized + - does not modify m in any way + !*/ + + ~auto_unlock ( + ); + /*! + ensures + - all resources allocated by *this have been freed + - calls unlock() on the mutex associated with *this + !*/ + + private: + // restricted functions + auto_unlock(auto_unlock&); // copy constructor + auto_unlock& operator=(auto_unlock&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_AUTO_UNLOCK_EXTENSIOn_ABSTRACT_ + + diff --git a/dlib/threads/create_new_thread_extension.h b/dlib/threads/create_new_thread_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..1c45b4d581e9b4465b242018d8bf6b3cfb90b6f2 --- /dev/null +++ b/dlib/threads/create_new_thread_extension.h @@ -0,0 +1,46 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_CREATE_NEW_THREAD_EXTENSIOn_ +#define DLIB_CREATE_NEW_THREAD_EXTENSIOn_ + +#include "threads_kernel_abstract.h" +#include "create_new_thread_extension_abstract.h" +#include "../threads.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + void (T::*funct)() + > + inline void dlib_create_new_thread_helper ( + void* obj + ) + { + T* o = reinterpret_cast(obj); + (o->*funct)(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + void (T::*funct)() + > + inline bool create_new_thread ( + T& obj + ) + { + return create_new_thread(dlib_create_new_thread_helper,&obj); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CREATE_NEW_THREAD_EXTENSIOn_ + + diff --git a/dlib/threads/create_new_thread_extension_abstract.h b/dlib/threads/create_new_thread_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..cf15b346fe95c669cffc11dfd562eb1abed17718 --- /dev/null +++ b/dlib/threads/create_new_thread_extension_abstract.h @@ -0,0 +1,33 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_CREATE_NEW_THREAD_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_CREATE_NEW_THREAD_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + void (T::*funct)() + > + bool create_new_thread ( + T& obj + ); + /*! + ensures + - creates a new thread and calls obj.*funct() from it. + - returns true upon success and false upon failure to create the new thread. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_CREATE_NEW_THREAD_EXTENSIOn_ABSTRACT_ + + + diff --git a/dlib/threads/multithreaded_object_extension.cpp b/dlib/threads/multithreaded_object_extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f7cf647b76c3f345130de8ebbd6b09927a197b0 --- /dev/null +++ b/dlib/threads/multithreaded_object_extension.cpp @@ -0,0 +1,245 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP +#define DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP + +#include "multithreaded_object_extension.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + multithreaded_object:: + multithreaded_object ( + ): + s(m), + is_running_(false), + should_stop_(false), + threads_started(0) + { + } + +// ---------------------------------------------------------------------------------------- + + multithreaded_object:: + ~multithreaded_object ( + ) + { + DLIB_ASSERT(number_of_threads_alive() == 0, + "\tmultithreaded_object::~multithreaded_object()" + << "\n\tYou have let a multithreaded object destruct itself before terminating its threads" + << "\n\tthis: " << this + ); + } + +// ---------------------------------------------------------------------------------------- + + void multithreaded_object:: + clear ( + ) + { + auto_mutex M(m); + stop(); + wait(); + dead_threads.clear(); + is_running_ = false; + should_stop_ = false; + } + +// ---------------------------------------------------------------------------------------- + + bool multithreaded_object:: + is_running ( + ) const + { + auto_mutex M(m); + return is_running_; + } + +// ---------------------------------------------------------------------------------------- + + unsigned long multithreaded_object:: + number_of_threads_registered ( + ) const + { + auto_mutex M(m); + return thread_ids.size() + dead_threads.size(); + } + +// ---------------------------------------------------------------------------------------- + + unsigned long multithreaded_object:: + number_of_threads_alive ( + ) const + { + auto_mutex M(m); + return threads_started; + } + +// ---------------------------------------------------------------------------------------- + + void multithreaded_object:: + wait ( + ) const + { + auto_mutex M(m); + + DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()) == false, + "\tvoid multithreaded_object::wait()" + << "\n\tYou can NOT call this function from one of the threads registered in this object" + << "\n\tthis: " << this + ); + + while (threads_started > 0) + s.wait(); + } + +// ---------------------------------------------------------------------------------------- + + void multithreaded_object:: + start ( + ) + { + auto_mutex M(m); + const unsigned long num_threads_registered = dead_threads.size() + thread_ids.size(); + // start any dead threads + for (unsigned long i = threads_started; i < num_threads_registered; ++i) + { + if (create_new_thread(*this) == false) + { + should_stop_ = true; + is_running_ = false; + throw thread_error(); + } + ++threads_started; + } + is_running_ = true; + should_stop_ = false; + s.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + void multithreaded_object:: + pause ( + ) + { + auto_mutex M(m); + is_running_ = false; + } + +// ---------------------------------------------------------------------------------------- + + void multithreaded_object:: + stop ( + ) + { + auto_mutex M(m); + should_stop_ = true; + is_running_ = false; + s.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + bool multithreaded_object:: + should_stop ( + ) const + { + auto_mutex M(m); + DLIB_ASSERT(thread_ids.is_in_domain(get_thread_id()), + "\tbool multithreaded_object::should_stop()" + << "\n\tYou can only call this function from one of the registered threads in this object" + << "\n\tthis: " << this + ); + while (is_running_ == false && should_stop_ == false) + s.wait(); + return should_stop_; + } + +// ---------------------------------------------------------------------------------------- + + void multithreaded_object:: + thread_helper( + ) + { + mfp mf; + const thread_id_type id = get_thread_id(); + + try + { + // if there is a dead_thread sitting around then pull it + // out and put it into mf + { + auto_mutex M(m); + if (dead_threads.size() > 0) + { + dead_threads.dequeue(mf); + mfp temp; + thread_id_type id_temp = id; + temp = mf; + thread_ids.add(id_temp,temp); + } + } + + if (mf.is_set()) + { + // call the registered thread function + mf(); + + auto_mutex M(m); + if (thread_ids.is_in_domain(id)) + { + mfp temp; + thread_id_type id_temp; + thread_ids.remove(id,id_temp,temp); + + } + + // put this thread's registered function back into the dead_threads queue + dead_threads.enqueue(mf); + } + + auto_mutex M(m); + --threads_started; + // If this is the last thread to terminate then + // signal that that is the case. + if (threads_started == 0) + { + is_running_ = false; + should_stop_ = false; + s.broadcast(); + } + } + catch (...) + { + auto_mutex M(m); + if (thread_ids.is_in_domain(id)) + { + mfp temp; + thread_id_type id_temp; + thread_ids.remove(id,id_temp,temp); + } + + --threads_started; + // If this is the last thread to terminate then + // signal that that is the case. + if (threads_started == 0) + { + is_running_ = false; + should_stop_ = false; + s.broadcast(); + } + throw; + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_CPP + + diff --git a/dlib/threads/multithreaded_object_extension.h b/dlib/threads/multithreaded_object_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..7c90e03c330221fc0b32a74b18e5c9e127e91a0c --- /dev/null +++ b/dlib/threads/multithreaded_object_extension.h @@ -0,0 +1,144 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ +#define DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ + +#include "multithreaded_object_extension_abstract.h" +#include "threads_kernel.h" +#include "auto_mutex_extension.h" +#include "../threads.h" +#include "rmutex_extension.h" +#include "rsignaler_extension.h" +#include "../algs.h" +#include "../assert.h" +#include "../map.h" +#include "../member_function_pointer.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class multithreaded_object + { + /*! + INITIAL VALUE + - is_running_ == false + - should_stop_ == false + - thread_ids.size() == 0 + - dead_threads.size() == 0 + - threads_started == 0 + + CONVENTION + - number_of_threads_registered() == thread_ids.size() + dead_threads.size() + - number_of_threads_alive() == threads_started + + - is_running() == is_running_ + - should_stop() == should_stop_ + + - thread_ids == a map of current thread ids to the member function + pointers that that thread runs. + - threads_started == the number of threads that have been spawned to run + thread_helper but haven't ended yet. + + - dead_threads == a queue that contains all the member function pointers + for threads that are currently registered but not running + + - m == the mutex used to protect all our variables + - s == the signaler for m + !*/ + + public: + + multithreaded_object ( + ); + + virtual ~multithreaded_object ( + ) = 0; + + void clear ( + ); + + bool is_running ( + ) const; + + unsigned long number_of_threads_alive ( + ) const; + + unsigned long number_of_threads_registered ( + ) const; + + void wait ( + ) const; + + void start ( + ); + + void pause ( + ); + + void stop ( + ); + + protected: + + bool should_stop ( + ) const; + + template < + typename T + > + void register_thread ( + T& object, + void (T::*thread)() + ) + { + auto_mutex M(m); + try + { + mfp mf; + mf.set(object,thread); + dead_threads.enqueue(mf); + if (is_running_) + start(); + } + catch (...) + { + is_running_ = false; + should_stop_ = true; + s.broadcast(); + throw; + } + } + + private: + + void thread_helper( + ); + + typedef member_function_pointer<>::kernel_1a_c mfp; + + rmutex m; + rsignaler s; + map::kernel_2a>::kernel_1a thread_ids; + queue::kernel_2a>::kernel_1a dead_threads; + + bool is_running_; + bool should_stop_; + unsigned long threads_started; + + // restricted functions + multithreaded_object(multithreaded_object&); // copy constructor + multithreaded_object& operator=(multithreaded_object&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "multithreaded_object_extension.cpp" +#endif + +#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ + diff --git a/dlib/threads/multithreaded_object_extension_abstract.h b/dlib/threads/multithreaded_object_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..102b1db0db789daea8a4c3b5e840e16a2f0dd785 --- /dev/null +++ b/dlib/threads/multithreaded_object_extension_abstract.h @@ -0,0 +1,186 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class multithreaded_object + { + /*! + INITIAL VALUE + - is_running() == false + - number_of_threads_alive() == 0 + - number_of_threads_registered() == 0 + + WHAT THIS OBJECT REPRESENTS + This object represents a multithreaded object. It is similar to + the threaded_object except it allows you to have many threads in a + single object rather than just one. To use it you inherit from it + and register the member functions in your new class that you want + to run in their own threads by calling register_thread(). Then when + you call start() it will spawn all the registered functions + in their own threads. + !*/ + + public: + + multithreaded_object ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create threading objects. + !*/ + + virtual ~multithreaded_object ( + ) = 0; + /*! + requires + - number_of_threads_alive() == 0 + (i.e. in the destructor for the object you derive from this one you + must wait for all the threads to end.) + ensures + - all resources allocated by *this have been freed. + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - blocks until all threads have terminated + throws + - std::bad_alloc or dlib::thread_error + if an exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + bool is_running ( + ) const; + /*! + ensures + - if (number_of_threads_alive() > 0 && the threads are currently supposed to be executing) then + - returns true + - else + - returns false + !*/ + + unsigned long number_of_threads_alive ( + ) const; + /*! + ensures + - returns the number of threads that are currently alive (i.e. + the number of threads that have started but not yet terminated) + !*/ + + unsigned long number_of_threads_registered ( + ) const; + /*! + ensures + - returns the number of threads that have been registered by + calls to register_thread() + !*/ + + void wait ( + ) const; + /*! + requires + - is not called from one of this object's threads + ensures + - if (number_of_threads_alive() > 0) then + - blocks until all the threads in this object have terminated + (i.e. blocks until number_of_threads_alive() == 0) + !*/ + + void start ( + ); + /*! + ensures + - #number_of_threads_alive() == number_of_threads_registered() + - #is_running() == true + - #should_stop() == false + - all the threads registered are up and running. + throws + - std::bad_alloc or dlib::thread_error + If either of these exceptions are thrown then + #is_running() == false and should_stop() == true + !*/ + + void pause ( + ); + /*! + ensures + - #is_running() == false + !*/ + + void stop ( + ); + /*! + ensures + - #should_stop() == true + - #is_running() == false + !*/ + + protected: + + template < + typename T + > + void register_thread ( + T& object, + void (T::*thread)() + ); + /*! + requires + - (object.*thread)() forms a valid function call + - the thread function does not throw + ensures + - registers the member function pointed to by thread as one of the threads + that runs when is_running() == true + - #number_of_threads_registered() == number_of_threads_registered() + 1 + - if (is_running() == true) + - spawns this new member function in its own thread + - #number_of_threads_alive() += number_of_threads_alive() + 1 + throws + - std::bad_alloc or dlib::thread_error + If either of these exceptions are thrown then + #is_running() == false and should_stop() == true + !*/ + + bool should_stop ( + ) const; + /*! + requires + - is only called from one of the registered threads in this object + ensures + - if (is_running() == false && should_stop() == false) then + - blocks until (#is_running() == true || #should_stop() == true) + - if (this thread is supposed to terminate) then + - returns true + - else + - returns false + !*/ + + private: + + // restricted functions + multithreaded_object(multithreaded_object&); // copy constructor + multithreaded_object& operator=(multithreaded_object&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_MULTITHREADED_OBJECT_EXTENSIOn_ABSTRACT_ + diff --git a/dlib/threads/posix.h b/dlib/threads/posix.h new file mode 100644 index 0000000000000000000000000000000000000000..113e66ae1385884da5599ccebce8e4afd1e6ae29 --- /dev/null +++ b/dlib/threads/posix.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEl_1_ +#include "threads_kernel_2.h" +#endif + diff --git a/dlib/threads/rmutex_extension.h b/dlib/threads/rmutex_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..589db2527397d79a6ce25b49b7ae61e987740885 --- /dev/null +++ b/dlib/threads/rmutex_extension.h @@ -0,0 +1,109 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RMUTEX_EXTENSIOn_ +#define DLIB_RMUTEX_EXTENSIOn_ + +#include "threads_kernel.h" +#include "rmutex_extension_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class rmutex + { + /*! + INITIAL VALUE + count == 0 + thread_id == 0 + + CONVENTION + - count == lock_count() + + - if (no thread currently has a lock on this mutex) then + - count == 0 + - else + - count == the number of times the thread that owns this mutex has + called lock() + - thread_id == the id of this thread. + !*/ + public: + + rmutex ( + ) : s(m), + thread_id(0), + count(0) + {} + + ~rmutex ( + ) + {} + + unsigned long lock_count ( + ) const + { + return count; + } + + void lock ( + unsigned long times = 1 + ) const + { + const thread_id_type current_thread_id = get_thread_id(); + m.lock(); + if (thread_id == current_thread_id) + { + // we already own this mutex in this case + count += times; + } + else + { + // wait for our turn to claim this rmutex + while (count != 0) + s.wait(); + + count = times; + thread_id = current_thread_id; + } + m.unlock(); + } + + void unlock ( + unsigned long times = 1 + ) const + { + const thread_id_type current_thread_id = get_thread_id(); + m.lock(); + if (thread_id == current_thread_id) + { + if (count <= times) + { + count = 0; + s.signal(); + } + else + { + count -= times; + } + } + m.unlock(); + } + + private: + mutex m; + signaler s; + mutable thread_id_type thread_id; + mutable unsigned long count; + + // restricted functions + rmutex(rmutex&); // copy constructor + rmutex& operator=(rmutex&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RMUTEX_EXTENSIOn_ + diff --git a/dlib/threads/rmutex_extension_abstract.h b/dlib/threads/rmutex_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..d00eaa2916dc2cc0551eaff36d24897a4a5ec55f --- /dev/null +++ b/dlib/threads/rmutex_extension_abstract.h @@ -0,0 +1,107 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RMUTEX_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_RMUTEX_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class rmutex + { + /*! + INITIAL VALUE + rmutex is in the unlocked state + + WHAT THIS OBJECT REPRESENTS + This object represents a recursive mutex intended to be used for synchronous + thread control of shared data. When a thread wants to access some + shared data it locks out other threads by calling lock() and calls + unlock() when it is finished. + + The difference between this and the normal mutex object is that it is safe to + call lock() from a thread that already has a lock on this mutex. Doing + so just increments a counter but otherwise has no effect on the mutex. + Note that unlock() must be called for each call to lock() to release the + mutex. + !*/ + public: + + rmutex ( + ); + /*! + ensures + - #*this is properly initialized + throws + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create the rmutex. + !*/ + + ~rmutex ( + ); + /*! + requires + - *this is not locked + ensures + - all resources allocated by *this have been freed + !*/ + + unsigned long lock_count ( + ) const; + /*! + requires + - the calling thread has a lock on this mutex + ensures + - returns the number of times the thread has called lock() + !*/ + + void lock ( + unsigned long times = 1 + ) const; + /*! + ensures + - if (*this is currently locked by another thread) then + - the thread that called lock() on *this is put to sleep until + it becomes available. + - #lock_count() == times + - if (*this is currently unlocked) then + - #*this becomes locked and the current thread is NOT put to sleep + but now "owns" #*this + - #lock_count() == times + - if (*this is locked and owned by the current thread) then + - the calling thread retains its lock on *this and isn't put to sleep. + - #lock_count() == lock_count() + times + !*/ + + void unlock ( + unsigned long times = 1 + ) const; + /*! + ensures + - if (*this is currently locked and owned by the thread calling unlock) then + - if (lock_count() <= times ) then + - #*this is unlocked (i.e. other threads may now lock this object) + - else + - #*this will remain locked + - #lock_count() == lock_count() - times + - else + - the call to unlock() has no effect + !*/ + + + private: + // restricted functions + rmutex(rmutex&); // copy constructor + rmutex& operator=(rmutex&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RMUTEX_EXTENSIOn_ABSTRACT_ + diff --git a/dlib/threads/rsignaler_extension.h b/dlib/threads/rsignaler_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..0da988de987e82f88bad84b3e726b905a697d4b2 --- /dev/null +++ b/dlib/threads/rsignaler_extension.h @@ -0,0 +1,91 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_RSIGNALER_EXTENSIOn_ +#define DLIB_RSIGNALER_EXTENSIOn_ + +#include "rsignaler_extension_abstract.h" +#include "../threads.h" +#include "rmutex_extension.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class rsignaler + { + public: + rsignaler ( + const rmutex& associated_mutex + ) : + assoc_mutex(associated_mutex), + s(m) + {} + + ~rsignaler ( + ) + {} + + void wait ( + ) const + { + m.lock(); + const unsigned long lock_count = assoc_mutex.lock_count(); + assoc_mutex.unlock(lock_count); + s.wait(); + m.unlock(); + assoc_mutex.lock(lock_count); + } + + bool wait_or_timeout ( + unsigned long milliseconds + ) const + { + m.lock(); + const unsigned long lock_count = assoc_mutex.lock_count(); + assoc_mutex.unlock(lock_count); + bool res = s.wait_or_timeout(milliseconds); + m.unlock(); + assoc_mutex.lock(lock_count); + return res; + } + + void signal ( + ) const + { + m.lock(); + s.signal(); + m.unlock(); + } + + void broadcast ( + ) const + { + m.lock(); + s.broadcast(); + m.unlock(); + } + + const rmutex& get_mutex ( + ) const { return assoc_mutex; } + + private: + + const rmutex& assoc_mutex; + mutex m; + signaler s; + + + // restricted functions + rsignaler(rsignaler&); // copy constructor + rsignaler& operator=(rsignaler&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RSIGNALER_EXTENSIOn_ + + + diff --git a/dlib/threads/rsignaler_extension_abstract.h b/dlib/threads/rsignaler_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..b7b26cf2da0d384dfc4d0e38e4485b88c6279a77 --- /dev/null +++ b/dlib/threads/rsignaler_extension_abstract.h @@ -0,0 +1,123 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_RSIGNALER_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_RSIGNALER_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" +#include "rmutex_extension_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class rsignaler + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents an event signaling system for threads. It gives + a thread the ability to wake up other threads that are waiting for a + particular signal. + + Each rsignaler object is associated with one and only one rmutex object. + More than one rsignaler object may be associated with a single rmutex + but a signaler object may only be associated with a single rmutex. + + NOTE: + You must guard against spurious wakeups. This means that a thread + might return from a call to wait even if no other thread called + signal. This is rare but must be guarded against. + + Also note that this object is identical to the signaler object + except that it works with rmutex objects rather than mutex objects. + !*/ + + public: + + rsignaler ( + const rmutex& associated_mutex + ); + /*! + ensures + - #*this is properly initialized + - #get_mutex() == associated_mutex + throws + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create the signaler. + !*/ + + + ~rsignaler ( + ); + /*! + ensures + - all resources allocated by *this have been freed + !*/ + + void wait ( + ) const; + /*! + requires + - get_mutex() is locked and owned by the calling thread + ensures + - atomically unlocks get_mutex() and blocks the calling thread + - calling thread may wake if another thread calls signal() or broadcast() + on *this + - when wait() returns the calling thread again has a lock on get_mutex() + !*/ + + bool wait_or_timeout ( + unsigned long milliseconds + ) const; + /*! + requires + - get_mutex() is locked and owned by the calling thread + ensures + - atomically unlocks get_mutex() and blocks the calling thread + - calling thread may wake if another thread calls signal() or broadcast() + on *this + - after the specified number of milliseconds has elapsed the calling thread + will wake once get_mutex() is free + - when wait returns the calling thread again has a lock on get_mutex() + + - returns false if the call to wait_or_timeout timed out + - returns true if the call did not time out + !*/ + + void signal ( + ) const; + /*! + ensures + - if (at least one thread is waiting on *this) then + - at least one of the waiting threads will wake + !*/ + + void broadcast ( + ) const; + /*! + ensures + - any and all threads waiting on *this will wake + !*/ + + const rmutex& get_mutex ( + ) const; + /*! + ensures + - returns a const reference to the rmutex associated with *this + !*/ + + + private: + // restricted functions + rsignaler(rsignaler&); // copy constructor + rsignaler& operator=(rsignaler&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_RSIGNALER_EXTENSIOn_ABSTRACT_ + + diff --git a/dlib/threads/thread_function_extension.h b/dlib/threads/thread_function_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..8c7db8fb9c30c51a6d8862f13c632b1ab6041abe --- /dev/null +++ b/dlib/threads/thread_function_extension.h @@ -0,0 +1,150 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREAD_FUNCTIOn_ +#define DLIB_THREAD_FUNCTIOn_ + +#include "thread_function_extension_abstract.h" +#include "threads_kernel.h" +#include "auto_mutex_extension.h" +#include "threaded_object_extension.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class thread_function : private threaded_object + { + + class base_funct + { + public: + virtual void go() = 0; + + virtual ~base_funct() {} + }; + + template + class super_funct_arg : public base_funct + { + public: + super_funct_arg ( + void (*funct)(T), + T arg + ) + { + a = arg; + f = funct; + } + + void go() { f(a); } + + + T a; + void (*f)(T); + }; + + + class super_funct_no_arg : public base_funct + { + public: + super_funct_no_arg ( + void (*funct)() + ) + { + f = funct; + } + + void go() { f(); } + + void (*f)(); + + }; + + template + class super_Tfunct_no_arg : public base_funct + { + public: + super_Tfunct_no_arg ( + const T& funct + ) + { + f = funct; + } + + void go() { f(); } + + T f; + + }; + + public: + + template + thread_function ( + const T& funct + ) + { + f = new super_Tfunct_no_arg(funct); + start(); + } + + thread_function ( + void (*funct)() + ) + { + f = new super_funct_no_arg(funct); + start(); + } + + template + thread_function ( + void (*funct)(T), + T arg + ) + { + f = new super_funct_arg(funct,arg); + start(); + } + + ~thread_function ( + ) + { + threaded_object::wait(); + delete f; + } + + bool is_alive ( + ) const + { + return threaded_object::is_alive(); + } + + void wait ( + ) const + { + threaded_object::wait(); + } + + private: + + void thread () + { + f->go(); + } + + base_funct* f; + + // restricted functions + thread_function(thread_function&); // copy constructor + thread_function& operator=(thread_function&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREAD_FUNCTIOn_ + + + diff --git a/dlib/threads/thread_function_extension_abstract.h b/dlib/threads/thread_function_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..ddd489f85b6a31eff1f01f6cc847e1d71f504220 --- /dev/null +++ b/dlib/threads/thread_function_extension_abstract.h @@ -0,0 +1,107 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_THREAD_FUNCTIOn_ABSTRACT_ +#ifdef DLIB_THREAD_FUNCTIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class thread_function + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a thread on a global C++ function. That is, + it allows you to run a global function in its own thread. + !*/ + public: + + template + thread_function ( + const T& funct + ); + /*! + ensures + - #*this is properly initialized + - the function object funct has been started in its own thread + throws + - std::bad_alloc + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create threading objects. + !*/ + + thread_function ( + void (*funct)() + ); + /*! + ensures + - #*this is properly initialized + - the function pointed to by funct has been started in its own thread + throws + - std::bad_alloc + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create threading objects. + !*/ + + template + thread_function ( + void (*funct)(T), + T arg + ); + /*! + ensures + - #*this is properly initialized + - the function pointed to by funct has been started in its own thread and + passed the argument arg + throws + - std::bad_alloc + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create threading objects. + !*/ + + ~thread_function ( + ); + /*! + ensures + - all resources allocated by *this have been freed. + - blocks until is_alive() == false + !*/ + + bool is_alive ( + ) const; + /*! + ensures + - if (this object's thread has yet to terminate) then + - returns true + - else + - returns false + !*/ + + void wait ( + ) const; + /*! + ensures + - if (is_alive() == true) then + - blocks until this object's thread terminates + !*/ + + private: + + // restricted functions + thread_function(thread_function&); // copy constructor + thread_function& operator=(thread_function&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREAD_FUNCTIOn_ABSTRACT_ + + diff --git a/dlib/threads/thread_specific_data_extension.h b/dlib/threads/thread_specific_data_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..dfeaeeb926d2214e976cbac9f351de7dc282877a --- /dev/null +++ b/dlib/threads/thread_specific_data_extension.h @@ -0,0 +1,116 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ +#define DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ + +#include "thread_specific_data_extension_abstract.h" +#include "threads_kernel_abstract.h" +#include "../binary_search_tree.h" +#include "auto_mutex_extension.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class thread_specific_data + { + /*! + CONVENTION + - for all valid ID: + (*items[ID]) == pointer to the data for thread with id ID + !*/ + public: + + thread_specific_data ( + ){} + + ~thread_specific_data ( + ) + { + items.reset(); + while (items.move_next()) + { + delete items.element().value(); + } + } + + inline T& data ( + ) { return get_data(); } + + inline const T& data ( + ) const { return get_data(); } + + private: + + T& get_data ( + ) const + { + thread_id_type id = get_thread_id(); + auto_mutex M(m); + + T** item = items[id]; + if (item) + { + return **item; + } + else + { + // register an end handler for this thread so long as it is a dlib created thread. + T* new_item = new T; + + bool in_tree = false; + try + { + T* temp_item = new_item; + thread_id_type temp_id = id; + items.add(temp_id,temp_item); + in_tree = true; + + if (is_dlib_thread(id)) + register_thread_end_handler(const_cast(*this),&thread_specific_data::thread_end_handler); + } + catch (...) + { + if (in_tree) + { + items.destroy(id); + } + delete new_item; + throw; + } + + return *new_item; + } + } + + void thread_end_handler ( + ) + { + const thread_id_type id = get_thread_id(); + thread_id_type junk; + T* item; + auto_mutex M(m); + items.remove(id,junk,item); + delete item; + } + + mutable typename binary_search_tree::kernel_2a items; + mutex m; + + // restricted functions + thread_specific_data(thread_specific_data&); // copy constructor + thread_specific_data& operator=(thread_specific_data&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ + + + diff --git a/dlib/threads/thread_specific_data_extension_abstract.h b/dlib/threads/thread_specific_data_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..2796c3227eef4617706e02297ddbc3acd417c40a --- /dev/null +++ b/dlib/threads/thread_specific_data_extension_abstract.h @@ -0,0 +1,87 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class thread_specific_data + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents a container of thread specific data. When + a thread calls the data() member function it gets a reference to a T object + that is specific to its own thread. Each subsequent call to data() from that + thread returns the same instance. Also note that when a thread ends + the instance of its data() object gets destroyed and freed (if the thread + was created by the dlib library). So any pointers or references to the object + will be invalid after the thread has ended. + !*/ + public: + + thread_specific_data ( + ); + /*! + ensures + - #*this is properly initialized + !*/ + + ~thread_specific_data ( + ); + /*! + ensures + - all resources allocated by *this have been freed. This includes + all the thread specific data returned by the data() functions. + !*/ + + T& data ( + ); + /*! + ensures + - if (the calling thread has NOT called this->data() before) then + - constructs an instance of T that is specific to the calling + thread. + - returns a reference to the T instance that was constructed for + the calling thread. + throws + - std::bad_alloc or any exception thrown by T's constructor + If an exception is thrown then the call to data() will have + no effect on *this. + !*/ + + const T& data ( + ) const; + /*! + ensures + - if (the calling thread has NOT called this->data() before) then + - constructs an instance of T that is specific to the calling + thread. + - returns a const reference to the T instance that was constructed for + the calling thread. + throws + - std::bad_alloc or any exception thrown by T's constructor + If an exception is thrown then the call to data() will have + no effect on *this. + !*/ + + private: + // restricted functions + thread_specific_data(thread_specific_data&); // copy constructor + thread_specific_data& operator=(thread_specific_data&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_ABSTRACT_ + + diff --git a/dlib/threads/threaded_object_extension.cpp b/dlib/threads/threaded_object_extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9091bdaa08e1ecee0d55f1894c1ea7a55799fcbb --- /dev/null +++ b/dlib/threads/threaded_object_extension.cpp @@ -0,0 +1,201 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADED_OBJECT_EXTENSIOn_CPP +#define DLIB_THREADED_OBJECT_EXTENSIOn_CPP + +#include "threaded_object_extension.h" +#include "create_new_thread_extension.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + threaded_object:: + threaded_object ( + ): + s(m), + id1(0), + is_running_(false), + is_alive_(false), + should_stop_(false), + id_valid(false) + { + } + +// ---------------------------------------------------------------------------------------- + + threaded_object:: + ~threaded_object ( + ) + { + DLIB_ASSERT(is_alive() == false, + "\tthreaded_object::~threaded_object()" + << "\n\tYou have let a threaded object destruct itself before terminating its thread" + << "\n\tthis: " << this + ); + } + +// ---------------------------------------------------------------------------------------- + + bool threaded_object:: + is_running ( + ) const + { + auto_mutex M(m); + + DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, + "\tbool threaded_object::is_running()" + << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + + return is_running_; + } + +// ---------------------------------------------------------------------------------------- + + bool threaded_object:: + is_alive ( + ) const + { + auto_mutex M(m); + + DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, + "\tbool threaded_object::is_alive()" + << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + + return is_alive_; + } + +// ---------------------------------------------------------------------------------------- + + void threaded_object:: + wait ( + ) const + { + auto_mutex M(m); + + DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, + "\tvoid threaded_object::wait()" + << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + + while (is_alive_) + s.wait(); + } + +// ---------------------------------------------------------------------------------------- + + void threaded_object:: + start ( + ) + { + auto_mutex M(m); + + DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, + "\tvoid threaded_object::start()" + << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + + if (is_alive_ == false) + { + if (create_new_thread(*this) == false) + { + is_running_ = false; + throw thread_error(); + } + } + is_alive_ = true; + is_running_ = true; + should_stop_ = false; + s.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + void threaded_object:: + pause ( + ) + { + auto_mutex M(m); + + DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, + "\tvoid threaded_object::pause()" + << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + + is_running_ = false; + } + +// ---------------------------------------------------------------------------------------- + + void threaded_object:: + stop ( + ) + { + auto_mutex M(m); + + DLIB_ASSERT(id1 != get_thread_id() || id_valid == false, + "\tvoid threaded_object::stop()" + << "\n\tYou can NOT call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + + should_stop_ = true; + is_running_ = false; + s.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + bool threaded_object:: + should_stop ( + ) const + { + auto_mutex M(m); + DLIB_ASSERT(is_alive_ && id1 == get_thread_id() && id_valid == true, + "\tbool threaded_object::should_stop()" + << "\n\tYou can only call this function from the thread that executes threaded_object::thread" + << "\n\tthis: " << this + ); + while (is_running_ == false && should_stop_ == false) + s.wait(); + return should_stop_; + } + +// ---------------------------------------------------------------------------------------- + + void threaded_object:: + thread_helper( + ) + { +#ifdef ENABLE_ASSERTS + id1 = get_thread_id(); + id_valid = true; +#endif + + thread(); + auto_mutex M(m); + +#ifdef ENABLE_ASSERTS + id_valid = false; +#endif + + is_alive_ = false; + is_running_ = false; + should_stop_ = false; + s.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREADED_OBJECT_EXTENSIOn_CPP + diff --git a/dlib/threads/threaded_object_extension.h b/dlib/threads/threaded_object_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..c068753a8fc2d02f2f5fb638178a87d65633502b --- /dev/null +++ b/dlib/threads/threaded_object_extension.h @@ -0,0 +1,111 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADED_OBJECT_EXTENSIOn_ +#define DLIB_THREADED_OBJECT_EXTENSIOn_ + +#include "threaded_object_extension_abstract.h" +#include "threads_kernel.h" +#include "auto_mutex_extension.h" +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class threaded_object + { + /*! + INITIAL VALUE + - is_running_ == false + - is_alive_ == false + - should_stop_ == false + +#ifdef ENABLE_ASSERTS + - id_valid == false + - id1 == get_main_thread_id() +#endif + + CONVENTION + - is_running() == is_running_ + - is_alive() == is_alive_ + - should_stop() == should_stop_ + + +#ifdef ENABLE_ASSERTS + - if (when thread() is executing) then + - id1 == the id of the running thread + - id_valid == true + - else + - id1 == an undefined value + - id_valid == false +#endif + + - m == the mutex used to protect all our variables + - s == the signaler for m + !*/ + + public: + + threaded_object ( + ); + + virtual ~threaded_object ( + ); + + bool is_running ( + ) const; + + bool is_alive ( + ) const; + + void wait ( + ) const; + + void start ( + ); + + void pause ( + ); + + void stop ( + ); + + protected: + + bool should_stop ( + ) const; + + private: + + void thread_helper( + ); + + virtual void thread ( + ) = 0; + + mutex m; + signaler s; + thread_id_type id1; + bool is_running_; + bool is_alive_; + bool should_stop_; + bool id_valid; + + // restricted functions + threaded_object(threaded_object&); // copy constructor + threaded_object& operator=(threaded_object&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "threaded_object_extension.cpp" +#endif + +#endif // DLIB_THREADED_OBJECT_EXTENSIOn_ + + diff --git a/dlib/threads/threaded_object_extension_abstract.h b/dlib/threads/threaded_object_extension_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..0fbb35554b2b27e042aa36de13ebb0bddc332191 --- /dev/null +++ b/dlib/threads/threaded_object_extension_abstract.h @@ -0,0 +1,156 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_THREADED_OBJECT_EXTENSIOn_ABSTRACT_ +#ifdef DLIB_THREADED_OBJECT_EXTENSIOn_ABSTRACT_ + +#include "threads_kernel_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class threaded_object + { + /*! + INITIAL VALUE + - is_running() == false + - is_alive() == false + + WHAT THIS OBJECT REPRESENTS + This object represents a simple threaded object. To use it you inherit + from it and define the thread() function. Then when you call start() + it will spawn a thread that calls this->thread(). + !*/ + public: + + threaded_object ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create threading objects. + !*/ + + virtual ~threaded_object ( + ); + /*! + requires + - is_alive() == false + (i.e. in the destructor for the object you derive from this one you + must wait for this->thread() to end.) + ensures + - all resources allocated by *this have been freed. + !*/ + + bool is_running ( + ) const; + /*! + requires + - is not called from this->thread() + ensures + - if (is_alive() && this->thread() is currently supposed to be executing) then + - returns true + - else + - returns false + !*/ + + bool is_alive ( + ) const; + /*! + requires + - is not called from this->thread() + ensures + - if (this->thread() has been called by some thread and has yet to terminate) then + - returns true + - else + - returns false + !*/ + + void wait ( + ) const; + /*! + requires + - is not called from this->thread() + ensures + - if (is_alive() == true) then + - blocks until this->thread() terminates + !*/ + + void start ( + ); + /*! + requires + - is not called from this->thread() + ensures + - #is_alive() == true + - #is_running() == true + - #should_stop() == false + throws + - std::bad_alloc or dlib::thread_error + If either of these exceptions are thrown then + #is_alive() == false and #is_running() == false + !*/ + + void pause ( + ); + /*! + requires + - is not called from this->thread() + ensures + - #is_running() == false + !*/ + + void stop ( + ); + /*! + requires + - is not called from this->thread() + ensures + - #should_stop() == true + - #is_running() == false + !*/ + + protected: + + bool should_stop ( + ) const; + /*! + requires + - is only called from the thread that executes this->thread() + ensures + - if (is_running() == false && should_stop() == false) then + - blocks until (#is_running() == true || #should_stop() == true) + - if (this thread is supposed to terminate) then + - returns true + - else + - returns false + !*/ + + private: + + virtual void thread ( + ) = 0; + /*! + requires + - is executed in its own thread + - is only executed in one thread at a time + throws + - does not throw any exceptions + !*/ + + // restricted functions + threaded_object(threaded_object&); // copy constructor + threaded_object& operator=(threaded_object&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREADED_OBJECT_EXTENSIOn_ABSTRACT_ + diff --git a/dlib/threads/threads_kernel.h b/dlib/threads/threads_kernel.h new file mode 100644 index 0000000000000000000000000000000000000000..cd667233d8f8eecea26c4a325fdbd592129228da --- /dev/null +++ b/dlib/threads/threads_kernel.h @@ -0,0 +1,18 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADs_KERNEL_ +#define DLIB_THREADs_KERNEL_ + +#include "../platform.h" + +#ifdef WIN32 +#include "windows.h" +#endif + +#ifndef WIN32 +#include "posix.h" +#endif + +#endif // DLIB_THREADs_KERNEL_ + + diff --git a/dlib/threads/threads_kernel_1.cpp b/dlib/threads/threads_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ad925e1e047a8328044a14404a492534e7c49ed --- /dev/null +++ b/dlib/threads/threads_kernel_1.cpp @@ -0,0 +1,83 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEL_1_CPp_ +#define DLIB_THREADS_KERNEL_1_CPp_ + +#include "../platform.h" + +#ifdef WIN32 + +#include "threads_kernel_1.h" + +#include + + +namespace dlib +{ + namespace threads_kernel_shared_helpers + { + + // ----------------------------------------------------------------------------------- + + struct info + { + void* param; + void (*funct)(void*); + }; + + // ----------------------------------------------------------------------------------- + + unsigned int __stdcall thread_starter ( + void* param + ) + { + info* alloc_p = reinterpret_cast(param); + info p = *alloc_p; + delete alloc_p; + + p.funct(p.param); + return 0; + } + + // ----------------------------------------------------------------------------------- + + bool spawn_thread ( + void (*funct)(void*), + void* param + ) + { + info* p; + try { p = new info; } + catch (...) { return false; } + + p->funct = funct; + p->param = param; + + + unsigned int garbage; + + HANDLE thandle = (HANDLE)_beginthreadex (NULL,0,thread_starter,p,0,&garbage); + // make thread and add it to the pool + + // return false if _beginthreadex didn't work + if ( thandle == 0) + { + delete p; + return false; + } + + // throw away the thread handle + CloseHandle(thandle); + return true; + } + + // ----------------------------------------------------------------------------------- + + } + +} + +#endif // WIN32 + +#endif // DLIB_THREADS_KERNEL_1_CPp_ + diff --git a/dlib/threads/threads_kernel_1.h b/dlib/threads/threads_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..9090a11f33ef19cace10bf17a8c539562757978b --- /dev/null +++ b/dlib/threads/threads_kernel_1.h @@ -0,0 +1,277 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEl_1_ +#define DLIB_THREADS_KERNEl_1_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#include "threads_kernel_abstract.h" + +#include "../windows_magic.h" +#include +#include "../algs.h" + + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + typedef DWORD thread_id_type; + + inline thread_id_type get_thread_id ( + ) + { + return GetCurrentThreadId(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // mutex object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + // forward declaration of signaler + class signaler; + + class mutex + { + // give signaler access to hMutex + friend class signaler; + public: + + mutex ( + ) : + hMutex(CreateMutex(NULL,FALSE,NULL)) + { + if (hMutex == NULL) + { + throw dlib::thread_error(ECREATE_MUTEX, + "in function mutex::mutex() an error occurred making the mutex" + ); + } + } + + ~mutex ( + ) { CloseHandle(hMutex); } + + void lock ( + ) const { WaitForSingleObject (hMutex,INFINITE); } + + void unlock ( + ) const { ReleaseMutex(hMutex); } + + private: + + mutable HANDLE hMutex; + + // restricted functions + mutex(mutex&); // copy constructor + mutex& operator=(mutex&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // signaler object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class signaler + { + + public: + signaler ( + const mutex& associated_mutex + ) : + hSemaphore(CreateSemaphore (NULL, 0, 100000000, NULL)), + waiters(0), + hWaitersMutex(CreateMutex(NULL,FALSE,NULL)), + hCountSema(CreateSemaphore (NULL,0,100000000,NULL)), + m(associated_mutex) + { + if (hSemaphore == NULL || hWaitersMutex == NULL || hCountSema == NULL) + { + if (hSemaphore != NULL) + { + CloseHandle(hSemaphore); + } + + if (hWaitersMutex != NULL) + { + CloseHandle(hWaitersMutex); + } + + if (hCountSema != NULL) + { + CloseHandle(hCountSema); + } + + throw dlib::thread_error(ECREATE_SIGNALER, + "in function signaler::signaler() an error occurred making the signaler" + ); + } + } + + ~signaler ( + ) { CloseHandle(hSemaphore); CloseHandle(hWaitersMutex); CloseHandle(hCountSema);} + + void wait ( + ) const + { + // get a lock on the mutex for the waiters variable + WaitForSingleObject (hWaitersMutex,INFINITE); + // mark that one more thread will be waiting on this signaler + ++waiters; + // release the mutex for waiters + ReleaseMutex(hWaitersMutex); + + // release the assocaited mutex + ReleaseMutex(m.hMutex); + + // wait for the semaphore to be signaled + WaitForSingleObject (hSemaphore,INFINITE); + + // signal that we are awake + ReleaseSemaphore(hCountSema,(LONG)1,NULL); + + // relock the associated mutex + WaitForSingleObject (m.hMutex,INFINITE); + } + + bool wait_or_timeout ( + unsigned long milliseconds + ) const + { + // get a lock on the mutex for the waiters variable + WaitForSingleObject (hWaitersMutex,INFINITE); + // mark that one more thread will be waiting on this signaler + ++waiters; + // release the mutex for waiters + ReleaseMutex(hWaitersMutex); + + // release the assocaited mutex + ReleaseMutex(m.hMutex); + + bool value; + + // wait for the semaphore to be signaled + if ( WaitForSingleObject (hSemaphore, milliseconds ) == WAIT_TIMEOUT ) + { + // in this case we should decrement waiters because we are returning + // due to a timeout rather than because someone called signal() or + // broadcast(). + value = false; + + // get a lock on the mutex for the waiters variable + WaitForSingleObject (hWaitersMutex,INFINITE); + // mark that one less thread will be waiting on this signaler. + if (waiters != 0) + --waiters; + // release the mutex for waiters + ReleaseMutex(hWaitersMutex); + } + else + { + value = true; + } + + // signal that we are awake + ReleaseSemaphore(hCountSema,(LONG)1,NULL); + + // relock the associated mutex + WaitForSingleObject (m.hMutex,INFINITE); + + return value; + } + + void signal ( + ) const + { + // get a lock on the mutex for the waiters variable + WaitForSingleObject (hWaitersMutex,INFINITE); + + if (waiters > 0) + { + --waiters; + // make the semaphore release one waiting thread + ReleaseSemaphore(hSemaphore,1,NULL); + + // wait for signaled thread to wake up + WaitForSingleObject(hCountSema,INFINITE); + } + + // release the mutex for waiters + ReleaseMutex(hWaitersMutex); + } + + void broadcast ( + ) const + { + // get a lock on the mutex for the waiters variable + WaitForSingleObject (hWaitersMutex,INFINITE); + + if (waiters > 0) + { + // make the semaphore release all the waiting threads + ReleaseSemaphore(hSemaphore,(LONG)waiters,NULL); + + // wait for count to be zero + for (unsigned long i = 0; i < waiters; ++i) + { + WaitForSingleObject(hCountSema,INFINITE); + } + + waiters = 0; + } + + // release the mutex for waiters + ReleaseMutex(hWaitersMutex); + } + + const mutex& get_mutex ( + ) const { return m; } + + private: + + mutable HANDLE hSemaphore; + + mutable unsigned long waiters; + mutable HANDLE hWaitersMutex; + + + mutable HANDLE hCountSema; + + const mutex& m; + + // restricted functions + signaler(signaler&); // copy constructor + signaler& operator=(signaler&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + + namespace threads_kernel_shared_helpers + { + bool spawn_thread ( + void (*funct)(void*), + void* param + ); + /*! + is identical to create_new_thread() but just doesn't use any thread pooling. + !*/ + } + +// ---------------------------------------------------------------------------------------- + +} + +#include "threads_kernel_shared.h" + +#ifdef NO_MAKEFILE +#include "threads_kernel_1.cpp" +#endif + +#endif // DLIB_THREADS_KERNEl_1_ + diff --git a/dlib/threads/threads_kernel_2.cpp b/dlib/threads/threads_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe1f5f5f18c6a007a93ab9596bbb856da7fd17e3 --- /dev/null +++ b/dlib/threads/threads_kernel_2.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEL_2_CPp_ +#define DLIB_THREADS_KERNEL_2_CPp_ + +#include "../platform.h" + +#ifdef POSIX + +#include "threads_kernel_2.h" + + +namespace dlib +{ + namespace threads_kernel_shared_helpers + { + + // ----------------------------------------------------------------------------------- + + struct info + { + void* param; + void (*funct)(void*); + }; + + // ----------------------------------------------------------------------------------- + + void* thread_starter ( + void* param + ) + { + info* alloc_p = reinterpret_cast(param); + info p = *alloc_p; + delete alloc_p; + + // detach self + pthread_detach(pthread_self()); + + p.funct(p.param); + return 0; + } + + // ----------------------------------------------------------------------------------- + + bool spawn_thread ( + void (*funct)(void*), + void* param + ) + { + info* p; + try { p = new info; } + catch (...) { return false; } + + p->funct = funct; + p->param = param; + + pthread_t thread_id; + if ( pthread_create (&thread_id, 0, thread_starter, p) ) + { + delete p; + return false; + } + return true; + } + + // ----------------------------------------------------------------------------------- + + } + +} + +#endif // POSIX + +#endif // DLIB_THREADS_KERNEL_2_CPp_ + diff --git a/dlib/threads/threads_kernel_2.h b/dlib/threads/threads_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..9753ad88434be09c73170ce1f1987dfae6a0d2d1 --- /dev/null +++ b/dlib/threads/threads_kernel_2.h @@ -0,0 +1,180 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEl_2_ +#define DLIB_THREADS_KERNEl_2_ + +#ifdef DLIB_ISO_CPP_ONLY +#error "DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code. Turn DLIB_ISO_CPP_ONLY off if you want to use it." +#endif + +#include "threads_kernel_abstract.h" +#include +#include +#include +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + typedef pthread_t thread_id_type; + + inline thread_id_type get_thread_id ( + ) + { + return pthread_self(); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // mutex object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + // forward declaration of signaler + class signaler; + + class mutex + { + // give signaler access to hMutex + friend class signaler; + public: + + mutex ( + ) + { + if (pthread_mutex_init(&myMutex,0)) + { + throw dlib::thread_error(ECREATE_MUTEX, + "in function mutex::mutex() an error occurred making the mutex" + ); + } + } + + ~mutex ( + ) { pthread_mutex_destroy(&myMutex); } + + void lock ( + ) const { pthread_mutex_lock(&myMutex); } + + void unlock ( + ) const { pthread_mutex_unlock(&myMutex); } + + private: + + mutable pthread_mutex_t myMutex; + + // restricted functions + mutex(mutex&); // copy constructor + mutex& operator=(mutex&); // assignement opertor + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // signaler object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class signaler + { + + public: + + + signaler ( + const mutex& assoc_mutex + ) : + associated_mutex(&assoc_mutex.myMutex), + m(assoc_mutex) + { + if (pthread_cond_init(&cond,0)) + { + throw dlib::thread_error(ECREATE_SIGNALER, + "in function signaler::signaler() an error occurred making the signaler" + ); + } + } + + ~signaler ( + ) { pthread_cond_destroy(&cond); } + + void wait ( + ) const + { + pthread_cond_wait(&cond,associated_mutex); + } + + bool wait_or_timeout ( + unsigned long milliseconds + ) const + { + timespec time_to_wait; + + timeval curtime; + gettimeofday(&curtime,0); + + // get the time and adjust the timespec object by the appropriate amount + time_to_wait.tv_sec = milliseconds/1000 + curtime.tv_sec; + time_to_wait.tv_nsec = curtime.tv_usec; + time_to_wait.tv_nsec *= 1000; + time_to_wait.tv_nsec += (milliseconds%1000)*1000000; + + time_to_wait.tv_sec += time_to_wait.tv_nsec/1000000000; + time_to_wait.tv_nsec = time_to_wait.tv_nsec%1000000000; + + if ( pthread_cond_timedwait(&cond,associated_mutex,&time_to_wait) == ETIMEDOUT) + { + return false; + } + else + { + return true; + } + } + + void signal ( + ) const { pthread_cond_signal(&cond); } + + void broadcast ( + ) const { pthread_cond_broadcast(&cond); } + + const mutex& get_mutex ( + ) const { return m; } + + private: + + pthread_mutex_t* const associated_mutex; + mutable pthread_cond_t cond; + const mutex& m; + + // restricted functions + signaler(signaler&); // copy constructor + signaler& operator=(signaler&); // assignement opertor + }; + +// ---------------------------------------------------------------------------------------- + + namespace threads_kernel_shared_helpers + { + bool spawn_thread ( + void (*funct)(void*), + void* param + ); + /*! + is identical to create_new_thread() but just doesn't use any thread pooling. + !*/ + } + +// ---------------------------------------------------------------------------------------- + +} + +#include "threads_kernel_shared.h" + +#ifdef NO_MAKEFILE +#include "threads_kernel_2.cpp" +#endif + +#endif // DLIB_THREADS_KERNEl_2_ + diff --git a/dlib/threads/threads_kernel_abstract.h b/dlib/threads/threads_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..587ff5e40a92b67fffe9377be1b537ba086384cd --- /dev/null +++ b/dlib/threads/threads_kernel_abstract.h @@ -0,0 +1,338 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_THREADS_KERNEl_ABSTRACT_ +#ifdef DLIB_THREADS_KERNEl_ABSTRACT_ + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + GENERAL COMMENTS + Unlike the other API wrappers you may make instances of these objects at the + global scope and call these functions before main() has been entered. + + PROGRAM TERMINATION + When the main() function ends the program will wait until all outstanding + threads have terminated before allowing the program itself to terminate. + This means that if you want your program to actually be able to terminate + you have to ensure that all your threads will eventually end. To help you + make sure all your threads end you can use the register_program_ending_handler() + function. It allows you to register a member function that will be called after + main() has ended. Thus, you can register a function that can tell your + threads to end. + + Note that you can't safely use the destructor of a global static object + to tell a thread to end. This is because the order in which global objects + in different translation units is undefined. So what may happen if you + attempt this is that dlib may begin to wait for threads to terminate ( + in the main program thread, i.e. the one that executes global object's + destructors) before your object is destructed. Thus your program would + hang forever. So just use the register_thread_end_handler() function + instead of a global object's destructor if you have threads that will + survive beyond the end of main(). + + Finally, note that once main() ends C++ will start destructing global and + static objects so any threads making use of those resources may get into + trouble. So you probably just want to ensure that all your threads are + done *before* you try to terminate the program. But if that isn't possible + for whatever reason then you can use the register_program_ending_handler() + function to notify those threads that it is time to end. + + THREAD POOL + When threads end they go into a global thread pool and each waits there + for 30 seconds before timing out and having its resources returned to the + operating system. When create_new_thread() is called it first looks in the + thread pool to see if there are any threads it can snatch from the pool, if + not then it makes a new one. + + Note that whenever I say something happens when a thread "terminates" or "ends" + I mean "when it returns to the thread pool." From the client programmer point + of view a thread terminates/ends when it returns to the dlib thread pool and you + shouldn't and indeed don't need to know when it actually gets its resources + reclaimed by the operating system. + + If you want to change the timeout to a different value you can #define + DLIB_THREAD_POOL_TIMEOUT to whatever value (in milliseconds) that you like. + !*/ + +// ---------------------------------------------------------------------------------------- + + thread_id_type get_thread_id ( + ); + /*! + ensures + - returns a unique id for the calling thread. Note that while the id is unique + among all currently existing threads it may have been used by a previous + thread that has terminated. + !*/ + +// ---------------------------------------------------------------------------------------- + + bool is_dlib_thread ( + thread_id_type id = get_thread_id() + ); + /*! + ensures + - if (the thread with the given id was spawned by a call to + dlib::create_new_thread) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void register_thread_end_handler ( + T& obj, + void (T::*handler)() + ); + /*! + requires + - handler == a valid member function pointer for class T + - handler does not throw + - handler does not call register_thread_end_handler() + - handler does not block + - is_dlib_thread() == true (i.e. the calling thread was spawned by dlib::create_new_thread()) + ensures + - let ID == the thread id for the thread calling register_thread_end_handler() + - (obj.*handler)() will be called when the thread with thread id ID is + terminating and it will be called from within that terminating thread. + (i.e. inside the handler function get_thread_id() == ID == the id of the + thread that is terminating. ) + - each call to this function adds another handler that will be called when + the given thread terminates. This means that if you call it a bunch of + times then you will end up registering multiple handlers (or single + handlers multiple times) that will be called when the thread ends. + throws + - std::bad_alloc + If this exception is thrown then the call to this function had no effect. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void register_program_ending_handler ( + T& obj, + void (T::*handler)() + ); + /*! + requires + - handler == a valid member function pointer for class T + - handler does not throw + - handler does not call register_thread_end_handler() + - handler does not call register_program_ending_handler() + - handler does not block + ensures + - (obj.*handler)() will be called after main() has terminated. + - each call to this function adds another handler that will be called at + program termination. This means that if you call it a bunch of + times then you will end up registering multiple handlers (or single + handlers multiple times). + throws + - std::bad_alloc + If this exception is thrown then the call to this function had no effect. + !*/ + +// ---------------------------------------------------------------------------------------- + + bool create_new_thread ( + void (*funct)(void*), + void* param + ); + /*! + ensures + - creates a new thread for the function pointed to by funct + - passes it param as its parameter + - returns true upon success and false upon failure to create the new thread + !*/ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // mutex object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class mutex + { + /*! + INITIAL VALUE + mutex is in the unlocked state + + WHAT THIS OBJECT REPRESENTS + This object represents a mutex intended to be used for synchronous + thread control of shared data. When a thread wants to access some + shared data it locks out other threads by calling lock() and calls + unlock() when it is finished. + !*/ + public: + + mutex ( + ); + /*! + ensures + - #*this is properly initialized + throws + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create the mutex. + !*/ + + ~mutex ( + ); + /*! + requires + - *this is not locked + ensures + - all resources allocated by *this have been freed + !*/ + + void lock ( + ) const; + /*! + requires + - the thread calling lock() does not already have a lock on *this + ensures + - if (*this is currently locked by another thread) then + - the thread that called lock() on *this is put to sleep until + it becomes available + - if (*this is currently unlocked) then + - #*this becomes locked and the current thread is NOT put to sleep + but now "owns" #*this + !*/ + + void unlock ( + ) const; + /*! + ensures + - if (*this is currently locked and owned by the thread calling unlock) then + - #*this is unlocked (i.e. other threads may now lock this object) + - else + - the call to unlock() has no effect + !*/ + + + private: + // restricted functions + mutex(mutex&); // copy constructor + mutex& operator=(mutex&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // signaler object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class signaler + { + /*! + + WHAT THIS OBJECT REPRESENTS + This object represents an event signaling system for threads. It gives + a thread the ability to wake up other threads that are waiting for a + particular signal. + + Each signaler object is associated with one and only one mutex object. + More than one signaler object may be associated with a single mutex + but a signaler object may only be associated with a single mutex. + + NOTE: + You must guard against spurious wakeups. This means that a thread + might return from a call to wait even if no other thread called + signal. This is rare but must be guarded against. + !*/ + public: + + signaler ( + const mutex& associated_mutex + ); + /*! + ensures + - #*this is properly initialized + - #get_mutex() == associated_mutex + throws + - dlib::thread_error + the constructor may throw this exception if there is a problem + gathering resources to create the signaler. + !*/ + + + ~signaler ( + ); + /*! + ensures + - all resources allocated by *this have been freed + !*/ + + void wait ( + ) const; + /*! + requires + - get_mutex() is locked and owned by the calling thread + ensures + - atomically unlocks get_mutex() and blocks the calling thread + - calling thread may wake if another thread calls signal() or broadcast() + on *this + - when wait() returns the calling thread again has a lock on get_mutex() + !*/ + + bool wait_or_timeout ( + unsigned long milliseconds + ) const; + /*! + requires + - get_mutex() is locked and owned by the calling thread + ensures + - atomically unlocks get_mutex() and blocks the calling thread + - calling thread may wake if another thread calls signal() or broadcast() + on *this + - after the specified number of milliseconds has elapsed the calling thread + will wake once get_mutex() is free + - when wait returns the calling thread again has a lock on get_mutex() + + - returns false if the call to wait_or_timeout timed out + - returns true if the call did not time out + !*/ + + + void signal ( + ) const; + /*! + ensures + - if (at least one thread is waiting on *this) then + - at least one of the waiting threads will wake + !*/ + + void broadcast ( + ) const; + /*! + ensures + - any and all threads waiting on *this will wake + !*/ + + const mutex& get_mutex ( + ) const; + /*! + ensures + - returns a const reference to the mutex associated with *this + !*/ + + private: + // restricted functions + signaler(signaler&); // copy constructor + signaler& operator=(signaler&); // assignment operator + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREADS_KERNEl_ABSTRACT_ + diff --git a/dlib/threads/threads_kernel_shared.cpp b/dlib/threads/threads_kernel_shared.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0687f47e8ce05065fadb5091adfc99f3857afd1 --- /dev/null +++ b/dlib/threads/threads_kernel_shared.cpp @@ -0,0 +1,287 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEL_SHARED_CPp_ +#define DLIB_THREADS_KERNEL_SHARED_CPp_ + +#include "threads_kernel_shared.h" +#include "../assert.h" +#include + + +#ifndef DLIB_THREAD_POOL_TIMEOUT +// default to 30000 milliseconds +#define DLIB_THREAD_POOL_TIMEOUT 30000 +#endif + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// threader functions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + namespace threads_kernel_shared + { + + threader& thread_pool ( + ) + { + static threader thread_pool; + return thread_pool; + } + +// ---------------------------------------------------------------------------------------- + + bool threader:: + is_dlib_thread ( + thread_id_type id + ) + { + auto_mutex M(data_mutex); + return thread_ids.is_member(id); + } + +// ---------------------------------------------------------------------------------------- + + threader:: + threader ( + ) : + total_count(0), + pool_count(0), + data_ready(data_mutex), + data_empty(data_mutex), + destruct(false), + destructed(data_mutex) + {} + +// ---------------------------------------------------------------------------------------- + + threader:: + ~threader ( + ) + { + data_mutex.lock(); + destruct = true; + data_ready.broadcast(); + + member_function_pointer<>::kernel_1a mfp; + // call all the handlers for anything that has registered for this event + while(queue_of_enders.size()) + { + queue_of_enders.dequeue(mfp); + + data_mutex.unlock(); + mfp(); + data_mutex.lock(); + } + + // wait for all the threads to end + while (total_count > 0) + destructed.wait(); + data_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + void threader:: + add_ender ( + member_function_pointer<>::kernel_1a mfp + ) + { + auto_mutex M(data_mutex); + queue_of_enders.enqueue(mfp); + } + +// ---------------------------------------------------------------------------------------- + + void threader:: + call_end_handlers ( + ) + { + reg.m.lock(); + const thread_id_type id = get_thread_id(); + thread_id_type id_copy; + unsigned long count = reg.reg.count(id); + member_function_pointer<>::kernel_1a mfp; + + // Remove all the member function pointers for this thread from the tree + // and call them. + for (unsigned long i = 0; i < count; ++i) + { + reg.reg.remove(id,id_copy,mfp); + reg.m.unlock(); + mfp(); + reg.m.lock(); + } + reg.m.unlock(); + } + + // ------------------------------------------------------------------------------------ + + bool threader:: + create_new_thread ( + void (*funct)(void*), + void* param + ) + { + + // get a lock on the data mutex + auto_mutex M(data_mutex); + + // loop to ensure that the new function poitner is in the data + while (true) + { + // if the data is empty then add new data and quit loop + if (function_pointer == 0) + { + parameter = param; + function_pointer = funct; + break; + } + else + { + // wait for data to become empty + data_empty.wait(); + } + } + + + // get a thread for this new data + // if a new thread must be crated + if (pool_count == 0) + { + // make thread and add it to the pool + if ( threads_kernel_shared_helpers::spawn_thread(thread_starter, this) == false ) + { + function_pointer = 0; + parameter = 0; + data_empty.signal(); + return false; + } + ++total_count; + } + // wake up a thread from the pool + else + { + data_ready.signal(); + } + + return true; + } + + // ------------------------------------------------------------------------------------ + + void thread_starter ( + void* object + ) + { + // get a reference to the calling threader object + threader& self = *reinterpret_cast(object); + + + auto_mutex M(self.data_mutex); + + // add this thread id + thread_id_type thread_id = get_thread_id(); + self.thread_ids.add(thread_id); + + // indicate that this thread is now in the thread pool + ++self.pool_count; + + while (true) + { + // if data is ready then process it and launch the thread + // if its not ready then go back into the pool + while (self.function_pointer != 0) + { + // indicate that this thread is now out of the thread pool + --self.pool_count; + + // get the data for the function call + void (*funct)(void*) = self.function_pointer; + void* param = self.parameter; + self.function_pointer = 0; + + // signal that the data is now empty + self.data_empty.signal(); + + self.data_mutex.unlock(); + // call funct with its intended parameter + try + { + funct(param); + self.call_end_handlers(); + } + catch (std::exception& e) + { + std::cerr << "An exception was thrown in a thread and was not caught. Its what() string is:\n" + << e.what() << std::endl; + + self.data_mutex.lock(); + --self.total_count; + self.destructed.signal(); + self.data_mutex.unlock(); + + abort(); + } + catch (...) + { + std::cerr << "An exception was thrown in a thread and was not caught." << std::endl; + + self.data_mutex.lock(); + --self.total_count; + self.destructed.signal(); + self.data_mutex.unlock(); + + abort(); + } + + self.data_mutex.lock(); + + // indicate that this thread is now back in the thread pool + ++self.pool_count; + } + + if (self.destruct == true) + break; + + // if we timed out and there isn't any work to do then + // this thread will quit this loop and end. + if (self.data_ready.wait_or_timeout(DLIB_THREAD_POOL_TIMEOUT) == false && + self.function_pointer == 0) + break; + + } + + // remove this thread id from thread_ids + thread_id = get_thread_id(); + self.thread_ids.destroy(thread_id); + + // indicate that this thread is now out of the thread pool + --self.pool_count; + --self.total_count; + + self.destructed.signal(); + } + + // ------------------------------------------------------------------------------------ + + } + +// ---------------------------------------------------------------------------------------- + + bool is_dlib_thread ( + thread_id_type id + ) + { + return threads_kernel_shared::thread_pool().is_dlib_thread(id); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_THREADS_KERNEL_SHARED_CPp_ + diff --git a/dlib/threads/threads_kernel_shared.h b/dlib/threads/threads_kernel_shared.h new file mode 100644 index 0000000000000000000000000000000000000000..1f8af5011324f190729e93de4dc034e3c4660ec7 --- /dev/null +++ b/dlib/threads/threads_kernel_shared.h @@ -0,0 +1,229 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEl_SHARED_ +#define DLIB_THREADS_KERNEl_SHARED_ + +// this file should be included at the bottom of one of the thread kernel headers for a +// specific platform. +//#include "../threads.h" +#include "auto_mutex_extension.h" +#include "../binary_search_tree.h" +#include "../member_function_pointer.h" +#include "../memory_manager.h" +#include "../queue.h" +#include "../set.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace threads_kernel_shared + { + void thread_starter ( + void* + ); + + class threader + { + /*! + INITIAL VALUE + - pool_count == 0 and + - data_ready is associated with the mutex data_mutex + - data_empty is associated with the mutex data_mutex + - destructed is associated with the mutex data_mutex + - destruct == false + - total_count == 0 + + CONVENTION + - data_ready is associated with the mutex data_mutex + - data_empty is associated with the mutex data_mutex + - data_ready == a signaler used signal when there is new data waiting + to start a thread with. + - data_empty == a signaler used to signal when the data is now empty + - pool_count == the number of suspended threads in the thread pool + - total_count == the number of threads that are executing anywhere. i.e. + pool_count + the ones that are currently running some user function. + - if (function_pointer != 0) then + - parameter == a void pointer pointing to the parameter which + should be used to start the next thread + - function_pointer == a pointer to the next function to make a + new thread with + + - if (the destructor is running) then + - destruct == true + - else + - destruct == false + + - queue_of_enders is locked by the data_mutex + - queue_of_enders == a set of member_function_pointers that should be called + when we want to end all the threads. these come from calls made to + register_program_ending_handler(). + - thread_ids is locked by the data_mutex + - thread_ids == a set that contains the thread id for each thread spawned by this + object. + !*/ + + + public: + threader ( + ); + + ~threader ( + ); + + void add_ender ( + member_function_pointer<>::kernel_1a mfp + ); + + bool create_new_thread ( + void (*funct)(void*), + void* param + ); + + template < + typename T + > + void register_thread_end_handler ( + T& obj, + void (T::*handler)() + ) + { + thread_id_type id = get_thread_id(); + member_function_pointer<>::kernel_1a mfp; + mfp.set(obj,handler); + + auto_mutex M(reg.m); + reg.reg.add(id,mfp); + } + + bool is_dlib_thread ( + thread_id_type id + ); + + private: + + friend void thread_starter ( + void* + ); + + void call_end_handlers ( + ); + /*! + ensures + - calls the registered end handlers for the calling thread and + then removes them from reg.reg + !*/ + + + // private data + set::kernel_2b>::kernel_1b_c thread_ids; + queue::kernel_1a>::kernel_1a queue_of_enders; + unsigned long total_count; + void* parameter; + void (*function_pointer)(void*); + unsigned long pool_count; + mutex data_mutex; // mutex to protect the above data + signaler data_ready; // signaler to signal when there is new data + signaler data_empty; // signaler to signal when the data is empty + bool destruct; + signaler destructed; // signaler to signal when a thread has ended + + struct registry_type + { + mutex m; + binary_search_tree< + thread_id_type, + member_function_pointer<>::kernel_1a, + memory_manager::kernel_2a + >::kernel_2a_c reg; + }; + + // stuff for the register_thread_end_handler + registry_type reg; + + + // restricted functions + threader(threader&); // copy constructor + threader& operator=(threader&); // assignement opertor + + }; + + // ------------------------------------------------------------------------------------ + + threader& thread_pool ( + ); + /*! + ensures + - returns a reference to the global threader object + !*/ + + // ------------------------------------------------------------------------------------ + + } + + bool is_dlib_thread ( + thread_id_type id = get_thread_id() + ); + +// ---------------------------------------------------------------------------------------- + + inline bool create_new_thread ( + void (*funct)(void*), + void* param + ) + { + try + { + // now make this thread + return threads_kernel_shared::thread_pool().create_new_thread(funct,param); + } + catch (std::bad_alloc&) + { + return false; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + inline void register_thread_end_handler ( + T& obj, + void (T::*handler)() + ) + { + DLIB_ASSERT(is_dlib_thread(), + "\tvoid register_thread_end_handler" + << "\n\tYou can't register a thread end handler for a thread dlib didn't spawn." + ); + + threads_kernel_shared::thread_pool().register_thread_end_handler(obj,handler); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + inline void register_program_ending_handler ( + T& obj, + void (T::*handler)() + ) + { + member_function_pointer<>::kernel_1a mfp; + mfp.set(obj,handler); + threads_kernel_shared::thread_pool().add_ender(mfp); + } + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "threads_kernel_shared.cpp" +#endif + +#endif // DLIB_THREADS_KERNEl_SHARED_ + diff --git a/dlib/threads/windows.h b/dlib/threads/windows.h new file mode 100644 index 0000000000000000000000000000000000000000..434ef801b303e18fdf12d1dca02ff11366a6dca8 --- /dev/null +++ b/dlib/threads/windows.h @@ -0,0 +1,6 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_THREADS_KERNEl_2_ +#include "threads_kernel_1.h" +#endif + diff --git a/dlib/time_this.h b/dlib/time_this.h new file mode 100644 index 0000000000000000000000000000000000000000..df7fb6590a6343409e6deee5d02c6144551edf3a --- /dev/null +++ b/dlib/time_this.h @@ -0,0 +1,76 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIME_THIs_ +#define DLIB_TIME_THIs_ + + +#include "platform.h" + + + +#ifndef WIN32 + +#include +#include +#include +#include +// ---------------------------------------------------------------------------------------- + +#define TIME_THIS_TO(op,out) \ + { \ + clock_t start, end; \ + tms timesbuf; \ + start = times(×buf); \ + op; \ + end = times(×buf); \ + long ticks = sysconf(_SC_CLK_TCK); \ + if ((double)(end-start)/(double)ticks < 1) \ + { \ + out << "\ntime: " \ + << (int)(1000*((double)(end-start)/(double)ticks)) << "ms\n"; \ + } \ + else \ + { \ + out << "\ntime: " \ + << (double)(end-start)/(double)ticks << "sec\n"; \ + } \ + } \ + + +#define TIME_THIS(op) TIME_THIS_TO(op,std::cout) + +// ---------------------------------------------------------------------------------------- + + +#endif + +#ifdef WIN32 + +#include "windows_magic.h" +#include // for GetTickCount() +#include + +// ---------------------------------------------------------------------------------------- + +#define TIME_THIS_TO(op,out) \ + { \ + unsigned long count = GetTickCount(); \ + op; \ + count = GetTickCount() - count; \ + if (count < 1000) \ + { \ + out << "\ntime: " << count << "ms\n"; \ + } \ + else \ + { \ + out << "\ntime: " << static_cast(count)/1000 << "sec\n"; \ + } \ + } \ + +#define TIME_THIS(op) TIME_THIS_TO(op,std::cout) + +// ---------------------------------------------------------------------------------------- + +#endif + +#endif // DLIB_TIME_THIs_ diff --git a/dlib/timeout.h b/dlib/timeout.h new file mode 100644 index 0000000000000000000000000000000000000000..b2c89630609a5a5c91918fb574ffa97b94979ed0 --- /dev/null +++ b/dlib/timeout.h @@ -0,0 +1,29 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIMEOUt_ +#define DLIB_TIMEOUt_ + +#include "timeout/timeout_kernel_1.h" + +namespace dlib +{ + + class timeout + { + timeout() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef timeout_kernel_1 + kernel_1a; + + }; +} + +#endif // DLIB_TIMEOUt_ + + diff --git a/dlib/timeout/timeout_kernel_1.h b/dlib/timeout/timeout_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..ab0e579e66bd43321787e8c9f0e2ab18412210d4 --- /dev/null +++ b/dlib/timeout/timeout_kernel_1.h @@ -0,0 +1,166 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIMEOUT_KERNEl_1_ +#define DLIB_TIMEOUT_KERNEl_1_ + +#include "../threads.h" +#include "../algs.h" +#include "../misc_api.h" +#include "timeout_kernel_abstract.h" +#include "../uintn.h" +#include "../timer.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + class timeout_kernel_1 + { + /*! + INITIAL VALUE + - b == a pointer to some kind of bind object + + CONVENTION + - b == a pointer to some kind of bind object + !*/ + + class bind + { + public: + virtual void go() = 0; + virtual ~bind() {} + }; + + template + class zero : public bind + { + public: + T* object; + R (T::*callback_function)(); + void go() { (object->*callback_function)(); } + + }; + + template + class one : public bind + { + public: + T* object; + R (T::*callback_function)(U); + U val; + void go() { (object->*callback_function)(val); } + }; + + public: + + template < + typename T + > + timeout_kernel_1 ( + T& object, + void (T::*callback_function)(), + unsigned long ms_to_timeout + ): + t(*this,&timeout_kernel_1::trigger_timeout) + { + zero* B = new zero; + b = B; + B->object = &object; + B->callback_function = callback_function; + t.set_delay_time(ms_to_timeout); + t.start(); + } + + template < + typename T, + typename U + > + timeout_kernel_1 ( + T& object, + void (T::*callback_function)(U callback_function_argument), + unsigned long ms_to_timeout, + U callback_function_argument + ): + t(*this,&timeout_kernel_1::trigger_timeout) + { + one* B = new one; + b = B; + B->object = &object; + B->callback_function = callback_function; + B->val = callback_function_argument; + t.set_delay_time(ms_to_timeout); + t.start(); + } + + template < + typename T + > + timeout_kernel_1 ( + T& object, + int (T::*callback_function)(), + unsigned long ms_to_timeout + ): + t(*this,&timeout_kernel_1::trigger_timeout) + { + zero* B = new zero; + b = B; + B->object = &object; + B->callback_function = callback_function; + t.set_delay_time(ms_to_timeout); + t.start(); + } + + template < + typename T, + typename U + > + timeout_kernel_1 ( + T& object, + int (T::*callback_function)(U callback_function_argument), + unsigned long ms_to_timeout, + U callback_function_argument + ): + t(*this,&timeout_kernel_1::trigger_timeout) + { + one* B = new one; + b = B; + B->object = &object; + B->callback_function = callback_function; + B->val = callback_function_argument; + t.set_delay_time(ms_to_timeout); + t.start(); + } + + virtual ~timeout_kernel_1 ( + ) + { + t.stop_and_wait(); + delete b; + } + + private: + + void trigger_timeout () + { + b->go(); + t.stop(); + } + + dlib::timer::kernel_2a t; + bind* b; + + // restricted functions + timeout_kernel_1(const timeout_kernel_1&); // copy constructor + timeout_kernel_1& operator=(const timeout_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TIMEOUT_KERNEl_1_ + + + diff --git a/dlib/timeout/timeout_kernel_abstract.h b/dlib/timeout/timeout_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..d0389a5ecc2ca3a0118d45174921eb1be7db5666 --- /dev/null +++ b/dlib/timeout/timeout_kernel_abstract.h @@ -0,0 +1,154 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_TIMEOUT_KERNEl_ABSTRACT_ +#ifdef DLIB_TIMEOUT_KERNEl_ABSTRACT_ + +#include "../threads.h" + +namespace dlib +{ + + class timeout + { + /*! + WHAT THIS OBJECT REPRESENTS + This object provides a simple way to implement a timeout. An example will make + its use clear. Suppose we want to read from a socket but we want to terminate the + connection if the read takes longer than 10 seconds. This could be accomplished + as follows: + + connection* con = a connection from somewhere; + { + // setup a timer that will call con->shutdown() in 10 seconds + timeout t(*con,&connection::shutdown,10000); + // Now call read on the connection. If this call to read() takes + // more than 10 seconds then the t timeout will trigger and shutdown + // the connection. If read completes in less than 10 seconds then + // the t object will be destructed on the next line due to the } + // and then the timeout won't trigger. + con->read(buf,100); + } + + THREAD SAFETY + All methods of this class are thread safe. + !*/ + + public: + + template < + typename T + > + timeout ( + T& object, + void (T::*callback_function)(), + unsigned long ms_to_timeout + ); + /*! + requires + - callback_function does not throw + ensures + - does not block. + - #*this is properly initialized + - if (this object isn't destructed in ms_to_timeout milliseconds) then + - (object.*callback_function)() will be called in ms_to_timeout + milliseconds. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + template < + typename T, + typename U + > + timeout ( + T& object, + void (T::*callback_function)(U callback_function_argument), + unsigned long ms_to_timeout, + U callback_function_argument + ); + /*! + requires + - callback_function does not throw + ensures + - does not block. + - #*this is properly initialized + - if (this object isn't destructed in ms_to_timeout milliseconds) then + - (object.*callback_function)(callback_function_argument) will be + called in ms_to_timeout milliseconds. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + template < + typename T + > + timeout ( + T& object, + int (T::*callback_function)(), + unsigned long ms_to_timeout + ); + /*! + requires + - callback_function does not throw + ensures + - does not block. + - #*this is properly initialized + - if (this object isn't destructed in ms_to_timeout milliseconds) then + - (object.*callback_function)() will be called in ms_to_timeout + milliseconds. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + template < + typename T, + typename U + > + timeout ( + T& object, + int (T::*callback_function)(U callback_function_argument), + unsigned long ms_to_timeout, + U callback_function_argument + ); + /*! + requires + - callback_function does not throw + ensures + - does not block. + - #*this is properly initialized + - if (this object isn't destructed in ms_to_timeout milliseconds) then + - (object.*callback_function)(callback_function_argument) will be + called in ms_to_timeout milliseconds. + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~timeout ( + ); + /*! + requires + - is not called from inside the callback_function given to the + constructor. + ensures + - any resources associated with *this have been released + - if (the callback_function hasn't been called yet) then + - the callback_function specified in the constructor will not be called + !*/ + + private: + + // restricted functions + timeout(const timeout&); // copy constructor + timeout& operator=(const timeout&); // assignment operator + + }; + +} + +#endif // DLIB_TIMEOUT_KERNEl_ABSTRACT_ + + diff --git a/dlib/timer.h b/dlib/timer.h new file mode 100644 index 0000000000000000000000000000000000000000..d34724b581505af06fe5ea013c2291f0f795ccbd --- /dev/null +++ b/dlib/timer.h @@ -0,0 +1,38 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIMEr_ +#define DLIB_TIMEr_ + +#include "timer/timer_kernel_1.h" +#include "timer/timer_kernel_2.h" +#include "uintn.h" +#include "memory_manager.h" + +namespace dlib +{ + + template < + typename T + > + class timer + { + timer() {} + + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef timer_kernel_1 + kernel_1a; + + // kernel_2a + typedef timer_kernel_2 + kernel_2a; + }; +} + +#endif // DLIB_TIMEr_ + diff --git a/dlib/timer/timer_kernel_1.h b/dlib/timer/timer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..ec32a3f0479c6bc10f0e4747cfca0cdd878d6f5e --- /dev/null +++ b/dlib/timer/timer_kernel_1.h @@ -0,0 +1,380 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIMER_KERNEl_1_ +#define DLIB_TIMER_KERNEl_1_ + +#include "../threads.h" +#include "../algs.h" +#include "../misc_api.h" +#include "timer_kernel_abstract.h" + +namespace dlib +{ + + template < + typename T + > + class timer_kernel_1 + { + /*! + INITIAL VALUE + - running == false + - delay == 1000 + - ao == a pointer to the action_object() + - af == a pointer to the action_function() + - m == a mutex that locks everything in this class + - s == a signaler for mutex m + - stop_running == false + + CONVENTION + - running && !stop_running == is_running() + - delay == delay_time() + - *ao == action_object() + - af == action_function() + + - if (running) then + - there is a thread running + - if (is_running()) then + - next_time_to_run == the time when the next execution of the action + function should occurr. (the time is given by ts.get_timestamp()) + + - stop_running is used to tell the thread to quit. If it is + set to true then the thread should end. + !*/ + + public: + + typedef void (T::*af_type)(); + + timer_kernel_1( + T& ao_, + af_type af_ + ); + + virtual ~timer_kernel_1( + ); + + void clear( + ); + + af_type action_function ( + ) const; + + const T& action_object ( + ) const; + + T& action_object ( + ); + + bool is_running ( + ) const; + + unsigned long delay_time ( + ) const; + + void set_delay_time ( + unsigned long milliseconds + ); + + void start ( + ); + + void stop ( + ); + + void stop_and_wait ( + ); + + private: + + void thread ( + ); + /*! + requires + - is run in its own thread + ensures + - calls the action function for the given timer object in the manner + specified by timer_kernel_abstract.h + !*/ + + // data members + T& ao; + const af_type af; + unsigned long delay; + mutex m; + signaler s; + + bool running; + bool stop_running; + timestamper ts; + uint64 next_time_to_run; + + // restricted functions + timer_kernel_1(const timer_kernel_1&); // copy constructor + timer_kernel_1& operator=(const timer_kernel_1&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + timer_kernel_1:: + timer_kernel_1( + T& ao_, + af_type af_ + ) : + ao(ao_), + af(af_), + delay(1000), + s(m), + running(false), + stop_running(false) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + timer_kernel_1:: + ~timer_kernel_1( + ) + { + stop_and_wait(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_1:: + clear( + ) + { + m.lock(); + stop_running = true; + delay = 1000; + s.broadcast(); + m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename timer_kernel_1::af_type timer_kernel_1:: + action_function ( + ) const + { + return af; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + const T& timer_kernel_1:: + action_object ( + ) const + { + return ao; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + T& timer_kernel_1:: + action_object ( + ) + { + return ao; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool timer_kernel_1:: + is_running ( + ) const + { + auto_mutex M(m); + return running && !stop_running; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + unsigned long timer_kernel_1:: + delay_time ( + ) const + { + auto_mutex M(m); + return delay; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_1:: + set_delay_time ( + unsigned long milliseconds + ) + { + m.lock(); + + // if (is_running()) then we should adjust next_time_to_run + if (running && !stop_running) + { + next_time_to_run -= delay*1000; + next_time_to_run += milliseconds*1000; + } + + delay = milliseconds; + s.broadcast(); + m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_1:: + start ( + ) + { + auto_mutex M(m); + + // if (is_running() == false) then reset the countdown to the next call + // to the action_function() + if ( (running && !stop_running) == false) + next_time_to_run = ts.get_timestamp() + delay*1000; + + stop_running = false; + if (running == false) + { + running = true; + + // start the thread + if (create_new_thread(*this) == false) + { + running = false; + throw dlib::thread_error("error creating new thread in timer_kernel_1::start"); + } + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_1:: + stop ( + ) + { + m.lock(); + stop_running = true; + s.broadcast(); + m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_1:: + thread ( + ) + { + auto_mutex M(m); + unsigned long delay_remaining; + uint64 current_time = ts.get_timestamp(); + + if (current_time < next_time_to_run) + delay_remaining = static_cast((next_time_to_run-current_time)/1000); + else + delay_remaining = 0; + + while (stop_running == false) + { + if (delay_remaining > 0) + s.wait_or_timeout(delay_remaining); + + if (stop_running) + break; + + current_time = ts.get_timestamp(); + if (current_time < next_time_to_run) + { + // then we woke up too early so we should keep waiting + delay_remaining = static_cast((next_time_to_run-current_time)/1000); + + // rounding might make this be zero anyway. So if it is + // then we will say we have hit the next time to run. + if (delay_remaining > 0) + continue; + } + + // call the action function + m.unlock(); + (ao.*af)(); + m.lock(); + + current_time = ts.get_timestamp(); + next_time_to_run = current_time + delay*1000; + delay_remaining = delay; + } + running = false; + stop_running = false; + s.broadcast(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_1:: + stop_and_wait ( + ) + { + m.lock(); + if (running) + { + // make the running thread terminate + stop_running = true; + + s.broadcast(); + // wait for the thread to quit + while (running) + s.wait(); + } + m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TIMER_KERNEl_1_ + diff --git a/dlib/timer/timer_kernel_2.cpp b/dlib/timer/timer_kernel_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7444f4a8030b2efa6c738c00ac1215b02cf3a41a --- /dev/null +++ b/dlib/timer/timer_kernel_2.cpp @@ -0,0 +1,218 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIMER_KERNEl_2_CPP +#define DLIB_TIMER_KERNEl_2_CPP + +#include "timer_kernel_2.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + timer_kernel_2_global_clock:: + timer_kernel_2_global_clock( + ): + s(m), + shutdown(false), + running(false) + { + register_program_ending_handler(*this,&timer_kernel_2_global_clock::destruct); + } + +// ---------------------------------------------------------------------------------------- + + void timer_kernel_2_global_clock:: + destruct ( + ) + { + delete this; + } + +// ---------------------------------------------------------------------------------------- + + timer_kernel_2_global_clock:: + ~timer_kernel_2_global_clock() + { + m.lock(); + shutdown = true; + s.signal(); + m.unlock(); + wait(); + } + +// ---------------------------------------------------------------------------------------- + + void timer_kernel_2_global_clock:: + add ( + timer_kernel_2_base* r + ) + { + if (r->in_global_clock == false) + { + // if the thread isn't running then start it up + if (!running) + { + start(); + running = true; + } + + uint64 t = ts.get_timestamp() + r->delay*1000; + tm.reset(); + if (!tm.move_next() || t < tm.element().key()) + { + // we need to make the thread adjust its next time to + // trigger if this new event occurrs sooner than the + // next event in tm + s.signal(); + } + timer_kernel_2_base* rtemp = r; + uint64 ttemp = t; + tm.add(ttemp,rtemp); + r->next_time_to_run = t; + r->in_global_clock = true; + } + } + +// ---------------------------------------------------------------------------------------- + + void timer_kernel_2_global_clock:: + remove ( + timer_kernel_2_base* r + ) + { + if (r->in_global_clock) + { + tm.position_enumerator(r->next_time_to_run-1); + do + { + if (tm.element().value() == r) + { + uint64 t; + timer_kernel_2_base* rtemp; + tm.remove_current_element(t,rtemp); + r->in_global_clock = false; + break; + } + } while (tm.move_next()); + } + } + +// ---------------------------------------------------------------------------------------- + + void timer_kernel_2_global_clock:: + adjust_delay ( + timer_kernel_2_base* r, + unsigned long new_delay + ) + { + if (r->in_global_clock) + { + remove(r); + // compute the new next_time_to_run and store it in t + uint64 t = r->next_time_to_run; + t -= r->delay*1000; + t += new_delay*1000; + + tm.reset(); + if (!tm.move_next() || t < tm.element().key()) + { + // we need to make the thread adjust its next time to + // trigger if this new event occurrs sooner than the + // next event in tm + s.signal(); + } + + // set this incase add throws + r->running = false; + r->delay = new_delay; + + timer_kernel_2_base* rtemp = r; + uint64 ttemp = t; + tm.add(ttemp,rtemp); + r->next_time_to_run = t; + r->in_global_clock = true; + + // put this back now that we know add didn't throw + r->running = true; + + } + else + { + r->delay = new_delay; + } + } + +// ---------------------------------------------------------------------------------------- + + void timer_kernel_2_global_clock:: + thread() + { + auto_mutex M(m); + while (!shutdown) + { + unsigned long delay = 100000; + + tm.reset(); + tm.move_next(); + // loop and start all the action functions for timers that should have + // triggered. + while(tm.current_element_valid()) + { + const uint64 cur_time = ts.get_timestamp(); + uint64 t = tm.element().key(); + // if the next event in tm is ready to trigger + if (t <= cur_time + 999) + { + // remove this event from the tm map + timer_kernel_2_base* r = tm.element().value(); + timer_kernel_2_base* rtemp; + tm.remove_current_element(t,rtemp); + r->in_global_clock = false; + + // if this timer is still "running" then start its action function + if (r->running) + { + r->start(); + } + } + else + { + // there aren't any more timers that should trigger so we compute + // the delay to the next timer event. + delay = static_cast((t - cur_time)/1000); + break; + } + } + + s.wait_or_timeout(delay); + } + } + +// ---------------------------------------------------------------------------------------- + + timer_kernel_2_global_clock& get_global_clock() + { + static timer_kernel_2_global_clock* d = new timer_kernel_2_global_clock; + return *d; + } + +// ---------------------------------------------------------------------------------------- + + // do this just to make sure get_global_clock() gets called at program startup + class timer_kernel_2_global_clock_helper + { + public: + timer_kernel_2_global_clock_helper() + { + get_global_clock(); + } + }; + static timer_kernel_2_global_clock_helper call_get_global_clock; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TIMER_KERNEl_2_CPP + diff --git a/dlib/timer/timer_kernel_2.h b/dlib/timer/timer_kernel_2.h new file mode 100644 index 0000000000000000000000000000000000000000..c884c2a36c994e60e9b757be9cf2ba45412a1d7d --- /dev/null +++ b/dlib/timer/timer_kernel_2.h @@ -0,0 +1,422 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TIMER_KERNEl_2_ +#define DLIB_TIMER_KERNEl_2_ + +#include "../threads.h" +#include "../algs.h" +#include "../misc_api.h" +#include "timer_kernel_abstract.h" +#include "../uintn.h" +#include "../binary_search_tree.h" + +namespace dlib +{ + + struct timer_kernel_2_base : public threaded_object + { + /*! + WHAT THIS OBJECT REPRESENTS + This object contains the base members of the timer_kernel_2 object. + It exists so that we can access them from outside any templated functions. + !*/ + + unsigned long delay; + // these are only modified by the global_clock + uint64 next_time_to_run; + timestamper ts; + bool running; + bool in_global_clock; + }; + +// ---------------------------------------------------------------------------------------- + + class timer_kernel_2_global_clock : private threaded_object + { + /*! + This object sets up a timer that triggers the action function + for timer_kernel_2 objects that are tracked inside this object. + INITIAL VALUE + - shutdown == false + - running == false + + CONVENTION + - if (shutdown) then + - thread() should terminate + - else (running) then + - thread() is running + + - tm[time] == pointer to a timer_kernel_2_base object + !*/ + typedef binary_search_tree::kernel_2b>::kernel_2a_c time_map; + public: + + ~timer_kernel_2_global_clock(); + + void add ( + timer_kernel_2_base* r + ); + /*! + requires + - m is locked + ensures + - starts the thread if it isn't already started + - adds r to tm + - #r->in_global_clock == true + - updates r->next_time_to_run appropriately according to + r->delay + !*/ + + void remove ( + timer_kernel_2_base* r + ); + /*! + requires + - m is locked + ensures + - if (r is in tm) then + - removes r from tm + - #r->in_global_clock == false + !*/ + + void adjust_delay ( + timer_kernel_2_base* r, + unsigned long new_delay + ); + /*! + requires + - m is locked + ensures + - #r->delay == new_delay + - if (r->in_global_clock) then + - the time to the next event will have been appropriately adjusted + !*/ + + mutex m; + + friend timer_kernel_2_global_clock& get_global_clock(); + + private: + timer_kernel_2_global_clock(); + + void destruct(); + /*! + ensures + - calls delete this; + !*/ + + time_map tm; + signaler s; + bool shutdown; + bool running; + timestamper ts; + + void thread(); + /*! + ensures + - spawns timer tasks as is appropriate + !*/ + }; + timer_kernel_2_global_clock& get_global_clock(); + /*! + ensures + - returns the global instance of the timer_kernel_2_global_clock object + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + class timer_kernel_2 : private timer_kernel_2_base + { + /*! + INITIAL VALUE + - running == false + - delay == 1000 + - ao == a pointer to the action_object() + - af == a pointer to the action_function() + - in_global_clock == false + - next_time_to_run == 0 + + CONVENTION + - the mutex used to lock everything is get_global_clock().m + - running == is_running() + - delay == delay_time() + - *ao == action_object() + - af == action_function() + - if (!running) then + - in_global_clock == false + - else + - next_time_to_run == the next time this timer should run according + to the timestamper in the global_clock + !*/ + + public: + + typedef void (T::*af_type)(); + + timer_kernel_2( + T& ao_, + af_type af_ + ); + + virtual ~timer_kernel_2( + ); + + void clear( + ); + + af_type action_function ( + ) const; + + const T& action_object ( + ) const; + + T& action_object ( + ); + + bool is_running ( + ) const; + + unsigned long delay_time ( + ) const; + + void set_delay_time ( + unsigned long milliseconds + ); + + void start ( + ); + + void stop ( + ); + + void stop_and_wait ( + ); + + private: + + void thread ( + ); + /*! + ensures + - calls the action function + !*/ + + // data members + T& ao; + const af_type af; + + // restricted functions + timer_kernel_2(const timer_kernel_2&); // copy constructor + timer_kernel_2& operator=(const timer_kernel_2&); // assignment operator + + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + timer_kernel_2:: + timer_kernel_2( + T& ao_, + af_type af_ + ) : + ao(ao_), + af(af_) + { + delay = 1000; + next_time_to_run = 0; + running = false; + in_global_clock = false; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + timer_kernel_2:: + ~timer_kernel_2( + ) + { + clear(); + wait(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_2:: + clear( + ) + { + auto_mutex M(get_global_clock().m); + running = false; + get_global_clock().remove(this); + delay = 1000; + next_time_to_run = 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + typename timer_kernel_2::af_type timer_kernel_2:: + action_function ( + ) const + { + return af; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + const T& timer_kernel_2:: + action_object ( + ) const + { + return ao; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + T& timer_kernel_2:: + action_object ( + ) + { + return ao; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + bool timer_kernel_2:: + is_running ( + ) const + { + auto_mutex M(get_global_clock().m); + return running; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + unsigned long timer_kernel_2:: + delay_time ( + ) const + { + auto_mutex M(get_global_clock().m); + return delay; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_2:: + set_delay_time ( + unsigned long milliseconds + ) + { + auto_mutex M(get_global_clock().m); + get_global_clock().adjust_delay(this,milliseconds); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_2:: + start ( + ) + { + auto_mutex M(get_global_clock().m); + if (!running) + { + get_global_clock().add(this); + running = true; + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_2:: + stop ( + ) + { + get_global_clock().m.lock(); + running = false; + get_global_clock().remove(this); + get_global_clock().m.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_2:: + thread ( + ) + { + // call the action function + (ao.*af)(); + auto_mutex M(get_global_clock().m); + if (running) + { + get_global_clock().remove(this); + get_global_clock().add(this); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename T + > + void timer_kernel_2:: + stop_and_wait ( + ) + { + get_global_clock().m.lock(); + running = false; + get_global_clock().remove(this); + get_global_clock().m.unlock(); + wait(); + } + +// ---------------------------------------------------------------------------------------- + +} + +#ifdef NO_MAKEFILE +#include "timer_kernel_2.cpp" +#endif + +#endif // DLIB_TIMER_KERNEl_2_ + + diff --git a/dlib/timer/timer_kernel_abstract.h b/dlib/timer/timer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..5b0a71a67674d403fee0a2ff0c83cbc05cc13bf7 --- /dev/null +++ b/dlib/timer/timer_kernel_abstract.h @@ -0,0 +1,190 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_TIMER_KERNEl_ABSTRACT_ +#ifdef DLIB_TIMER_KERNEl_ABSTRACT_ + +#include "../threads.h" + +namespace dlib +{ + + template < + typename T + > + class timer + { + /*! + INITIAL VALUE + is_running() == false + delay_time() == 1000 + action_object() == The object that is passed into the constructor + action_function() == The member function pointer that is passed to + the constructor. + + WHAT THIS OBJECT REPRESENTS + This object represents a timer that will call a given member function + (the action function) repeatedly at regular intervals and in its own + thread. + + Note that the delay_time() is measured in milliseconds but you are not + guaranteed to have that level of resolution. The actual resolution + is implementation dependent. + + THREAD SAFETY + All methods of this class are thread safe. + !*/ + + public: + + typedef void (T::*af_type)(); + + timer ( + T& ao, + af_type af + ); + /*! + requires + - af does not throw + ensures + - does not block. + - #*this is properly initialized + - #action_object() == ao + - #action_function() == af + (af is a member function pointer to a member in the class T) + throws + - std::bad_alloc + - dlib::thread_error + !*/ + + virtual ~timer ( + ); + /*! + requires + - is not called from inside the action_function() + ensures + - any resources associated with *this have been released + - will not call the action_function() anymore. + - if (the action function is currently executing) then + - blocks until it finishes + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + - does not block + throws + - std::bad_alloc or dlib::thread_error + If either of these exceptions are thrown then #*this is unusable + until clear() is called and succeeds. + !*/ + + af_type action_function ( + ) const; + /*! + ensures + - does not block. + - returns a pointer to the member function of action_object() that is + called by *this. + !*/ + + const T& action_object ( + ) const; + /*! + ensures + - does not block. + - returns a const reference to the object used to call the member + function pointer action_function() + !*/ + + T& action_object ( + ); + /*! + ensures + - does not block. + - returns a non-const reference to the object used to call the member + function pointer action_function() + !*/ + + bool is_running ( + ) const; + /*! + ensures + - does not block. + - if (*this is currently scheduled to call the action_function()) then + - returns true + - else + - returns false + !*/ + + unsigned long delay_time ( + ) const; + /*! + ensures + - does not block. + - returns the amount of time that *this will wait between the return of + one call to the action_function() and the beginning of the next call + to the action_function(). + !*/ + + void set_delay_time ( + unsigned long milliseconds + ); + /*! + ensures + - does not block. + - #delay_time() == milliseconds + throws + - std::bad_alloc or dlib::thread_error + If either of these exceptions are thrown then #is_running() == false + but otherwise this function succeeds + !*/ + + void start ( + ); + /*! + ensures + - does not block. + - if (is_running() == false) then + - #is_running() == true + - The action_function() will run in another thread. + - The first call to the action_function() will occur in roughly + delay_time() milliseconds. + - else + - this call to start() has no effect + throws + - dlib::thread_error or std::bad_alloc + If this exception is thrown then #is_running() == false but + otherwise this call to start() has no effect. + !*/ + + void stop ( + ); + /*! + enusres + - #is_running() == false + - does not block. + !*/ + + void stop_and_wait ( + ); + /*! + enusres + - #is_running() == false + - if (the action function is currently executing) then + - blocks until it finishes + !*/ + + private: + + // restricted functions + timer(const timer&); // copy constructor + timer& operator=(const timer&); // assignment operator + + }; + +} + +#endif // DLIB_TIMER_KERNEl_ABSTRACT_ + diff --git a/dlib/tokenizer.h b/dlib/tokenizer.h new file mode 100644 index 0000000000000000000000000000000000000000..a35aa4a8d15a330b488944b5815907f92ed756e3 --- /dev/null +++ b/dlib/tokenizer.h @@ -0,0 +1,33 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TOKENIZEr_ +#define DLIB_TOKENIZEr_ + +#include "tokenizer/tokenizer_kernel_1.h" +#include "tokenizer/tokenizer_kernel_c.h" + + +namespace dlib +{ + + class tokenizer + { + tokenizer() {} + + + public: + + //----------- kernels --------------- + + // kernel_1a + typedef tokenizer_kernel_1 + kernel_1a; + typedef tokenizer_kernel_c + kernel_1a_c; + + + }; +} + +#endif // DLIB_TOKENIZEr_ + diff --git a/dlib/tokenizer/tokenizer_kernel_1.cpp b/dlib/tokenizer/tokenizer_kernel_1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c5800c3ed3eaca888d0b202d8cc5e2e07f5f7f3 --- /dev/null +++ b/dlib/tokenizer/tokenizer_kernel_1.cpp @@ -0,0 +1,294 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TOKENIZER_KERNEL_1_CPp_ +#define DLIB_TOKENIZER_KERNEL_1_CPp_ +#include "tokenizer_kernel_1.h" + +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + tokenizer_kernel_1:: + tokenizer_kernel_1 ( + ) : + headset(0), + bodyset(0), + have_peeked(false) + { + try + { + headset = new bool[UCHAR_MAX]; + bodyset = new bool[UCHAR_MAX]; + + clear(); + } + catch (...) + { + if (headset) delete [] headset; + if (bodyset) delete [] headset; + throw; + } + } + +// ---------------------------------------------------------------------------------------- + + tokenizer_kernel_1:: + ~tokenizer_kernel_1 ( + ) + { + delete [] bodyset; + delete [] headset; + } + +// ---------------------------------------------------------------------------------------- + + void tokenizer_kernel_1:: + clear( + ) + { + using namespace std; + + in = 0; + streambuf = 0; + have_peeked = false; + + head = "_" + lowercase_letters() + uppercase_letters(); + body = "_" + lowercase_letters() + uppercase_letters() + numbers(); + + for (unsigned long i = 0; i < UCHAR_MAX; ++i) + { + headset[i] = false; + bodyset[i] = false; + } + + for (string::size_type i = 0; i < head.size(); ++i) + headset[static_cast(head[i])] = true; + for (string::size_type i = 0; i < body.size(); ++i) + bodyset[static_cast(body[i])] = true; + } + +// ---------------------------------------------------------------------------------------- + + void tokenizer_kernel_1:: + set_stream ( + std::istream& in_ + ) + { + in = &in_; + streambuf = in_.rdbuf(); + have_peeked = false; + } + +// ---------------------------------------------------------------------------------------- + + bool tokenizer_kernel_1:: + stream_is_set ( + ) const + { + return (in != 0); + } + +// ---------------------------------------------------------------------------------------- + + std::istream& tokenizer_kernel_1:: + get_stream ( + ) const + { + return *in; + } + +// ---------------------------------------------------------------------------------------- + + void tokenizer_kernel_1:: + get_token ( + int& type, + std::string& token + ) + { + if (!have_peeked) + { + std::streambuf::int_type ch; + ch = streambuf->sbumpc(); + + switch (ch) + { + case EOF: + type = END_OF_FILE; + token.clear(); + return; + + case '\n': + type = END_OF_LINE; + token = "\n"; + return; + + case '\r': + case ' ': + case '\t': + type = WHITE_SPACE; + token = static_cast(ch); + ch = streambuf->sgetc(); + while ((ch == ' ' || ch == '\t' || ch == '\r') && ch != EOF) + { + token += static_cast(ch); + ch = streambuf->snextc(); + } + return; + + default: + if (headset[static_cast(ch)]) + { + type = IDENTIFIER; + token = static_cast(ch); + ch = streambuf->sgetc(); + while ( bodyset[static_cast(ch)] && ch != EOF ) + { + token += static_cast(ch); + ch = streambuf->snextc(); + } + } + else if ('0' <= ch && ch <= '9') + { + type = NUMBER; + token = static_cast(ch); + ch = streambuf->sgetc(); + while (('0' <= ch && ch <= '9') && ch != EOF) + { + token += static_cast(ch); + ch = streambuf->snextc(); + } + } + else + { + type = CHAR; + token = static_cast(ch); + } + return; + } // switch (ch) + } + + // if we get this far it means we have peeked so we should + // return the peek data. + type = next_type; + token = next_token; + have_peeked = false; + } + +// ---------------------------------------------------------------------------------------- + + int tokenizer_kernel_1:: + peek_type ( + ) const + { + const_cast(this)->get_token(next_type,next_token); + have_peeked = true; + return next_type; + } + +// ---------------------------------------------------------------------------------------- + + const std::string& tokenizer_kernel_1:: + peek_token ( + ) const + { + const_cast(this)->get_token(next_type,next_token); + have_peeked = true; + return next_token; + } + +// ---------------------------------------------------------------------------------------- + + void tokenizer_kernel_1:: + swap ( + tokenizer_kernel_1& item + ) + { + exchange(in,item.in); + exchange(streambuf,item.streambuf); + exchange(head,item.head); + exchange(body,item.body); + exchange(bodyset,item.bodyset); + exchange(headset,item.headset); + exchange(have_peeked,item.have_peeked); + exchange(next_type,item.next_type); + exchange(next_token,item.next_token); + } + +// ---------------------------------------------------------------------------------------- + + void tokenizer_kernel_1:: + set_identifier_token ( + const std::string& head_, + const std::string& body_ + ) + { + using namespace std; + + head = head_; + body = body_; + + for (unsigned long i = 0; i < UCHAR_MAX; ++i) + { + headset[i] = false; + bodyset[i] = false; + } + + for (string::size_type i = 0; i < head.size(); ++i) + headset[static_cast(head[i])] = true; + for (string::size_type i = 0; i < body.size(); ++i) + bodyset[static_cast(body[i])] = true; + } + +// ---------------------------------------------------------------------------------------- + + const std::string tokenizer_kernel_1:: + get_identifier_head ( + ) const + { + return head; + } + +// ---------------------------------------------------------------------------------------- + + const std::string tokenizer_kernel_1:: + get_identifier_body ( + ) const + { + return body; + } + +// ---------------------------------------------------------------------------------------- + + const std::string tokenizer_kernel_1:: + lowercase_letters ( + ) const + { + return std::string("abcdefghijklmnopqrstuvwxyz"); + } + +// ---------------------------------------------------------------------------------------- + + const std::string tokenizer_kernel_1:: + uppercase_letters ( + ) const + { + return std::string("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + +// ---------------------------------------------------------------------------------------- + + const std::string tokenizer_kernel_1:: + numbers ( + ) const + { + return std::string("0123456789"); + } + +// ---------------------------------------------------------------------------------------- + +} +#endif // DLIB_TOKENIZER_KERNEL_1_CPp_ + diff --git a/dlib/tokenizer/tokenizer_kernel_1.h b/dlib/tokenizer/tokenizer_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..c1987ba533d380b5ce69aa05cb8a5afec1eecb5d --- /dev/null +++ b/dlib/tokenizer/tokenizer_kernel_1.h @@ -0,0 +1,155 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TOKENIZER_KERNEl_1_ +#define DLIB_TOKENIZER_KERNEl_1_ + +#include +#include +#include +#include "../algs.h" +#include "tokenizer_kernel_abstract.h" + +namespace dlib +{ + + class tokenizer_kernel_1 + { + /*! + INITIAL VALUE + - in == 0 + - streambuf == 0 + - have_peeked == false + - head == "_" + lowercase_letters() + uppercase_letters() + - body == "_" + lowercase_letters() + uppercase_letters() + numbers() + - headset == pointer to an array of UCHAR_MAX bools and set according + to the CONVENTION. + - bodyset == pointer to an array of UCHAR_MAX bools and set according + to the CONVENTION. + + CONVENTION + - if (stream_is_set()) then + - get_stream() == *in + - streambuf == in->rdbuf() + - else + - in == 0 + - streambuf == 0 + + - body == get_identifier_body() + - head == get_identifier_head() + + - if (the char x appears in head) then + - headset[static_cast(x)] == true + - else + - headset[static_cast(x)] == false + + - if (the char x appears in body) then + - bodyset[static_cast(x)] == true + - else + - bodyset[static_cast(x)] == false + + - if (have_peeked) then + - next_token == the next token to be returned from get_token() + - next_type == the type of token in peek_token + !*/ + + public: + + // The name of this enum is irrelevant but on some compilers (gcc on MAC OS X) not having it named + // causes an error for whatever reason + enum some_random_name + { + END_OF_LINE, + END_OF_FILE, + IDENTIFIER, + CHAR, + NUMBER, + WHITE_SPACE + }; + + tokenizer_kernel_1 ( + ); + + virtual ~tokenizer_kernel_1 ( + ); + + void clear( + ); + + void set_stream ( + std::istream& in + ); + + bool stream_is_set ( + ) const; + + std::istream& get_stream ( + ) const; + + void get_token ( + int& type, + std::string& token + ); + + void swap ( + tokenizer_kernel_1& item + ); + + void set_identifier_token ( + const std::string& head, + const std::string& body + ); + + int peek_type ( + ) const; + + const std::string& peek_token ( + ) const; + + const std::string get_identifier_head ( + ) const; + + const std::string get_identifier_body ( + ) const; + + const std::string lowercase_letters ( + ) const; + + const std::string uppercase_letters ( + ) const; + + const std::string numbers ( + ) const; + + private: + + // restricted functions + tokenizer_kernel_1(const tokenizer_kernel_1&); // copy constructor + tokenizer_kernel_1& operator=(const tokenizer_kernel_1&); // assignment operator + + + // data members + std::istream* in; + std::streambuf* streambuf; + std::string head; + std::string body; + bool* headset; + bool* bodyset; + + mutable std::string next_token; + mutable int next_type; + mutable bool have_peeked; + }; + + inline void swap ( + tokenizer_kernel_1& a, + tokenizer_kernel_1& b + ) { a.swap(b); } + +} + +#ifdef NO_MAKEFILE +#include "tokenizer_kernel_1.cpp" +#endif + +#endif // DLIB_TOKENIZER_KERNEl_1 + diff --git a/dlib/tokenizer/tokenizer_kernel_abstract.h b/dlib/tokenizer/tokenizer_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..e1e273d0fd49f1aa5e9b16b6be6b0389d31b0ac6 --- /dev/null +++ b/dlib/tokenizer/tokenizer_kernel_abstract.h @@ -0,0 +1,289 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_TOKENIZER_KERNEl_ABSTRACT_ +#ifdef DLIB_TOKENIZER_KERNEl_ABSTRACT_ + +#include +#include + +namespace dlib +{ + + class tokenizer + { + /*! + INITIAL VALUE + stream_is_set() == false + get_identifier_head() == "_" + lowercase_letters() + uppercase_letters() + get_identifier_body() == "_" + lowercase_letters() + uppercase_letters() + + numbers() + + WHAT THIS OBJECT REPRESENTS + This object represents a simple tokenizer for textual data. + + BUFFERING + This object is allowed to buffer data from the input stream. + Thus if you clear it or switch streams (via calling set_stream()) + any buffered data will be lost. + + TOKENS + When picking out tokens the tokenizer will always extract the + longest token it can. For example, if faced with the string + "555" it will consider the three 5s to be a single NUMBER + token not three smaller NUMBER tokens. + + Also note that no characters in the input stream are discarded. + They will all be returned in the text of some token. + Additionally, each character will never be returned more than once. + This means that if you concatenated all returned tokens it would exactly + reproduce the contents of the input stream. + + The tokens are defined as follows: + + END_OF_LINE + This is a single character token and is always the '\n' + character. + + END_OF_FILE + This token represents the end of file. It doesn't have any + actual characters associated with it. + + IDENTIFIER + This is a multi-character token. It is defined as a string that + begins with a character from get_identifier_head() and is + followed by any number of characters from get_identifier_body(). + + NUMBER + This is a multi-character token. It is defined as a sequence of + numbers. + + WHITE_SPACE + This is a multi character token. It is defined as a sequence of + one or more spaces, carrage returns, and tabs. I.e. It is + composed of characters from the following string " \r\t". + + CHAR + This is a single character token. It matches anything that isn't + part of one of the above tokens. + !*/ + + public: + + enum + { + END_OF_LINE, + END_OF_FILE, + IDENTIFIER, + CHAR, + NUMBER, + WHITE_SPACE + }; + + tokenizer ( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~tokenizer ( + ); + /*! + ensures + - any resources associated with *this have been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + If this exception is thrown then #*this is unusable + until clear() is called and succeeds. + !*/ + + void set_stream ( + std::istream& in + ); + /*! + ensures + - #*this will read data from in and tokenize it + - #stream_is_set() == true + - #get_stream() == in + !*/ + + bool stream_is_set ( + ) const; + /*! + ensures + - returns true if a stream has been associated with *this by calling + set_stream() + !*/ + + std::istream& get_stream ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns a reference to the istream object that *this is reading + from. + !*/ + + void get_token ( + int& type, + std::string& token + ); + /*! + requires + - stream_is_set() == true + ensures + - #token == the next token from the input stream get_stream() + - #type == the type of the token in #token + throws + - bad_alloc + If this exception is thrown then the call to this function will + have no effect on *this but the values of #type and #token will be + undefined. Additionally, some characters may have been read + from the stream get_stream() and lost. + !*/ + + int peek_type ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns the type of the token that will be returned from + the next call to get_token() + throws + - bad_alloc + If this exception is thrown then the call to this function will + have no effect on *this. However, some characters may have been + read from the stream get_stream() and lost. + !*/ + + const std::string& peek_token ( + ) const; + /*! + requires + - stream_is_set() == true + ensures + - returns the text of the token that will be returned from + the next call to get_token() + throws + - bad_alloc + If this exception is thrown then the call to this function will + have no effect on *this. However, some characters may have been + read from the stream get_stream() and lost. + !*/ + + void set_identifier_token ( + const std::string& head, + const std::string& body + ); + /*! + requires + - head.find_first_of(" \r\t\n0123456789") == std::string::npos + (i.e. head doesn't contain any characters from the string + " \r\t\n0123456789"). + - body.find_frst_of(" \r\t\n") == std::string::npos + (i.e. body doesn't contain any characters from the string " \r\t\n"). + ensures + - #get_identifier_head() == head + - #get_identifier_body() == body + throws + - std::bad_alloc + If this exception is thrown then #*this is unusable + until clear() is called and succeeds. + !*/ + + const std::string get_identifier_head ( + ) const; + /*! + ensures + - returns a string containing the characters that can be the start + of an IDENTIFIER token. + throws + - std::bad_alloc + If this exception is thrown then the call to this function + has no effect. + !*/ + + const std::string get_identifier_body ( + ) const; + /*! + ensures + - returns a string containing the characters that can appear in the + body of an IDENTIFIER token. + throws + - std::bad_alloc + If this exception is thrown then the call to this function + has no effect. + !*/ + + const std::string lowercase_letters ( + ) const; + /*! + ensures + - returns "abcdefghijklmnopqrstuvwxyz" + throws + - std::bad_alloc + If this exception is thrown then the call to this function + has no effect. + !*/ + + const std::string uppercase_letters ( + ) const; + /*! + ensures + - returns "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + throws + - std::bad_alloc + If this exception is thrown then the call to this function + has no effect. + !*/ + + const std::string numbers ( + ) const; + /*! + ensures + - returns "0123456789" + throws + - std::bad_alloc + If this exception is thrown then the call to this function + has no effect. + !*/ + + void swap ( + tokenizer& item + ); + /*! + ensures + - swaps *this and item + !*/ + + private: + + // restricted functions + tokenizer(const tokenizer&); // copy constructor + tokenizer& operator=(const tokenizer&); // assignment operator + + }; + + inline void swap ( + tokenizer& a, + tokenizer& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_TOKENIZER_KERNEl_ABSTRACT_ + diff --git a/dlib/tokenizer/tokenizer_kernel_c.h b/dlib/tokenizer/tokenizer_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..9f7a79444e9187eede8cb2651ed1d869985acab6 --- /dev/null +++ b/dlib/tokenizer/tokenizer_kernel_c.h @@ -0,0 +1,167 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TOKENIZER_KERNEl_C_ +#define DLIB_TOKENIZER_KERNEl_C_ + +#include "tokenizer_kernel_abstract.h" +#include "../assert.h" +#include +#include + +namespace dlib +{ + + template < + typename tokenizer + > + class tokenizer_kernel_c : public tokenizer + { + + public: + std::istream& get_stream ( + ) const; + + void get_token ( + int& type, + std::string& token + ); + + void set_identifier_token ( + const std::string& head, + const std::string& body + ); + + int peek_type ( + ) const; + + const std::string& peek_token ( + ) const; + }; + + template < + typename tokenizer + > + inline void swap ( + tokenizer_kernel_c& a, + tokenizer_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + void tokenizer_kernel_c:: + set_identifier_token ( + const std::string& head, + const std::string& body + ) + { + using namespace std; + // make sure requires clause is not broken + DLIB_CASSERT( head.find_first_of(" \r\t\n0123456789") == string::npos && + body.find_first_of(" \r\t\n") == string::npos , + "\tvoid tokenizer::set_identifier_token()" + << "\n\tyou can't define the IDENTIFIER token this way." + << "\n\thead: " << head + << "\n\tbody: " << body + << "\n\tthis: " << this + ); + + // call the real function + tokenizer::set_identifier_token(head,body); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + std::istream& tokenizer_kernel_c:: + get_stream ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tstd::istream& tokenizer::get_stream()" + << "\n\tyou must set a stream for this object before you can get it" + << "\n\tthis: " << this + ); + + // call the real function + return tokenizer::get_stream(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + int tokenizer_kernel_c:: + peek_type ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tint tokenizer::peek_type()" + << "\n\tyou must set a stream for this object before you peek at what it contains" + << "\n\tthis: " << this + ); + + // call the real function + return tokenizer::peek_type(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + const std::string& tokenizer_kernel_c:: + peek_token ( + ) const + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tint tokenizer::peek_token()" + << "\n\tyou must set a stream for this object before you peek at what it contains" + << "\n\tthis: " << this + ); + + // call the real function + return tokenizer::peek_token(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename tokenizer + > + void tokenizer_kernel_c:: + get_token ( + int& type, + std::string& token + ) + { + // make sure requires clause is not broken + DLIB_CASSERT( this->stream_is_set() == true, + "\tvoid tokenizer::get_token()" + << "\n\tyou must set a stream for this object before you can get tokens from it." + << "\n\tthis: " << this + ); + + // call the real function + tokenizer::get_token(type,token); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TOKENIZER_KERNEl_C_ + + diff --git a/dlib/tuple.h b/dlib/tuple.h new file mode 100644 index 0000000000000000000000000000000000000000..5a2fc16f4c2d2ba18bb4493b60fe5d5166dac46e --- /dev/null +++ b/dlib/tuple.h @@ -0,0 +1,10 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TUPLe_TOP_ +#define DLIB_TUPLe_TOP_ + +#include "tuple/tuple.h" + +#endif // DLIB_TUPLe_TOP__ + + diff --git a/dlib/tuple/tuple.h b/dlib/tuple/tuple.h new file mode 100644 index 0000000000000000000000000000000000000000..8ec62ddf7ce0d43f4d1cb52347e986195fa8daa0 --- /dev/null +++ b/dlib/tuple/tuple.h @@ -0,0 +1,410 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_TUPLe_H_ +#define DLIB_TUPLe_H_ + +#include "../enable_if.h" +#include "../algs.h" +#include "../serialize.h" +#include "tuple_abstract.h" + +// ---------------------------------------------------------------------------------------- + +#define DLIB_TUPLE_GLOBAL_HELPERS(N) \ + DLIB_TUPLE_GH(N##0) DLIB_TUPLE_GH(N##1) DLIB_TUPLE_GH(N##2) DLIB_TUPLE_GH(N##3) \ + DLIB_TUPLE_GH(N##4) DLIB_TUPLE_GH(N##5) DLIB_TUPLE_GH(N##6) DLIB_TUPLE_GH(N##7) + +#define DLIB_TUPLE_GH(N) DLIB_TUPLE_GET_INDEX(N) DLIB_TUPLE_GET_ITEM(N) DLIB_TUPLE_GET_HELPER_STRUCT(N) + +#define DLIB_TUPLE_MEMBER_GET(N) \ + DLIB_TUPLE_MG(N##0) DLIB_TUPLE_MG(N##1) DLIB_TUPLE_MG(N##2) DLIB_TUPLE_MG(N##3) \ + DLIB_TUPLE_MG(N##4) DLIB_TUPLE_MG(N##5) DLIB_TUPLE_MG(N##6) DLIB_TUPLE_MG(N##7) + +#define DLIB_TUPLE_GET_INDEX(N) \ + template const typename enable_if, long>::type get_index (const T&) {return N;} + +#define DLIB_TUPLE_GET_ITEM(N) \ + template const typename enable_if,Q>::type& get_item_const (const T& t) {return t.v##N;}\ + template typename enable_if,Q>::type& get_item ( T& t) {return t.v##N;} + + +#define DLIB_TUPLE_GET_HELPER_STRUCT(N) \ + template struct get_helper \ + { \ + typedef typename T::type##N type; \ + static const type& get(const T& t) { return t.v##N; } \ + static type& get( T& t) { return t.v##N; } \ + }; + +#define DLIB_TUPLE_TEMPLATE_LIST(N) \ + class T##N##0 = null_type, class T##N##1 = null_type, class T##N##2 = null_type, class T##N##3 = null_type, \ + class T##N##4 = null_type, class T##N##5 = null_type, class T##N##6 = null_type, class T##N##7 = null_type + +#define DLIB_TUPLE_VARIABLE_LIST(N) \ + T##N##0 v##N##0; T##N##1 v##N##1; T##N##2 v##N##2; T##N##3 v##N##3; \ + T##N##4 v##N##4; T##N##5 v##N##5; T##N##6 v##N##6; T##N##7 v##N##7; \ + typedef T##N##0 type##N##0; typedef T##N##1 type##N##1; typedef T##N##2 type##N##2; \ + typedef T##N##3 type##N##3; typedef T##N##4 type##N##4; typedef T##N##5 type##N##5; \ + typedef T##N##6 type##N##6; typedef T##N##7 type##N##7; + +// ---------------------------------------------------------------------------------------- + +namespace dlib +{ + + struct null_type{}; + + // provide default serialization for the null_type + inline void serialize ( + const null_type& , + std::ostream& + ){} + inline void deserialize ( + null_type& , + std::istream& + ){} + +// ---------------------------------------------------------------------------------------- + + namespace tuple_helpers + { + template struct get_helper; + + // use these preprocessor macros to declare all the global stuff used by the + // tuple member functions. + DLIB_TUPLE_GLOBAL_HELPERS(0) + DLIB_TUPLE_GLOBAL_HELPERS(01) + DLIB_TUPLE_GLOBAL_HELPERS(02) + DLIB_TUPLE_GLOBAL_HELPERS(03) + + // ------------------------------------------------------------------------------------ + + // use templates to recursively enumerate everything in the tuple that isn't a null_type + template < + typename T, + typename F, + long i = 0, + typename enabled = void + > + struct for_each + { + static void go( + T& a, + F& funct + ) + { + funct(a.template get()); + for_each::go(a,funct); + } + + static bool go( + T& a, + F& funct, + long idx + ) + /*! + ensures + - returns true if the function was applied to the given index + - returns false if the index is invalid so the function wasn't + applied to anything + !*/ + { + if (idx == i) + { + funct(a.template get()); + return true; + } + else + { + return for_each::go(a,funct,idx); + } + } + }; + + template struct template_or { const static bool value = true; }; + template <> struct template_or { const static bool value = false; }; + + // the base case of the recursion + template < + typename T, + typename F, + long i + > + struct for_each::type >::value> >::type > + { + static void go( T&, F& ) { } + static bool go( T&, F&, long ) { return false; } + }; + + // ------------------------------------------------------------------------------------ + + // use templates to recursively enumerate everything in the tuple that isn't a null_type + template < + typename T, + long i = 0, + typename enabled = void + > + struct tuple_swap + { + static void go( + T& a, + T& b + ) + { + exchange(a.template get(), b.template get()); + tuple_swap::go(a,b); + } + }; + + template + struct at_base_case + { + + }; + + // the base case of the recursion + template < + typename T, + long i + > + struct tuple_swap::type >::value > >::type > + { static void go( T&, T& ) { } }; + + // ------------------------------------------------------------------------------------ + + struct tuple_serialize + { + tuple_serialize (std::ostream& out_) : out(out_){} + std::ostream& out; + + template + void operator() ( + T& a + ) const { serialize(a,out); } + }; + + // ------------------------------------------------------------------------------------ + + struct tuple_deserialize + { + tuple_deserialize (std::istream& in_) : in(in_){} + std::istream& in; + template + void operator() ( + T& a + ) const { deserialize(a,in); } + }; + + + } + +// ---------------------------------------------------------------------------------------- + + // use these preprocessor macros to declare 4*8 template arguments (below we count them in octal) + template < + DLIB_TUPLE_TEMPLATE_LIST(0), // args 00-07 + DLIB_TUPLE_TEMPLATE_LIST(01), // args 010-017 + DLIB_TUPLE_TEMPLATE_LIST(02), // args 020-027 + DLIB_TUPLE_TEMPLATE_LIST(03) // args 030-037 + > + class tuple + { + public: + + // use these macros to declare 8*4 member variables + DLIB_TUPLE_VARIABLE_LIST(0) + DLIB_TUPLE_VARIABLE_LIST(01) + DLIB_TUPLE_VARIABLE_LIST(02) + DLIB_TUPLE_VARIABLE_LIST(03) + + const static long max_fields = 4*8; + + template < long idx > + struct get_type + { + typedef typename tuple_helpers::get_helper::type type; + }; + + template < long idx > + const typename tuple_helpers::get_helper::type& get ( + ) const { return tuple_helpers::get_helper::get(*this); } + + template < long idx > + typename tuple_helpers::get_helper::type& get ( + ) { return tuple_helpers::get_helper::get(*this); } + + template < class Q> + const long index ( + ) const { return tuple_helpers::get_index(*this); } + + template + const Q& get ( + ) const {return tuple_helpers::get_item_const(*this);} + + template + Q& get ( + ) {return tuple_helpers::get_item(*this);} + + + + + template + void for_index ( + F& funct, + long idx + ) + { + // do this #ifdef stuff to avoid getting a warning about valid_idx not being + // used when ENABLE_ASSERTS isn't defined. +#ifdef ENABLE_ASSERTS + const bool valid_idx = tuple_helpers::for_each::go(*this,funct,idx); +#else + tuple_helpers::for_each::go(*this,funct,idx); +#endif + DLIB_ASSERT(valid_idx, + "\tvoid tuple::for_index()" + << "\n\tYou have attempted to call for_index() with an index out of the valid range" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + } + + template + void for_index ( + F& funct, + long idx + ) const + { + // do this #ifdef stuff to avoid getting a warning about valid_idx not being + // used when ENABLE_ASSERTS isn't defined. +#ifdef ENABLE_ASSERTS + const bool valid_idx = tuple_helpers::for_each::go(*this,funct,idx); +#else + tuple_helpers::for_each::go(*this,funct,idx); +#endif + DLIB_ASSERT(valid_idx, + "\tvoid tuple::for_index()" + << "\n\tYou have attempted to call for_index() with an index out of the valid range" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + } + + template + void for_index ( + const F& funct, + long idx + ) + { + // do this #ifdef stuff to avoid getting a warning about valid_idx not being + // used when ENABLE_ASSERTS isn't defined. +#ifdef ENABLE_ASSERTS + const bool valid_idx = tuple_helpers::for_each::go(*this,funct,idx); +#else + tuple_helpers::for_each::go(*this,funct,idx); +#endif + DLIB_ASSERT(valid_idx, + "\tvoid tuple::for_index()" + << "\n\tYou have attempted to call for_index() with an index out of the valid range" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + } + + template + void for_index ( + const F& funct, + long idx + ) const + { + // do this #ifdef stuff to avoid getting a warning about valid_idx not being + // used when ENABLE_ASSERTS isn't defined. +#ifdef ENABLE_ASSERTS + const bool valid_idx = tuple_helpers::for_each::go(*this,funct,idx); +#else + tuple_helpers::for_each::go(*this,funct,idx); +#endif + DLIB_ASSERT(valid_idx, + "\tvoid tuple::for_index()" + << "\n\tYou have attempted to call for_index() with an index out of the valid range" + << "\n\tidx: " << idx + << "\n\tthis: " << this + ); + } + + + + + template + void for_each ( + F& funct + ) { tuple_helpers::for_each::go(*this,funct); } + + template + void for_each ( + F& funct + ) const { tuple_helpers::for_each::go(*this,funct); } + + template + void for_each ( + const F& funct + ) const { tuple_helpers::for_each::go(*this,funct); } + + template + void for_each ( + const F& funct + ) { tuple_helpers::for_each::go(*this,funct); } + + + + + inline friend void serialize ( + tuple& item, + std::ostream& out + ) + { + try + { + item.for_each(tuple_helpers::tuple_serialize(out)); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing an object of type dlib::tuple<>"); + } + } + + inline friend void deserialize ( + tuple& item, + std::istream& in + ) + { + try + { + item.for_each(tuple_helpers::tuple_deserialize(in)); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing an object of type dlib::tuple<>"); + } + } + + inline friend void swap ( + tuple& a, + tuple& b + ) + { + tuple_helpers::tuple_swap::go(a,b); + } + + inline void swap( + tuple& item + ) { tuple_helpers::tuple_swap::go(item,*this); } + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TUPLe_H_ + diff --git a/dlib/tuple/tuple_abstract.h b/dlib/tuple/tuple_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..62d0b4e3703dc2dc4d14b6e96b5e066ce814c602 --- /dev/null +++ b/dlib/tuple/tuple_abstract.h @@ -0,0 +1,302 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_TUPLe_ABSTRACT_H_ +#ifdef DLIB_TUPLe_ABSTRACT_H_ + +#include "../algs.h" +#include "../serialize.h" +#include "tuple_abstract.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + struct null_type + { + /*! + WHAT THIS OBJECT REPRESENTS + This object is the default type used as the default + template argument to the tuple object's template arguments. + + Also note that it has no state associated with it. + !*/ + }; + + inline void serialize ( + const null_type& , + std::ostream& + ){} + inline void deserialize ( + null_type& , + std::istream& + ){} + /*! + Serialization support is provided for null_type because in some cases + it makes your code a little more concise and easier to deal with + when using tuple objects and serialization. The serialization literally + does nothing though. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T0 = null_type, + typename T1 = null_type, + typename T2 = null_type, + typename T3 = null_type, + ... + typename T31 = null_type + > + class tuple + { + /*! + INITIAL VALUE + Each object in the tuple is default initialized by its own constructor. + The tuple object itself does not modify them or add any additional + state. + + WHAT THIS OBJECT REPRESENTS + This object represents a container of between 0 and 31 objects + where the objects contained are specified in the template + arguments. + + EXAMPLE + We can declare a tuple that contains an int, a float, and a char like so: + tuple ex; + + Then we can access each of these by their index number. The index number + is just the order each type has in the template argument list. So we have: + ex.get<0>() = 5; // assign the int the value 5 + ex.get<1>() = 3.14; // assign the float the value 3.14 + ex.get<2>() = 'c'; // assign the char the value 'c' + + Also, since we only have one of each type in this example tuple we can + unambiguously access each field in the tuple by their types. So for + example, we can use this syntax to access our fields: + ex.get() // returns 5 + ex.get() // returns 3.14 + ex.get() // returns 'c' + + We can also get the indexes of each of these fields like so: + ex.index() // returns 0 + ex.index() // returns 1 + ex.index() // returns 2 + !*/ + + public: + // the maximum number of items this tuple tepmlate can contain + const static long max_fields = 32; + + template + struct get_type + { + typedef (the type of the Tindex template argument) type; + }; + + template + const get_type::type& get ( + ) const; + /*! + requires + - 0 <= index <= 31 + ensures + - returns a const reference to the index(th) object contained + inside this tuple + !*/ + + template + get_type::type& get ( + ); + /*! + requires + - 0 <= index <= 31 + ensures + - returns a non-const reference to the index(th) object contained + inside this tuple + !*/ + + template + const long index ( + ) const; + /*! + requires + - Q is a type of object contained in this tuple and there is + only one object of that type in the tuple + ensures + - returns the index of the object in this tuple with type Q + !*/ + + template + const Q& get ( + ) const; + /*! + requires + - Q is a type of object contained in this tuple and there is + only one object of that type in the tuple + ensures + - returns a const reference to the object in this tuple + with type Q + !*/ + + template + Q& get ( + ); + /*! + requires + - Q is a type of object contained in this tuple and there is + only one object of that type in the tuple + ensures + - returns a non-const reference to the object in this tuple + with type Q + !*/ + + template + void for_each ( + F& funct + ); + /*! + requires + - funct is a templated function object + ensures + - for each item X in this tuple that isn't a null_type object: + - calls funct(X); + !*/ + + template + void for_each ( + F& funct + ) const; + /*! + requires + - funct is a templated function object + ensures + - for each item X in this tuple that isn't a null_type object: + - calls funct(X); + !*/ + + template + void for_each ( + const F& funct + ); + /*! + requires + - funct is a templated function object + ensures + - for each item X in this tuple that isn't a null_type object: + - calls funct(X); + !*/ + + template + void for_each ( + const F& funct + ) const; + /*! + requires + - funct is a templated function object + ensures + - for each item X in this tuple that isn't a null_type object: + - calls funct(X); + !*/ + + template + void for_index ( + F& funct, + long idx + ); + /*! + requires + - funct is a templated function object + - 0 <= idx < max_fields && get_type::type != null_type + (i.e. idx must be the index of a non-null_type object in this tuple) + ensures + - calls funct(this->get()); + !*/ + + template + void for_index ( + F& funct, + long idx + ) const; + /*! + requires + - funct is a templated function object + - 0 <= idx < max_fields && get_type::type != null_type + (i.e. idx must be the index of a non-null_type object in this tuple) + ensures + - calls funct(this->get()); + !*/ + + template + void for_index ( + const F& funct, + long idx + ); + /*! + requires + - funct is a templated function object + - 0 <= idx < max_fields && get_type::type != null_type + (i.e. idx must be the index of a non-null_type object in this tuple) + ensures + - calls funct(this->get()); + !*/ + + template + void for_index ( + const F& funct, + long idx + ) const; + /*! + requires + - funct is a templated function object + - 0 <= idx < max_fields && get_type::type != null_type + (i.e. idx must be the index of a non-null_type object in this tuple) + ensures + - calls funct(this->get()); + !*/ + + void swap ( + tuple& item + ); + /*! + ensures + - swaps *this and item + !*/ + + // ------------------------------------------------- + // global functions for tuple objects + // ------------------------------------------------- + + friend void swap ( + tuple& a, + tuple& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + + friend void serialize ( + const tuple& item, + std::ostream& out + ); + /*! + provides serialization support + !*/ + + friend void deserialize ( + tuple& item, + std::istream& in + ); + /*! + provides deserialization support + !*/ + + }; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_TUPLe_ABSTRACT_H_ + + diff --git a/dlib/uintn.h b/dlib/uintn.h new file mode 100644 index 0000000000000000000000000000000000000000..ccdd21c0c196905b15d44f8add942a5b356bdbbb --- /dev/null +++ b/dlib/uintn.h @@ -0,0 +1,79 @@ +// Copyright (C) 2005 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. + +#ifndef DLIB_UINtn_ +#define DLIB_UINtn_ + +#include "assert.h" + +namespace dlib +{ + + /*! + uint64 is a typedef for an unsigned integer that is exactly 64 bits wide. + uint32 is a typedef for an unsigned integer that is exactly 32 bits wide. + uint16 is a typedef for an unsigned integer that is exactly 16 bits wide. + uint8 is a typedef for an unsigned integer that is exactly 8 bits wide. + !*/ + + +#ifdef __GNUC__ + typedef unsigned long long uint64; +#elif __BORLANDC__ + typedef unsigned __int64 uint64; +#elif _MSC_VER + typedef unsigned __int64 uint64; +#else + typedef unsigned long long uint64; +#endif + + typedef unsigned short uint16; + typedef unsigned int uint32; + typedef unsigned char uint8; + + + + // make sure these types have the right sizes on this platform + COMPILE_TIME_ASSERT(sizeof(uint8) == 1); + COMPILE_TIME_ASSERT(sizeof(uint16) == 2); + COMPILE_TIME_ASSERT(sizeof(uint32) == 4); + COMPILE_TIME_ASSERT(sizeof(uint64) == 8); + + + + template + struct unsigned_type; + template + struct unsigned_type { typedef uint8 type; }; + template + struct unsigned_type { typedef uint16 type; }; + template + struct unsigned_type { typedef uint32 type; }; + template + struct unsigned_type { typedef uint64 type; }; + /*! + ensures + - sizeof(unsigned_type::type) == sizeof(T) + - unsigned_type::type is an unsigned integral type + !*/ + + template + T zero_extend_cast( + const U val + ) + /*! + requires + - U and T are integral types + ensures + - let ut be a typedef for unsigned_type::type + - return static_cast(static_cast(val)); + !*/ + { + typedef typename unsigned_type::type ut; + return static_cast(static_cast(val)); + } + +} + +#endif // DLIB_UINtn_ + diff --git a/dlib/unicode.h b/dlib/unicode.h new file mode 100644 index 0000000000000000000000000000000000000000..341b00fed9efebf29d2efde5640e046e2ad57e08 --- /dev/null +++ b/dlib/unicode.h @@ -0,0 +1,9 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_UNICODe_TOP_ +#define DLIB_UNICODe_TOP_ + +#include "unicode/unicode.h" + +#endif // DLIB_UNICODe_TOP_ + diff --git a/dlib/unicode/unicode.h b/dlib/unicode/unicode.h new file mode 100644 index 0000000000000000000000000000000000000000..42ce04bd82d6523f30b1b5c5bd3bf4b9c1ff4378 --- /dev/null +++ b/dlib/unicode/unicode.h @@ -0,0 +1,494 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_UNICODe_H_ +#define DLIB_UNICODe_H_ + +#include "../uintn.h" +#include "../algs.h" +#include "unicode_abstract.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + typedef uint32 unichar; + typedef std::basic_string ustring; + +// ---------------------------------------------------------------------------------------- + + namespace unicode_helpers + { + + template < + typename charT + > + int u8_to_u32( + charT& result, + std::istream& in + ) + /*! + ensures + - if (there just wasn't any more data and we hit EOF) then + - returns 0 + - else if (we decoded another character without error) then + - #result == the decoded character + - returns the number of bytes consumed to make this character + - else + - some error occurred + - returns -1 + !*/ + { + int val = in.get(); + if (val == EOF) + return 0; + + unichar ch[4]; + ch[0] = zero_extend_cast(val); + if ( ch[0] < 0x80 ) + { + result = static_cast(ch[0]); + return 1; + } + if ( ( ch[0] & ~0x3F ) == 0x80 ) + { + // invalid leading byte + return -1; + } + if ( ( ch[0] & ~0x1F ) == 0xC0 ) + { + val = in.get(); + if ( val == EOF ) + return -1; + + ch[1] = zero_extend_cast(val); + if ( ( ch[1] & ~0x3F ) != 0x80 ) + return -1; // invalid tail + if ( ( ch[0] & ~0x01 ) == 0xC0 ) + return -1; // overlong form + ch[0] &= 0x1F; + ch[1] &= 0x3F; + result = static_cast(( ch[0] << 6 ) | ch[1]); + return 2; + } + if ( ( ch[0] & ~0x0F ) == 0xE0 ) + { + for ( unsigned n = 1;n < 3;n++ ) + { + val = in.get(); + if ( val == EOF ) + return -1; + ch[n] = zero_extend_cast(val); + if ( ( ch[n] & ~0x3F ) != 0x80 ) + return -1; // invalid tail + ch[n] &= 0x3F; + } + ch[0] &= 0x0F; + result = static_cast(( ch[0] << 12 ) | ( ch[1] << 6 ) | ch[2]); + if ( result < 0x0800 ) + return -1; // overlong form + if ( result >= 0xD800 && result < 0xE000 ) + return -1; // invalid character (UTF-16 surrogate pairs) + if ( result >= 0xFDD0 && result <= 0xFDEF ) + return -1; // noncharacter + if ( result >= 0xFFFE ) + return -1; // noncharacter + return 3; + } + if ( ( ch[0] & ~0x07 ) == 0xF0 ) + { + for ( unsigned n = 1;n < 4;n++ ) + { + val = in.get(); + if ( val == EOF ) + return -1; + ch[n] = zero_extend_cast(val); + if ( ( ch[n] & ~0x3F ) != 0x80 ) + return -1; // invalid tail + ch[n] &= 0x3F; + } + if ( ( ch[0] ^ 0xF6 ) < 4 ) + return -1; + ch[0] &= 0x07; + result = static_cast(( ch[0] << 18 ) | ( ch[1] << 12 ) | ( ch[2] << 6 ) | ch[3]); + if ( result < 0x10000 ) + return -1; // overlong form + if ( (result & 0xFFFF) >= 0xFFFE ) + return -1; // noncharacter + return 4; + } + return -1; + } + + // ------------------------------------------------------------------------------------ + + template + class basic_utf8_streambuf : public std::basic_streambuf + { + public: + basic_utf8_streambuf ( + std::ifstream& fin_ + ) : + fin(fin_) + { + setg(in_buffer+max_putback, + in_buffer+max_putback, + in_buffer+max_putback); + } + + protected: + + typedef typename std::basic_streambuf::int_type int_type; + + // input functions + int_type underflow( + ) + { + if (this->gptr() < this->egptr()) + { + return zero_extend_cast(*this->gptr()); + } + + int num_put_back = static_cast(this->gptr() - this->eback()); + if (num_put_back > max_putback) + { + num_put_back = max_putback; + } + + // copy the putback characters into the putback end of the in_buffer + std::memmove(in_buffer+(max_putback-num_put_back), this->gptr()-num_put_back, num_put_back); + + + // fill the buffer with characters + int n = in_buffer_size-max_putback; + int i; + for (i = 0; i < n; ++i) + { + charT ch; + if (unicode_helpers::u8_to_u32(ch,fin) > 0) + { + (in_buffer+max_putback)[i] = ch; + } + else + { + break; + } + } + + if (i == 0) + { + // an error occurred or we hit EOF + return EOF; + } + + // reset in_buffer pointers + setg (in_buffer+(max_putback-num_put_back), + in_buffer+max_putback, + in_buffer+max_putback+i); + + return zero_extend_cast(*this->gptr()); + } + + private: + std::ifstream& fin; + static const int max_putback = 4; + static const int in_buffer_size = 10; + charT in_buffer[in_buffer_size]; + }; + } + +// ---------------------------------------------------------------------------------------- + + template + bool is_combining_char( + const T ch_ + ) + { + const unichar ch = zero_extend_cast(ch_); + if ( ch < 0x300 ) return false; + if ( ch < 0x370 ) return true; + + if ( ch < 0x800 ) + { + if ( ch < 0x483 )return false;if ( ch < 0x48A )return true; + + if ( ch < 0x591 )return false;if ( ch < 0x5D0 ) + { + if ( ch == 0x5C0 )return false; + if ( ch == 0x5C3 )return false; + if ( ch == 0x5C6 )return false; + return true; + } + if ( ch < 0x610 )return false;if ( ch < 0x616 )return true; + if ( ch < 0x64B )return false;if ( ch < 0x660 )return true; + + if ( ch == 0x670 )return true; + + if ( ch < 0x6D6 )return false;if ( ch < 0x6EE ) + { + if ( ch == 0x6DD )return false; + if ( ch == 0x6E5 )return false; + if ( ch == 0x6E6 )return false; + if ( ch == 0x6E9 )return false; + return true; + } + if ( ch == 0x711 )return true; + + if ( ch < 0x730 )return false;if ( ch < 0x74B )return true; + if ( ch < 0x7A6 )return false;if ( ch < 0x7B1 )return true; + if ( ch < 0x7EB )return false;if ( ch < 0x7F4 )return true; + return false; + } + if ( ch < 0xA00 ) + { + if ( ch < 0x901 )return false;if ( ch < 0x904 )return true; + if ( ch < 0x93C )return false;if ( ch < 0x955 ) + { + if ( ch == 0x93D )return false; + if ( ch == 0x950 )return false; + return true; + } + if ( ch < 0x962 )return false;if ( ch < 0x964 )return true; + if ( ch < 0x981 )return false;if ( ch < 0x984 )return true; + if ( ch < 0x9BC )return false;if ( ch < 0x9D8 ) + { + if ( ch == 0x9BD )return false; + if ( ch == 0x9CE )return false; + return true; + } + if ( ch < 0x9E2 )return false;if ( ch < 0x9E4 )return true; + return false; + } + if ( ch < 0xC00 ) + { + if ( ch < 0xA01 )return false;if ( ch < 0xA04 )return true; + if ( ch < 0xA3C )return false;if ( ch < 0xA4E )return true; + if ( ch < 0xA70 )return false;if ( ch < 0xA72 )return true; + if ( ch < 0xA81 )return false;if ( ch < 0xA84 )return true; + if ( ch < 0xABC )return false;if ( ch < 0xACE ) + { + if ( ch == 0xABD )return false; + return true; + } + if ( ch < 0xAE2 )return false;if ( ch < 0xAE4 )return true; + if ( ch < 0xB01 )return false;if ( ch < 0xB04 )return true; + if ( ch < 0xB3C )return false;if ( ch < 0xB58 ) + { + if ( ch == 0xB3D )return false; + return true; + } + if ( ch == 0xB82 )return true; + + if ( ch < 0xBBE )return false;if ( ch < 0xBD8 )return true; + + if ( ch == 0xBF4 )return true; + if ( ch == 0xBF8 )return true; + return false; + } + if(ch < 0xE00) + { + if ( ch < 0xC01 )return false;if ( ch < 0xC04 )return true; + if ( ch < 0xC3E )return false;if ( ch < 0xC57 )return true; + if ( ch < 0xC82 )return false;if ( ch < 0xC84 )return true; + if ( ch < 0xCBC )return false;if ( ch < 0xCD7 ) + { + if ( ch == 0xCBD )return false; + return true; + } + if ( ch < 0xCE2 )return false;if ( ch < 0xCE4 )return true; + if ( ch < 0xD02 )return false;if ( ch < 0xD04 )return true; + if ( ch < 0xD3E )return false;if ( ch < 0xD58 )return true; + if ( ch < 0xD82 )return false;if ( ch < 0xD84 )return true; + if ( ch < 0xDCA )return false;if ( ch < 0xDF4 )return true; + return false; + } + if(ch < 0x1000) + { + if ( ch == 0xE31 )return true; + + if ( ch < 0xE34 )return false;if ( ch < 0xE3B )return true; + if ( ch < 0xE47 )return false;if ( ch < 0xE4F )return true; + + if ( ch == 0xEB1 )return true; + + if ( ch < 0xEB4 )return false;if ( ch < 0xEBD )return true; + if ( ch < 0xEC8 )return false;if ( ch < 0xECE )return true; + if ( ch < 0xF18 )return false;if ( ch < 0xF1A )return true; + + if ( ch == 0xF35 )return true; + if ( ch == 0xF37 )return true; + if ( ch == 0xF39 )return true; + + if ( ch < 0xF3E )return false;if ( ch < 0xF40 )return true; + if ( ch < 0xF71 )return false;if ( ch < 0xF88 ) + { + if ( ch == 0xF85 )return false; + return true; + } + if ( ch < 0xF90 )return false;if ( ch < 0xFBD )return true; + + if ( ch == 0xFC6 )return true; + return false; + } + if ( ch < 0x1800 ) + { + if ( ch < 0x102C )return false;if ( ch < 0x1040 )return true; + if ( ch < 0x1056 )return false;if ( ch < 0x105A )return true; + + if ( ch == 0x135F )return true; + + if ( ch < 0x1712 )return false;if ( ch < 0x1715 )return true; + if ( ch < 0x1732 )return false;if ( ch < 0x1735 )return true; + if ( ch < 0x1752 )return false;if ( ch < 0x1754 )return true; + if ( ch < 0x1772 )return false;if ( ch < 0x1774 )return true; + if ( ch < 0x17B6 )return false;if ( ch < 0x17D4 )return true; + + if ( ch == 0x17DD )return true; + return false; + } + if(ch < 0x2000) + { + if ( ch < 0x180B )return false;if ( ch < 0x180E )return true; + + if ( ch == 0x18A9 )return true; + + if ( ch < 0x1920 )return false;if ( ch < 0x193C )return true; + if ( ch < 0x19B0 )return false;if ( ch < 0x19C1 )return true; + if ( ch < 0x19C8 )return false;if ( ch < 0x19CA )return true; + if ( ch < 0x1A17 )return false;if ( ch < 0x1A1C )return true; + if ( ch < 0x1B00 )return false;if ( ch < 0x1B05 )return true; + if ( ch < 0x1B34 )return false;if ( ch < 0x1B45 )return true; + if ( ch < 0x1B6B )return false;if ( ch < 0x1B74 )return true; + if ( ch < 0x1DC0 )return false;if ( ch < 0x1E00 )return true; + return false; + } + if ( ch < 0x20D0 )return false;if ( ch < 0x2100 )return true; + if ( ch < 0x302A )return false;if ( ch < 0x3030 )return true; + if ( ch < 0x3099 )return false;if ( ch < 0x309B )return true; + + if ( ch == 0xA802 )return true; + if ( ch == 0xA806 )return true; + if ( ch == 0xA80B )return true; + + if ( ch < 0xA823 )return false;if ( ch < 0xA828 )return true; + + if ( ch == 0xFB1E )return true; + + if ( ch < 0xFE00 )return false;if ( ch < 0xFE10 )return true; + if ( ch < 0xFE20 )return false;if ( ch < 0xFE30 )return true; + if ( ch < 0x10A01 )return false;if ( ch < 0x10A10 )return true; + if ( ch < 0x10A38 )return false;if ( ch < 0x10A40 )return true; + if ( ch < 0x1D165 )return false;if ( ch < 0x1D16A )return true; + if ( ch < 0x1D16D )return false;if ( ch < 0x1D173 )return true; + if ( ch < 0x1D17B )return false;if ( ch < 0x1D183 )return true; + if ( ch < 0x1D185 )return false;if ( ch < 0x1D18C )return true; + if ( ch < 0x1D1AA )return false;if ( ch < 0x1D1AE )return true; + if ( ch < 0x1D242 )return false;if ( ch < 0x1D245 )return true; + if ( ch < 0xE0100 )return false;if ( ch < 0xE01F0 )return true; + return false; + } + +// ---------------------------------------------------------------------------------------- + + class invalid_utf8_error : public error + { + public: + invalid_utf8_error():error(EUTF8_TO_UTF32) {} + }; + + inline const ustring convert_utf8_to_utf32 ( + const std::string& str + ) + { + using namespace unicode_helpers; + ustring temp; + std::istringstream sin(str); + + temp.reserve(str.size()); + + int status; + unichar ch; + while ( (status = u8_to_u32(ch,sin)) > 0) + temp.push_back(ch); + + if (status < 0) + throw invalid_utf8_error(); + + return temp; + } + +// ---------------------------------------------------------------------------------------- + + template + class basic_utf8_ifstream : public std::basic_istream + { + public: + + basic_utf8_ifstream ( + ) : std::basic_istream(&buf), buf(fin) {} + + basic_utf8_ifstream ( + const char* file_name + ) : + std::basic_istream(&buf), + buf(fin) + { + fin.open(file_name); + // make this have the same error state as fin + this->clear(fin.rdstate()); + } + + basic_utf8_ifstream ( + const std::string& file_name + ) : + std::basic_istream(&buf), + buf(fin) + { + fin.open(file_name.c_str()); + // make this have the same error state as fin + this->clear(fin.rdstate()); + } + + void open( + const std::string& file_name + ) + { + open(file_name.c_str()); + } + + void open ( + const char* file_name + ) + { + fin.close(); + fin.clear(); + fin.open(file_name); + // make this have the same error state as fin + this->clear(fin.rdstate()); + } + + void close ( + ) + { + fin.close(); + // make this have the same error state as fin + this->clear(fin.rdstate()); + } + + private: + + std::ifstream fin; + unicode_helpers::basic_utf8_streambuf buf; + }; + + typedef basic_utf8_ifstream utf8_uifstream; + typedef basic_utf8_ifstream utf8_wifstream; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_UNICODe_H_ + diff --git a/dlib/unicode/unicode_abstract.h b/dlib/unicode/unicode_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..451902242ff6d6c825634768374101ff147d9b35 --- /dev/null +++ b/dlib/unicode/unicode_abstract.h @@ -0,0 +1,131 @@ +// Copyright (C) 2007 Davis E. King (davisking@users.sourceforge.net), and Nils Labugt +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_UNICODe_ABSTRACT_H_ +#ifdef DLIB_UNICODe_ABSTRACT_H_ + +#include "../uintn.h" +#include "../error.h" +#include +#include + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + // a typedef for an unsigned 32bit integer to hold our UNICODE characters + typedef uint32 unichar; + + // a typedef for a string object to hold our UNICODE strings + typedef std::basic_string ustring; + +// ---------------------------------------------------------------------------------------- + + template + bool is_combining_char( + const T ch_ + ); + /*! + ensures + - if (ch_ is a unicode combining character) then + - returns true + - else + - returns false + !*/ + +// ---------------------------------------------------------------------------------------- + + class invalid_utf8_error : public error + { + public: + invalid_utf8_error():error(EUTF8_TO_UTF32) {} + }; + + const ustring convert_utf8_to_utf32 ( + const std::string& str + ); + /*! + ensures + - if (str is a valid UTF-8 encoded string) then + - returns a copy of str that has been converted into a + unichar string + - else + - throws invalid_utf8_error + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename charT + > + class basic_utf8_ifstream : public std::basic_istream + { + /*! + WHAT THIS OBJECT REPRESENTS + This object represents an input file stream much like the + normal std::ifstream except that it knows how to read UTF-8 + data. So when you read characters out of this stream it will + automatically convert them from the UTF-8 multibyte encoding + into a fixed width wide character encoding. + !*/ + + public: + + basic_utf8_ifstream ( + ); + /*! + ensures + - constructs an input stream that isn't yet associated with + a file. + !*/ + + basic_utf8_ifstream ( + const char* file_name + ); + /*! + ensures + - tries to open the given file for reading by this stream + !*/ + + basic_utf8_ifstream ( + const std::string& file_name + ); + /*! + ensures + - tries to open the given file for reading by this stream + !*/ + + void open( + const std::string& file_name + ); + /*! + ensures + - tries to open the given file for reading by this stream + !*/ + + void open ( + const char* file_name + ); + /*! + ensures + - tries to open the given file for reading by this stream + !*/ + + void close ( + ); + /*! + ensures + - any file opened by this stream has been closed + !*/ + }; + + typedef basic_utf8_ifstream utf8_uifstream; + typedef basic_utf8_ifstream utf8_wifstream; + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_UNICODe_ABSTRACT_H_ + + diff --git a/dlib/windows_magic.h b/dlib/windows_magic.h new file mode 100644 index 0000000000000000000000000000000000000000..7235f9e2def78ec045cac53c90855129eb29ace3 --- /dev/null +++ b/dlib/windows_magic.h @@ -0,0 +1,30 @@ +// Copyright (C) 2006 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_WINDOWS_MAGIc_ +#define DLIB_WINDOWS_MAGIc_ + +// This file contains all the magical #defines you have to setup before you +// include the windows header files. + +#ifndef NOMINMAX +#define NOMINMAX // prevent windows from messing with std::min and std::max +#endif + +#ifdef NO_MAKEFILE +// only define this if all the cpp files are going to be sucked into the headers +// because otherwise we don't need it since everything is isolated in the sockets +// cpp file and this declaration for _WINSOCKAPI_ appears there also. +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ +#endif +#endif + +// This is something stupid you have to do to make visual studio include the right +// stuff. I don't really know what the deal is with this. +#if _WIN32_WINNT < 0x0500 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0500 +#endif + +#endif // DLIB_WINDOWS_MAGIc_ + diff --git a/dlib/xml_parser.h b/dlib/xml_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..05e0e8f3dcc544aed10dbb1598b07e17cb761569 --- /dev/null +++ b/dlib/xml_parser.h @@ -0,0 +1,51 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_XML_PARSEr_ +#define DLIB_XML_PARSEr_ + +#include + +#include "xml_parser/xml_parser_kernel_interfaces.h" +#include "xml_parser/xml_parser_kernel_1.h" +#include "xml_parser/xml_parser_kernel_c.h" + +#include "map.h" +#include "stack.h" +#include "sequence.h" + + +namespace dlib +{ + + + class xml_parser + { + + + + + typedef map::kernel_2a>::kernel_1b map1a; + typedef stack::kernel_2a>::kernel_1a stack1a; + typedef sequence::kernel_2a seq_dh2a; + typedef sequence::kernel_2a seq_eh2a; + + + + + xml_parser() {} + public: + + //----------- kernels --------------- + + // kernel_1a + typedef xml_parser_kernel_1 + kernel_1a; + typedef xml_parser_kernel_c + kernel_1a_c; + + + }; +} + +#endif // DLIB_XML_PARSEr_ + diff --git a/dlib/xml_parser/xml_parser_kernel_1.h b/dlib/xml_parser/xml_parser_kernel_1.h new file mode 100644 index 0000000000000000000000000000000000000000..86235c445abe85ebc39dc950e60acd7fdc423798 --- /dev/null +++ b/dlib/xml_parser/xml_parser_kernel_1.h @@ -0,0 +1,1463 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_XML_PARSER_KERNEl_1_ +#define DLIB_XML_PARSER_KERNEl_1_ + +#include +#include +#include "xml_parser_kernel_interfaces.h" +#include "xml_parser_kernel_abstract.h" +#include "../algs.h" + +namespace dlib +{ + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + class xml_parser_kernel_1 + { + + /*! + REQUIREMENTS ON map + is an implementation of map/map_kernel_abstract.h or + is an implementation of hash_map/hash_map_kernel_abstract.h and + is instantiated to map items of type std::string to std::string + + REQUIREMENTS ON stack + is an implementation of stack/stack_kernel_abstract.h and + is instantiated with std::string + + REQUIREMENTS ON seq_dh + is an implementation of sequence/sequence_kernel_abstract.h and + is instantiated with document_handler* + + REQUIREMENTS ON seq_eh + is an implementation of sequence/sequence_kernel_abstract.h and + is instantiated with error_handler* + + + + + INITIAL VALUE + dh_list.size() == 0 + eh_list.size() == 0 + + CONVENTION + dh_list == a sequence of pointers to all the document_handlers that + have been added to the xml_parser + eh_list == a sequence of pointers to all the error_handlers that + have been added to the xml_parser + + use of template parameters: + map is used to implement the attribute_list interface + stack is used just inside the parse function + seq_dh is used to make the dh_list member variable + seq_eh is used to make the eh_list member variable + !*/ + + + + public: + + + xml_parser_kernel_1( + ); + + virtual ~xml_parser_kernel_1( + ); + + void clear( + ); + + void parse ( + std::istream& in + ); + + void add_document_handler ( + document_handler& item + ); + + void add_error_handler ( + error_handler& item + ); + + + void swap ( + xml_parser_kernel_1& item + ); + + + private: + + // ----------------------------------- + + // attribute_list interface implementation + class attrib_list : public attribute_list + { + public: + // the list of attribute name/value pairs + map list; + + bool is_in_list ( + const std::string& key + ) const + { + return list.is_in_domain(key); + } + + const std::string& operator[] ( + const std::string& key + ) const + { + return list[key]; + } + + bool at_start ( + ) const { return list.at_start(); } + + void reset ( + ) const { return list.reset(); } + + bool current_element_valid ( + ) const { return list.current_element_valid(); } + + const type& element ( + ) const { return list.element(); } + + type& element ( + ) { return list.element(); } + + bool move_next ( + ) const { return list.move_next(); } + + unsigned long size ( + ) const { return list.size(); } + }; + + + // ----------------------------------- + + enum token_type + { + element_start, // the first tag of an element + element_end, // the last tag of an element + empty_element, // the singular tag of an empty element + pi, // processing instruction + chars, // the non-markup data between tags + chars_cdata, // the data from a CDATA section + eof, // this token is returned when we reach the end of input + error, // this token indicates that the tokenizer couldn't + // determine which category the next token fits into + dtd, // this token is for an entire dtd + comment // this is a token for comments + }; + /* + notes about the tokens: + the tokenizer guarantees that the following tokens to not + contain the '<' character except as the first character of the token + element_start, element_end, empty_element, and pi. they also only + contain the '>' characer as their last character. + + it is also guaranteed that pi is at least of the form . that + is to say that it always always begins with . + + it is also guaranteed that all markup tokens will begin with the '<' + character and end with the '>'. there won't be any leading or + trailing whitespaces. this whitespace is considered a chars token. + */ + + + // private member functions + void get_next_token( + std::istream& in, + std::string& token_text, + int& token_kind, + unsigned long& line_number + ); + /*! + ensures + gets the next token from in and puts it in token_text and + token_kind == the kind of the token found and + line_number is incremented every time a '\n' is encountered and + entity references are translated into the characters they represent + only for chars tokens + !*/ + + int parse_element ( + const std::string& token, + std::string& name, + attrib_list& atts + ); + /*! + requires + token is a token of kind start_element or empty_element + ensures + gets the element name and puts it into the string name and + parses out the attributes and puts them into the attribute_list atts + + return 0 upon success or + returns -1 if it failed to parse token + !*/ + + int parse_pi ( + const std::string& token, + std::string& target, + std::string& data + ); + /*! + requires + token is a token of kind pi + ensures + the target from the processing instruction is put into target and + the data from the processing instruction is put into data + + return 0 upon success or + returns -1 if it failed to parse token + !*/ + + int parse_element_end ( + const std::string& token, + std::string& name + ); + /*! + requires + token is a token of kind element_end + ensures + the name from the ending element tag is put into the string name + + return 0 upon success or + returns -1 if it failed to parse token + !*/ + + inline int change_entity ( + std::istream& in + ); + /*! + ensures + performs the following translations and returns the new character + amp; -> & + lt; -> < + gt; -> > + apos; -> ' + quot; -> " + + or returns -1 if we hit an undefined entity reference or EOF. + (i.e. it was not one of the entities listed above) + + !*/ + + // ----------------------------------- + + // private member data + seq_dh dh_list; + seq_eh eh_list; + + // ----------------------------------- + + // restricted functions: assignment and copy construction + xml_parser_kernel_1(xml_parser_kernel_1&); + xml_parser_kernel_1& operator= ( + xml_parser_kernel_1& + ); + + }; + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + inline void swap ( + xml_parser_kernel_1& a, + xml_parser_kernel_1& b + ) { a.swap(b); } + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + xml_parser_kernel_1:: + xml_parser_kernel_1( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + xml_parser_kernel_1:: + ~xml_parser_kernel_1( + ) + { + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + void xml_parser_kernel_1:: + clear( + ) + { + // unregister all event handlers + eh_list.clear(); + dh_list.clear(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + void xml_parser_kernel_1:: + parse ( + std::istream& in + ) + { + + // save which exceptions in will throw and make it so it won't throw any + // for the life of this function + std::ios::iostate old_exceptions = in.exceptions(); + // set it to not throw anything + in.exceptions(std::ios::goodbit); + + + try + { + unsigned long line_number = 1; + + // skip any whitespace before the start of the document + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n' || in.peek() == '\r' ) + { + if (in.peek() == '\n') + ++line_number; + in.get(); + } + + + + stack tags; // this stack contains the last start tag seen + bool seen_fatal_error = false; + bool seen_root_tag = false; // this is true after we have seen the root tag + + + + // notify all the document_handlers that we are about to being parsing + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->start_document(); + } + + + std::string chars_buf; // used to collect chars data between consecutive + // chars and chars_cdata tokens so that + // document_handlers receive all chars data between + // tags in one call + + // variables to be used with the parsing functions + attrib_list atts; + std::string name; + std::string target; + std::string data; + + + + // variables to use with the get_next_token() function + std::string token_text; + int token_kind; + + get_next_token(in,token_text,token_kind,line_number); + + + while (token_kind != eof) + { + bool is_empty = false; // this becomes true when this token is an empty_element + + switch (token_kind) + { + + + case empty_element: is_empty = true; + case element_start: + { + seen_root_tag = true; + + int status = parse_element(token_text,name,atts); + // if there was no error parsing the element + if (status == 0) + { + // notify all the document_handlers + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->start_element(line_number,name,atts); + if (is_empty) + dh_list[i]->end_element(line_number,name); + } + } + else + { + seen_fatal_error = true; + } + + // if this is an element_start token then push the name of + // the element on to the stack + if (token_kind == element_start) + { + tags.push(name); + } + + }break; + + // ---------------------------------------- + + case element_end: + { + + int status = parse_element_end (token_text,name); + + // if there was no error parsing the element + if (status == 0) + { + // make sure this ending element tag matches the last start + // element tag we saw + if ( tags.size() == 0 || name != tags.current()) + { + // they don't match so signal a fatal error + seen_fatal_error = true; + } + else + { + // notify all the document_handlers + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->end_element(line_number,name); + } + + // they match so throw away this element name + tags.pop(name); + } + } + else + { + seen_fatal_error = true; + } + + + }break; + + // ---------------------------------------- + + case pi: + { + + int status = parse_pi (token_text,target,data); + // if there was no error parsing the element + if (status == 0) + { + // notify all the document_handlers + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->processing_instruction(line_number,target,data); + } + } + else + { + // notify all the error_handlers + for (unsigned long i = 0; i < eh_list.size(); ++i) + { + eh_list[i]->error(line_number); + } + } + while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n' || in.peek() == '\r' ) + { + if (in.peek() == '\n') + ++line_number; + in.get(); + } + + + }break; + + // ---------------------------------------- + + case chars: + { + if (tags.size() != 0) + { + chars_buf += token_text; + } + else if (token_text.find_first_not_of(" \t\r\n") != std::string::npos) + { + // you can't have non whitespace chars data outside the root element + seen_fatal_error = true; + } + }break; + + // ---------------------------------------- + + case chars_cdata: + { + if (tags.size() != 0) + { + chars_buf += token_text; + } + else + { + // you can't have chars_data outside the root element + seen_fatal_error = true; + } + }break; + + // ---------------------------------------- + + case eof: + break; + + // ---------------------------------------- + + case error: + { + seen_fatal_error = true; + }break; + + // ---------------------------------------- + + case dtd: // fall though + case comment: // do nothing + break; + + // ---------------------------------------- + + + } + + // if there was a fatal error then quit loop + if (seen_fatal_error) + break; + + // if we have seen the last tag then quit the loop + if (tags.size() == 0 && seen_root_tag) + break; + + + get_next_token(in,token_text,token_kind,line_number); + + // if the next token is not a chars or chars_cdata token then flush + // the chars_buf to the document_handlers + if ( (token_kind != chars) && + (token_kind != chars_cdata) && + (token_kind != dtd) && + (token_kind != comment) && + (chars_buf.size() != 0) + ) + { + // notify all the document_handlers + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->characters(chars_buf); + } + chars_buf.erase(); + } + + + } //while (token_kind != eof) + + + + + // you can't have any unmatched tags or any fatal erros + if (tags.size() != 0 || seen_fatal_error) + { + // notify all the error_handlers + for (unsigned long i = 0; i < eh_list.size(); ++i) + { + eh_list[i]->fatal_error(line_number); + } + + } + + + // notify all the document_handlers that we have ended parsing + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->end_document(); + } + + } + catch (...) + { + // notify all the document_handlers that we have ended parsing + for (unsigned long i = 0; i < dh_list.size(); ++i) + { + dh_list[i]->end_document(); + } + + // restore the old exception settings to in + in.exceptions(old_exceptions); + + } + + // restore the old exception settings to in + in.exceptions(old_exceptions); + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + void xml_parser_kernel_1:: + add_document_handler ( + document_handler& item + ) + { + document_handler* temp = &item; + dh_list.add(dh_list.size(),temp); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + void xml_parser_kernel_1:: + add_error_handler ( + error_handler& item + ) + { + error_handler* temp = &item; + eh_list.add(eh_list.size(),temp); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + void xml_parser_kernel_1:: + swap ( + xml_parser_kernel_1& item + ) + { + dh_list.swap(item.dh_list); + eh_list.swap(item.eh_list); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // private member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + void xml_parser_kernel_1:: + get_next_token( + std::istream& in, + std::string& token_text, + int& token_kind, + unsigned long& line_number + ) + { + + token_text.erase(); + + std::istream::int_type ch1 = in.get(); + std::istream::int_type ch2; + + + switch (ch1) + { + + // ----------------------------------------- + + // this is the start of some kind of a tag + case '<': + { + ch2 = in.get(); + switch (ch2) + { + + // --------------------------------- + + // this is a dtd, comment, or chars_cdata token + case '!': + { + // if this is a CDATA section ******************************* + if ( in.peek() == '[') + { + token_kind = chars_cdata; + + // throw away the '[' + in.get(); + + // make sure the next chars are CDATA[ + std::istream::int_type ch = in.get(); + if (ch != 'C') + token_kind = error; + ch = in.get(); + if (ch != 'D') + token_kind = error; + ch = in.get(); + if (ch != 'A') + token_kind = error; + ch = in.get(); + if (ch != 'T') + token_kind = error; + ch = in.get(); + if (ch != 'A') + token_kind = error; + ch = in.get(); + if (ch != '[') + token_kind = error; + // if this is an error token then end + if (token_kind == error) + break; + + + // get the rest of the chars and put them into token_text + int brackets_seen = 0; // this is the number of ']' chars + // we have seen in a row + bool seen_closing = false; // true if we have seen ]]> + do + { + ch = in.get(); + + if (ch == '\n') + ++line_number; + + token_text += ch; + + // if this is the closing + if (brackets_seen == 2 && ch == '>') + seen_closing = true; + // if we are seeing a bracket + else if (ch == ']') + ++brackets_seen; + // if we didn't see a bracket + else + brackets_seen = 0; + + + } while ( (!seen_closing) && (ch != EOF) ); + + // check if this is an error token + if (ch == EOF) + { + token_kind = error; + } + else + { + token_text.erase(token_text.size()-3); + } + + + + } + // this is a comment token **************************** + else if (in.peek() == '-') + { + + token_text += ch1; + token_text += ch2; + token_text += '-'; + + token_kind = comment; + + // throw away the '-' char + in.get(); + + // make sure the next char is another '-' + std::istream::int_type ch = in.get(); + if (ch != '-') + { + token_kind = error; + break; + } + + token_text += '-'; + + + // get the rest of the chars and put them into token_text + int hyphens_seen = 0; // this is the number of '-' chars + // we have seen in a row + bool seen_closing = false; // true if we have seen ]]> + do + { + ch = in.get(); + + if (ch == '\n') + ++line_number; + + token_text += ch; + + // if this should be a closing block + if (hyphens_seen == 2) + { + if (ch == '>') + seen_closing = true; + else // this isn't a closing so make it signal error + ch = EOF; + } + // if we are seeing a hyphen + else if (ch == '-') + ++hyphens_seen; + // if we didn't see a hyphen + else + hyphens_seen = 0; + + + } while ( (!seen_closing) && (ch != EOF) ); + + // check if this is an error token + if (ch == EOF) + { + token_kind = error; + } + + + + + + } + else // this is a dtd token ************************* + { + + token_text += ch1; + token_text += ch2; + int bracket_depth = 1; // this is the number of '<' chars seen + // minus the number of '>' chars seen + + std::istream::int_type ch; + do + { + ch = in.get(); + if (ch == '>') + --bracket_depth; + else if (ch == '<') + ++bracket_depth; + else if (ch == '\n') + ++line_number; + + token_text += ch; + + } while ( (bracket_depth > 0) && (ch != EOF) ); + + // make sure we didn't just hit EOF + if (bracket_depth == 0) + { + token_kind = dtd; + } + else + { + token_kind = error; + } + } + } + break; + + // --------------------------------- + + // this is a pi token + case '?': + { + token_text += ch1; + token_text += ch2; + std::istream::int_type ch; + + do + { + ch = in.get(); + token_text += ch; + if (ch == '\n') + ++line_number; + // else if we hit a < then thats an error + else if (ch == '<') + ch = EOF; + } while (ch != '>' && ch != EOF); + // if we hit the end of the pi + if (ch == '>') + { + // make sure there was a trailing '?' + if ( (token_text.size() > 3) && + (token_text[token_text.size()-2] != '?') + ) + { + token_kind = error; + } + else + { + token_kind = pi; + } + } + // if we hit EOF unexpectidely then error + else + { + token_kind = error; + } + } + break; + + // --------------------------------- + + // this is an error token + case EOF: + { + token_kind = error; + } + break; + + // --------------------------------- + // this is an element_end token + case '/': + { + token_kind = element_end; + token_text += ch1; + token_text += ch2; + std::istream::int_type ch; + do + { + ch = in.get(); + if (ch == '\n') + ++line_number; + // else if we hit a < then thats an error + else if (ch == '<') + ch = EOF; + token_text += ch; + } while ( (ch != '>') && (ch != EOF)); + + // check if this is an error token + if (ch == EOF) + { + token_kind = error; + } + } + break; + + + // --------------------------------- + + // this is an element_start or empty_element token + default: + { + + token_text += ch1; + token_text += ch2; + std::istream::int_type ch = '\0'; + std::istream::int_type last; + do + { + last = ch; + ch = in.get(); + if (ch == '\n') + ++line_number; + // else if we hit a < then thats an error + else if (ch == '<') + ch = EOF; + token_text += ch; + } while ( (ch != '>') && (ch != EOF)); + + // check if this is an error token + if (ch == EOF) + { + token_kind = error; + } + // if this is an empty_element + else if (last == '/') + { + token_kind = empty_element; + } + else + { + token_kind = element_start; + } + + + } + break; + + // --------------------------------- + + } + + } + break; + + // ----------------------------------------- + + // this is an eof token + case EOF: + { + token_kind = eof; + } + break; + + // ----------------------------------------- + + // this is a chars token + default: + { + if (ch1 == '\n') + { + ++line_number; + token_text += ch1; + } + // if the first thing in this chars token is an entity reference + else if (ch1 == '&') + { + + int temp = change_entity(in); + if (temp == -1) + { + token_kind = error; + break; + } + else + { + token_text += temp; + } + } + else + { + token_text += ch1; + } + + + token_kind = chars; + + std::istream::int_type ch = 0; + while (in.peek() != '<' && in.peek() != EOF) + { + ch = in.get(); + + if (ch == '\n') + ++line_number; + + // if this is one of the predefined entity references then change it + if (ch == '&') + { + int temp = change_entity(in); + if (temp == -1) + { + ch = EOF; + break; + } + else + token_text += temp; + } + else + { + token_text += ch; + } + } + + // if this is an error token + if (ch == EOF) + { + token_kind = error; + } + + } + break; + + // ----------------------------------------- + + } + + + } + + + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + int xml_parser_kernel_1:: + parse_element ( + const std::string& token, + std::string& name, + attrib_list& atts + ) + { + name.erase(); + atts.list.clear(); + + // there must be at least one character between the <> + if (token[1] == '>') + return -1; + + std::string::size_type i; + std::istream::int_type ch = token[1]; + i = 2; + + // fill out name. the name can not contain any of the following characters + while ( (ch != '>') && + (ch != ' ') && + (ch != '=') && + (ch != '/') && + (ch != '\t') && + (ch != '\r') && + (ch != '\n') + ) + { + name += ch; + ch = token[i]; + ++i; + } + + // skip any whitespaces + while ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' ) + { + ch = token[i]; + ++i; + } + + // find any attributes + while (ch != '>' && ch != '/') + { + std::string attribute_name; + std::string attribute_value; + + // fill out attribute_name + while ( (ch != '=') && + (ch != ' ') && + (ch != '\t') && + (ch != '\r') && + (ch != '\n') && + (ch != '>') + ) + { + attribute_name += ch; + ch = token[i]; + ++i; + } + + // you can't have empty attribute names + if (attribute_name.size() == 0) + return -1; + + // if we hit > too early then return error + if (ch == '>') + return -1; + + // skip any whitespaces + while (ch == ' ' || ch == '\t' || ch =='\n' || ch =='\r') + { + ch = token[i]; + ++i; + } + + // the next char should be a '=', error if it's not + if (ch != '=') + return -1; + + // get the next char + ch = token[i]; + ++i; + + // skip any whitespaces + while (ch == ' ' || ch == '\t' || ch =='\n' || ch =='\r') + { + ch = token[i]; + ++i; + } + + + // get the delimiter for the attribute value + std::istream::int_type delimiter = ch; // this should be either a ' or " character + ch = token[i]; // get the next char + ++i; + if (delimiter != '\'' && delimiter!='"') + return -1; + + + // fill out attribute_value + while ( (ch != delimiter) && + (ch != '>') + ) + { + attribute_value += ch; + ch = token[i]; + ++i; + } + + + // if there was no delimiter then this is an error + if (ch == '>') + { + return -1; + } + + // go to the next char + ch = token[i]; + ++i; + + // the next char must be either a '>' or '/' (denoting the end of the tag) + // or a white space character + if (ch != '>' && ch != ' ' && ch != '/' && ch != '\t' && ch !='\n' && ch !='\r') + return -1; + + // skip any whitespaces + while (ch == ' ' || ch == '\t' || ch =='\n' || ch =='\r') + { + ch = token[i]; + ++i; + } + + + // add attribute_value and attribute_name to atts + if (atts.list.is_in_domain(attribute_name)) + { + // attributes may not be multiply defined + return -1; + } + else + { + atts.list.add(attribute_name,attribute_value); + } + + + } + + // you can't have an element with no name + if (name.size() == 0) + return -1; + + return 0; + + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + int xml_parser_kernel_1:: + parse_pi ( + const std::string& token, + std::string& target, + std::string& data + ) + { + target.erase(); + data.erase(); + + std::istream::int_type ch = token[2]; + std::string::size_type i = 3; + while (ch != ' ' && ch != '?' && ch != '\t' && ch != '\n' && ch!='\r') + { + target += ch; + ch = token[i]; + ++i; + } + if (target.size() == 0) + return -1; + + // if we aren't at a ? character then go to the next character + if (ch != '?' ) + { + ch = token[i]; + ++i; + } + + // if we still aren't at the end of the processing instruction then + // set this stuff in the data section + while (ch != '?') + { + data += ch; + ch = token[i]; + ++i; + } + + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + int xml_parser_kernel_1:: + parse_element_end ( + const std::string& token, + std::string& name + ) + { + name.erase(); + std::string::size_type end = token.size()-1; + for (std::string::size_type i = 2; i < end; ++i) + { + if (token[i] == ' ' || token[i] == '\t' || token[i] == '\n'|| token[i] == '\r') + break; + name += token[i]; + } + + if (name.size() == 0) + return -1; + + return 0; + } + +// ---------------------------------------------------------------------------------------- + + template < + typename map, + typename stack, + typename seq_dh, + typename seq_eh + > + int xml_parser_kernel_1:: + change_entity ( + std::istream& in + ) + { + + std::istream::int_type buf[6]; + + + buf[1] = in.get(); + + // if this is an undefined entity reference then return error + if (buf[1] != 'a' && + buf[1] != 'l' && + buf[1] != 'g' && + buf[1] != 'q' + ) + return -1; + + + buf[2] = in.get(); + // if this is an undefined entity reference then return error + if (buf[2] != 'm' && + buf[2] != 't' && + buf[2] != 'p' && + buf[2] != 'u' + ) + return -1; + + + buf[3] = in.get(); + // if this is an undefined entity reference then return error + if (buf[3] != 'p' && + buf[3] != ';' && + buf[3] != 'o' + ) + return -1; + + // check if this is < or > + if (buf[3] == ';') + { + if (buf[2] != 't') + return -1; + + // if this is < then return '<' + if (buf[1] == 'l') + return '<'; + // if this is > then return '>' + if (buf[1] == 'g') + return '>'; + + // it is neither so it must be an undefined entity reference + return -1; + } + + + buf[4] = in.get(); + // if this should be & + if (buf[4] == ';') + { + // if this is not & then return error + if (buf[1] != 'a' || + buf[2] != 'm' || + buf[3] != 'p' + ) + return -1; + + return '&'; + } + + buf[5] = in.get(); + + // if this should be ' + if (buf[1] == 'a' && + buf[2] == 'p' && + buf[3] == 'o' && + buf[4] == 's' && + buf[5] == ';' + ) + return '\''; + + + // if this should be " + if (buf[1] == 'q' && + buf[2] == 'u' && + buf[3] == 'o' && + buf[4] == 't' && + buf[5] == ';' + ) + return '"'; + + + // it was an undefined entity reference + return -1; + + } + + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_XML_PARSER_KERNEl_1_ + diff --git a/dlib/xml_parser/xml_parser_kernel_abstract.h b/dlib/xml_parser/xml_parser_kernel_abstract.h new file mode 100644 index 0000000000000000000000000000000000000000..a72d12b03645e22bccd6507e385ca15d7ff7c732 --- /dev/null +++ b/dlib/xml_parser/xml_parser_kernel_abstract.h @@ -0,0 +1,155 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_XML_PARSER_KERNEl_ABSTRACT_ +#ifdef DLIB_XML_PARSER_KERNEl_ABSTRACT_ + +#include +#include +#include "xml_parser_kernel_interfaces.h" + +namespace dlib +{ + + class xml_parser + { + + /*! + INITIAL VALUE + no objects are registered to receive events + + + WHAT THIS OBJECT REPRESENTS + This object represents a simple SAX style event driven XML parser. + It takes its input from an input stream object and sends events to all + registered document_handler and error_handler objects. + + note that this xml parser ignores all DTD related XML markup. It will + parse XML documents with DTD's but it just won't check if the document + is valid. This also means that entity references may not be used except + for the predefined ones which are as follows: + & + < + > + ' + " + + also note that there is no interpreting of entity references inside + a CDATA section or inside of tags, they are only interpreted inside + normal non-markup data. + + This parser considers the end of the xml document to be the closing + tag of the root tag (as opposed to using EOF as the end of the + document). This is a deviation from the xml standard. + + Aside from ignoring DTD stuff and entity references everywhere but + data, and the above comment regarding EOF, this parser should conform + to the rest of the XML standard. + !*/ + + public: + + + xml_parser( + ); + /*! + ensures + - #*this is properly initialized + throws + - std::bad_alloc + !*/ + + virtual ~xml_parser( + ); + /*! + ensures + - all memory associated with *this has been released + !*/ + + void clear( + ); + /*! + ensures + - #*this has its initial value + throws + - std::bad_alloc + if this exception is thrown then *this is unusable + until clear() is called and succeeds + !*/ + + void parse ( + std::istream& in + ); + /*! + requires + - in.fail() == false + ensures + - the data from the input stream in will be parsed and the appropriate + events will be generated + - parsing will stop when the parser has reached the closing tag + for the xml document or EOF (which ever comes first). Note that + hitting EOF first is a fatal error. + throws + - std::bad_alloc + if parse() throws then it will be unusable until clear() is + called and succeeds + - other exceptions + document_handlers and error_handlers my throw any exception. If + they throw while parse() is running then parse() will let the + exception propagate out and the xml_parser object will be unusable + until clear() is called and succeeds. note that end_document() + is still called. + !*/ + + void add_document_handler ( + document_handler& item + ); + /*! + ensures + - item will now receive document events from the parser + throws + - std::bad_alloc + if add_document_handler() throws then it has no effect + !*/ + + void add_error_handler ( + error_handler& item + ); + /*! + ensures + - item will now receive error events from the parser + throws + - std::bad_alloc + if add_error_handler() throws then it has no effect + !*/ + + + void swap ( + xml_parser& item + ); + /*! + ensures + - swaps *this and item + !*/ + + + private: + + // restricted functions + xml_parser(xml_parser&); // copy constructor + xml_parser& operator=(xml_parser&); // assignment operator + + }; + + + inline void swap ( + xml_parser& a, + xml_parser& b + ) { a.swap(b); } + /*! + provides a global swap function + !*/ + +} + +#endif // DLIB_XML_PARSER_KERNEl_ABSTRACT_ + diff --git a/dlib/xml_parser/xml_parser_kernel_c.h b/dlib/xml_parser/xml_parser_kernel_c.h new file mode 100644 index 0000000000000000000000000000000000000000..02652caf9d439ae1e74a1de6876035a1e4121600 --- /dev/null +++ b/dlib/xml_parser/xml_parser_kernel_c.h @@ -0,0 +1,64 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_XML_PARSER_KERNEL_C_ +#define DLIB_XML_PARSER_KERNEL_C_ + +#include "xml_parser_kernel_abstract.h" +#include +#include +#include "../algs.h" +#include "../assert.h" + +namespace dlib +{ + + template < + typename xml_parser_base + > + class xml_parser_kernel_c : public xml_parser_base + { + public: + void parse ( + std::istream& in + ); + }; + + + template < + typename xml_parser_base + > + inline void swap ( + xml_parser_kernel_c& a, + xml_parser_kernel_c& b + ) { a.swap(b); } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + // member function definitions +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + + template < + typename xml_parser_base + > + void xml_parser_kernel_c:: + parse ( + std::istream& in + ) + { + DLIB_CASSERT ( in.fail() == false , + "\tvoid xml_parser::parse" + << "\n\tthe input stream must not be in the fail state" + << "\n\tthis: " << this + ); + + return xml_parser_base::parse(in); + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_XML_PARSER_KERNEL_C_ + diff --git a/dlib/xml_parser/xml_parser_kernel_interfaces.h b/dlib/xml_parser/xml_parser_kernel_interfaces.h new file mode 100644 index 0000000000000000000000000000000000000000..cac5fb6a63ea94200fa3e6417f021d543aaf694c --- /dev/null +++ b/dlib/xml_parser/xml_parser_kernel_interfaces.h @@ -0,0 +1,229 @@ +// Copyright (C) 2003 Davis E. King (davisking@users.sourceforge.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_XML_PARSER_KERNEl_INTERFACES_ +#define DLIB_XML_PARSER_KERNEl_INTERFACES_ + +#include +#include "../interfaces/enumerable.h" +#include "../interfaces/map_pair.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class attribute_list : public enumerable > + { + + /*! + WHAT THIS OBJECT REPRESENTS + this object represents a list of the attributes found in + an XML element. each attribute is associated with a value. + !*/ + + + public: + + inline virtual ~attribute_list ( + ) =0; + + + virtual bool is_in_list ( + const std::string& key + ) const =0; + /*! + ensures + - returns true if there is an attribute named key in the list + - returns false + !*/ + + virtual const std::string& operator[] ( + const std::string& key + ) const =0; + /*! + requires + - is_in_list(key) == true + ensures + - returns a const reference to the value associated with the + attribute named key. + !*/ + + protected: + + // restricted functions + attribute_list& operator=(attribute_list&) {return *this;} + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class document_handler + { + /*! + EXCEPTIONS + a document_handler is allowed to throw any exception + + + WHAT THIS OBJECT REPRESENTS + this object is an interface for handling the basic events + generated by an XML parser + !*/ + + + public: + + inline virtual ~document_handler ( + ) =0; + + virtual void start_document ( + )=0; + /*! + requires + - is called when the document parsing begins + !*/ + + virtual void end_document ( + )=0; + /*! + requires + - is called after the document parsing has ended. note that this + is always called, even if an error occurs. + !*/ + + virtual void start_element ( + const unsigned long line_number, + const std::string& name, + const dlib::attribute_list& atts + )=0; + /*! + requires + - is called when an opening element tag is encountered. + - line_number == the line number where the opening tag for this element + was encountered. + - name == the name of the element encountered + - atts == a list containing all the attributes in this element and their + associated values + !*/ + + virtual void end_element ( + const unsigned long line_number, + const std::string& name + )=0; + /*! + requires + - is called when a closing element tag is encountered. (note that this + includes tags such as . I.e. the previous tag would + trigger a start_element() callback as well as an end_element() callback) + - line_number == the line number where the closing tag for this + element was encountered and + - name == the name of the element encountered + !*/ + + virtual void characters ( + const std::string& data + )=0; + /*! + requires + - is called just before we encounter a start_element, end_element, or + processing_instruction tag but only if there was data between the + last and next tag. + (i.e. data will never be "") + - data == all the normal non-markup data and CDATA between the next and + last tag in the document. + !*/ + + virtual void processing_instruction ( + const unsigned long line_number, + const std::string& target, + const std::string& data + )=0; + /*! + requires + - is called when a processing instruction is encountered + - line_number == the line number where this processing instruction + was encountered + - target == the target value for this processing instruction + - data == the data value for this processing instruction + !*/ + + protected: + + // restricted functions + document_handler& operator=(document_handler&) { return *this; } + }; + + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + class error_handler + { + /*! + EXCEPTIONS + an error_handler is allowed to throw any exception + + + WHAT THIS OBJECT REPRESENTS + this object is an interface for handling the error/warning + events generated by an XML parser + !*/ + + public: + + inline virtual ~error_handler ( + ) =0; + + virtual void error ( + const unsigned long line_number + )=0; + /*! + requires + - is called when an error that does NOT require the parser to halt + is encountered. (i.e. somewhat minor errors in the input) + - line_number == the line number where this error was encountered + + the following events trigger an error: + an invalid processing instruction + !*/ + + virtual void fatal_error ( + const unsigned long line_number + )=0; + /*! + requires + - is called when an error that requires the parser to abort its parsing + is encountered (i.e. fatal errors in the input) + - line_number == the line number where this fatal error was encountered + + the following events trigger a fatal_error: + Everything other than the events listed above for error. + Also note that encountering an entity reference other than the + predefined ones listed in xml_parser_kernel_abstract is a fatal_error. + Hitting EOF before the closing tag for the document is also a fatal_error. + !*/ + + protected: + + // restricted functions + error_handler& operator=(error_handler&) { return *this;} + }; + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + document_handler::~document_handler ( + ){} + attribute_list::~attribute_list ( + ){} + error_handler::~error_handler ( + ){} + +} + +#endif // DLIB_XML_PARSER_KERNEl_INTERFACES_ + diff --git a/docs/.current_minor_release_number b/docs/.current_minor_release_number new file mode 100644 index 0000000000000000000000000000000000000000..00750edc07d6415dcc07ae0351e9397b0222b7ba --- /dev/null +++ b/docs/.current_minor_release_number @@ -0,0 +1 @@ +3 diff --git a/docs/.current_release_number b/docs/.current_release_number new file mode 100644 index 0000000000000000000000000000000000000000..98d9bcb75a685dfbfd60f611c309410152935b3d --- /dev/null +++ b/docs/.current_release_number @@ -0,0 +1 @@ +17 diff --git a/docs/.logger_revnum b/docs/.logger_revnum new file mode 100644 index 0000000000000000000000000000000000000000..811f4e3ac161305d3c6f449106da9b125f721cc6 --- /dev/null +++ b/docs/.logger_revnum @@ -0,0 +1 @@ +2193 diff --git a/docs/docs/algorithms.xml b/docs/docs/algorithms.xml new file mode 100644 index 0000000000000000000000000000000000000000..7c08ebae9c3f730ecb03999efa5d1d2b639b87bd --- /dev/null +++ b/docs/docs/algorithms.xml @@ -0,0 +1,1249 @@ + + + + + Algorithms + + + + +

+ +

+ This page documents library components that are all basically just implementations of + mathematical functions or algorithms without any really significant data structures + associated with them. So this includes things like checksums, cryptographic hashes, sorting, etc... +

+ +

+ Everything in this section basically follows the same conventions as + the rest of the library. So to get a bigint for example you would need to write something + like typedef dlib::bigint::kernel_2a bint; and from then on make your big ints like + bint my_bigint;. +

+ + + + + + + +
+ Objects + bigint + crc32 + rand + mlp + + Geometry + + rectangle + vector + point + + + + Bayes Utilities + + assignment + joint_probability_table + conditional_probability_table + bayes_node + bayesian_network_gibbs_sampler + bayesian_network_join_tree + + + + SVM Utilities + + radial_basis_kernel + polynomial_kernel + linear_kernel + decision_function + probabilistic_decision_function + + +
+ +
+ Global Functions + randomize_samples + hsort_array + isort_array + md5 + median + qsort_array + square_root + + Geometry + + centered_rect + translate_rect + resize_rect + resize_rect_width + resize_rect_height + move_rect + nearest_point + + + + SVM Utilities + + svm_nu_train + svm_nu_train_prob + svm_nu_cross_validate + + + + Set Utilities + + set_intersection_size + set_intersection + set_union + set_difference + + + + Graph Utilities + + graph_contains_directed_cycle + graph_contains_undirected_cycle + create_moral_graph + triangulate_graph_and_find_cliques + graph_contains_length_one_cycle + find_connected_nodes + graph_is_connected + is_clique + is_maximal_clique + copy_graph_structure + edge + is_join_tree + create_join_tree + + + + Bayes Node Utilities + + set_node_value + node_value + node_is_evidence + set_node_as_evidence + set_node_as_nonevidence + set_node_num_values + node_num_values + node_probability + set_node_probability + node_first_parent_assignment + node_next_parent_assignment + node_cpt_filled_out + + +
+ + +
+
+ + + + + + + + + + + bayesian_network_join_tree + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This object represents an implementation of the join tree algorithm + (a.k.a. the junction tree algorithm) + for inference in bayesian networks. + + + bayes_net_ex.cpp.html + bayes_net_gui_ex.cpp.html + bayes_net_from_disk_ex.cpp.html + + + + + + + + bayesian_network_gibbs_sampler + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This object performs Markov Chain Monte Carlo sampling of a bayesian + network using the Gibbs sampling technique. + + + bayes_net_ex.cpp.html + + + + + + + + bayes_node + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This object represents a node in a bayesian network. It is + intended to be used inside the directed_graph object to + represent bayesian networks. + + + + bayes_net_ex.cpp.html + bayes_net_gui_ex.cpp.html + + + + + + + conditional_probability_table + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This object represents a conditional probability table. + + + + + + + + joint_probability_table + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This object represents a joint probability table. + + + + + + + + assignment + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This object models an assignment of random variables to particular values. + It is used with the joint_probability_table and + conditional_probability_table + objects to represent assignments of various random variables to actual values. + + + bayes_net_ex.cpp.html + bayes_net_gui_ex.cpp.html + + + + + + + + set_node_probability + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily set the probability of a + bayes_node given its parents when it is inside + a directed_graph object. + + + bayes_net_ex.cpp.html + + + + + + + + node_first_parent_assignment + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily obtain an assignment + that contains all the parents of a node in a bayesian network. + + + bayes_net_gui_ex.cpp.html + + + + + + + node_next_parent_assignment + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily loop through all the parent assignments + of a node in a bayesian network. + + + bayes_net_gui_ex.cpp.html + + + + + + + + node_cpt_filled_out + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily verify that a node + in a bayesian network has its conditional_probability_table + completely filled out. + + + bayes_net_gui_ex.cpp.html + + + + + + + + node_probability + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily obtain the probability of a + bayes_node given its parents when it is inside + a directed_graph object. + + + + + + + node_num_values + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily obtain the number of values of a + bayes_node when it is inside + a directed_graph object. + + + + + + + set_node_num_values + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily set the number of values of a + bayes_node when it is inside + a directed_graph object. + + + bayes_net_ex.cpp.html + + + + + + + set_node_as_nonevidence + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily remove the evidence flag of a + bayes_node when it is inside + a directed_graph object. + + + bayes_net_ex.cpp.html + + + + + + + set_node_as_evidence + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily set the evidence flag of a + bayes_node when it is inside + a directed_graph object. + + + bayes_net_ex.cpp.html + + + + + + + node_is_evidence + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily determine if a + bayes_node is evidence when it is inside + a directed_graph object. + + + + + + + + node_value + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily obtain the value of a + bayes_node when it is inside a + directed_graph object. + + + + + + + + set_node_value + dlib/bayes_utils.h + dlib/bayes_utils/bayes_utils_abstract.h + + This is a function declared in the dlib::bayes_node_utils namespace. It + is a convenience function that allows you to easily modify the value of a + bayes_node when it is inside a + directed_graph object. + + + bayes_net_ex.cpp.html + + + + + + + + bigint + dlib/bigint.h + dlib/bigint/bigint_kernel_abstract.h + + This object represents an arbitrary precision unsigned integer. It's pretty simple. + It's interface is just like a normal int, you don't have to tell it how much memory + to use or anything unusual. It just goes :) + + + + + bigint_kernel_1 + dlib/bigint/bigint_kernel_1.h + + This implementation is done using an array of unsigned shorts. It is also reference counted. + For further details see the above link. Also note that kernel_2 should be + faster in almost every case so you should really just use that version of the bigint object. + + + + + kernel_1a + is a typedef for bigint_kernel_1 + + + + + + + bigint_kernel_2 + dlib/bigint/bigint_kernel_2.h + + This implementation is basically the same as kernel_1 except it uses the + Fast Fourier Transform to perform multiplcations much faster. + + + + + kernel_2a + is a typedef for bigint_kernel_2 + + + + + + + + + + + + + + crc32 + dlib/crc32.h + dlib/crc32/crc32_kernel_abstract.h + + This object represents the CRC-32 algorithm for calculating + checksums. + + + + + crc32_kernel_1 + dlib/crc32/crc32_kernel_1.h + + This implementation uses the polynomial 0xedb88320. + + + + + kernel_1a + is a typedef for crc32_kernel_1 + + + + + + + + + + + + rand + dlib/rand.h + dlib/rand/rand_kernel_abstract.h + + This object represents a pseudorandom number generator. + + + + + rand_kernel_1 + dlib/rand/rand_kernel_1.h + + This implementation is done using the Mersenne Twister algorithm. + + + + + kernel_1a + is a typedef for rand_kernel_1 + + + + + + + + + + + rand_float + dlib/rand/rand_float_abstract.h + + This extension gives rand the ability to generate random floating point numbers. + + + + + rand_float_1 + dlib/rand/rand_float_1.h + + The implementation is obvious. Click on the link if you want to see. + + + + + float_1a + is a typedef for rand_kernel_1a extended by rand_float_1 + + + + + + + + + + + + + + + + + + rectangle + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This object represents a rectangular region inside a cartesian + coordinate system. It allows you to easily represent and manipulate + rectangles. + + + + + + + mlp + dlib/mlp.h + dlib/mlp/mlp_kernel_abstract.h + + This object represents a multilayer layer perceptron network that is + trained using the back propagation algorithm. The training algorithm also + incorporates the momentum method. That is, each round of back propagation + training also adds a fraction of the previous update. This fraction + is controlled by the momentum term set in the constructor. + + + + mlp_ex.cpp.html + + + + + mlp_kernel_1 + dlib/mlp/mlp_kernel_1.h + + This is implemented in the obvious way. + + + + + kernel_1a + is a typedef for mlp_kernel_1 + + + + + + + + + + + + + vector + dlib/geometry.h + dlib/geometry/vector_abstract.h + + This object represents a three dimensional vector. + + + + + + + point + dlib/geometry.h + dlib/geometry/vector_abstract.h + + This object represents a point inside a Cartesian coordinate system. + + + + + + + svm_nu_train_prob + dlib/svm.h + dlib/svm/svm_abstract.h + +

+ Trains a nu support vector classifier and outputs a + probabilistic_decision_function. +

+ This function uses the svm_nu_train function and creates the + probability model using the technique described in the paper: +
+ Probabilistic Outputs for Support Vector Machines and + Comparisons to Regularized Likelihood Methods by + John C. Platt. Match 26, 1999 +
+
+ + svm_ex.cpp.html + + +
+ + + + + svm_nu_train + dlib/svm.h + dlib/svm/svm_abstract.h + +

+ Trains a nu support vector classifier and outputs a decision_function. +

+ The implementation of the nu-svm training algorithm used by this library is based + on the following excellent papers: +
    +
  • Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms
  • +
  • Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector + machines, 2001. Software available at + http://www.csie.ntu.edu.tw/~cjlin/libsvm
  • +
+
+ + svm_ex.cpp.html + + +
+ + + + + probabilistic_decision_function + dlib/svm.h + dlib/svm/svm_abstract.h + + This object represents a binary decision function for use with + support vector machines. It returns an + estimate of the probability that a given sample is in the +1 class. + + + svm_ex.cpp.html + + + + + + + + decision_function + dlib/svm.h + dlib/svm/svm_abstract.h + + This object represents a binary decision function for use with + support vector machines. + + + svm_ex.cpp.html + + + + + + + + linear_kernel + dlib/svm.h + dlib/svm/svm_abstract.h + + This object represents a linear function kernel for use with + support vector machines. + + + + + + + + polynomial_kernel + dlib/svm.h + dlib/svm/svm_abstract.h + + This object represents a polynomial kernel for use with + support vector machines. + + + + + + + + radial_basis_kernel + dlib/svm.h + dlib/svm/svm_abstract.h + + This object represents a radial basis function kernel for use with + support vector machines. + + + svm_ex.cpp.html + + + + + + + + randomize_samples + dlib/svm.h + dlib/svm/svm_abstract.h + + Randomizes the order of samples in a column vector containing sample data. + + + svm_ex.cpp.html + + + + + + + + svm_nu_cross_validate + dlib/svm.h + dlib/svm/svm_abstract.h + + Performs k-fold cross validation using the svm_nu_train() function. + + + svm_ex.cpp.html + + + + + + + + hsort_array + dlib/sort.h + dlib/sort.h + + hsort_array is an implementation of the heapsort algorithm. It will sort anything that has an + array like operator[] interface. + + + + + + + + isort_array + dlib/sort.h + dlib/sort.h + + isort_array is an implementation of the insertion sort algorithm. It will sort anything that has an + array like operator[] interface. + + + + + + + + + qsort_array + dlib/sort.h + dlib/sort.h + + qsort_array is an implementation of the QuickSort algorithm. It will sort anything that has an array like + operator[] interface. If the quick sort becomes unstable then it switches to a heap sort. This + way sorting is guaranteed to take at most N*log(N) time. + + + + + + + + + md5 + dlib/md5.h + dlib/md5/md5_kernel_abstract.h + + This is an implementation of The MD5 Message-Digest Algorithm as described in rfc1321. + + + + + + + + + + median + dlib/algs.h + dlib/algs.h + + This function takes three paramaters and finds the median of the three. The median is swapped into + the first parameter and the first parameter ends up in one of the other two, unless the first parameter was + the median to begin with of course. + + + + + + + + square_root + dlib/algs.h + dlib/algs.h + + square_root is a function which takes an unsigned long and returns the square root of it or + if the root is not an integer then it is rounded up to the next integer. + + + + + + + + edge + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph object and a + pair of indices. It returns a reference to the edge object between the two nodes + with the given indices. + + + + + + + + is_join_tree + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes two graph objects and + checks if the second of the two graphs is a valid join tree (aka tree decomposition) + of the first graph. + + + + + + + + create_join_tree + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph object and + creates a join tree for that graph. Or in other words, this function finds a + tree decomposition of the given graph. + + + + + + + + graph_contains_directed_cycle + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function checks a directed_graph for directed cycles. + + + + + + + + set_intersection + dlib/set_utils.h + dlib/set_utils/set_utils_abstract.h + + This function takes two set objects and + gives you their intersection. + + + + + + + + set_union + dlib/set_utils.h + dlib/set_utils/set_utils_abstract.h + + This function takes two set objects and + gives you their union. + + + + + + + + set_difference + dlib/set_utils.h + dlib/set_utils/set_utils_abstract.h + + This function takes two set objects and + gives you their difference. + + + + + + + + set_intersection_size + dlib/set_utils.h + dlib/set_utils/set_utils_abstract.h + + This function takes two set objects and tells you + how many items they have in common. + + + + + + + + triangulate_graph_and_find_cliques + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph and + turns it into a chordal graph. It also returns a + set that contains + all the cliques present in the choral graph. + + + + + + + + create_moral_graph + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a directed_graph + and returns the moralized version of the graph in the form of a + graph object. + + + + + + + + graph_contains_length_one_cycle + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph + or directed_graph object and + returns true if and only if the graph contains a node that has an edge that + links back to itself. + + + + + + + + find_connected_nodes + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a node from a graph + or directed_graph object and a + set of unsigned longs. It finds all the + nodes in the given graph that are connected to the given node by an + undirected path and returns them in the set (also note that the + original query node is also returned in this set). + + + + + + + + graph_is_connected + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph or + directed_graph object and + determines if the graph is connected. That is, it returns true if and only if + there is an undirected path between any two nodes in the given graph. + + + + + + + + is_clique + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph and a + set of node index values and checks + if the specified set of nodes is a clique in the graph. + + + + + + + + copy_graph_structure + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph or + directed_graph and copies + its structure to another graph or directed_graph object. The only + restriction is that you can't copy the structure of a graph into a + directed_graph. The three other possible combinations are allowed + however. + + + + + + + + is_maximal_clique + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function takes a graph and a + set of node index values and checks + if the specified set of nodes is a maximal clique in the graph. + + + + + + + + nearest_point + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This function takes a rectangle and a + point and returns the point in the given + rectangle that is nearst to the given point. + + + + + + + + move_rect + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This function takes a rectangle and moves + it so that it's upper left corner occupies the given location. + + + + + + + + resize_rect_height + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This function takes a rectangle and + returns a new rectangle with the given height but otherwise with the + same edge points as the original rectangle. + + + + + + + + resize_rect_width + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This function takes a rectangle and + returns a new rectangle with the given width but otherwise with the + same edge points as the original rectangle. + + + + + + + + resize_rect + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This function takes a rectangle and + returns a new rectangle with the given size but with the same upper + left corner as the original rectangle. + + + + + + + + translate_rect + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + This function takes a rectangle and moves + it by a given number of units along the x and y axis relative to + where it was before the move. + + + + + + + + centered_rect + dlib/geometry.h + dlib/geometry/rectangle_abstract.h + + There are various overloads of this function but the basic idea is + that it returns a rectangle with a given + width and height and centered about a given point. + + + + + + + + graph_contains_undirected_cycle + dlib/graph_utils.h + dlib/graph_utils/graph_utils_abstract.h + + This function checks a directed_graph for undirected cycles. + + + + + + +
+ + + + + + diff --git a/docs/docs/api.xml b/docs/docs/api.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f853909e4eef1a6e60c334f300b01f0387f40a5 --- /dev/null +++ b/docs/docs/api.xml @@ -0,0 +1,1089 @@ + + + + + API Wrappers + + + + +

+ +

+ + These wrappers provide a portable object oriented interface for networking, multithreading, + GUI development, and file browsing. + Programs written using them can be compiled under POSIX or MS Windows platforms without changing the code. +

+ + + +

One important thing to note about the API wrappers (except the threading wrappers) + is that some platforms + need to be initialized in some way or another before the API will work right. + Because of this it is never safe to call API wrapper functions before + main() has been entered. This means no global objects with + constructors that call them or any weird stuff like that.

+ + + + + + + + + + +
+ API + + + + + gui_widgets + + + widgets + + + dragable + dlib/gui_widgets/base_widgets_abstract.h.html#dragable + + + arrow_button + dlib/gui_widgets/base_widgets_abstract.h.html#arrow_button + + + tooltip + dlib/gui_widgets/base_widgets_abstract.h.html#tooltip + + + button_action + dlib/gui_widgets/base_widgets_abstract.h.html#button_action + + + scrollable_region + dlib/gui_widgets/base_widgets_abstract.h.html#scrollable_region + + + zoomable_region + dlib/gui_widgets/base_widgets_abstract.h.html#zoomable_region + + + mouse_over_event + dlib/gui_widgets/base_widgets_abstract.h.html#mouse_over_event + + + scroll_bar + dlib/gui_widgets/base_widgets_abstract.h.html#scroll_bar + + + widget_group + dlib/gui_widgets/base_widgets_abstract.h.html#widget_group + + + image_widget + dlib/gui_widgets/base_widgets_abstract.h.html#image_widget + + + popup_menu + dlib/gui_widgets/base_widgets_abstract.h.html#popup_menu + + + menu_item + dlib/gui_widgets/base_widgets_abstract.h.html#menu_item + + + menu_item_text + dlib/gui_widgets/base_widgets_abstract.h.html#menu_item_text + + + menu_item_separator + dlib/gui_widgets/base_widgets_abstract.h.html#menu_item_separator + + + menu_item_submenu + dlib/gui_widgets/base_widgets_abstract.h.html#menu_item_submenu + + + named_rectangle + dlib/gui_widgets/widgets_abstract.h.html#named_rectangle + + + menu_bar + dlib/gui_widgets/widgets_abstract.h.html#menu_bar + + + message_box + dlib/gui_widgets/widgets_abstract.h.html#message_box + + + message_box_blocking + dlib/gui_widgets/widgets_abstract.h.html#message_box + + + open_file_box + dlib/gui_widgets/widgets_abstract.h.html#open_file_box + + + open_existing_file_box + dlib/gui_widgets/widgets_abstract.h.html#open_existing_file_box + + + save_file_box + dlib/gui_widgets/widgets_abstract.h.html#save_file_box + + + label + dlib/gui_widgets/widgets_abstract.h.html#label + + + button + dlib/gui_widgets/widgets_abstract.h.html#button + + + toggle_button + dlib/gui_widgets/widgets_abstract.h.html#toggle_button + + + text_grid + dlib/gui_widgets/widgets_abstract.h.html#text_grid + + + directed_graph_drawer + dlib/gui_widgets/widgets_abstract.h.html#directed_graph_drawer + + + list_box + dlib/gui_widgets/widgets_abstract.h.html#list_box + + + check_box + dlib/gui_widgets/widgets_abstract.h.html#check_box + + + radio_button + dlib/gui_widgets/widgets_abstract.h.html#radio_button + + + text_field + dlib/gui_widgets/widgets_abstract.h.html#text_field + + + tabbed_display + dlib/gui_widgets/widgets_abstract.h.html#tabbed_display + + + mouse_tracker + dlib/gui_widgets/widgets_abstract.h.html#mouse_tracker + + + + + styles + + + button_style + dlib/gui_widgets/style_abstract.h.html#button_style + + + button_style_default + dlib/gui_widgets/style_abstract.h.html#button_style_default + + + button_style_toolbar1 + dlib/gui_widgets/style_abstract.h.html#button_style_toolbar1 + + + button_style_toolbar_icon1 + dlib/gui_widgets/style_abstract.h.html#button_style_toolbar_icon1 + + + toggle_button_style + dlib/gui_widgets/style_abstract.h.html#toggle_button_style + + + toggle_button_style_default + dlib/gui_widgets/style_abstract.h.html#toggle_button_style_default + + + toggle_button_style_check_box + dlib/gui_widgets/style_abstract.h.html#toggle_button_style_check_box + + + toggle_button_style_radio_button + dlib/gui_widgets/style_abstract.h.html#toggle_button_style_radio_button + + + + + canvas drawing functions + + + draw_line + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_line + + + draw_rectangle + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_rectangle + + + draw_circle + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_circle + + + draw_pixel + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_pixel + + + draw_solid_circle + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_solid_circle + + + draw_button_down + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_button_down + + + draw_sunken_rectangle + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_sunken_rectangle + + + draw_button_up + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_button_up + + + draw_checkered + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_checkered + + + draw_image + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_image + + + fill_rect + dlib/gui_widgets/canvas_drawing_abstract.h.html#fill_rect + + + fill_rect_with_vertical_gradient + dlib/gui_widgets/canvas_drawing_abstract.h.html#fill_rect_with_vertical_gradient + + + fill_gradient_rounded + dlib/gui_widgets/canvas_drawing_abstract.h.html#fill_gradient_rounded + + + draw_rounded_rectangle + dlib/gui_widgets/canvas_drawing_abstract.h.html#draw_rounded_rectangle + + + + + drawable + dlib/gui_widgets/drawable_abstract.h.html#drawable + + + set_main_font + dlib/gui_widgets/drawable_abstract.h.html#set_main_font + + + main_font + dlib/gui_widgets/drawable_abstract.h.html#main_font + + + z_order + dlib/gui_widgets/drawable_abstract.h.html#z_order + + + next_free_user_event_number + dlib/gui_widgets/drawable_abstract.h.html#next_free_user_event_number + + + set_z_order + dlib/gui_widgets/drawable_abstract.h.html#set_z_order + + + shape + + + get_rect + dlib/gui_widgets/drawable_abstract.h.html#get_rect + + + bottom + dlib/gui_widgets/drawable_abstract.h.html#bottom + + + top + dlib/gui_widgets/drawable_abstract.h.html#top + + + left + dlib/gui_widgets/drawable_abstract.h.html#left + + + right + dlib/gui_widgets/drawable_abstract.h.html#right + + + width + dlib/gui_widgets/drawable_abstract.h.html#width + + + height + dlib/gui_widgets/drawable_abstract.h.html#height + + + + + set_pos + dlib/gui_widgets/drawable_abstract.h.html#set_pos + + + is_enabled + dlib/gui_widgets/drawable_abstract.h.html#is_enabled + + + enable + dlib/gui_widgets/drawable_abstract.h.html#enable + + + disable + dlib/gui_widgets/drawable_abstract.h.html#disable + + + is_hidden + dlib/gui_widgets/drawable_abstract.h.html#is_hidden + + + show + dlib/gui_widgets/drawable_abstract.h.html#show + + + hide + dlib/gui_widgets/drawable_abstract.h.html#hide + + + parent_window + dlib/gui_widgets/drawable_abstract.h.html#parent_window + + + enable_events + dlib/gui_widgets/drawable_abstract.h.html#enable_events + + + events_are_enabled + dlib/gui_widgets/drawable_abstract.h.html#events_are_enabled + + + disable_events + dlib/gui_widgets/drawable_abstract.h.html#disable_events + + + events + + + on_window_resized + dlib/gui_widgets/drawable_abstract.h.html#on_window_resized + + + on_window_moved + dlib/gui_widgets/drawable_abstract.h.html#on_window_moved + + + on_focus_gained + dlib/gui_widgets/drawable_abstract.h.html#on_focus_gained + + + on_focus_lost + dlib/gui_widgets/drawable_abstract.h.html#on_focus_lost + + + on_mouse_up + dlib/gui_widgets/drawable_abstract.h.html#on_mouse_up + + + on_mouse_move + dlib/gui_widgets/drawable_abstract.h.html#on_mouse_move + + + on_mouse_enter + dlib/gui_widgets/drawable_abstract.h.html#on_mouse_enter + + + on_mouse_leave + dlib/gui_widgets/drawable_abstract.h.html#on_mouse_leave + + + on_mouse_down + dlib/gui_widgets/drawable_abstract.h.html#on_mouse_down + + + on_wheel_up + dlib/gui_widgets/drawable_abstract.h.html#on_wheel_up + + + on_wheel_down + dlib/gui_widgets/drawable_abstract.h.html#on_wheel_down + + + on_keydown + dlib/gui_widgets/drawable_abstract.h.html#on_keydown + + + on_user_event + dlib/gui_widgets/drawable_abstract.h.html#on_user_event + + + draw + dlib/gui_widgets/drawable_abstract.h.html#draw + + + + + + + drawable_window + dlib/gui_widgets/drawable_abstract.h.html#drawable_window + + + fonts + + + letter + dlib/gui_widgets/fonts_abstract.h.html#letter + + + font + dlib/gui_widgets/fonts_abstract.h.html#font + + + default_font + dlib/gui_widgets/fonts_abstract.h.html#default_font + + + bdf_font + dlib/gui_widgets/fonts_abstract.h.html#bdf_font + + + + + + + + gui_core + + + base_window + dlib/gui_core/gui_core_kernel_abstract.h.html#base_window + + + canvas + dlib/gui_core/gui_core_kernel_abstract.h.html#canvas + + + get_from_clipboard + dlib/gui_core/gui_core_kernel_abstract.h.html#get_from_clipboard + + + put_on_clipboard + dlib/gui_core/gui_core_kernel_abstract.h.html#put_on_clipboard + + + + + + dir_nav + + + get_filesystem_roots + dlib/dir_nav/dir_nav_kernel_abstract.h.html#get_filesystem_roots + + + file + dlib/dir_nav/dir_nav_kernel_abstract.h.html#file + + + directory + dlib/dir_nav/dir_nav_kernel_abstract.h.html#directory + + + + + misc_api + + + sleep + dlib/misc_api/misc_api_kernel_abstract.h.html#sleep + + + get_current_dir + dlib/misc_api/misc_api_kernel_abstract.h.html#get_current_dir + + + create_directory + dlib/misc_api/misc_api_kernel_abstract.h.html#create_directory + + + timestamper + dlib/misc_api/misc_api_kernel_abstract.h.html#timestamper + + + + + threads + + + extensions + + + thread_specific_data + dlib/threads/thread_specific_data_extension_abstract.h.html + + + create_new_thread extension + dlib/threads/create_new_thread_extension_abstract.h.html#create_new_thread + + + rsignaler + dlib/threads/rsignaler_extension_abstract.h.html#rsignaler + + + rmutex + dlib/threads/rmutex_extension_abstract.h.html#rmutex + + + auto_mutex + dlib/threads/auto_mutex_extension_abstract.h.html#auto_mutex + + + auto_unlock + dlib/threads/auto_unlock_extension_abstract.h.html#auto_unlock + + + threaded_object + dlib/threads/threaded_object_extension_abstract.h.html#threaded_object + + + thread_function + dlib/threads/thread_function_extension_abstract.h.html#thread_function + + + multithreaded_object + dlib/threads/multithreaded_object_extension_abstract.h.html#multithreaded_object + + + + + is_dlib_thread + dlib/threads/threads_kernel_abstract.h.html#is_dlib_thread + + + create_new_thread + dlib/threads/threads_kernel_abstract.h.html#create_new_thread + + + mutex + dlib/threads/threads_kernel_abstract.h.html#mutex + + + register_thread_end_handler + dlib/threads/threads_kernel_abstract.h.html#register_thread_end_handler + + + register_program_ending_handler + dlib/threads/threads_kernel_abstract.h.html#register_program_ending_handler + + + signaler + dlib/threads/threads_kernel_abstract.h.html#signaler + + + get_thread_id + dlib/threads/threads_kernel_abstract.h.html#get_thread_id + + + + + sockets + + + extensions + + + connect + dlib/sockets/sockets_extensions_abstract.h.html#connect + + + is_ip_address + dlib/sockets/sockets_extensions_abstract.h.html#is_ip_address + + + close_gracefully + dlib/sockets/sockets_extensions_abstract.h.html#close_gracefully + + + + + objects + + + connection + dlib/sockets/sockets_kernel_abstract.h.html#connection + + + listener + dlib/sockets/sockets_kernel_abstract.h.html#listener + + + + + functions + + + create_connection + dlib/sockets/sockets_kernel_abstract.h.html#create_connection + + + create_listener + dlib/sockets/sockets_kernel_abstract.h.html#create_listener + + + get_local_hostname + dlib/sockets/sockets_kernel_abstract.h.html#get_local_hostname + + + hostname_to_ip + dlib/sockets/sockets_kernel_abstract.h.html#hostname_to_ip + + + ip_to_hostname + dlib/sockets/sockets_kernel_abstract.h.html#ip_to_hostname + + + + + +
+
+
+ + + + + + + + + dir_nav + dlib/dir_nav.h + dlib/dir_nav/dir_nav_kernel_abstract.h + + This is a set of objects that provide an easy and portable way to traverse a directory tree. + + + + dir_nav_ex.cpp.html + + + + + dir_nav_kernel_1 + dlib/dir_nav/dir_nav_kernel_1.h + + MS Windows implementation + + + + + dir_nav_kernel_2 + dlib/dir_nav/dir_nav_kernel_2.h + + POSIX implementation + + + + + + + + + + + + + gui_core + dlib/gui_core.h + dlib/gui_core/gui_core_kernel_abstract.h + + This is a set of objects and functions which provide a very basic + framework for manipulating windows. It is intended to provide a portable + interface which can be used to build a more complex windowing toolkit. + + + + + gui_core_kernel_1 + dlib/gui_core/gui_core_kernel_1.h + + MS Windows implementation + + + + + gui_core_kernel_2 + dlib/gui_core/gui_core_kernel_2.h + + X Windows implementation + + + + + + + + + + + + + misc_api + dlib/misc_api.h + dlib/misc_api/misc_api_kernel_abstract.h + + This is just a collection of miscellaneous APIs that were small/simple + enough not to warrant their own module. + + + + + misc_api_kernel_1 + dlib/misc_api/misc_api_kernel_1.h + + MS Windows implementation + + + + + misc_api_kernel_2 + dlib/misc_api/misc_api_kernel_2.h + + POSIX implementation + + + + + + + + + + + + + sockets + dlib/sockets.h + dlib/sockets/sockets_kernel_abstract.h + + This is a set of objects that provides an easy to use and object oriented + interface for dealing with TCP networking. There are currently two implementations, + one for UNIX and another for all versions of Windows after Windows95. + Both provide the exact same interface so programs written with them can be + recompiled on either platform without a problem. +

+ You also may want to take note of the timeout object. + It provides a mechanism which you can use to add a timeout to a network operation. +

+
+ + + sockets_ex.cpp.html + sockstreambuf_ex.cpp.html + sockets_ex_2.cpp.html + + + + + sockets_kernel_1 + dlib/sockets/sockets_kernel_1.h + + MS Windows implementation + + + + + sockets_kernel_2 + dlib/sockets/sockets_kernel_2.h + + POSIX implementation + + + + + + + + + sockets_extensions + dlib/sockets/sockets_extensions_abstract.h + +

+ This is just some miscellaneous extensions to the socket api. +

+ The implementation of this extension can be found + here. +
+
+ +
+ + +
+ + + + + + + threads + dlib/threads.h + dlib/threads/threads_kernel_abstract.h + + This is a set of objects that provides an easy to use and object oriented interface + for creating multi-threaded programs. There are currently two implementations, one + for UNIX and another for any variant of MS Windows after Windows 95. Both provide + the exact same interface so programs written with them can be recompiled on either + platform without a problem. Both implementations also pool their threads so repeated + calls to create_new_thread are nice and speedy :) +

+ You also probably want to take note of the pipe object. + It provides an easy to use typesafe mechanism to send messages between threads. +

+
+ + + threads_ex.cpp.html + logger_ex_2.cpp.html + pipe_ex.cpp.html + threaded_object_ex.cpp.html + multithreaded_object_ex.cpp.html + thread_function_ex.cpp.html + + + + + threads_kernel_1 + dlib/threads/threads_kernel_1.h + + MS Windows implementation + + + + + threads_kernel_2 + dlib/threads/threads_kernel_2.h + + POSIX implementation + + + + + + + + + rsignaler + dlib/threads/rsignaler_extension_abstract.h + +

+ This extension adds a signaler object that can be used with the rmutex object. + Also note that this extension is included by dlib/threads.h so you don't have to include + anything extra to get it. +

+ The implementation of this extension can be found + here. +
+
+ + + + thread_specific_data + dlib/threads/thread_specific_data_extension_abstract.h + +

+ This extension adds the ability to easily create thread specific data. +

+ The implementation of this extension can be found + here. +
+
+ + + + rmutex + dlib/threads/rmutex_extension_abstract.h + +

+ This extension adds a mutex object that can handle recursive calls + to lock(). + Also note that this extension is included by dlib/threads.h so you don't have to include + anything extra to get it. +

+ The implementation of this extension can be found + here. +
+
+ + + create_new_thread extension + dlib/threads/create_new_thread_extension_abstract.h + +

+ This extension adds some templated overloads to the + create_new_thread() function. They allow you to create new threads using member functions from a class. + Also note that this extension is included by dlib/threads.h so you don't have to include + anything extra to get it. +

+ The implementation of this extension can be found + here. +
+ + +
+ + + auto_mutex + dlib/threads/auto_mutex_extension_abstract.h + +

+ This extension adds a mechanism to automatically lock and unlock a mutex. + Also note that this extension is included by dlib/threads.h so you don't have to include + anything extra to get it. +

+ The implementation of this extension can be found + here. +
+ + +
+ + thread_function + dlib/threads/thread_function_extension_abstract.h + +

+ This object represents a thread on a global C++ function. That is, it allows you + to run a global function in its own thread. +

+ The implementation of this extension can be found + here. +
+ + + thread_function_ex.cpp.html + + + +
+ + + threaded_object + dlib/threads/threaded_object_extension_abstract.h + +

+ This extension represents a simple threaded object. It provides a convenient + mechanism to create an object that contains a thread. +

+ The implementation of this extension can be found + here. +
+ + + threaded_object_ex.cpp.html + + + +
+ + + multithreaded_object + dlib/threads/multithreaded_object_extension_abstract.h + +

+ This object represents a multithreaded object. It is similar to + the threaded_object except it allows you to have many threads in a + single object rather than just one. +

+ The implementation of this extension can be found + here. +
+ + + multithreaded_object_ex.cpp.html + pipe_ex.cpp.html + +
+ + + auto_unlock + dlib/threads/auto_unlock_extension_abstract.h + +

+ This extension adds a mechanism to automatically unlock a mutex. + Also note that this extension is included by dlib/threads.h so you don't have to include + anything extra to get it. +

+ The implementation of this extension can be found + here. +
+ + +
+
+ + + +
+ + + + + + + + gui_widgets + dlib/gui_widgets.h + +

+ This component is a collection of various windowing widgets such as buttons, + labels, text boxes, and so on. It also includes the drawable + interface, drawable_window, and font handling objects. + dlib/gui_widgets/widgets_abstract.h + defines all of the high level graphical widgets provided by this + component that can appear in a drawable_window. To view the specifications for the other members of this + component look at dlib/gui_widgets/fonts_abstract.h, + dlib/gui_widgets/drawable_abstract.h, + and dlib/gui_widgets/base_widgets_abstract.h. +

+

This component isn't actually a wrapper on top of OS APIs. Rather, it is + implemented on top of the gui_core + component. I put it on this page just because I expect that people would + look here when searching for the sort of functionality provided by this component. +

+
+ + + gui_api_ex.cpp.html + image_ex.cpp.html + bayes_net_gui_ex.cpp.html + +
+ + + + + +
+ + + + +
diff --git a/docs/docs/boost.png b/docs/docs/boost.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d51fcd5c9149fd77f5ca6ed2b6b1b70e8fe24f Binary files /dev/null and b/docs/docs/boost.png differ diff --git a/docs/docs/change_log.xml b/docs/docs/change_log.xml new file mode 100644 index 0000000000000000000000000000000000000000..dcbbb4f42626a261091ecf3ca04e9deec72ea47c --- /dev/null +++ b/docs/docs/change_log.xml @@ -0,0 +1,11 @@ + + + + + Change Log + +
+
Old Change Logs
+
+ +
diff --git a/docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE b/docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE2 b/docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE2 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE3 b/docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE3 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docs/docs/chm/README.txt b/docs/docs/chm/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab4a6df1aa0e61e58872bcb7870b0c3fbc42eca6 --- /dev/null +++ b/docs/docs/chm/README.txt @@ -0,0 +1,5 @@ +The Table of Contents.hhc file is auto generated by the toc.xml and htmlhelp_stylesheet.xsl files. +You really can edit it if you want but I suggest you use the stylesheet to auto generate it instead. + +If you want to regenerate the table of contents file you can do so with +the command "msxsl toc.xml htmlhelp_stylesheet.xsl" if you are using msxsl.exe. \ No newline at end of file diff --git a/docs/docs/chm/documentation.html b/docs/docs/chm/documentation.html new file mode 100644 index 0000000000000000000000000000000000000000..cfe2b69271ee004f797d1eb7169d827449d96f9e --- /dev/null +++ b/docs/docs/chm/documentation.html @@ -0,0 +1,20 @@ + + +dlib C++ library + + + + + + + + +

+ +click here to go to the documentation +

+ + + \ No newline at end of file diff --git a/docs/docs/chm/htmlhelp/hha.dll b/docs/docs/chm/htmlhelp/hha.dll new file mode 100644 index 0000000000000000000000000000000000000000..07518f2c1287c50005e997030fdea8984cb8012a Binary files /dev/null and b/docs/docs/chm/htmlhelp/hha.dll differ diff --git a/docs/docs/chm/htmlhelp/hhc.exe b/docs/docs/chm/htmlhelp/hhc.exe new file mode 100644 index 0000000000000000000000000000000000000000..9a1f31de1f0e9da543ae12502902f78f933fed2d Binary files /dev/null and b/docs/docs/chm/htmlhelp/hhc.exe differ diff --git a/docs/docs/chm/htmlhelp/htmlhelp.reg b/docs/docs/chm/htmlhelp/htmlhelp.reg new file mode 100644 index 0000000000000000000000000000000000000000..3d91e08b04d9256c8cd8a82aa2503660c36d6bbb --- /dev/null +++ b/docs/docs/chm/htmlhelp/htmlhelp.reg @@ -0,0 +1,5 @@ +REGEDIT4 + + +[HKEY_CURRENT_USER\Software\Wine\AppDefaults\hhc.exe\DllOverrides] +"itss"="native" diff --git a/docs/docs/chm/htmlhelp/itcc.dll b/docs/docs/chm/htmlhelp/itcc.dll new file mode 100644 index 0000000000000000000000000000000000000000..5e78ebb8ecfce2df6a237215c564ce3dbc2d1176 Binary files /dev/null and b/docs/docs/chm/htmlhelp/itcc.dll differ diff --git a/docs/docs/chm/htmlhelp/itircl.dll b/docs/docs/chm/htmlhelp/itircl.dll new file mode 100644 index 0000000000000000000000000000000000000000..85d1ec9ae8a819deecb0410bce7d70ca07525f30 Binary files /dev/null and b/docs/docs/chm/htmlhelp/itircl.dll differ diff --git a/docs/docs/chm/htmlhelp/itss.dll b/docs/docs/chm/htmlhelp/itss.dll new file mode 100644 index 0000000000000000000000000000000000000000..da3293be44c210077cf70028c23239ad13793ed8 Binary files /dev/null and b/docs/docs/chm/htmlhelp/itss.dll differ diff --git a/docs/docs/chm/htmlhelp/setup_htmlhelp.sh b/docs/docs/chm/htmlhelp/setup_htmlhelp.sh new file mode 100755 index 0000000000000000000000000000000000000000..5c10519190cc4a76e2104a08814d27bbbdc822cd --- /dev/null +++ b/docs/docs/chm/htmlhelp/setup_htmlhelp.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# Setup the registry +wine regedit htmlhelp.reg + +wine regsvr32 itcc.dll +wine regsvr32 itircl.dll + diff --git a/docs/docs/chm/htmlhelp_stylesheet.xsl b/docs/docs/chm/htmlhelp_stylesheet.xsl new file mode 100644 index 0000000000000000000000000000000000000000..ef1233711f85c0a3024dfb012021e0ce38a64083 --- /dev/null +++ b/docs/docs/chm/htmlhelp_stylesheet.xsl @@ -0,0 +1,223 @@ + + + + + + + + + + + abcdefghijklmnopqrstuvwxyz + ABCDEFGHIJKLMNOPQRSTUVWXYZ + + + + + + + +
    + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + +
  • + + +
  • +
      + + + + + + + +
    +
    + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + +
  • + + + + + + + + + + + + + +
  • + + + +
      + + + + + + + +
    +
    + +
      + + + + +
    +
    +
    +
    + + + +
  • + + + +
  • + + + +
      + + + +
    • + + + +
    • +
      + +
    • + + + +
    • +
      +
      +
      + + + + +
    • + + + +
    • +
      + +
    • + + + +
    • +
      +
      +
      +
      + +
    • + + + +
    • +
      + +
    • + + +
    • +
        + +
      • + + + +
      • +
        +
      +
      +
    +
    +
    +
    +
    +
    + + + +
      + + + + +
    +
    + + + + +
    diff --git a/docs/docs/chm/lib.hhp b/docs/docs/chm/lib.hhp new file mode 100644 index 0000000000000000000000000000000000000000..ba8dd69dadd288d56d9f82af7600dac3d81f4f14 --- /dev/null +++ b/docs/docs/chm/lib.hhp @@ -0,0 +1,52 @@ +[OPTIONS] +Binary TOC=Yes +Compatibility=1.1 or later +Compiled file=help.chm +Contents file=Table of Contents.hhc +Default topic=docs/index.html +Display compile progress=Yes +Full-text search=Yes +Language=0x409 English (United States) +Title=dLib + + +[FILES] +docs/api.html +docs/dlib/test/makefile +docs/right.gif +docs/down.gif +docs/plus.gif +docs/minus.gif +docs/change_log.html +docs/compile.html +docs/compress_stream_ex.cpp.html +docs/compression.html +docs/containers.html +docs/dir_nav_ex.cpp.html +docs/gui_api_ex.cpp.html +docs/index.html +docs/intro.html +docs/kernel_1a.html +docs/kernel_1b.html +docs/kernel_1c.html +docs/kernel_1da.html +docs/kernel_1db.html +docs/kernel_1ea.html +docs/kernel_1eb.html +docs/kernel_1ec.html +docs/kernel_2a.html +docs/kernel_3a.html +docs/kernel_3b.html +docs/license.html +docs/network.html +docs/other.html +docs/metaprogramming.html +docs/imaging.html +docs/parsing.html +docs/queue_ex.cpp.html +docs/release_notes.html +docs/old_release_notes.html +docs/sockets_ex.cpp.html + +[INFOTYPES] + diff --git a/docs/docs/chm/toc.xml b/docs/docs/chm/toc.xml new file mode 100644 index 0000000000000000000000000000000000000000..e1c5c255aca49b1cc16b32de75061793a76b6884 --- /dev/null +++ b/docs/docs/chm/toc.xml @@ -0,0 +1,10 @@ + + + + + docs + ../main_menu.xml + false + + + diff --git a/docs/docs/compile.xml b/docs/docs/compile.xml new file mode 100644 index 0000000000000000000000000000000000000000..ae47d6d00239c9aeb9bcbb90a555858c056e31fa --- /dev/null +++ b/docs/docs/compile.xml @@ -0,0 +1,230 @@ + + + + + How to compile + + + + + + + + +

    + + + +

    + To use this library all you have to do is extract the library somewhere, make sure the folder containing + the dlib folder is in your include path, and finally add dlib/all/source.cpp + to your project. +

    +

    + An example makefile that uses this library can be found here: + dlib/test/makefile. It is the makefile used to build the regression + test suite for this library. There is also a + CMake CMake makefile that builds the + regression test suite at dlib/test/CMakeLists.txt and another + CMake makefile that builds all the example programs at + examples/CMakeLists.txt +

    +

    + I try to make sure everything compiles fine under Visual Studio .NET 2003 (and above) and gcc. The compilers that will give you trouble are listed at the bottom of the page. +

    +

    + Again, note that you should not add the dlib folder itself to your compiler's include path. + Doing so will cause the + build to fail because of name collisions (such as dlib/string.h and string.h from the standard library). + Instead you should add the folder that contains the dlib folder to your include search path and then use + include statements of the form #include <dlib/queue.h>. This will ensure that everything + builds correctly. +

    + + +

    Preprocessor Directives

    + +

    + There are a few preprocessor directives that you can supply during the build process to cause the + library to build in various optional ways. The most people will probably not want + to mess with these at all and just use the library in its default build. But they are listed + here in the event that you need to use them. +

    + + DLIB_THREAD_POOL_TIMEOUT +

    #define DLIB_ISO_CPP_ONLY

    +

    + This is a #define directive that you can set to cause the library to exclude all non ISO C++ code (The things in the API wrappers section and any objects that depend on those wrappers). + This is useful if you are trying to build on a system that isn't fully supported by the library or if you + just decide you don't want any of that stuff compiled into your program for your own reasons. +

    + DLIB_NO_GUI_SUPPORT +

    #define DLIB_NO_GUI_SUPPORT

    +

    + This is just like the DLIB_ISO_CPP_ONLY option except that it excludes only the GUI part of the library. + An example of when you might want to use this would be if you don't need GUI support and you are building + on a UNIX platform that doesn't have the X11 headers installed. +

    + NO_MAKEFILE +

    #define NO_MAKEFILE

    +

    + This preprocessor directive causes the dlib headers to pull in all the + code that would normally be built in dlib/all/source.cpp. Thus if you #define NO_MAKEFILE you won't + have to add dlib/all/source.cpp to your project. The only time this is useful is when your + project consists of a single translation unit (i.e. a single cpp file). In this instance NO_MAKEFILE + allows you to easily build your project on the command line by saying something like g++ -DNO_MAKEFILE + project.cpp. But again, this is only for single cpp file projects. If you use NO_MAKEFILE with projects + that contain more than one cpp file you will get linker errors about multiply defined symbols. +

    + DLIB_THREAD_POOL_TIMEOUT +

    #define DLIB_THREAD_POOL_TIMEOUT <time-in-milliseconds>

    +

    + If you use the create_new_thread function + to create your threads then you receive the benefit of the dlib thread pool. This pool enables the create_new_thread + function to spawn new threads very rapidly since it draws threads back out of its thread pool when the pool isn't + empty. +

    +

    + Thus, when a thread that was created by create_new_thread ends it actually goes back into the dlib thread pool + and waits DLIB_THREAD_POOL_TIMEOUT milliseconds before totally terminating and releasing its resources back + to the operating system. The default timeout used by this library is 30,000 milliseconds (30 seconds). You + may however change this to whatever you like by defining DLIB_THREAD_POOL_TIMEOUT to some new value. +

    + DLIB_PNG_SUPPORT +

    #define DLIB_PNG_SUPPORT

    +

    + This preprocessor directive enables support for Portable Network Graphics (PNG) image files. So if you want + to be able to read them via the png_loader object you must + define this preprocessor directive. You must also ensure that you link to the + libpng library. Note that if you build using + the CMake file provided with the library it will automatically handle these things if libpng is + installed on your system. +

    + + +

    Compilers

    + + + + + +

    Visual Studio .NET 2003

    +

    You need to link to one of the multithreaded C run-time libraries if you are using the threading stuff. You can do + this by setting it in the project options. If you don't you will get some error about _beginthreadex not linking. +

    + + + +

    Visual C++ toolkit 2003

    +

    + This is a pretty good compiler and it is free. But it can be a major pain to use. + To get it working you have to download the platform sdk along with the toolkit itself. + both of these things are available from the microsoft web page for free. +

    +

    + Once you have the toolkit and platform sdk installed you should be ready to go. + Go to start -> programs -> microsoft visual c++ toolkit 2003 -> Visual C++ Toolkit 2003 Command Prompt. Then switch to the directory that contains your source and the dlib folder. +

    +

    + The following is the command I use and yours should look similar: + cl /O2 -DNO_MAKEFILE /EHsc /MT "%1"
    + The %1 should be replaced with the cpp file(s) you want to compile. +

    + +

    + You may also have to tell the compiler where the include and lib folders are in the platform sdk. + If the above command doesn't work try this one (change paths appropriately for your system): + cl /O2 -DNO_MAKEFILE /EHsc /MT /I"C:\Program Files\Microsoft Platform SDK\Include" "%1" /link /LIBPATH:"C:\Program Files\Microsoft Platform SDK\Lib\" +

    + + + + + + +

    gcc

    +

    + I generally use gcc version 4.1 but most other versions of gcc work just fine also (except 2.95, see below). +

    +

    + The command line I generally use is "g++ -D NO_MAKEFILE -lnsl -lpthread file.cpp" I think you need to + tell it to link nsl to make the threading stuff work right, I honestly can't remember what part of + the library requires it I have just been doing it for so long :) +

    +

    + If you are using the sockets stuff then on some platforms you need to supply the -lsocket option. Or if you are using the gui stuff you will need to supply the -lX11 option. +

    +

    + If you compile on solaris you have to give the -lsocket + option if you use the sockets API. +

    +

    gcc on windows

    +

    + The commands for gcc on windows are the same as above but you may also have to link (via the -l option) to the following libraries: gdi32, + comctl32, user32, or ws2_32. +

    + + + + + + + + + + + + + + + + + +

    Problem Compilers

    +

    + Below is a list of the problems I can remember with various compilers. All the problems here are + bugs in the compiler and are a pain to write workarounds for (or the workarounds are slow/unsatisfactory) so I have no plans to deal with them. Just avoid these compilers in the + given situations. +

    + + + + + +
  • Visual Studio .NET and earlier versions +
      + These compilers don't compile standard C++ very well. Visual Studio 6 + doesn't even make any pretenses about being standards compliant. Visual Studio .NET is a lot + better but has some bugs with how it implements namespace lookups so most of my code will not + compile in Visual Studio .NET. (Note that Visual Studio .NET 2003 works just fine) +
    + + + + + +
  • gcc 2.95 +
      +

      + The dir_nav component will not be able to list directories that contain files bigger than 4GB because + I had to use stat() rather than stat64() when compiling under this compiler. +

      +

      + There are also some other problems with gcc 2.95. + I believe all the containers work and all the API wrappers + but the GUI stuff works. It is sort of touch and go though. +

      +
    + + + + + + + + + + + + + diff --git a/docs/docs/compression.xml b/docs/docs/compression.xml new file mode 100644 index 0000000000000000000000000000000000000000..06d044da779eb6fb135b8f6f55d5b09b4d190c56 --- /dev/null +++ b/docs/docs/compression.xml @@ -0,0 +1,882 @@ + + + + + Data Compression + + + + +

    +

    + This page contains a bunch of objects that implement various parts of compression algorithms. + They can be put together in different ways to construct many different algorithms. + Note that the compress_stream object contains complete compression algorithms. So if you + just want to compress some data then you can easily use that object and not bother with the others. +

    +

    + In the column to the right you can see benchmark data for each of the compress_stream + typedefs. The times measured are the time it takes to compress and then + decompress each file. It was run on a 3.0ghz P4. For reference see the Canterbury corpus + web site. +

    + + + + + + + + + +
    + Objects + compress_stream + conditioning_class + entropy_decoder + entropy_encoder + entropy_decoder_model + entropy_encoder_model + lz77_buffer + lzp_buffer +
    + + + + +
    + Benchmarks + + kernel_1a + kernel_1a.html + + + kernel_1b + kernel_1b.html + + + kernel_1c + kernel_1c.html + + + kernel_1da + kernel_1da.html + + + kernel_1db + kernel_1db.html + + + kernel_1ea + kernel_1ea.html + + + kernel_1eb + kernel_1eb.html + + + kernel_1ec + kernel_1ec.html + + + kernel_2a + kernel_2a.html + + + kernel_3a + kernel_3a.html + + + kernel_3b + kernel_3b.html + +
    +
    +
    + + + + + + + + + + + + compress_stream + dlib/compress_stream.h + dlib/compress_stream/compress_stream_kernel_abstract.h + + This object is pretty straight forward. It has no state and just + contains the functions compress and decompress. + They do just what their names imply to iostream objects. + + + + compress_stream_ex.cpp.html + file_to_code_ex.cpp.html + + + + + compress_stream_kernel_1 + dlib/compress_stream/compress_stream_kernel_1.h + + This implementation is done using the entropy_encoder_model and + entropy_decoder_model objects. + + + + + + kernel_1a + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_1b and entropy_decoder_model_kernel_1b + + + kernel_1b + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_2b and entropy_decoder_model_kernel_2b + + + kernel_1c + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_3b and entropy_decoder_model_kernel_3b + + + kernel_1da + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_4a and entropy_decoder_model_kernel_4a + + + kernel_1db + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_4b and entropy_decoder_model_kernel_4b + + + kernel_1ea + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_5a and entropy_decoder_model_kernel_5a + + + kernel_1eb + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_5b and entropy_decoder_model_kernel_5b + + + kernel_1ec + is a typedef for compress_stream_kernel_1 which uses entropy_decoder_model_kernel_5c and entropy_decoder_model_kernel_5c + + + + + + + compress_stream_kernel_2 + dlib/compress_stream/compress_stream_kernel_2.h + + This implementation is done using the entropy_encoder_model and + entropy_decoder_model objects. It also uses the + lz77_buffer object. It uses the entropy coder models to + encode symbols when there is no match found by the lz77_buffer. + + + + + + kernel_2a + is a typedef for compress_stream_kernel_2 which uses entropy_encoder_model_kernel_2b, entropy_decoder_model_kernel_2b, and lz77_buffer_kernel_2a. + + + + + + + + compress_stream_kernel_3 + dlib/compress_stream/compress_stream_kernel_3.h + + This implementation is done using the the lzp_buffer object and + crc32 object. It does not use any sort of entropy coding, instead + a byte aligned output method is used. + + + + + + kernel_3a + is a typedef for compress_stream_kernel_3 which uses lzp_buffer_kernel_1. + + + kernel_3b + is a typedef for compress_stream_kernel_3 which uses lzp_buffer_kernel_2. + + + + + + + + + + + + + + conditioning_class + dlib/conditioning_class.h + dlib/conditioning_class/conditioning_class_kernel_abstract.h + + This object represents a conditioning class used for arithmetic style + compression. It maintains the cumulative counts which are needed + by the entropy_encoder and entropy_decoder objects below. + + + + + conditioning_class_kernel_1 + dlib/conditioning_class/conditioning_class_kernel_1.h + + This implementation is done using an array to store all the counts and they are summed + whenever the cumulative counts are requested. It's pretty straight forward. + + + + + kernel_1a + is a typedef for conditioning_class_kernel_1 + + + + + + conditioning_class_kernel_2 + dlib/conditioning_class/conditioning_class_kernel_2.h + + This implementation is done using a binary tree where each node in the tree represents one symbol and + contains that symbols count and the sum of all the counts for the nodes to the left. This way + when you request a cumulative count it can be computed by visiting log n nodes where n is the + size of the alphabet. + + + + + kernel_2a + is a typedef for conditioning_class_kernel_2 + + + + + + + conditioning_class_kernel_3 + dlib/conditioning_class/conditioning_class_kernel_3.h + + This implementation is done using an array to store all the counts and they are + summed whenever the cumulative counts are requested. The counts are also kept in + semi-sorted order to speed up the calculation of the cumulative count. + + + + + kernel_3a + is a typedef for conditioning_class_kernel_3 + + + + + + + conditioning_class_kernel_4 + dlib/conditioning_class/conditioning_class_kernel_4.h + + This implementation is done using a linked list to store all the counts and they are + summed whenever the cumulative counts are requested. The counts are also kept in + semi-sorted order to speed up the calculation of the cumulative count. This implementation + also uses the memory_manager component to create a + memory pool of linked list nodes. This implementation is especially useful for high order + contexts and/or very large and sparce alphabets. + + + + + + kernel_4a + is a typedef for conditioning_class_kernel_4 with a memory pool of 10,000 nodes. + + + kernel_4b + is a typedef for conditioning_class_kernel_4 with a memory pool of 100,000 nodes. + + + kernel_4c + is a typedef for conditioning_class_kernel_4 with a memory pool of 1,000,000 nodes. + + + kernel_4d + is a typedef for conditioning_class_kernel_4 with a memory pool of 10,000,000 nodes. + + + + + + + + + + + + + entropy_decoder + dlib/entropy_decoder.h + dlib/entropy_decoder/entropy_decoder_kernel_abstract.h + + This object represents an entropy decoder. E.g. the decoding part of + an arithmetic coder. + + + + + entropy_decoder_kernel_1 + dlib/entropy_decoder/entropy_decoder_kernel_1.h + + This object is implemented using arithmetic coding and is done in the + straight forward way using integers and fixed precision math. + + + + + kernel_1a + is a typedef for entropy_decoder_kernel_1 + + + + + + entropy_decoder_kernel_2 + dlib/entropy_decoder/entropy_decoder_kernel_2.h + + This object is implemented using "range" coding and is done + in the straight forward way using integers and fixed precision math. + + + + + kernel_2a + is a typedef for entropy_decoder_kernel_2 + + + + + + + + + + + + + + entropy_encoder + dlib/entropy_encoder.h + dlib/entropy_encoder/entropy_encoder_kernel_abstract.h + + This object represents an entropy encoder. E.g. the encoding part of + an arithmetic coder. + + + + + entropy_encoder_kernel_1 + dlib/entropy_encoder/entropy_encoder_kernel_1.h + + This object is implemented using arithmetic coding and is done in the + straight forward way using integers and fixed precision math. + + + + + kernel_1a + is a typedef for entropy_encoder_kernel_1 + + + + + + entropy_encoder_kernel_2 + dlib/entropy_encoder/entropy_encoder_kernel_2.h + + This object is implemented using "range" coding and is done + in the straight forward way using integers and fixed precision math. + + + + + kernel_2a + is a typedef for entropy_encoder_kernel_2 + + + + + + + + + + + + + + entropy_decoder_model + dlib/entropy_decoder_model.h + dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h + + This object represents some kind of statistical model. You + can use it to read symbols from an entropy_decoder and it will calculate + the cumulative counts/probabilities and manage contexts for you. + + + + + entropy_decoder_model_kernel_1 + dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h + + This object is implemented using the conditioning_class component. + It implements an order-0 finite context model and uses lazy exclusions and update exclusions. + The escape method used is method D. + + + + + kernel_1a + is a typedef for entropy_decoder_model_kernel_1 that uses conditioning_class_kernel_1a + + + kernel_1b + is a typedef for entropy_decoder_model_kernel_1 that uses conditioning_class_kernel_2a + + + kernel_1c + is a typedef for entropy_decoder_model_kernel_1 that uses conditioning_class_kernel_3a + + + + + + + entropy_decoder_model_kernel_2 + dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h + + This object is implemented using the conditioning_class component. + It implements an order-1-0 finite context model and uses lazy exclusions and update exclusions. + The escape method used is method D. + + + + + kernel_2a + is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_1a + + + kernel_2b + is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_2a + + + kernel_2c + is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_3a + + + kernel_2d + is a typedef for entropy_decoder_model_kernel_2 that uses conditioning_class_kernel_2a for its order-0 + context and conditioning_class_kernel_4b for its order-1 context. + + + + + + + entropy_decoder_model_kernel_3 + dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h + + This object is implemented using the conditioning_class component. + It implements an order-2-1-0 finite context model and uses lazy exclusions and update exclusions. + The escape method used is method D. + + + + + kernel_3a + is a typedef for entropy_decoder_model_kernel_3 that uses conditioning_class_kernel_1a for orders 0 and 1 + and conditioning_class_kernel_4b for order-2. + + + kernel_3b + is a typedef for entropy_decoder_model_kernel_3 that uses conditioning_class_kernel_2a for orders 0 and 1 + and conditioning_class_kernel_4b for order-2. + + + kernel_3c + is a typedef for entropy_decoder_model_kernel_3 that uses conditioning_class_kernel_3a for orders 0 and 1 + and conditioning_class_kernel_4b for order-2. + + + + + + + entropy_decoder_model_kernel_4 + dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h + + This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing + the PPM data compression scheme." + It provides template arguments to select the maximum order and maximum memory to use. For speed, + exclusions are not used. The escape method used is method D. + + + + + kernel_4a + is a typedef for entropy_decoder_model_kernel_4 with the max order set to 4 and the max number + of nodes set to 200,000 + + + kernel_4b + is a typedef for entropy_decoder_model_kernel_4 with the max order set to 5 and the max number + of nodes set to 1,000,000 + + + + + + + entropy_decoder_model_kernel_5 + dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h + + This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing + the PPM data compression scheme." + It provides template arguments to select the maximum order and maximum memory to use. Exclusions are used. The escape method used is method D. + This implementation is very much like kernel_4 except it is tuned for higher compression rather than speed. + This also uses Dmitry Shkarin's Information Inheritance scheme. + + + + + kernel_5a + is a typedef for entropy_decoder_model_kernel_5 with the max order set to 4 and the max number + of nodes set to 200,000 + + + kernel_5b + is a typedef for entropy_decoder_model_kernel_5 with the max order set to 5 and the max number + of nodes set to 1,000,000 + + + kernel_5c + is a typedef for entropy_decoder_model_kernel_5 with the max order set to 7 and the max number + of nodes set to 2,500,000 + + + + + + + entropy_decoder_model_kernel_6 + dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h + + This object just assigns every symbol the same probability. I.e. it uses an order-(-1) model. + + + + + kernel_6a + is a typedef for entropy_decoder_model_kernel_6 + + + + + + + + + + + + + + + entropy_encoder_model + dlib/entropy_encoder_model.h + dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h + + This object represents some kind of statistical model. You + can use it to write symbols to an entropy_encoder and it will calculate + the cumulative counts/probabilities and manage contexts for you. + + + + + entropy_encoder_model_kernel_1 + dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h + + This object is implemented using the conditioning_class component. + It implements an order-0 finite context model and uses lazy exclusions and update exclusions. + The escape method used is method D. + + + + + kernel_1a + is a typedef for entropy_encoder_model_kernel_1 that uses conditioning_class_kernel_1a + + + kernel_1b + is a typedef for entropy_encoder_model_kernel_1 that uses conditioning_class_kernel_2a + + + kernel_1c + is a typedef for entropy_encoder_model_kernel_1 that uses conditioning_class_kernel_3a + + + + + + + entropy_encoder_model_kernel_2 + dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h + + This object is implemented using the conditioning_class component. + It implements an order-1-0 finite context model and uses lazy exclusions and update exclusions. + The escape method used is method D. + + + + + kernel_2a + is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_1a + + + kernel_2b + is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_2a + + + kernel_2c + is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_3a + + + kernel_2d + is a typedef for entropy_encoder_model_kernel_2 that uses conditioning_class_kernel_2a for its order-0 + context and conditioning_class_kernel_4b for its order-1 context. + + + + + + + entropy_encoder_model_kernel_3 + dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h + + This object is implemented using the conditioning_class component. + It implements an order-2-1-0 finite context model and uses lazy exclusions and update exclusions. + The escape method used is method D. + + + + + kernel_3a + is a typedef for entropy_encoder_model_kernel_3 that uses conditioning_class_kernel_1a for orders 0 and 1 + and conditioning_class_kernel_4b for order-2. + + + kernel_3b + is a typedef for entropy_encoder_model_kernel_3 that uses conditioning_class_kernel_2a for orders 0 and 1 + and conditioning_class_kernel_4b for order-2. + + + kernel_3c + is a typedef for entropy_encoder_model_kernel_3 that uses conditioning_class_kernel_3a for orders 0 and 1 + and conditioning_class_kernel_4b for order-2. + + + + + + + entropy_encoder_model_kernel_4 + dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h + + This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing + the PPM data compression scheme." + It provides template arguments to select the maximum order and maximum memory to use. For speed, + exclusions are not used. The escape method used is method D. + + + + + kernel_4a + is a typedef for entropy_encoder_model_kernel_4 with the max order set to 4 and the max number + of nodes set to 200,000 + + + kernel_4b + is a typedef for entropy_encoder_model_kernel_4 with the max order set to 5 and the max number + of nodes set to 1,000,000 + + + + + + + entropy_encoder_model_kernel_5 + dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h + + This object is implemented using a variation of the PPM algorithm described by Alistair Moffat in his paper "Implementing + the PPM data compression scheme." + It provides template arguments to select the maximum order and maximum memory to use. Exclusions are used. The escape method used is method D. + This implementation is very much like kernel_4 except it is tuned for higher compression rather than speed. + This also uses Dmitry Shkarin's Information Inheritance scheme. + + + + + kernel_5a + is a typedef for entropy_encoder_model_kernel_5 with the max order set to 4 and the max number + of nodes set to 200,000 + + + kernel_5b + is a typedef for entropy_encoder_model_kernel_5 with the max order set to 5 and the max number + of nodes set to 1,000,000 + + + kernel_5c + is a typedef for entropy_encoder_model_kernel_5 with the max order set to 7 and the max number + of nodes set to 2,500,000 + + + + + + + entropy_encoder_model_kernel_6 + dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h + + This object just assigns every symbol the same probability. I.e. it uses an order-(-1) model. + + + + + kernel_6a + is a typedef for entropy_encoder_model_kernel_6 + + + + + + + + + + + + + + + lz77_buffer + dlib/lz77_buffer.h + dlib/lz77_buffer/lz77_buffer_kernel_abstract.h + + This object represents a pair of buffers (history and lookahead buffers) + used during lz77 style compression. + + + + + lz77_buffer_kernel_1 + dlib/lz77_buffer/lz77_buffer_kernel_1.h + + This object is implemented using the sliding_buffer and it + just does simple linear searches of the history buffer to find matches. + + + + + kernel_1a + is a typedef for lz77_buffer_kernel_1 that uses sliding_buffer_kernel_1 + + + + + + lz77_buffer_kernel_2 + dlib/lz77_buffer/lz77_buffer_kernel_2.h + + This object is implemented using the sliding_buffer. It + finds matches by using a hash table. + + + + + kernel_2a + is a typedef for lz77_buffer_kernel_2 that uses sliding_buffer_kernel_1 + + + + + + + + + + + + + + lzp_buffer + dlib/lzp_buffer.h + dlib/lzp_buffer/lzp_buffer_kernel_abstract.h + + This object represents some varation on the LZP algorithm + described by Charles Bloom in his paper "LZP: a new data + compression algorithm" + + + + + lzp_buffer_kernel_1 + dlib/lzp_buffer/lzp_buffer_kernel_1.h + + This object is implemented using the sliding_buffer and uses + an order-3 model to predict matches. + + + + + kernel_1a + is a typedef for lzp_buffer_kernel_1 that uses sliding_buffer_kernel_1 + + + + + + lzp_buffer_kernel_2 + dlib/lzp_buffer/lzp_buffer_kernel_2.h + + This object is implemented using the sliding_buffer and uses + an order-5-4-3 model to predict matches. + + + + + kernel_2a + is a typedef for lzp_buffer_kernel_2 that uses sliding_buffer_kernel_1 + + + + + + + + + + + + + + + + +
    diff --git a/docs/docs/containers.xml b/docs/docs/containers.xml new file mode 100644 index 0000000000000000000000000000000000000000..85bc7787d141b7960db5124f1b7834ce6db4abf4 --- /dev/null +++ b/docs/docs/containers.xml @@ -0,0 +1,1345 @@ + + + + + Containers + + + + +

    +

    + Many of these containers were inspired by the RESOLVE/C++ course sequence at Ohio State. As such, most of + the objects do not support copying in any form, only swapping is allowed. That is, when objects + are added or removed from any of these containers they are swapped in and out, not copied. + + This allows you to do things like have containers of containers of containers without encountering the + overhead of the massive copying that would likely result if you did the same thing with the STL. +

    + +

    + To use any of these containers all you need to do is #include the file indicated in the + short section about the component you would like to use. Then pick which implementation you + would like and typedef it to something nice. Here is an example of creating a typedef for + a set of integers using the first kernel implementation.
    + typedef dlib::set<int>::kernel_1a set_of_ints; +

    + + +

    + Note that it is assumed by these containers that swap() and operator< do not throw. They + may not function correctly if this assumption is broken. Also note that the built in types (int, long, + char, etc...) and std::string will not cause operator< or swap() to throw. +

    + + + + + + + + +
    + Objects + static_set + array + array2d + binary_search_tree + hash_map + hash_set + hash_table + directed_graph + graph + map + matrix + queue + reference_counter + sequence + set + stack + std_vector_c + static_map + sliding_buffer + tuple + + smart pointers + + scoped_ptr + shared_ptr + weak_ptr + + + +
    + +
    + Interfaces + map_pair + enumerable + + remover + + + remover + dlib/interfaces/remover.h.html#remover + + + asc_remover + dlib/interfaces/remover.h.html#asc_remover + + + pair_remover + dlib/interfaces/remover.h.html#pair_remover + + + asc_pair_remover + dlib/interfaces/remover.h.html#asc_pair_remover + + + +
    +
    +
    + + + + + + + + + array + dlib/array.h + dlib/array/array_kernel_abstract.h + + This object is just like a C style array and the accessor functions operate + in constant time. + + + + + array_kernel_1 + dlib/array/array_kernel_1.h + + This implementation is done using an array of pointers, each of which point to + small sections of the array. This implementation allows the array to use only + about as much memory as it needs at any given time. + It does not use the memory_manager at all. + + + + + + kernel_1a + is a typedef for array_kernel_1 + + + + + + + array_kernel_2 + dlib/array/array_kernel_2.h + + This implementation is done using a single array of max_size() elements. So this + is just a simple layer on top of a C style array. + It uses the memory_manager for all + memory allocations. + + + + + + kernel_2a + is a typedef for array_kernel_2 + + + + + + + + + + array_sort + dlib/array/array_sort_abstract.h + + This extension gives an array the ability to sort its contents. + + + + + array_sort_1 + dlib/array/array_sort_1.h + + This is a version of the QuickSort algorithm. It swaps the entire array into a C + style array, sorts it and then swaps it back into the array object. + + + + + sort_1a + is a typedef for array_kernel_1a extended by array_sort_1 + + + sort_1b + is a typedef for array_kernel_2a extended by array_sort_1 + + + + + + array_sort_2 + dlib/array/array_sort_2.h + + This is a version of the QuickSort algorithm. + + + + + sort_2a + is a typedef for array_kernel_1a extended by array_sort_2 + + + sort_2b + is a typedef for array_kernel_2a extended by array_sort_2 + + + + + + + + + + + + + array_expand + dlib/array/array_expand_abstract.h + + This extension gives an array the ability to expand its size() beyond + its max_size() without clearing out all its elements. It also adds a set of pop/push_back() + functions similar to the ones in the std::vector object. + + + + + array_expand_1 + dlib/array/array_expand_1.h + + This is implemented by creating a new bigger array if max_size() isn't big enough, + swapping everything into that new array, and then swapping that array with *this. + + + + + expand_1a + is a typedef for array_sort_1a extended by array_expand_1 + + + expand_1b + is a typedef for array_sort_1b extended by array_expand_1 + + + expand_1c + is a typedef for array_sort_2a extended by array_expand_1 + + + expand_1d + is a typedef for array_sort_2b extended by array_expand_1 + + + + + + + + + + + + + + + + + + + + sliding_buffer + dlib/sliding_buffer.h + dlib/sliding_buffer/sliding_buffer_kernel_abstract.h + + This object represents an array with the ability to rotate its contents + left or right. + + + + + sliding_buffer_kernel_1 + dlib/sliding_buffer/sliding_buffer_kernel_1.h + + This object is implemented using a C style array in the obvious way. See the code for details. + + + + + kernel_1a + is a typedef for sliding_buffer_kernel_1 + + + + + + + + + + + + + + array2d + dlib/array2d.h + dlib/array2d/array2d_kernel_abstract.h + + This object represents a 2-Dimensional array of objects. + + + + image_ex.cpp.html + + + + + array2d_kernel_1 + dlib/array2d/array2d_kernel_1.h + + This is implemented in the obvious way. See the source for details. + It uses the memory_manager for all memory allocations. + + + + + kernel_1a + is a typedef for array2d_kernel_1 + + + + + + + + + + + + binary_search_tree + dlib/binary_search_tree.h + dlib/binary_search_tree/binary_search_tree_kernel_abstract.h + + This object represents a data dictionary that is built on top of some kind of binary search tree. + + + + + binary_search_tree_kernel_1 + dlib/binary_search_tree/binary_search_tree_kernel_1.h + + This implementation is done using an AVL binary search tree. It uses the + memory_manager for all memory allocations. + + + + + kernel_1a + is a typedef for binary_search_tree_kernel_1 + + + + + + binary_search_tree_kernel_2 + dlib/binary_search_tree/binary_search_tree_kernel_2.h + + This implementation is done using a red-black binary search tree. It uses the + memory_manager for all memory allocations. + + + + kernel_2a + is a typedef for binary_search_tree_kernel_2 + + + + + + + + + + + + + + hash_map + dlib/hash_map.h + dlib/hash_map/hash_map_kernel_abstract.h + + This object represents a hashed mapping of items of type domain onto items of type range. + + + + + hash_map_kernel_1 + dlib/hash_map/hash_map_kernel_1.h + + This implementation is done using a hash_table object. It uses the + memory_manager for all memory allocations. + + + + + + + kernel_1a + is a typedef for hash_map_kernel_1 that uses hash_table_kernel_1a + + + kernel_1b + is a typedef for hash_map_kernel_1 that uses hash_table_kernel_2a + + + kernel_1c + is a typedef for hash_map_kernel_1 that uses hash_table_kernel_2b + + + + + + + + + + + + + + + + hash_set + dlib/hash_set.h + dlib/hash_set/hash_set_kernel_abstract.h + + This object represents a hashed unordered and unaddressed collection of unique items. + + + + + hash_set_kernel_1 + dlib/hash_set/hash_set_kernel_1.h + + This implementation is done using a hash_table object. It uses the + memory_manager for all memory allocations. + + + + + + + kernel_1a + is a typedef for hash_set_kernel_1 that uses hash_table_kernel_1a + + + kernel_1b + is a typedef for hash_set_kernel_1 that uses hash_table_kernel_2a + + + kernel_1c + is a typedef for hash_set_kernel_1 that uses hash_table_kernel_2b + + + + + + + + + + + + + + + + hash_table + dlib/hash_table.h + dlib/hash_table/hash_table_kernel_abstract.h + + This object represents a data dictionary that is built on top of some kind of + hash table. + + + + + hash_table_kernel_1 + dlib/hash_table/hash_table_kernel_1.h + + This implementation is done using singly linked lists as hashing buckets. It uses the + memory_manager for all memory allocations. + + + + + + kernel_1a + is a typedef for hash_table_kernel_1. + + + + + + + hash_table_kernel_2 + dlib/hash_table/hash_table_kernel_2.h + + This implementation is done using + binary_search_tree objects as hashing buckets. It uses the + memory_manager for all memory allocations. + + + + + + + kernel_2a + is a typedef for hash_table_kernel_2 that uses binary_search_tree_kernel_1 + + + kernel_2b + is a typedef for hash_table_kernel_2 that uses binary_search_tree_kernel_2 + + + + + + + + + + + + + + + + + map + dlib/map.h + dlib/map/map_kernel_abstract.h + + This object represents a mapping of items of type domain onto items of type range. + + + + + map_kernel_1 + dlib/map/map_kernel_1.h + + This is implemented using the binary_search_tree component. It uses the + memory_manager for all memory allocations. + + + + + + + kernel_1a + is a typedef for map_kernel_1 that uses binary_search_tree_kernel_1 + + + kernel_1b + is a typedef for map_kernel_1 that uses binary_search_tree_kernel_2 + + + + + + + + + + + + + + + + + enumerable + dlib/interfaces/enumerable.h + dlib/interfaces/enumerable.h + + This object is an abstract class which represents an interface for iterating over + all the elements of a container. + + + + + + + + + + map_pair + dlib/interfaces/map_pair.h + dlib/interfaces/map_pair.h + + This object is an abstract class which represents an interface for accessing a + pair from a container such as the map, hash_table, etc... + + + + + + + + + + remover + dlib/interfaces/remover.h + dlib/interfaces/remover.h + + This is a set of interfaces which gives the ability to remove all the items in a + container without actually knowing what kind of container contains them. + + + + + + + + + + weak_ptr + dlib/smart_pointers.h + dlib/smart_pointers/weak_ptr_abstract.h + +

    + The weak_ptr class template stores a weak reference to an object that is + already managed by a shared_ptr. To access the object, a weak_ptr can + be converted to a shared_ptr using the member function lock(). +

    + +

    + This is an implementation of the std::tr1::weak_ptr template from the + document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++ + Library Extensions. The only deviation from that document is that this + shared_ptr is declared inside the dlib namespace rather than std::tr1. +

    +
    + +
    + + + + + shared_ptr + dlib/smart_pointers.h + dlib/smart_pointers/shared_ptr_abstract.h + +

    + This object represents a reference counted smart pointer. Each shared_ptr + contains a pointer to some object and when the last shared_ptr that points + to the object is destructed or reset() then the object is guaranteed to be + deleted. +

    + +

    + This is an implementation of the std::tr1::shared_ptr template from the + document ISO/IEC PDTR 19768, Proposed Draft Technical Report on C++ + Library Extensions. The only deviation from that document is that this + shared_ptr is declared inside the dlib namespace rather than std::tr1. +

    +
    + +
    + + + + + tuple + dlib/tuple.h + dlib/tuple/tuple_abstract.h + + This is an implementation of a very simple templated container object. + It contains between 0 and 31 objects where each object is listed + explicity in the tuple's template arguments. + +

    + Note that there is only one implementation of this object so there aren't any + different kernels to choose from when you create instances of the matrix object. + So for example, you + could declare a tuple of 3 ints using the following statement: + dlib::tuple<int,int,int> t; +

    +
    + +
    + + + + + scoped_ptr + dlib/smart_pointers.h + dlib/smart_pointers/scoped_ptr_abstract.h + + This is a implementation of the scoped_ptr class found in the Boost C++ + library. It is a simple smart pointer class which guarantees that the + pointer contained within it will always be deleted. + + The class does not permit copying and so does not do any kind of + reference counting. Thus it is very simple and quite fast. + + + + + + + + graph + dlib/graph.h + dlib/graph/graph_kernel_abstract.h + + This object represents a graph which is a set of nodes with undirected + edges connecting various nodes. + + + + + graph_kernel_1 + dlib/graph/graph_kernel_1.h + + This is implemented using std::vector to contain all the nodes and edges. + + + + + kernel_1a + is a typedef for graph_kernel_1 + + + + + + + + + + + + directed_graph + dlib/directed_graph.h + dlib/directed_graph/directed_graph_kernel_abstract.h + + This object represents a directed graph which is a set of nodes with directed + edges connecting various nodes. + + + + + directed_graph_kernel_1 + dlib/directed_graph/directed_graph_kernel_1.h + + This is implemented using std::vector to contain all the nodes and edges. + + + + + kernel_1a + is a typedef for directed_graph_kernel_1 + + + + + + + + + + + + + queue + dlib/queue.h + dlib/queue/queue_kernel_abstract.h + + This object represents a first in first out queue. + + + + dir_nav_ex.cpp.html + queue_ex.cpp.html + + + + + queue_kernel_1 + dlib/queue/queue_kernel_1.h + + This is implemented in the obvious way using a singly linked list. It does not use the + memory_manager at all. + + + + + kernel_1a + is a typedef for queue_kernel_1 + + + + + + queue_kernel_2 + dlib/queue/queue_kernel_2.h + + This is implemented using a singly linked list and each node in the list + contains block_size (a template parameter) elements. It uses the + memory_manager for all memory allocations. + + + + + kernel_2a + is a typedef for queue_kernel_2 with a block_size of 20 + + + kernel_2b + is a typedef for queue_kernel_2 with a block_size of 100 + + + + + + + + + queue_sort + dlib/queue/queue_sort_abstract.h + + This extension gives a queue the ability to sort its contents. + + + + + queue_sort_1 + dlib/queue/queue_sort_1.h + + This is a version of the QuickSort algorithm. + + + + + sort_1a + is a typedef for queue_kernel_1a extended by queue_sort_1 + + + sort_1b + is a typedef for queue_kernel_2a extended by queue_sort_1 + + + sort_1c + is a typedef for queue_kernel_2b extended by queue_sort_1 + + + + + + + + + + + + + + + + + + + reference_counter + dlib/reference_counter.h + dlib/reference_counter/reference_counter_kernel_abstract.h + + This object represents a container for an object and provides reference counting + capabilities for the object it contains. + + + + + reference_counter_kernel_1 + dlib/reference_counter/reference_counter_kernel_1.h + + This implementation is done using pointers in the obvious way. + + + + + kernel_1a + is a typedef for reference_counter_kernel_1 + + + + + + + + + + + + + + + sequence + dlib/sequence.h + dlib/sequence/sequence_kernel_abstract.h + + This object represents an ordered sequence of items, each item is + associated with an integer value. The items are numbered from 0 to the number of items in the + sequence minus 1. + + + + + sequence_kernel_1 + dlib/sequence/sequence_kernel_1.h + + This is implemented as an AVL binary search tree. + Accessing(or adding or removing) an element always takes O(log n) time. + It uses the memory_manager for all memory allocations. + + + + + kernel_1a + is a typedef for sequence_kernel_1 + + + + + + sequence_kernel_2 + dlib/sequence/sequence_kernel_2.h + + This implementation is done using a doubly linked list in the shape of a ring. + It will remember the last element accessed(or added or removed) and give O(1) + access time to the elements just left and right of it. Aside from that, + accessing(or adding or removing) a random element will take O(n) and in the worst + case it will take time proportional to the size of the sequence/2. +

    + It does not use the + memory_manager at all. +

    + +
    + + + + kernel_2a + is a typedef for sequence_kernel_2 + + + +
    +
    + + + + + sequence_sort + dlib/sequence/sequence_sort_abstract.h + + This extension gives a sequence the ability to sort its contents. + + + + + sequence_sort_1 + dlib/sequence/sequence_sort_1.h + + This is a version of the QuickSort algorithm and it sorts sequences of less + than 30 elements with a selection sort. This implementation is fastest when + used with sequence_kernel_2 and fairly slow when used with sequence_kernel_1 + + + + + sort_1a + is a typedef for sequence_kernel_2a extended by sequence_sort_1 + + + + + + sequence_sort_2 + dlib/sequence/sequence_sort_2.h + + This is a version of the QuickSort algorithm. This implementation of sort is + the best to use with sequence_kernel_1 objects but gives extremely poor performance + with sequence_kernel_2 objects. + + + + + sort_2a + is a typedef for sequence_kernel_1a extended by sequence_sort_2 + + + + + + + + + + sequence_compare + dlib/sequence/sequence_compare_abstract.h + + This extension gives sequences the ability to compare themselves using + operator< and operator==. Thus they can be used in the other container classes + that require this ability. (maps, sets, etc...) + + + + + sequence_compare_1 + dlib/sequence/sequence_compare_1.h + + The implementation is obvious. Click on the sequence_compare_1 link if you want to see. + + + + + compare_1a + is a typedef for sequence_kernel_1a extended by sequence_compare_1 + + + compare_1b + is a typedef for sequence_kernel_2a extended by sequence_compare_1 + + + + + + + + + + + +
    + + + + + + + set + dlib/set.h + dlib/set/set_kernel_abstract.h + + This object represents an unordered and unaddressed collection of unique items. + + + + + set_kernel_1 + dlib/set/set_kernel_1.h + + This is implemented using the binary_search_tree component. It uses the + memory_manager for all memory allocations. + + + + + + kernel_1a + is a typedef for set_kernel_1 that uses binary_search_tree_kernel_1 + + + kernel_1b + is a typedef for set_kernel_1 that uses binary_search_tree_kernel_2 + + + + + + + + + + + set_compare + dlib/set/set_compare_abstract.h + + This extension gives sets the ability to compare themselves using operator< and + operator==. Thus they can be used in the other container classes that require + this ability. (maps, sets, etc...) + + + + + set_compare_1 + dlib/set/set_compare_1.h + + The implementation is obvious. Click on the set_compare_1 link if you want to see. + + + + + compare_1a + is a typedef for set_kernel_1a extended by set_compare_1 + + + compare_1b + is a typedef for set_kernel_1b extended by set_compare_1 + + + + + + + + + + + + + + + + + + stack + dlib/stack.h + dlib/stack/stack_kernel_abstract.h + + This object represents a last in first out stack. + + + + + stack_kernel_1 + dlib/stack/stack_kernel_1.h + + This implementation is done in the obvious way using a singly linked list. It uses the + memory_manager for all memory allocations. + + + + + + kernel_1a + is a typedef for stack_kernel_1 + + + + + + + + + + + + + + static_map + dlib/static_map.h + dlib/static_map/static_map_kernel_abstract.h + + This object represents a mapping of items of type domain onto items of type range. + The difference between this object and the normal map object is that it does not support adding + or removing individual objects from itself. This allows implementations to focus on using less memory and + achieving faster searching. + + + + + static_map_kernel_1 + dlib/static_map/static_map_kernel_1.h + + This implementation is just a sorted array which can be searched using a binary search. + + + + + kernel_1a + is a typedef for static_map_kernel_1 + + + + + + + + + + + + + + static_set + dlib/static_set.h + dlib/static_set/static_set_kernel_abstract.h + + This object represents an unordered and unaddressed collection of items. + The difference between this object and the normal set object is that it does not support adding + or removing individual objects from itself. This allows implementations to focus on using less memory and + achieving faster searching. + + + + dir_nav_ex.cpp.html + + + + + static_set_kernel_1 + dlib/static_set/static_set_kernel_1.h + + This implementation is just a sorted array which can be searched using a binary search. + + + + + kernel_1a + is a typedef for static_set_kernel_1 + + + + + + + + + + + static_set_compare + dlib/static_set/static_set_compare_abstract.h + + This extension gives static_sets the ability to compare themselves using operator< and + operator==. Thus they can be used in the other container classes that require + this ability. (maps, static_sets, etc...) + + + + + static_set_compare_1 + dlib/static_set/static_set_compare_1.h + + The implementation is obvious. Click on the static_set_compare_1 link if you want to see. + + + + + compare_1a + is a typedef for static_set_kernel_1a extended by static_set_compare_1 + + + + + + + + + + + + + + + + + matrix + dlib/matrix.h + dlib/matrix/matrix_abstract.h + + This is a 2D matrix object. It is implemented using the expression templates + technique which allows us to eliminate the temporary matrix objects that would + normally be returned from expressions such as M = A+B+C+D; Normally each + invocation of the + operator would construct and return a temporary matrix + object but using this technique we can avoid creating all of these temporary + objects and receive a large speed boost. +

    + Note that there is only one implementation of this object so there aren't any + different kernels to choose from when you create instances of the matrix object. + So for example, you + could declare a matrix of 2 rows and 3 columns using the following statement: + dlib::matrix<float,2,3> m; +

    +

    + It should also be noted that matrix multiplication is fastest when the two matrices + being multiplied are not complex matrix_exp objects returned from other expressions + (such as other matrix multiplies). This is because the matrix multiply operator will + evaluate each element of the matrices it is multiplying many times, and a matrix_exp + computes its elements' values each time they are queried. However, the matrix multiply + operator is the only one that evaluates its argument's elements multiple times so you can + stack up all the other operators however you want without any performance penalty. If + you want to multiply two complex matrix_exp expressions together you can easily convert them into + fully evaluated temporary matrix objects by using the tmp() function. For example, to + multiply four matrices together you should use an expression such as result = tmp(a*b)*tmp(c*d); +

    +
    + + + matrix_ex.cpp.html + + + + + matrix_utilities + dlib/matrix/matrix_utilities_abstract.h + This extension contains miscellaneous utility functions + for manipulating matrix objects. Note that you don't need to #include + anything to get them. They are included by the dlib/matrix.h file for you. + + + + matrix_math_functions + dlib/matrix/matrix_math_functions_abstract.h + This extension contains mathematical functions that operate on each + element of a matrix independently. Note that you don't need to #include + anything to get them. They are included by the dlib/matrix.h file for you. + + + + +
    + + + + + + std_vector_c + dlib/stl_checked.h + dlib/stl_checked/std_vector_c_abstract.h + + This object is a simple wrapper around the std::vector object. It + provides an identical interface but also checks the preconditions of + each member function. That is, if you violate a requires + clause the dlib::fatal_error exception is thrown. + + + + + +
    + + + + +
    diff --git a/docs/docs/down.gif b/docs/docs/down.gif new file mode 100644 index 0000000000000000000000000000000000000000..3bd1263b7fdcfe5d24ba2173bdd9d7019ee14ef4 Binary files /dev/null and b/docs/docs/down.gif differ diff --git a/docs/docs/enable_if.html b/docs/docs/enable_if.html new file mode 100644 index 0000000000000000000000000000000000000000..d9a540986d975e74495af6149f06f8a25f71aa1c --- /dev/null +++ b/docs/docs/enable_if.html @@ -0,0 +1,387 @@ + + +enable_if + + + + + + + + + + +
    +
    + + +

    +enable_if

    +
    +
    +Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.
    +
    + + +

    1  Introduction

    + + +The enable_if family of templates is a set of tools to allow a function template or a class template specialization +to include or exclude itself from a set of matching functions or specializations +based on properties of its template arguments. +For example, one can define function templates that +are only enabled for, and thus only match, an arbitrary set of types +defined by a traits class. The enable_if templates can also be +applied to enable class template specializations. Applications of +enable_if are discussed in length +in [1] and [2].
    +
    + + +

    1.1  Synopsis

    + + +
    namespace boost {
    +  template <class Cond, class T = void> struct enable_if;
    +  template <class Cond, class T = void> struct disable_if;
    +  template <class Cond, class T> struct lazy_enable_if;
    +  template <class Cond, class T> struct lazy_disable_if;
    +
    +  template <bool B, class T = void> struct enable_if_c;
    +  template <bool B, class T = void> struct disable_if_c;
    +  template <bool B, class T> struct lazy_enable_if_c;
    +  template <bool B, class T> struct lazy_disable_if_c;
    +}
    +
    + + +

    1.2  Background

    + + +Sensible operation of template function overloading in C++ relies +on the SFINAE (substitution-failure-is-not-an-error) +principle [3]: if an invalid argument +or return type is formed during the instantiation of a function +template, the instantiation is removed from the overload resolution +set instead of causing a compilation error. The following example, +taken from [1], +demonstrates why this is important: +
    int negate(int i) { return -i; }
    +
    +template <class F>
    +typename F::result_type negate(const F& f) { return -f(); }
    +
    +
    +Suppose the compiler encounters the call negate(1). The first +definition is obviously a better match, but the compiler must +nevertheless consider (and instantiate the prototypes) of both +definitions to find this out. Instantiating the latter definition with +F as int would result in: +
    int::result_type negate(const int&);
    +
    +
    +where the return type is invalid. If this was an error, adding an unrelated function template +(that was never called) could break otherwise valid code. +Due to the SFINAE principle the above example is not, however, erroneous. +The latter definition of negate is simply removed from the overload resolution set.
    +
    +The enable_if templates are tools for controlled creation of the SFINAE +conditions.
    +
    + + +

    2  The enable_if templates

    + + +The names of the enable_if templates have three parts: an optional lazy_ tag, +either enable_if or disable_if, and an optional _c tag. +All eight combinations of these parts are supported. +The meaning of the lazy_ tag is described in Section 3.3. +The second part of the name indicates whether a true condition argument should +enable or disable the current overload. +The third part of the name indicates whether the condition argument is a bool value +(_c suffix), or a type containing a static bool constant named value (no suffix). +The latter version interoperates with Boost.MPL.
    +
    +The definitions of enable_if_c and enable_if are as follows (we use enable_if templates +unqualified but they are in the boost namespace). +
    template <bool B, class T = void>
    +struct enable_if_c {
    +  typedef T type;
    +};
    +
    +template <class T>
    +struct enable_if_c<false, T> {};
    +
    +template <class Cond, class T = void>
    +struct enable_if : public enable_if_c<Cond::value, T> {};
    +
    +
    +An instantiation of the enable_if_c template with the parameter +B as true contains a member type type, defined +to be T. If B is +false, no such member is defined. Thus +enable_if_c<B, T>::type is either a valid or an invalid type +expression, depending on the value of B. +When valid, enable_if_c<B, T>::type equals T. +The enable_if_c template can thus be used for controlling when functions are considered for +overload resolution and when they are not. +For example, the following function is defined for all arithmetic types (according to the +classification of the Boost type_traits library): +
    template <class T>
    +typename enable_if_c<boost::is_arithmetic<T>::value, T>::type 
    +foo(T t) { return t; }
    +
    +
    +The disable_if_c template is provided as well, and has the +same functionality as enable_if_c except for the negated condition. The following +function is enabled for all non-arithmetic types. +
    template <class T>
    +typename disable_if_c<boost::is_arithmetic<T>::value, T>::type 
    +bar(T t) { return t; }
    +
    +
    +For easier syntax in some cases and interoperation with Boost.MPL we provide versions of +the enable_if templates taking any type with a bool member constant named +value as the condition argument. +The MPL bool_, and_, or_, and not_ templates are likely to be +useful for creating such types. Also, the traits classes in the Boost.Type_traits library +follow this convention. +For example, the above example function foo can be alternatively written as: +
    template <class T>
    +typename enable_if<boost::is_arithmetic<T>, T>::type 
    +foo(T t) { return t; }
    +
    +
    + + +

    3  Using enable_if

    + + +The enable_if templates are defined in +boost/utility/enable_if.hpp, which is included by boost/utility.hpp.
    +
    +The enable_if template can be used either as the return type, or as an +extra argument. For example, the foo function in the previous section could also be written +as: +
    template <class T>
    +T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0); 
    +
    +
    Hence, an extra parameter of type void* is added, but it is given +a default value to keep the parameter hidden from client code. +Note that the second template argument was not given to enable_if, as the default +void gives the desired behavior.
    +
    +Whether to write the enabler as an argument or within the return type is +largely a matter of taste, but for certain functions, only one +alternative is possible: +
    • +Operators have a fixed number of arguments, thus enable_if must be used in the return type. +
    • Constructors and destructors do not have a return type; an extra argument is the only option. +
    • There does not seem to be a way to specify an enabler for a conversion operator. Converting constructors, +however, can have enablers as extra default arguments. +
    + + +

    3.1  Enabling template class specializations

    + + +Class template specializations can be enabled or disabled with enable_if. +One extra template parameter needs to be added for the enabler expressions. +This parameter has the default value void. +For example: +
    template <class T, class Enable = void> 
    +class A { ... };
    +
    +template <class T>
    +class A<T, typename enable_if<is_integral<T> >::type> { ... };
    +
    +template <class T>
    +class A<T, typename enable_if<is_float<T> >::type> { ... };
    +
    +
    Instantiating A with any integral type matches the first specialization, +whereas any floating point type matches the second one. All other types +match the primary template. +The condition can be any compile-time boolean expression that depends on the +template arguments of the class. +Note that again, the second argument to enable_if is not needed; the default (void) +is the correct value.
    +
    + + +

    3.2  Overlapping enabler conditions

    + + +Once the compiler has examined the enabling conditions and included the +function into the overload resolution set, normal C++ overload resolution +rules are used to select the best matching function. +In particular, there is no ordering between enabling conditions. +Function templates with enabling conditions that are not mutually exclusive can +lead to ambiguities. For example: +
    template <class T>
    +typename enable_if<boost::is_integral<T>, void>::type 
    +foo(T t) {}
    +
    +template <class T>
    +typename enable_if<boost::is_arithmetic<T>, void>::type 
    +foo(T t) {}
    +
    +
    +All integral types are also arithmetic. Therefore, say, for the call foo(1), +both conditions are true and both functions are thus in the overload resolution set. +They are both equally good matches and thus ambiguous. +Of course, more than one enabling condition can be simultaneously true as long as +other arguments disambiguate the functions.
    +
    +The above discussion applies to using enable_if in class template +partial specializations as well.
    +
    + + +

    3.3  Lazy enable_if

    + + +In some cases it is necessary to avoid instantiating part of a +function signature unless an enabling condition is true. For example: +
    template <class T, class U> class mult_traits;
    +
    +template <class T, class U>
    +typename enable_if<is_multipliable<T, U>, typename mult_traits<T, U>::type>::type
    +operator*(const T& t, const U& u) { ... }
    +
    +
    Assume the class template mult_traits is a traits class defining +the resulting type of a multiplication operator. The is_multipliable traits +class specifies for which types to enable the operator. Whenever +is_multipliable<A, B>::value is true for some types A and B, +then mult_traits<A, B>::type is defined.
    +
    +Now, trying to invoke (some other overload) of operator* with, say, operand types C and D +for which is_multipliable<C, D>::value is false +and mult_traits<C, D>::type is not defined is an error on some compilers. +The SFINAE principle is not applied because +the invalid type occurs as an argument to another template. The lazy_enable_if +and lazy_disable_if templates (and their _c versions) can be used in such +situations: +
    template<class T, class U>
    +typename lazy_enable_if<is_multipliable<T, U>, mult_traits<T, U> >::type
    +operator*(const T& t, const U& u) { ... }
    +
    +
    The second argument of lazy_enable_if must be a class type +that defines a nested type named type whenever the first +parameter (the condition) is true.
    +
    + + +
    Note
    + +Referring to one member type or static constant in a traits class +causes all of the members (type and static constant) of that +specialization to be instantiated. Therefore, if your traits classes +can sometimes contain invalid types, you should use two distinct +templates for describing the conditions and the type mappings. In the +above example, is_multipliable<T, U>::value defines when +mult_traits<T, U>::type is valid.
    +
    + + +

    3.4  Compiler workarounds

    + + +Some compilers flag functions as ambiguous if the only distinguishing factor is a different +condition in an enabler (even though the functions could never be ambiguous). For example, +some compilers (e.g. GCC 3.2) diagnose the following two functions as ambiguous: +
    template <class T>
    +typename enable_if<boost::is_arithmetic<T>, T>::type 
    +foo(T t);
    +
    +template <class T>
    +typename disable_if<boost::is_arithmetic<T>, T>::type 
    +foo(T t);
    +
    +
    Two workarounds can be applied: +
    • +Use an extra dummy parameter which disambiguates the functions. Use a default value for +it to hide the parameter from the caller. For example: +
      template <int> struct dummy { dummy(int) {} };
      +
      +template <class T>
      +typename enable_if<boost::is_arithmetic<T>, T>::type 
      +foo(T t, dummy<0> = 0);
      +
      +template <class T>
      +typename disable_if<boost::is_arithmetic<T>, T>::type 
      +foo(T t, dummy<1> = 0);
      +

      +
      +
    • Define the functions in different namespaces and bring them into a common +namespace with using declarations: +
      namespace A {
      +  template <class T>
      +  typename enable_if<boost::is_arithmetic<T>, T>::type 
      +  foo(T t);
      +}
      +
      +namespace B {
      +  template <class T>
      +  typename disable_if<boost::is_arithmetic<T>, T>::type 
      +  foo(T t);
      +}
      +
      +using A::foo;
      +using B::foo;
      +
      +
      +Note that the second workaround above cannot be used for member +templates. On the other hand, operators do not accept extra arguments, +which makes the first workaround unusable. As the net effect, +neither of the workarounds are of assistance for templated operators that +need to be defined as member functions (assignment and +subscript operators). +
    + + +

    4  Acknowledgements

    + +We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides, and Richard +Smith whose findings have influenced the library.
    +
    + + +

    References

    +
    [1]
    +Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine. +Function overloading based on arbitrary properties of types. +C/C++ Users Journal, 21(6):25--32, June 2003.
    +
    +
    [2]
    +Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine. +Concept-controlled polymorphism. +In Frank Pfennig and Yannis Smaragdakis, editors, Generative + Programming and Component Engineering, volume 2830 of LNCS, pages + 228--244. Springer Verlag, September 2003.
    +
    +
    [3]
    +David Vandevoorde and Nicolai M. Josuttis. +C++ Templates: The Complete Guide. +Addison-Wesley, 2002.
    + + + + + +
    + +Contributed by:
    +Jaakko Järvi, Jeremiah Willcock and Andrew Lumsdaine
    +{jajarvi|jewillco|lums}@osl.iu.edu
    +Indiana University
    +Open Systems Lab + + + +
    +
    This document was translated from LATEX by +HEVEA. +
    + + diff --git a/docs/docs/imaging.xml b/docs/docs/imaging.xml new file mode 100644 index 0000000000000000000000000000000000000000..a9678b43f2f77790f69fcb5a8c790df03979d9d3 --- /dev/null +++ b/docs/docs/imaging.xml @@ -0,0 +1,544 @@ + + + + + Imaging + + + + +

    + +

    + This page documents the functionality present in this library that deals with the + management and manipulation of images. One thing to note is that there is no + explicit image object. Instead, everything deals with + array2d objects that contain various kinds of pixels. +

    + + + + + + + +
    + Objects + rgb_pixel + rgb_alpha_pixel + hsi_pixel + pixel_traits + png_loader +
    + +
    + Global Functions + assign_pixel + assign_pixel_intensity + get_pixel_intensity + load_bmp + draw_line + save_bmp + load_dng + save_dng + assign_image + assign_all_pixels + assign_border_pixels + equalize_histogram + edge_orientation + get_histogram + spatially_filter_image + + hysteresis_threshold + sobel_edge_detector + suppress_non_maximum_edges + zero_border_pixels + + threshold_image + auto_threshold_image + binary_dilation + binary_erosion + binary_open + binary_close + binary_intersection + binary_union + binary_difference + binary_complement +
    + +
    +
    + + + + + + + + + + + pixel_traits + dlib/pixel.h + dlib/pixel.h + + As the name implies, this is a traits class for pixel types. It allows you + to determine what sort of pixel type you are dealing with. + + + + + + + + hsi_pixel + dlib/pixel.h + dlib/pixel.h + + This is a simple struct that represents an HSI colored graphical pixel. Note that + since this is just a struct with no member functions there is only one + "implementation" of this object. + + + + + + + + rgb_alpha_pixel + dlib/pixel.h + dlib/pixel.h + + This is a simple struct that represents an RGB colored graphical pixel with an + alpha channel. Note that + since this is just a struct with no member functions there is only one + "implementation" of this object. + + + + + + + + rgb_pixel + dlib/pixel.h + dlib/pixel.h + + This is a simple struct that represents an RGB colored graphical pixel. Note that + since this is just a struct with no member functions there is only one + "implementation" of this object. + + + + + + + + assign_pixel + dlib/pixel.h + dlib/pixel.h + + assign_pixel() is a templated function that can assign any pixel type to another pixel type. + It will perform whatever conversion is necessary to make the assignment work. (E.g. color to + grayscale conversion) + + + + + + + + assign_pixel_intensity + dlib/pixel.h + dlib/pixel.h + + assign_pixel_intensity() is a templated function that can change the + intensity of a pixel. So if the pixel in question is a grayscale pixel + then it simply assigns that pixel the given value. However, if the + pixel is not a grayscale pixel then it converts the pixel to the + HSI color space and sets the I channel to the given intensity + and then converts this HSI value back to the original pixel's + color space. + + + + + + + + get_pixel_intensity + dlib/pixel.h + dlib/pixel.h + + get_pixel_intensity() is a templated function that + returns the grayscale intensity of a pixel. If the pixel isn't a grayscale + pixel then it converts the pixel to the HSI color space and returns the + obtained intensity value. + + + + + + + + png_loader + dlib/image_io.h + dlib/image_loader/png_loader_abstract.h + + This object loads a Portable Network Graphics (PNG) image file into + an array2d of pixels. +

    + Note that you must define DLIB_PNG_SUPPORT if you want to use this object. You + must also set your build environment to link to the libpng library. +

    +
    + +
    + + + + + load_dng + dlib/image_io.h + dlib/image_loader/image_loader_abstract.h + + This global function loads a dlib DNG file (a lossless compressed image format) into + an array2d of pixels. + + + + + + + + save_dng + dlib/image_io.h + dlib/image_saver/image_saver_abstract.h + + This global function writes an image out to an ostream as a dlib DNG file (a lossless + compressed image format). + + + + + + + + load_bmp + dlib/image_io.h + dlib/image_loader/image_loader_abstract.h + + This global function loads a MS Windows BMP file into an array2d of + pixels. + + + + image_ex.cpp.html + + + + + + + + save_bmp + dlib/image_io.h + dlib/image_saver/image_saver_abstract.h + + This global function writes an image out to an ostream as a MS Windows BMP file. + + + + + + + + draw_line + dlib/image_transforms.h + dlib/image_transforms/draw_abstract.h + + This global function draws a line onto an image. + + + + + + + + assign_border_pixels + dlib/image_transforms.h + dlib/image_transforms/assign_image_abstract.h + + This global function assigns all the pixels in the border of an image to + a specific value. + + + + + + + + + assign_all_pixels + dlib/image_transforms.h + dlib/image_transforms/assign_image_abstract.h + + This global function assigns all the pixels in an image a specific value. + + + + + + + + assign_image + dlib/image_transforms.h + dlib/image_transforms/assign_image_abstract.h + + This global function copies one image into another and performs any + necessary color space conversions to make it work right. + + + + + + + + get_histogram + dlib/image_transforms.h + dlib/image_transforms/equalize_histogram_abstract.h + + This global function computes an image's histogram and returns it in the + form of a column or row matrix object. + + + + + + + + edge_orientation + dlib/image_transforms.h + dlib/image_transforms/edge_detector_abstract.h + + This global function takes horizontal and vertical gradient magnitude + values and returns the orientation of the gradient. + + + + + + + + + equalize_histogram + dlib/image_transforms.h + dlib/image_transforms/equalize_histogram_abstract.h + + This global function performs histogram equalization on an image. + + + + + + + + hysteresis_threshold + dlib/image_transforms.h + dlib/image_transforms/thresholding_abstract.h + + This global function performs hysteresis thresholding on an image. + + + + + + + + sobel_edge_detector + dlib/image_transforms.h + dlib/image_transforms/edge_detector_abstract.h + + This global function performs spatial filtering on an image using the + sobel edge detection filters. + + + + image_ex.cpp.html + + + + + + + suppress_non_maximum_edges + dlib/image_transforms.h + dlib/image_transforms/edge_detector_abstract.h + + This global function performs non-maximum suppression on a gradient + image. + + + + image_ex.cpp.html + + + + + + + + zero_border_pixels + dlib/image_transforms.h + dlib/image_transforms/assign_image_abstract.h + + This global function zeros the pixels on the border of an image. + + + + + + + + spatially_filter_image + dlib/image_transforms.h + dlib/image_transforms/spatial_filtering_abstract.h + + This global function performs spatial filtering on an image with a user + supplied filter. + + + + + + + + auto_threshold_image + dlib/image_transforms.h + dlib/image_transforms/thresholding_abstract.h + + This global function performs a simple binary thresholding on an image with a user + supplied threshold. However, instead of taking a user supplied threshold + it computes one from the image using k-means clustering. + + + + + + + + threshold_image + dlib/image_transforms.h + dlib/image_transforms/thresholding_abstract.h + + This global function performs a simple binary thresholding on an image with a user + supplied threshold. + + + + + + + + binary_dilation + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function performs the morphological operation of dilation on an image. + + + + + + + + binary_erosion + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function performs the morphological operation of erosion on an image. + + + + + + + + binary_open + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function performs a morphological opening on an image. + + + + + + + + binary_close + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function performs a morphological closing on an image. + + + + + + + + binary_intersection + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function computes the intersection of two binary images. + + + + + + + + binary_union + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function computes the union of two binary images. + + + + + + + + binary_difference + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function computes the difference of two binary images. + + + + + + + + binary_complement + dlib/image_transforms.h + dlib/image_transforms/morphological_operations_abstract.h + + This global function computes the complement of a binary image. + + + + + + +
    + + + + +
    + diff --git a/docs/docs/index.xml b/docs/docs/index.xml new file mode 100644 index 0000000000000000000000000000000000000000..c9cf8580652b20f53f1f5abe52f6030658490f1b --- /dev/null +++ b/docs/docs/index.xml @@ -0,0 +1,171 @@ + + + + + + + + +

    dlib C++ library

    +

    + + +

    + Welcome to the dlib C++ library's homepage. + Welcome to the dlib C++ library documentation. + + It is a modern C++ library with a focus on portability + and program correctness. It strives to be easy to use right and hard to use wrong. + Thus, it comes with extensive documentation and thorough debugging modes. +

    + +

    + The library is open source software and is licensed + under the Boost Software License. + + The introduction contains everything you need to know to get + started using the library. However, if you have any questions, comments, or complaints feel free to + email me or post in the + sourceforge Forums. + + +

    + + +

    + For updates to this project check its sourceforge page at http://dclib.sourceforge.net. +

    +
    + +
    + +

    +

    Major Features

    +
      +
    • Documentation +
        +
      • Unlike a lot of open source projects, this one provides complete and precise + documentation for every class and function. There are also debugging modes that check the + documented preconditions for functions. When this is enabled it will catch the vast majority of + bugs caused by calling functions incorrectly or using objects in an incorrect manner. +
      • +
      • Lots of example programs are provided
      • +
      • I consider the documentation to be the most important part of the library. So if you find anything + that isn't documented, isn't clear, or has out of date documentation, tell me and I will fix it. +
      • +
      +
    • + +
    • Portable Code +
        +
      • All non ISO C++ code is isolated inside the OS abstraction layers which are kept as small as possible. + The rest of the library is either layered on top of the OS + abstraction layers or is pure ISO C++.
      • +
      • Big/little endian agnostic
      • +
      • No other packages are required to use the library. Only APIs that are + provided by an out of the box OS are used.
      • +
      • The library is tested regularly on win32, Linux, and Mac OS X systems. However, it should + work on any POSIX system and has been tested on Solaris, HPUX, and the BSDs.
      • +
      +
    • +
    • Threading + +
    • + +
    • Networking +
        +
      • The library provides a portable and simple TCP sockets API
      • +
      • An object to help you make TCP based servers
      • +
      • A streambuf object that enables TCP sockets + to interoperate with the C++ iostreams library
      • +
      • A simple HTTP server object you can use to embed a + web server into your applications
      • +
      +
    • + +
    • Graphical User Interfaces +
        +
      • The library provides a portable and simple core GUI API
      • +
      • Implemented on top of the core GUI API are numerous widgets
      • +
      • Unlike many other GUI toolkits, the entire dlib GUI toolkit is threadsafe
      • +
      +
    • + + +
    • Numerical Algorithms + +
    • + +
    • Machine Learning Algorithms + +
    • + +
    • Image Processing +
        +
      • Windows BMP read and write support
      • +
      • Automatic color space conversion between various pixel types
      • +
      • Common image operations such as edge finding and morphological operations
      • +
      +
    • + +
    • Data Compression and Integrity Algorithms +
        +
      • A CRC 32 object
      • +
      • MD5 functions
      • +
      • Various abstracted objects representing parts of data compression + algorithms. Many forms of the PPM algorithm are included.
      • +
      +
    • + +
    • Testing + +
    • + +
    • General Utilities + +
    • +
    + +

    + + + + + + +
    diff --git a/docs/docs/intro.xml b/docs/docs/intro.xml new file mode 100644 index 0000000000000000000000000000000000000000..717b5d0b61d483e98696773f891f0a4e3b6dbdfd --- /dev/null +++ b/docs/docs/intro.xml @@ -0,0 +1,400 @@ + + + + + Introduction + + + + + + +

    + + + + + + + + + + +

    Overview

    + +

    + This library is a collection of various C++ objects I have created and found to be useful + over the last few years. Generally speaking, there is no focus on any specific domain + in the library, it mostly contains general utility sorts of things. One of the bigger + and more notable features is the API abstraction layer which allows you to create portable applications + that make use of TCP sockets, threads, file browsing, and simple graphical user interfaces. There + is, however, much more than just that. +

    +

    + This library also aims to be simple, portable, and modern. Everything is developed with the + Design by Contract + methodology. You can read about Design by Contract on the internet + for more information but from + the point of view of a user of this library it basically means that there exists complete and precise + documentation and aggressive debugging modes that can be enabled. +

    +

    + I always try to make sure everything is as portable as possible. All platform specific code is + confined inside the API wrappers. Everything else is either layered on top of those wrappers + or is written in pure ISO standard C++. Currently the library is known to work on OS X, + MS Windows, Linux, Solaris, the BSDs, and HP-UX. It should work on any POSIX platform but I + haven't had the opportunity to test it on any others (if you have access to other platforms and + would like to help increase this list then let me know). +

    +

    + The rest of this page explains everything you need to know to get started using the library. It + explains where to find the documentation for each object/function and how to interpret + what you find there. For help compiling with dlib check out the how to compile + page. Or if you are having trouble finding where a particular object's documentation is located you may + be able to find it by consulting the index.

    +

    + The library is also covered by the very liberal Boost Software License so feel free to use it + however you like. +

    +

    + Much of the organization and notation used in this library I learned from the + Software Component Engineering + course sequence at OSU. As such, this library is heavily influenced by the Design by Contract and + generic programming methodologies. +

    + + + + + +

    Notation

    +

    + For the most part I try to document my code in a way that any C++ programmer would understand + but for the sake of brevity I use some of the following uncommon notation. +

    + +
      +
    • kernel, extension, and abstract +
        + Each component of the library has a specification which defines its core behavior and interface. This + specification defines what is called the component's kernel. Additionally, each component may have any number of + extensions. An extension is essentially a specification for something that layers functionality on top of the + kernel of a component. +
        +
        In the naming of files I use the word abstract to indicate that a file + contains a specification of a kernel component or extension rather than an actual implementation. +
      + + + + +
    • /*! comments like this !*/ +
        + This is just for "formal comments." Generally these appear after a function prototype and contain + the requires/ensures stuff or at the top of a class and tell you general things about the class. +
      + + + + +
    • requires/ensures/throws +
        + These words appear in the formal comment following function prototypes and have the following meanings. +
        requires: This defines a list of requirements for calling the function. These requirements + MUST be met or a call to the function has undefined results. (note that when the checking/debugging modes + are enabled on an object then it will throw the dlib::fatal_error exception with fatal_error::type == EBROKEN_ASSERT when the requires clause is + broken rather than causing "undefined results") +
        ensures: This defines what the function does. It is a list of conditions that will be + true after the function finishes executing. Note that if an exception is thrown or the function returns + indicating an error occurred then nothing in the ensures clause is guaranteed to be true. +
        throws: This defines what exceptions may be thrown by this function. It generally + tells you why the exception might be thrown. It also tells you what the function does in this event: + Does it have no effect at all? Does it corrupt any objects? etc... + +
        +
        + Sometimes these blocks do not appear in the formal comment. The meanings in these cases are as follows: +
        missing requires: There are no requirements, you may put anything in the function arguments. +
        missing ensures: This means that the effects of the function are unspecified. This is often used + for call backs where the client programmer implements the actual function. +
        missing throws: This means that the function does not throw anything. + +
        +
        + So in summary, the requires clause must always be satisfied, the ensures clause tells you what the + function does when it does not throw or return an error, and the throws clause tells you what happens when the function + does throw. + +
      + + + +
    • meaning_of_hash meaning of # symbol +
        + I use this as a prefix on identifiers to make reference to the value of the identifier "after" + some event has occurred. +

        + The most common place I use this notation is inside the formal comment following a function prototype. + If the # symbol appears in a requires/ensures/throws block then it means the value of + the identifier after the function has finished, otherwise all references to an identifier + refer to its value before the function was called. +

        + An example will make it clear. + + +
        int funct(
        +    int& something
        +);
        +/*!
        +    requires
        +        - something > 4     
        +    ensures
        +        - #some_other_function() == 9
        +        - #funct() == something 
        +        - #something == something + 1
        +!*/
        +                
        + + This says that funct() requires that "something" be greater than 4, that funct() will increment "something" + by 1, and funct() returns the original value of something. It also says that + after the call to funct() ends a call to some_other_function() will return the value 9. + +
      + +
    • CONVENTION CONVENTION +
        + This is a section of the formal comment which appears at the top of all classes which are + actual implementations (as opposed to specifications). This section of the comment contains + a list of invariants that tell you what the member variables are used for. It also relates + the state of the member variables to the class interface. +
        +
        + For example, you might see a line in this section that says "my_size == size()". This just means + that the member variable my_size always contains the value returned by the size() function. +
      + + + + +
    • "initial value for its type" +
        + I frequently say that after a function executes some variable or argument will have an + initial value for its type. This makes sense for objects with a user defined constructor, + but for anything else not so much. Therefore the initial value of a type with no user defined + constructor is undefined. +
      + +
    + + + + + + +

    Organization

    + +

    + The library can be thought of as a collection of components. + Each component consists of one "kernel" specification that defines exactly what the + component's interface looks like and what it does. Additionally each component may + have extensions to its kernel. Each kernel and extension specification can have many implementations. + +

    + + +
      + +
    • File organization +
        + Each component gets its own folder and one file in the root of the directory tree. +

        + I will use the queue object as a typical example and + explain what each of its files contain. + Below is the directory structure and all the files related to the queue component. + +

        +
        • file tree +
            +
          • dlib/ +
              +
            • queue.h +
            • queue/ +
                +
              • queue_kernel_abstract.h +
              • queue_kernel_1.h +
              • queue_kernel_2.h +
              • queue_kernel_c.h +
              • queue_sort_abstract.h +
              • queue_sort_1.h +
              +
            +
          + + +
          + +
        • queue.h +
            This file does not contain any executable code. All it does is define the typedefs such as + kernel_1a, kernel_1a_c, etc... for the queue object. See the Creating Objects + section to learn what these typedefs are for. +
          + +
        • queue_kernel_abstract.h +
            + This file does not contain any code. It even has preprocessor directives that prevent + any of its contents from being included. +
            +
            + The purpose of this file is to define exactly what a queue object does and what its + interface is. +
          + +
        • queue_sort_abstract.h +
            + This file also doesn't contain any code. Its only purpose is to define the sort + extension to queue objects. +
          + +
        • queue_kernel_1.h +
            + This file contains an implementation of the queue kernel specification found + in queue_kernel_abstract.h +
          + +
        • queue_kernel_2.h +
            + This file contains another implementation of the queue kernel specification found + in queue_kernel_abstract.h +
          + +
        • queue_sort_1.h +
            + This file contains an implementation of the queue sort extension specification found + in queue_sort_abstract.h +
          + +
        • queue_kernel_c.h +
            + This file contains a templated class which wraps any implementation of the queue kernel + specification. It is used during debugging to check that the requires clauses are never + violated. +
          +
        +
      +
    + + + + + + + + + + + creating_objects +

    Creating Objects

    + +

    + To create many of the objects in this library you need to choose which kernel implementation you would like and if you + want the checking version or any extensions. +

    +

    + To make this easy there are header files which define typedefs of all this stuff. For + example, to create a queue of ints using queue kernel implementation 1 you would type + dlib::queue<int>::kernel_1a my_queue;. Or to get the debugging/checking version you + would type dlib::queue<int>::kernel_1a_c my_queue;. +

    +

    + There can be a lot of different typedefs for each component. You can find a list of them + in the section for the component in question. For the queue component they can be found + here. +

    +

    + None of the above applies to the API components (or any global functions or objects that don't list multiple implemenations + in their documenation). To use/create them you just need to include + the appropriate headers. For example, to create a mutex object from the + threads component you would simply type dlib::mutex my_mutex;. There is no + need to specify which kernel implementation. The correct kernel implementation + is determined by which platform you compile under. There are also no explicit checking versions + of the API components. However, there are DLIB_ASSERT statements that perform checking and you can + enable them by #defining DEBUG or ENABLE_ASSERTS. +

    + + + + + + +

    Assumptions

    + There are some restrictions on the behavior of certain objects or functions. + Rather than replicating these restrictions all over the place in my documentation they + are listed here. + +
      + +
    • global swap() +
        + It is assumed that this operator does not throw. Undefined behavior results if it does. + Note that std::swap() for all intrinsics and std::string does not throw. +
      + + + +
    • operator<() +
        + It is assumed that this operator (or std::less or any similar functor supplied by you to the library) + does not throw. Undefined behavior results if it does. +
      + + + +
    • dlib::general_hash +
        + It is assumed that general_hash does not throw. Undefined behavior results if it does. + This is actually noted in the general hash spec file but I'm listing it here also for good measure. + +
      + + + +
    + + + + + + + + + thread_safety +

    Thread Safety

    + +

    + In the library there are three kinds of objects with regards to threading. There are objects + that are completely thread safe. Then there are objects that are not thread safe but can be + used if access to them is serialized using a mutex. Lastly, there are objects which share + some kind of global resource or are reference counted. The last kind of object is + extremely thread unfriendly and can only be used in a threaded program with great care. +

    + +

    + How do you know which components/objects are thread safe and which aren't? The rule is that if + the specification for the component doesn't mention threading or thread safety then + it is ok to use as long as you serialize access to it. If the component might have + some global resources or be reference counted then the specifications will tell you this. + And lastly if the component is thread safe then the specification will tell you this also. +

    + + + + + + + + + + + + +
    diff --git a/docs/docs/kernel_1a.txt b/docs/docs/kernel_1a.txt new file mode 100644 index 0000000000000000000000000000000000000000..d24ead0c38e498dc57141ca4970b82c222c7ca20 --- /dev/null +++ b/docs/docs/kernel_1a.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 86995 4.576 no +play: 125179 75430 4.82062 no +html: 24603 16209 5.27058 no +Csrc: 11150 7084 5.08269 no +list: 3721 2224 4.78151 no +Excl: 1029744 440758 3.42421 no +tech: 426754 248345 4.65552 no +poem: 481861 273394 4.53897 no +fax: 513216 75036 1.16966 no +SPRC: 38240 25660 5.3682 no +man: 4227 2663 5.03998 no + +average: 4.42981 + +time: 875ms + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 72533 5.21534 no +book1: 768771 435527 4.53219 no +book2: 610856 364597 4.7749 no +geo: 102400 72600 5.67188 no +news: 377109 244377 5.18422 no +obj1: 21504 16183 6.02046 no +obj2: 246814 189902 6.15531 no +paper1: 53161 33144 4.98772 no +paper2: 82199 47398 4.613 no +pic: 513216 75036 1.16966 no +progc: 39611 25885 5.22784 no +progl: 71646 42688 4.76655 no +progp: 49379 30180 4.88953 no +trans: 93695 64603 5.51603 no + +average: 4.9089 + +time: 1.11sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 7 56 no +aaa: 100000 20 0.0016 no +alphabet: 100000 58912 4.71296 no +random: 100000 75202 6.01616 no + +average: 16.6827 + +time: 93ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1162352 2.00462 no +bible: 4047392 2194059 4.33674 no +word: 2473400 1542086 4.98774 no + +average: 3.77637 + +time: 3.766sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1a.xml b/docs/docs/kernel_1a.xml new file mode 100644 index 0000000000000000000000000000000000000000..5472c3e4758d1588c83e0b29e80ed66bfbf4e210 --- /dev/null +++ b/docs/docs/kernel_1a.xml @@ -0,0 +1,8 @@ + + + + + kernel_1a + + + diff --git a/docs/docs/kernel_1b.txt b/docs/docs/kernel_1b.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8517f069fb43eaaa45be2caad27af4e0a2294c4 --- /dev/null +++ b/docs/docs/kernel_1b.txt @@ -0,0 +1,77 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 66165 3.48033 no +play: 125179 54572 3.48761 no +html: 24603 11661 3.79173 no +Csrc: 11150 4733 3.39587 no +list: 3721 1629 3.50228 no +Excl: 1029744 343447 2.66821 no +tech: 426754 188332 3.5305 no +poem: 481861 204240 3.39085 no +fax: 513216 54127 0.843731 no +SPRC: 38240 18307 3.82992 no +man: 4227 2100 3.97445 no + +average: 3.26323 + +time: 844ms + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 48130 3.46069 no +book1: 768771 346572 3.6065 no +book2: 610856 288605 3.77968 no +geo: 102400 61124 4.77531 no +news: 377109 196085 4.15975 no +obj1: 21504 12445 4.62984 no +obj2: 246814 127142 4.12106 no +paper1: 53161 25438 3.82807 no +paper2: 82199 37295 3.62973 no +pic: 513216 54127 0.843731 no +progc: 39611 19090 3.85549 no +progl: 71646 29773 3.32446 no +progp: 49379 20795 3.36904 no +trans: 93695 40922 3.49406 no + +average: 3.6341 + +time: 1.109sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 7 56 no +aaa: 100000 20 0.0016 no +alphabet: 100000 83 0.00664 no +random: 100000 77775 6.222 no + +average: 15.5576 + +time: 94ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1151913 1.98662 no +bible: 4047392 1651476 3.26428 no +word: 2473400 1133090 3.66488 no + +average: 2.97193 + +time: 3.672sec + \ No newline at end of file diff --git a/docs/docs/kernel_1b.xml b/docs/docs/kernel_1b.xml new file mode 100644 index 0000000000000000000000000000000000000000..77e1a4458a5585471defe94ca39b5ee93bed66f4 --- /dev/null +++ b/docs/docs/kernel_1b.xml @@ -0,0 +1,8 @@ + + + + + kernel_1b + + + diff --git a/docs/docs/kernel_1c.txt b/docs/docs/kernel_1c.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d82c27f65485e227fbd09f3c07940578b73a225 --- /dev/null +++ b/docs/docs/kernel_1c.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 51810 2.72525 no +play: 125179 44002 2.8121 no +html: 24603 8602 2.79706 no +Csrc: 11150 3399 2.43874 no +list: 3721 1272 2.73475 no +Excl: 1029744 237165 1.84252 no +tech: 426754 147090 2.75737 no +poem: 481861 169981 2.82208 no +fax: 513216 54230 0.845336 no +SPRC: 38240 15190 3.17782 no +man: 4227 1763 3.33665 no + +average: 2.57179 + +time: 1.031sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 37264 2.67939 no +book1: 768771 280052 2.91428 no +book2: 610856 221616 2.90237 no +geo: 102400 62115 4.85273 no +news: 377109 155282 3.29416 no +obj1: 21504 11235 4.17969 no +obj2: 246814 97319 3.15441 no +paper1: 53161 19664 2.95916 no +paper2: 82199 29837 2.90388 no +pic: 513216 54230 0.845336 no +progc: 39611 14610 2.9507 no +progl: 71646 21637 2.41599 no +progp: 49379 14204 2.30122 no +trans: 93695 27848 2.37776 no + +average: 2.90936 + +time: 1.297sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 7 56 no +aaa: 100000 18 0.00144 no +alphabet: 100000 65 0.0052 no +random: 100000 90704 7.25632 no + +average: 15.8157 + +time: 203ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1141437 1.96855 no +bible: 4047392 1263237 2.49689 no +word: 2473400 876621 2.83536 no + +average: 2.4336 + +time: 3.391sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1c.xml b/docs/docs/kernel_1c.xml new file mode 100644 index 0000000000000000000000000000000000000000..87573483ce635f8e969383caf5f402a1367c0473 --- /dev/null +++ b/docs/docs/kernel_1c.xml @@ -0,0 +1,8 @@ + + + + + kernel_1c + + + diff --git a/docs/docs/kernel_1da.txt b/docs/docs/kernel_1da.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2c8faa373ae947de24c32bf9d1260e265b0ecc6 --- /dev/null +++ b/docs/docs/kernel_1da.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 45580 2.39754 no +play: 125179 42432 2.71176 no +html: 24603 7745 2.51839 no +Csrc: 11150 3165 2.27085 no +list: 3721 1238 2.66165 no +Excl: 1029744 194875 1.51397 no +tech: 426754 111838 2.09653 no +poem: 481861 148110 2.45897 no +fax: 513216 56075 0.874096 no +SPRC: 38240 14248 2.98075 no +man: 4227 1736 3.28555 no + +average: 2.34273 + +time: 1.812sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 29161 2.09676 no +book1: 768771 235667 2.4524 no +book2: 610856 165032 2.16132 no +geo: 102400 67663 5.28617 no +news: 377109 128148 2.71853 no +obj1: 21504 10750 3.99926 no +obj2: 246814 82894 2.68685 no +paper1: 53161 17398 2.61816 no +paper2: 82199 26449 2.57414 no +pic: 513216 56075 0.874096 no +progc: 39611 13188 2.6635 no +progl: 71646 17135 1.9133 no +progp: 49379 11764 1.90591 no +trans: 93695 19602 1.67369 no + +average: 2.54458 + +time: 2.36sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 6 48 no +aaa: 100000 19 0.00152 no +alphabet: 100000 66 0.00528 no +random: 100000 89652 7.17216 no + +average: 13.7947 + +time: 375ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1130363 1.94945 no +bible: 4047392 871537 1.72266 no +word: 2473400 589688 1.9073 no + +average: 1.8598 + +time: 4.484sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1da.xml b/docs/docs/kernel_1da.xml new file mode 100644 index 0000000000000000000000000000000000000000..5a9bc602bd970f9d95f0a8404a22ce431b85ffe0 --- /dev/null +++ b/docs/docs/kernel_1da.xml @@ -0,0 +1,8 @@ + + + + + kernel_1da + + + diff --git a/docs/docs/kernel_1db.txt b/docs/docs/kernel_1db.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a789eb6a3217703f3adefd804332bc75c240229 --- /dev/null +++ b/docs/docs/kernel_1db.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 47843 2.51658 no +play: 125179 45069 2.88029 no +html: 24603 7914 2.57334 no +Csrc: 11150 3279 2.35265 no +list: 3721 1281 2.7541 no +Excl: 1029744 210286 1.6337 no +tech: 426754 115826 2.17129 no +poem: 481861 157348 2.61234 no +fax: 513216 56477 0.880362 no +SPRC: 38240 14466 3.02636 no +man: 4227 1780 3.36882 no + +average: 2.43362 + +time: 2.296sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 29758 2.13969 no +book1: 768771 247700 2.57762 no +book2: 610856 168694 2.20928 no +geo: 102400 67817 5.2982 no +news: 377109 126675 2.68729 no +obj1: 21504 10871 4.04427 no +obj2: 246814 82948 2.6886 no +paper1: 53161 18113 2.72576 no +paper2: 82199 27700 2.6959 no +pic: 513216 56477 0.880362 no +progc: 39611 13622 2.75115 no +progl: 71646 17263 1.92759 no +progp: 49379 12032 1.94933 no +trans: 93695 19505 1.6654 no + +average: 2.5886 + +time: 2.86sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 6 48 no +aaa: 100000 20 0.0016 no +alphabet: 100000 66 0.00528 no +random: 100000 88475 7.078 no + +average: 13.7712 + +time: 531ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1130433 1.94957 no +bible: 4047392 844807 1.66983 no +word: 2473400 504129 1.63056 no + +average: 1.74999 + +time: 5.266sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1db.xml b/docs/docs/kernel_1db.xml new file mode 100644 index 0000000000000000000000000000000000000000..80da1081a4cd37b21582131d5e1f43659387119d --- /dev/null +++ b/docs/docs/kernel_1db.xml @@ -0,0 +1,8 @@ + + + + + kernel_1db + + + diff --git a/docs/docs/kernel_1ea.txt b/docs/docs/kernel_1ea.txt new file mode 100644 index 0000000000000000000000000000000000000000..69934560c0f1e130a0bc9599c75935f151849663 --- /dev/null +++ b/docs/docs/kernel_1ea.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 40695 2.14059 no +play: 125179 37421 2.39152 no +html: 24603 6859 2.2303 no +Csrc: 11150 2792 2.00323 no +list: 3721 1084 2.33056 no +Excl: 1029744 156897 1.21892 no +tech: 426754 102805 1.9272 no +poem: 481861 136664 2.26894 no +fax: 513216 51109 0.796686 no +SPRC: 38240 12590 2.63389 no +man: 4227 1530 2.89567 no + +average: 2.07614 + +time: 3.062sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 26039 1.87228 no +book1: 768771 218772 2.27659 no +book2: 610856 151985 1.99045 no +geo: 102400 59371 4.63836 no +news: 377109 115334 2.4467 no +obj1: 21504 9832 3.65774 no +obj2: 246814 75065 2.43309 no +paper1: 53161 15263 2.29687 no +paper2: 82199 23368 2.27429 no +pic: 513216 51109 0.796686 no +progc: 39611 11549 2.33248 no +progl: 71646 15297 1.70806 no +progp: 49379 10447 1.69254 no +trans: 93695 17677 1.50932 no + +average: 2.28039 + +time: 4.172sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 7 56 no +aaa: 100000 17 0.00136 no +alphabet: 100000 65 0.0052 no +random: 100000 82599 6.60792 no + +average: 15.6536 + +time: 672ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1130095 1.94899 no +bible: 4047392 848956 1.67803 no +word: 2473400 542983 1.75623 no + +average: 1.79442 + +time: 6.516sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1ea.xml b/docs/docs/kernel_1ea.xml new file mode 100644 index 0000000000000000000000000000000000000000..b1f73ff8330524465f0bb23113ded11180e6d5e8 --- /dev/null +++ b/docs/docs/kernel_1ea.xml @@ -0,0 +1,8 @@ + + + + + kernel_1ea + + + diff --git a/docs/docs/kernel_1eb.txt b/docs/docs/kernel_1eb.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd5565863cd977441c971ac015a555b97f7b7cb6 --- /dev/null +++ b/docs/docs/kernel_1eb.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 40220 2.1156 no +play: 125179 37451 2.39344 no +html: 24603 6819 2.21729 no +Csrc: 11150 2770 1.98744 no +list: 3721 1085 2.33271 no +Excl: 1029744 158436 1.23088 no +tech: 426754 100243 1.87917 no +poem: 481861 136151 2.26042 no +fax: 513216 50374 0.785229 no +SPRC: 38240 12387 2.59142 no +man: 4227 1528 2.89189 no + +average: 2.06232 + +time: 4.875sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 25279 1.81764 no +book1: 768771 216389 2.25179 no +book2: 610856 146986 1.92498 no +geo: 102400 58768 4.59125 no +news: 377109 109292 2.31852 no +obj1: 21504 9819 3.6529 no +obj2: 246814 72662 2.3552 no +paper1: 53161 15128 2.27656 no +paper2: 82199 23186 2.25657 no +pic: 513216 50374 0.785229 no +progc: 39611 11434 2.30926 no +progl: 71646 14712 1.64274 no +progp: 49379 10210 1.65414 no +trans: 93695 16885 1.4417 no + +average: 2.23418 + +time: 5.421sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 7 56 no +aaa: 100000 17 0.00136 no +alphabet: 100000 64 0.00512 no +random: 100000 81881 6.55048 no + +average: 15.6392 + +time: 907ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1129161 1.94738 no +bible: 4047392 794809 1.571 no +word: 2473400 454450 1.46988 no + +average: 1.66275 + +time: 7.39sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1eb.xml b/docs/docs/kernel_1eb.xml new file mode 100644 index 0000000000000000000000000000000000000000..5773266e0927eeab3d662c6e9d5ae311ea27d1cd --- /dev/null +++ b/docs/docs/kernel_1eb.xml @@ -0,0 +1,8 @@ + + + + + kernel_1eb + + + diff --git a/docs/docs/kernel_1ec.txt b/docs/docs/kernel_1ec.txt new file mode 100644 index 0000000000000000000000000000000000000000..61764e089e39036de148283d719854f80d424fd4 --- /dev/null +++ b/docs/docs/kernel_1ec.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 40367 2.12334 no +play: 125179 37785 2.41478 no +html: 24603 6828 2.22022 no +Csrc: 11150 2710 1.94439 no +list: 3721 1084 2.33056 no +Excl: 1029744 162760 1.26447 no +tech: 426754 100488 1.88376 no +poem: 481861 139110 2.30955 no +fax: 513216 50276 0.783701 no +SPRC: 38240 12219 2.55628 no +man: 4227 1533 2.90135 no + +average: 2.06658 + +time: 5.484sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 25153 1.80858 no +book1: 768771 220128 2.2907 no +book2: 610856 146040 1.91259 no +geo: 102400 58737 4.58883 no +news: 377109 108774 2.30753 no +obj1: 21504 9823 3.65439 no +obj2: 246814 71148 2.30613 no +paper1: 53161 15116 2.27475 no +paper2: 82199 23346 2.27214 no +pic: 513216 50276 0.783701 no +progc: 39611 11351 2.29249 no +progl: 71646 14125 1.5772 no +progp: 49379 9966 1.61461 no +trans: 93695 16068 1.37194 no + +average: 2.21826 + +time: 6.188sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 7 56 no +aaa: 100000 17 0.00136 no +alphabet: 100000 65 0.0052 no +random: 100000 81869 6.54952 no + +average: 15.639 + +time: 1.109sec + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1160064 2.00068 no +bible: 4047392 760498 1.50319 no +word: 2473400 422419 1.36628 no + +average: 1.62338 + +time: 11.203sec + + \ No newline at end of file diff --git a/docs/docs/kernel_1ec.xml b/docs/docs/kernel_1ec.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e6558326492da9f6c0ec7edaa6a27a4322a77c9 --- /dev/null +++ b/docs/docs/kernel_1ec.xml @@ -0,0 +1,8 @@ + + + + + kernel_1ec + + + diff --git a/docs/docs/kernel_2a.txt b/docs/docs/kernel_2a.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e63d7dcb1db75c9c142f713fa39d3a2ebfdd570 --- /dev/null +++ b/docs/docs/kernel_2a.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 55655 2.9275 no +play: 125179 49648 3.17293 no +html: 24603 8345 2.71349 no +Csrc: 11150 3514 2.52126 no +list: 3721 1379 2.96479 no +Excl: 1029744 72617 0.564156 no +tech: 426754 145403 2.72575 no +poem: 481861 196109 3.25586 no +fax: 513216 49740 0.775346 no +SPRC: 38240 13253 2.77259 no +man: 4227 1857 3.51455 no + +average: 2.53711 + +time: 4.641sec + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 35687 2.566 no +book1: 768771 313140 3.2586 no +book2: 610856 210661 2.7589 no +geo: 102400 61070 4.77109 no +news: 377109 143307 3.04012 no +obj1: 21504 11004 4.09375 no +obj2: 246814 83289 2.69965 no +paper1: 53161 19433 2.9244 no +paper2: 82199 30671 2.98505 no +pic: 513216 49740 0.775346 no +progc: 39611 14142 2.85618 no +progl: 71646 17196 1.92011 no +progp: 49379 12045 1.95144 no +trans: 93695 19849 1.69478 no + +average: 2.73539 + +time: 4.89sec + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 6 48 no +aaa: 100000 58 0.00464 no +alphabet: 100000 87 0.00696 no +random: 100000 77815 6.2252 no + +average: 13.5592 + +time: 235ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 1349400 2.32721 no +bible: 4047392 1206327 2.3844 no +word: 2473400 703195 2.27442 no + +average: 2.32868 + +time: 8.75sec + + \ No newline at end of file diff --git a/docs/docs/kernel_2a.xml b/docs/docs/kernel_2a.xml new file mode 100644 index 0000000000000000000000000000000000000000..bcc62cb69f3771a66afe3870d716b4088f575f93 --- /dev/null +++ b/docs/docs/kernel_2a.xml @@ -0,0 +1,8 @@ + + + + + kernel_2a + + + diff --git a/docs/docs/kernel_3a.txt b/docs/docs/kernel_3a.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d0546cd1e968b63de560ef568356fd680c43204 --- /dev/null +++ b/docs/docs/kernel_3a.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 118620 6.2395 no +play: 125179 103761 6.63121 no +html: 24603 14067 4.57408 no +Csrc: 11150 5805 4.16502 no +list: 3721 2142 4.60521 no +Excl: 1029744 390978 3.03748 no +tech: 426754 310347 5.81782 no +poem: 481861 435150 7.22449 no +fax: 513216 116298 1.81285 no +SPRC: 38240 23076 4.82762 no +man: 4227 3177 6.01278 no + +average: 4.99528 + +time: 547ms + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 68949 4.95764 no +book1: 768771 683415 7.11177 no +book2: 610856 435186 5.69936 no +geo: 102400 105111 8.2118 no +news: 377109 266382 5.65103 no +obj1: 21504 15714 5.84598 no +obj2: 246814 139671 4.52717 no +paper1: 53161 37476 5.63962 no +paper2: 82199 63198 6.15073 no +pic: 513216 116298 1.81285 no +progc: 39611 25398 5.12948 no +progl: 71646 31905 3.56252 no +progp: 49379 20943 3.39302 no +trans: 93695 34056 2.90782 no + +average: 5.04291 + +time: 610ms + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 9 72 no +aaa: 100000 3771 0.30168 no +alphabet: 100000 486 0.03888 no +random: 100000 112491 8.99928 no + +average: 20.335 + +time: 47ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 4752396 8.1961 no +bible: 4047392 2649303 5.23656 no +word: 2473400 1452177 4.69694 no + +average: 6.0432 + +time: 2.5sec + + \ No newline at end of file diff --git a/docs/docs/kernel_3a.xml b/docs/docs/kernel_3a.xml new file mode 100644 index 0000000000000000000000000000000000000000..0f663b4f10060715dbec52db4e58b7d910ab0dc1 --- /dev/null +++ b/docs/docs/kernel_3a.xml @@ -0,0 +1,8 @@ + + + + + kernel_3a + + + diff --git a/docs/docs/kernel_3b.txt b/docs/docs/kernel_3b.txt new file mode 100644 index 0000000000000000000000000000000000000000..30731e79b29d4865f41c668faa0d2392175425ad --- /dev/null +++ b/docs/docs/kernel_3b.txt @@ -0,0 +1,78 @@ + + + + The Canterbury Corpus + +file size packed size bpb corruption + +text: 152089 111537 5.86693 no +play: 125179 101457 6.48396 no +html: 24603 13914 4.52433 no +Csrc: 11150 5760 4.13274 no +list: 3721 2160 4.64391 no +Excl: 1029744 407466 3.16557 no +tech: 426754 291483 5.46419 no +poem: 481861 417897 6.93805 no +fax: 513216 114138 1.77918 no +SPRC: 38240 23184 4.85021 no +man: 4227 3159 5.97871 no + +average: 4.89343 + +time: 734ms + + + + The Calgary Corpus + +file size packed size bpb corruption + +bib: 111261 63729 4.58231 no +book1: 768771 655227 6.81844 no +book2: 610856 409392 5.36155 no +geo: 102400 108099 8.44523 no +news: 377109 259065 5.49581 no +obj1: 21504 15768 5.86607 no +obj2: 246814 138564 4.49128 no +paper1: 53161 35901 5.40261 no +paper2: 82199 60291 5.86781 no +pic: 513216 114138 1.77918 no +progc: 39611 24984 5.04587 no +progl: 71646 31113 3.47408 no +progp: 49379 20772 3.36532 no +trans: 93695 33093 2.82559 no + +average: 4.9158 + +time: 907ms + + + + The Artificial Corpus + +file size packed size bpb corruption + +a: 1 9 72 no +aaa: 100000 3771 0.30168 no +alphabet: 100000 486 0.03888 no +random: 100000 112509 9.00072 no + +average: 20.3353 + +time: 78ms + + + + The Large Corpus + +file size packed size bpb corruption + +E.coli: 4638690 4747257 8.18724 no +bible: 4047392 2466675 4.87558 no +word: 2473400 1301805 4.21058 no + +average: 5.7578 + +time: 3.25sec + + \ No newline at end of file diff --git a/docs/docs/kernel_3b.xml b/docs/docs/kernel_3b.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba59722ba52485be19b25e2fcb51842fab6ac404 --- /dev/null +++ b/docs/docs/kernel_3b.xml @@ -0,0 +1,8 @@ + + + + + kernel_3b + + + diff --git a/docs/docs/license.xml b/docs/docs/license.xml new file mode 100644 index 0000000000000000000000000000000000000000..7bbc416c9e69988a5f91f6893a782830470e9e6d --- /dev/null +++ b/docs/docs/license.xml @@ -0,0 +1,36 @@ + + + + + License +
    +
    +
    +Boost Software License - Version 1.0 - August 17th, 2003
    +
    +Permission is hereby granted, free of charge, to any person or organization
    +obtaining a copy of the software and accompanying documentation covered by
    +this license (the "Software") to use, reproduce, display, distribute,
    +execute, and transmit the Software, and to prepare derivative works of the
    +Software, and to permit third-parties to whom the Software is furnished to
    +do so, all subject to the following:
    +
    +The copyright notices in the Software and this entire statement, including
    +the above license grant, this restriction and the following disclaimer,
    +must be included in all copies of the Software, in whole or in part, and
    +all derivative works of the Software, unless such copies or derivative
    +works are solely in the form of machine-executable object code generated by
    +a source language processor.
    +
    +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
    +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
    +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
    +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    +DEALINGS IN THE SOFTWARE.
    +
    +
    +
    +   
    +
    diff --git a/docs/docs/main_menu.xml b/docs/docs/main_menu.xml new file mode 100644 index 0000000000000000000000000000000000000000..f9420fde4feca3f7d0f673127277138bb8026982 --- /dev/null +++ b/docs/docs/main_menu.xml @@ -0,0 +1,259 @@ + + + + + +
    + The Library + + Algorithms + algorithms.html + algorithms.xml + + + Containers + containers.html + containers.xml + + + API Wrappers + api.html + api.xml + + + Network + network.html + network.xml + + + Compression + compression.html + compression.xml + + + Parsing + parsing.html + parsing.xml + + + Imaging + imaging.html + imaging.xml + + + Metaprogramming + metaprogramming.html + metaprogramming.xml + + + Miscellaneous + other.html + other.xml + +
    + + +
    + Help/Info + + Home + index.html + + + Introduction + intro.html + intro.xml + + + How to compile + compile.html + + + License + license.html + + + Index + term_index.html + + + Examples + + + Member_Function_Pointer + member_function_pointer_ex.cpp.html + + + Matrix + matrix_ex.cpp.html + + + Image + image_ex.cpp.html + + + Support_Vector_Machine + svm_ex.cpp.html + + + Neural_Network + mlp_ex.cpp.html + + + Bayesian_Network_From_Disk + bayes_net_from_disk_ex.cpp.html + + + Bayesian_Network_GUI + bayes_net_gui_ex.cpp.html + + + Bayesian_Network + bayes_net_ex.cpp.html + + + Std_C++_Allocator + std_allocator_ex.cpp.html + + + HTTP_Server + server_http_ex.cpp.html + + + Base64_Encoder + file_to_code_ex.cpp.html + + + Sockstreambuf + sockstreambuf_ex.cpp.html + + + Logger + logger_ex.cpp.html + + + Logger_Advanced + logger_ex_2.cpp.html + + + XML_Parser + xml_parser_ex.cpp.html + + + Threads + threads_ex.cpp.html + + + Directory_Navigation + dir_nav_ex.cpp.html + + + GUI + gui_api_ex.cpp.html + + + Sockets + sockets_ex.cpp.html + + + Sockets_2 + sockets_ex_2.cpp.html + + + Queue + queue_ex.cpp.html + + + Pipe + pipe_ex.cpp.html + + + Timer + timer_ex.cpp.html + + + Compress_Stream + compress_stream_ex.cpp.html + + + Cmd_Line_Parser + compress_stream_ex.cpp.html#_top + + + Threaded_Object + threaded_object_ex.cpp.html + + + Thread_Function + thread_function_ex.cpp.html + + + Multithreaded_Object + multithreaded_object_ex.cpp.html + + + +
    + +
    + Current Release + Version: + + Release Notes + release_notes.html + + + Change Log + change_log.html + + +
    + + + +
    + Sourceforge + + Summary + http://sourceforge.net/projects/dclib/ + + + Forums + http://sourceforge.net/forum/?group_id=130373 + + + Download Files + http://sourceforge.net/project/platformdownload.php?group_id=130373 + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +Ohloh project report for dlib C++ Library + +
    + +
    +
    + Last Modified:
    + +
    +
    +
    + +
    + +
    + diff --git a/docs/docs/metaprogramming.xml b/docs/docs/metaprogramming.xml new file mode 100644 index 0000000000000000000000000000000000000000..8852f39f8ca4384116d19909a588afa3d9d129ac --- /dev/null +++ b/docs/docs/metaprogramming.xml @@ -0,0 +1,419 @@ + + + + + Metaprogramming + + + + +

    + +

    + This page documents library components that provide metaprogramming sorts of functionality. For + the most part they are useful for putting design by contract checks into code or doing various kinds of + clever things with templates. +

    +

    + For example, you might have a templated function that is templated on a type T and you want to + make sure that T is either a char or wchar_t type. You could place the following into your code + and it would cause the compile to error out when T was set to something other than char or wchar_t. +
    + COMPILE_TIME_ASSERT((is_same_type<T,char>::value || is_same_type<T,wchar_t>::value)); +

    + + + + + + + +
    + Objects + is_pointer_type + is_same_type + is_signed_type + is_unsigned_type + static_switch + noncopyable + enable_if + is_graph + is_matrix + is_directed_graph + is_built_in_scalar_type + unsigned_type +
    + +
    + Global Functions + DLIB_ASSERT + DLIB_CASSERT + COMPILE_TIME_ASSERT + ASSERT_ARE_SAME_TYPE + ASSERT_ARE_NOT_SAME_TYPE + _dT + TIME_THIS + assign_zero_if_built_in_scalar_type +
    + +
    + Other + portability_macros +
    + +
    +
    + + + + + + + + + + + unsigned_type + dlib/uintn.h + dlib/uintn.h + + This is a template that allows you to obtain the unsigned version + of any integral type. For example, unsigned_type<signed short>::type == + unsigned short. + + + + + + + + static_switch + dlib/algs.h + dlib/algs.h + + To use this template you give it some number of boolean expressions and it + tells you which one of them is true. If more than one of them is true then + it causes a compile time error. It is useful for cases where you want to + specialize a template and you want to specialize it not by + the type of object it gets per say but instead according to the values of some + type traits associated with the various template arguments. A simple example of + this can be seen in the assign_pixel's + implementation which can be found at the bottom of the + dlib/pixel.h file. + + + + + + + + enable_if + dlib/enable_if.h + + This is a family of templates from the Boost C++ libraries that makes it somewhat easier to control + template specilization. For the details see + this page. Note that the header dlib/enable_if.h brings + these templates into the dlib namespace.
    +
    + +
    + + + + + noncopyable + dlib/noncopyable.h + dlib/noncopyable.h + + This is a simple class that makes it easy to declare a non-copyable object. + To use it to make your own class non-copyable just inherit from it. + + + + + + + + is_same_type + dlib/algs.h + dlib/algs.h + + This is a template where is_same_type<T,U>::value == true when T and U are + the same type and false otherwise. + + + + + + + + is_signed_type + dlib/algs.h + dlib/algs.h + + This is a template where is_signed_type<T>::value == true when T is + a signed integral type and false when it is an unsigned integral + type. + + + + + + + + is_unsigned_type + dlib/algs.h + dlib/algs.h + + This is a template where is_unsigned_type<T>::value == true when T is + an unsigned integral type and false when it is a signed integral + type. + + + + + + + + is_directed_graph + dlib/is_kind.h + dlib/is_kind.h + + This is a template where is_directed_graph<T>::value == true when T + is a directed_graph object. + + + + + + + + is_built_in_scalar_type + dlib/algs.h + dlib/algs.h + + This is a template where is_built_in_scalar_type<T>::value == true when T + is a built in scalar type such as int, char, float, etc... + + + + + + + + + is_matrix + dlib/is_kind.h + dlib/is_kind.h + + This is a template where is_matrix<T>::value == true when T + is a matrix object. + + + + + + + + + is_graph + dlib/is_kind.h + dlib/is_kind.h + + This is a template where is_graph<T>::value == true when T + is a graph object. + + + + + + + + is_pointer_type + dlib/algs.h + dlib/algs.h + + This is a template where is_pointer_type<T>::value == true when T is a pointer + type ane false otherwise. + + + + + + + + ASSERT_ARE_NOT_SAME_TYPE + dlib/assert.h + dlib/assert.h + +

    + This is a macro function for debuging. Its form is ASSERT_ARE_NOT_SAME_TYPE(type1, type2). + If type1 and type2 are the same type then the compile will fail. This is sometimes useful + in validating template arguments. +

    +
    + +
    + + + + + ASSERT_ARE_SAME_TYPE + dlib/assert.h + dlib/assert.h + +

    + This is a macro function for debuging. Its form is ASSERT_ARE_SAME_TYPE(type1, type2). + If type1 and type2 are not the same type then the compile will fail. This is sometimes useful + in validating template arguments. +

    +
    + +
    + + + + + COMPILE_TIME_ASSERT + dlib/assert.h + dlib/assert.h + +

    + This is a macro function for debuging. Its form is COMPILE_TIME_ASSERT(condition that should + be true). The condition must be a compile time constant and if it is false then the compile + will fail. +

    +
    + +
    + + + + + DLIB_CASSERT + dlib/assert.h + dlib/assert.h + +

    + This is a macro function that is identicial to the DLIB_ASSERT macro + except that it is always enabled. Even if _DEBUG, DEBUG and ENABLE_ASSERTS are not defined. +

    +

    + Note that when this macro fails and throws an exception it also calls the global + C function dlib_assert_breakpoint(). This behavior makes it easy to set a debugging + tool to break when DLIB_CASSERT fails by setting a breakpoing on dlib_assert_breakpoint(). +

    +
    + +
    + + + + + + DLIB_ASSERT + dlib/assert.h + dlib/assert.h + +

    + This is a macro function for debuging. Its form is DLIB_ASSERT(condition that should be + true,error message). If the condition is false DLIB_ASSERT throws an exception of type + dlib::fatal_error with fatal_error::type == EBROKEN_ASSERT. An error message detailing + the nature of the problem is stored in the member variable info which is of type std::string. + Look in the following file for more details. The exception classes are defined + here. +

    +

    + This macro is only enabled if _DEBUG, DEBUG or ENABLE_ASSERTS is defined. Also, if this macro is + enabled then ENABLE_ASSERTS will be defined even if you didn't define it. +

    +

    + Note that when this macro fails and throws an exception it also calls the global + C function dlib_assert_breakpoint(). This behavior makes it easy to set a debugging + tool to break when DLIB_CASSERT fails by setting a breakpoing on dlib_assert_breakpoint(). +

    +
    + +
    + + + + + + _dT + dlib/algs.h + dlib/algs.h + + This is a macro function for converting a string/character literal to either a char or wchar_t literal. + Its form is _dT(target character type,string or character literal) + + + + + + + + assign_zero_if_built_in_scalar_type + dlib/algs.h + dlib/algs.h + +

    + This function assigns its argument the value of 0 if it is a built in scalar + type according to the is_built_in_scalar_type + template. If it isn't a built in scalar type then it does nothing. +

    +

    + This function is useful for suppressing compiler warnings about uninitialized + types inside of templates that are designed to accept the built in types + as well as user defined classes. +

    + +
    + +
    + + + + + + TIME_THIS + dlib/time_this.h + dlib/time_this.h + +

    + This is a macro function for timing blocks of code. Its form is TIME_THIS(whatever you want to time) + It's pretty straight forward. It just prints the time it took to std::cout. +

    +

    + There is another version of this function called TIME_THIS_TO which takes as a parameter an ostream + object to write its output to. Its form is TIME_THIS_TO(what you want to time, the output stream); +

    + +
    + +
    + + + + + + portability_macros + dlib/platform.h + dlib/platform.h + + This file #defines various macros depending on the platform being compiled under. + See the file itself for the specifics. + + + + + + + +
    + + + + +
    + diff --git a/docs/docs/minus.gif b/docs/docs/minus.gif new file mode 100644 index 0000000000000000000000000000000000000000..1deac2fe1a42e35b994f1b855488f392c50f6a89 Binary files /dev/null and b/docs/docs/minus.gif differ diff --git a/docs/docs/network.xml b/docs/docs/network.xml new file mode 100644 index 0000000000000000000000000000000000000000..90682086f3c2b1a30646586db5c5e59d8bb657be --- /dev/null +++ b/docs/docs/network.xml @@ -0,0 +1,251 @@ + + + + + Networking + + + + +

    +

    + To use any of these objects all you need to do is #include the file indicated in the + short section about the component you would like to use. Pick which implementation you + would like and typedef it to something nice. Here is an example of creating a typedef for + a linker using the first kernel implementation.
    + typedef dlib::linker::kernel_1a linker1; +

    + + + + + + + +
    + Objects + linker + server + sockstreambuf + +
    + +
    + +
    + + + + + + + + + + + + linker + dlib/linker.h + dlib/linker/linker_kernel_abstract.h + + This object represents something that takes two connections and lets + them talk to each other. ie. any incoming data from one connection is + passed unaltered to the other and vice versa. + + + + + linker_kernel_1 + dlib/linker/linker_kernel_1.h + + This implementation is done just using the objects defined in the + sockets and threads packages. + + + + + kernel_1a + is a typedef for linker_kernel_1 + + + + + + + + + + + + + server + dlib/server.h + dlib/server/server_kernel_abstract.h + + This object represents a server that listens on a port and spawns new + threads to handle each new connection. It also manages the connections + and threads for you. + + + + sockets_ex.cpp.html + sockstreambuf_ex.cpp.html + server_http_ex.cpp.html + + + + + server_kernel_1 + dlib/server/server_kernel_1.h + + This implementation is done using the objects defined in the + sockets and threads packages. + It also uses a set to keep track of the connections. + + + + + kernel_1a + is a typedef for server_kernel_1 that uses set_kernel_1a + + + + + + + + + + + iostream + dlib/server/server_iostream_abstract.h + + This extension redefines the on_connect() function so that + instead of giving you a connection object you get an istream + and ostream object. + + + + + server_iostream_1 + dlib/server/server_iostream_1.h + + This is implemented in the obvious way using the sockstreambuf object. + + + + + iostream_1a + is a typedef for server_kernel_1a extended by server_iostream_1 that uses + sockstreambuf_kernel_2a + + + + + + + + + + + + http + dlib/server/server_http_abstract.h + + This extension turns the server object into a simple HTTP server. + + + + server_http_ex.cpp.html + + + + + server_http_1 + dlib/server/server_http_1.h + + This is implemented in the obvious way. + + + + + http_1a + is a typedef for server_iostream_1a extended by server_http_1 + + + + + + + + + + + + + + + + + + + + sockstreambuf + dlib/sockstreambuf.h + dlib/sockstreambuf/sockstreambuf_kernel_abstract.h + + This object represents a stream buffer for connection objects. + + + + sockstreambuf_ex.cpp.html + sockets_ex_2.cpp.html + + + + + sockstreambuf_kernel_1 + dlib/sockstreambuf/sockstreambuf_kernel_1.h + + This implementation is done in the obvious way without any sort of buffering. + + + + + kernel_1a + is a typedef for sockstreambuf_kernel_1 + + + + + + + sockstreambuf_kernel_2 + dlib/sockstreambuf/sockstreambuf_kernel_2.h + + This implementation is done in the obvious way but with buffering. Thus, it is + considerably faster than the unbuffered version of this object. + + + + + kernel_2a + is a typedef for sockstreambuf_kernel_2 + + + + + + + + + + + + + + + + + +
    diff --git a/docs/docs/old_change_log.xml b/docs/docs/old_change_log.xml new file mode 100644 index 0000000000000000000000000000000000000000..00e98e5fa392b46c53621e8d0aecdea3ea61f8e8 --- /dev/null +++ b/docs/docs/old_change_log.xml @@ -0,0 +1,7 @@ + + + + + Old Change Logs + + diff --git a/docs/docs/old_release_notes.xml b/docs/docs/old_release_notes.xml new file mode 100644 index 0000000000000000000000000000000000000000..e9e7c408b5dbacdc16ef7c86d1ee6658f2dea5e3 --- /dev/null +++ b/docs/docs/old_release_notes.xml @@ -0,0 +1,10 @@ + + + + + Old Release Notes + + + + + diff --git a/docs/docs/other.xml b/docs/docs/other.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e0be611ee77e70c6f1b182e82804d5622e63070 --- /dev/null +++ b/docs/docs/other.xml @@ -0,0 +1,853 @@ + + + + + Miscellaneous + + + + +

    + +

    + + This page documents library components that don't really fit in anywhere else. + They all basically follow the same conventions as + the rest of the library. So to get a pipe for example you would need to write something + like typedef dlib::pipe::kernel_1a pipe_type; and from then on make your pipes like + pipe_type my_pipe(pipe_size);. +

    + + + + + + + +
    + Objects + bit_stream + byte_orderer + std_allocator + memory_manager + memory_manager_global + memory_manager_stateless + sync_extension + timer + timeout + member_function_pointer + error + pipe + copy_functor + logger + uint64 + uint32 + uint16 + uint8 +
    + +
    + Global Functions + deserialize + serialize + zero_extend_cast + +
    + +
    + Testing + dlib_testing_suite +
    + +
    +
    + + + + + + + + + + + + zero_extend_cast + dlib/uintn.h + dlib/uintn.h + + This is a global function that performs a zero extending cast + from one integral type to another integral type. + + + + + + + + uint32 + dlib/uintn.h + dlib/uintn.h + + This is just a typedef for a 32 bit unsigned integer. + + + + + + + + uint8 + dlib/uintn.h + dlib/uintn.h + + This is just a typedef for an 8 bit unsigned integer. + + + + + + + + + uint16 + dlib/uintn.h + dlib/uintn.h + + This is just a typedef for a 16 bit unsigned integer. + + + + + + + + std_allocator + dlib/std_allocator.h + dlib/std_allocator.h + + This object is an implementation of an allocator that conforms to the C++ standard + requirements for allocator objects. The M template argument is one of the dlib + memory manager objects and this allocator implementation will do all of its memory allocations + using whatever dlib memory manager you supply. + +

    + Thus, using this allocator object you can use any of the dlib memory manager objects with + the containers in the STL or with any other object that requires an STL style allocator object. +

    +
    + + + std_allocator_ex.cpp.html + + +
    + + + + + uint64 + dlib/uintn.h + dlib/uintn.h + + This is just a typedef for a 64 bit unsigned integer. + + + + + + + + copy_functor + dlib/algs.h + dlib/algs.h + + This is a templated function object that makes coppies of something. + + + + + + + + logger + dlib/logger.h + dlib/logger/logger_kernel_abstract.h + + This component is a logging output stream in the style of the log4j + logger available for Java. + Note that unlike most other objects in this library there is only + one implementation. Thus, to create instances + of the logger you would simply write logger my_logger("some_name");. + + + + logger_ex.cpp.html + logger_ex_2.cpp.html + pipe_ex.cpp.html + + + + + extra_logger_headers + dlib/logger/extra_logger_headers.h + This extension contains additional logger headers you may chose to use instead of the + default one. + + + config_file + dlib/logger/logger_config_file.h + This extension provides the configure_loggers_from_file() function + which reads a configuration file from disk that sets up all your loggers. + + + + + + + + + + error + dlib/error.h + dlib/error.h + + This is the base exception class from which all exceptions in this + library inherit. + + + + + + + + pipe + dlib/pipe.h + dlib/pipe/pipe_kernel_abstract.h + + This is a first in first out queue with a fixed maximum size containing items + of type T. It is suitable for passing objects between threads. + + + + pipe_ex.cpp.html + + + + + pipe_kernel_1 + dlib/pipe/pipe_kernel_1.h + + This implementation is done using a circular buffer in the obvious way. See the source for details. + + + + + kernel_1a + is a typedef for pipe_kernel_1 + + + + + + + + + + + + + + + member_function_pointer + dlib/member_function_pointer.h + dlib/member_function_pointer/member_function_pointer_kernel_abstract.h + + This object represents a member function pointer. It is useful because + instances of this object can be created without needing to know the type + of object whose member function we will be calling. + + + + member_function_pointer_ex.cpp.html + + + + + member_function_pointer_kernel_1 + dlib/member_function_pointer/member_function_pointer_kernel_1.h + + This implementation is done using virtual functions in the obvious way (sorta). + + + + + kernel_1a + is a typedef for member_function_pointer_kernel_1 + + + + + + + + + + + + + + + bit_stream + dlib/bit_stream.h + dlib/bit_stream/bit_stream_kernel_abstract.h + + This object represents a middle man between a user and the iostream classes that allows single + bits to be read/written easily from/to the iostream classes + + + + + bit_stream_kernel_1 + dlib/bit_stream/bit_stream_kernel_1.h + + This implementation is done by buffering single bits in the obvious way. + + + + + kernel_1a + is a typedef for bit_stream_kernel_1 + + + + + + + + + + + bit_stream_multi + dlib/bit_stream/bit_stream_multi_abstract.h + This extension gives a bit_stream object the ability to read/write multible bits at a time. + + + bit_stream_multi_1 + dlib/bit_stream/bit_stream_multi_1.h + This implementation is done by calling the read/write functions in the bit_stream kernel. + + + multi_1a + is a typedef for bit_stream_kernel_1 extended by bit_stream_multi_1 + + + + + + + + + + + + + + byte_orderer + dlib/byte_orderer.h + dlib/byte_orderer/byte_orderer_kernel_abstract.h + + This object provides a simple type safe mechanism to convert data + to and from network and host byte orders. I.e. to convert things + between big and little endian byte ordering. + + + + + byte_orderer_kernel_1 + dlib/byte_orderer/byte_orderer_kernel_1.h + + This implementation is done in the obvious way. + + + + + kernel_1a + is a typedef for byte_orderer_kernel_1 + + + + + + + + + + + + memory_manager_stateless + dlib/memory_manager_stateless.h + dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h + + This object represents some kind of stateless memory manager or memory pool. + Stateless means that all instances (instances of the same type that is) + of this object are identical and can be used interchangably. Note that + implementations are allowed to have some shared global state such as a + global memory pool. This object is also thread safe. + + + + + memory_manager_stateless_kernel_1 + dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h + + This implementation just calls new and delete. So it doesn't do anything special. + + + + + kernel_1a + is a typedef for memory_manager_stateless_kernel_1 + + + + + + + memory_manager_stateless_kernel_2 + dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h + + This implementation uses a global instance of a memory_manager object + guarded by a mutex as its implementation. + + + + + kernel_2_1a + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1a + + + kernel_2_1b + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1b + + + kernel_2_1c + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1c + + + kernel_2_1d + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1d + + + kernel_2_1e + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1e + + + kernel_2_1f + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_1f + + + kernel_2_2a + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2a + + + kernel_2_2b + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2b + + + kernel_2_2c + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2c + + + kernel_2_2d + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2d + + + kernel_2_2e + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_2e + + + + kernel_2_3a + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3a + + + kernel_2_3b + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3b + + + kernel_2_3c + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3c + + + kernel_2_3d + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3d + + + kernel_2_3e + is a typedef for memory_manager_stateless_kernel_2 that uses memory_manager_3e + + + + + + + + + + + + memory_manager_global + dlib/memory_manager_global.h + dlib/memory_manager_global/memory_manager_global_kernel_abstract.h + + This object represents some kind of global memory manager or memory pool. + + + + + memory_manager_global_kernel_1 + dlib/memory_manager_global/memory_manager_global_kernel_1.h + + This is implemented in the obvious way. See the code for details. + + + + + kernel_1a + is a typedef for memory_manager_global_kernel_1 + + + + + + + + + + + + memory_manager + dlib/memory_manager.h + dlib/memory_manager/memory_manager_kernel_abstract.h + + This object represents a memory pool. + + + + + memory_manager_kernel_1 + dlib/memory_manager/memory_manager_kernel_1.h + + This memory manager implementation allocates objects one at a time when there are + allocation requests. Then when there is a deallocate request the returning object + is placed into a list of free blocks if that list has less than max_pool_size + blocks in it. Subsequent allocation requests will be serviced by drawing from the + free list whenever it isn't empty. Array allocations, on the other hand, are not + managed at all but are passed directly on to new and delete. +

    + When this object's max_pool_size template parameter is set to 0 it simply calls + new and delete directly and doesn't function as a memory pool. +

    +
    + + + + kernel_1a + is a typedef for memory_manager_kernel_1 with a max_pool_size of 0 + + + kernel_1b + is a typedef for memory_manager_kernel_1 with a max_pool_size of 10 + + + kernel_1c + is a typedef for memory_manager_kernel_1 with a max_pool_size of 100 + + + kernel_1d + is a typedef for memory_manager_kernel_1 with a max_pool_size of 1000 + + + kernel_1e + is a typedef for memory_manager_kernel_1 with a max_pool_size of 10000 + + + kernel_1f + is a typedef for memory_manager_kernel_1 with a max_pool_size of 100000 + + + +
    + + + memory_manager_kernel_2 + dlib/memory_manager/memory_manager_kernel_2.h + + This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T) + bytes. All the sizeof(T) subblocks are kept in a linked list of free memory blocks + and are given out whenever an allocation request occurs. Also, memory is not freed + until this object is destructed. + Also note that array allocations are not managed at all but are passed directly + on to new and delete. + + + + + kernel_2a + is a typedef for memory_manager_kernel_2 with a chunk_size of 10 + + + kernel_2b + is a typedef for memory_manager_kernel_2 with a chunk_size of 100 + + + kernel_2c + is a typedef for memory_manager_kernel_2 with a chunk_size of 1000 + + + kernel_2d + is a typedef for memory_manager_kernel_2 with a chunk_size of 10000 + + + kernel_2e + is a typedef for memory_manager_kernel_2 with a chunk_size of 100000 + + + + + + + memory_manager_kernel_3 + dlib/memory_manager/memory_manager_kernel_3.h + + This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T) + bytes. All the sizeof(T) subblocks are kept in a linked list of free memory blocks + and are given out whenever an allocation request occurs. Note that array allocations + are managed. So this object is just like kernel_2 but it also pools memory from + array allocations (chunk_size has no effect with respect to array allocations, each array + is allocated one at a time). + Also, memory is not freed until this object is destructed. + + + + + kernel_3a + is a typedef for memory_manager_kernel_3 with a chunk_size of 10 + + + kernel_3b + is a typedef for memory_manager_kernel_3 with a chunk_size of 100 + + + kernel_3c + is a typedef for memory_manager_kernel_3 with a chunk_size of 1000 + + + kernel_3d + is a typedef for memory_manager_kernel_3 with a chunk_size of 10000 + + + kernel_3e + is a typedef for memory_manager_kernel_3 with a chunk_size of 100000 + + + + +
    + +
    + + + + + sync_extension + dlib/sync_extension.h + dlib/sync_extension/sync_extension_kernel_abstract.h + + + This object represents a general extension to any object. This object gives any object which it extends + an integrated rmutex and rsignaler object. The extended object will + then be able to be treated as if it was also a rmutex and + rsignaler. + + + + + + sync_extension_kernel_1 + dlib/sync_extension/sync_extension_kernel_1.h + + This is implemented using a rmutex + and rsignaler in the obvious way. + + + + + kernel_1a + is a typedef for sync_extension_kernel_1 + + + + + + + + + + + + + + timeout + dlib/timeout.h + dlib/timeout/timeout_kernel_abstract.h + + This object provides a simple way to implement a timeout. + + + + + timeout_kernel_1 + dlib/timeout/timeout_kernel_1.h + + This is implemented in the obvious way using virtual functions and templates. + + + + + kernel_1a + is a typedef for timeout_kernel_1 + + + + + + + + + + + + + timer + dlib/timer.h + dlib/timer/timer_kernel_abstract.h + + This object represents a timer that will call a given member function + repeatedly at regular intervals. + + + + timer_ex.cpp.html + + + + + timer_kernel_1 + dlib/timer/timer_kernel_1.h + + This is implemented in the obvious way. + + + + + kernel_1a + is a typedef for timer_kernel_1 + + + + + + + timer_kernel_2 + dlib/timer/timer_kernel_2.h + + This implemenation has a single master thread that does all the waiting. + This master thread creates and dispatches threads to specific timer objects + when they need to run their action functions. When a timer object isn't executing + its action function then it doesn't have any thread allocated to it at all. So + it is much more efficient than timer_kernel_1. + + + + + kernel_2a + is a typedef for timer_kernel_2 + + + + + + + + + + + + + deserialize + dlib/serialize.h + dlib/serialize.h + + This is actually a set of overloaded functions which provide the ability to restore an object's state + from an input stream. Currently all dlib container classes, non pointer C++ intrinsics, std::string, + std::vector, std::map, std::complex, dlib::bigint, dlib::uint64, C style arrays, and dlib::vector objects are serializable. + + + + + + + + serialize + dlib/serialize.h + dlib/serialize.h + + This is actually a set of overloaded functions which provide the ability to save an object's state + to an output stream. Currently all dlib container classes, non pointer C++ intrinsics, std::string, + std::vector, std::map, std::complex, dlib::bigint, dlib::uint64, C style arrays, and dlib::vector objects are serializable. + + + + + + + + dlib_testing_suite + +

    + This library comes with a command line driven regression test suite. All the testing code + is located in the dlib/testdlib/test folder. If you want to build it and test the library on your + system you can use the makefile at dlib/test/makefile (you may + have to edit it to make it work on your system) or use the CMake CMakeLists.txt file at + dlib/test/CMakeLists.txt to build it. +

    +

    + What you may find more useful however is the testing framework itself. It uses a faily simple + and modular design. Each test is contained in its own cpp file and when compiled into the + program it automatically shows up in the list of tests to run. If you want to use the + testing framework all you need to do is add the files dlib/test/tester.h, + dlib/test/tester.cpp, and dlib/test/main.cpp + to your project and then add cpp files that contain your tests (see + dlib/test/example.cpp and + dlib/test/example_args.cpp + for some examples). +

    +

    + From the command line you can choose to run all the installed tests, enable or disable the loggers, + set various logging levels, specify how many times to run the tests, or pick just one or two tests + to run at a time rather than the entire suite. +

    +
    + +
    + + + +
    + + + + +
    diff --git a/docs/docs/parsing.xml b/docs/docs/parsing.xml new file mode 100644 index 0000000000000000000000000000000000000000..10e630eadb3ea2f5fe9b554147f2f49cc4a6cbcd --- /dev/null +++ b/docs/docs/parsing.xml @@ -0,0 +1,686 @@ + + + + + Parsing + + + + +

    + +

    + This page documents the objects and functions that in some way deal with parsing or otherwise + manipulating text. + Everything here follows the same conventions as the rest of the library. +

    + + + + + + + + + +
    + Objects + cmd_line_parser + config_reader + cpp_pretty_printer + cpp_tokenizer + tokenizer + xml_parser + base64 + unichar + ustring + basic_utf8_ifstream + +
    + +
    + Global Functions + string_cast + cast_to_string + cast_to_wstring + wrap_string + narrow + trim + ltrim + rtrim + pad + lpad + rpad + left_substr + right_substr + tolower + toupper + convert_utf8_to_utf32 + is_combining_char +
    +
    +
    + + + + + + + + + + + + + toupper + dlib/string.h + dlib/string/string_abstract.h + + This is a function to convert a string to all uppercase. + + + + + + + + tolower + dlib/string.h + dlib/string/string_abstract.h + + This is a function to convert a string to all lowercase. + + + + + + + + + right_substr + dlib/string.h + dlib/string/string_abstract.h + + This is a function to return the part of a string to the right of a user supplied delimiter. + + + + + + + left_substr + dlib/string.h + dlib/string/string_abstract.h + + This is a function to return the part of a string to the left of a user supplied delimiter. + + + + + + + + rpad + dlib/string.h + dlib/string/string_abstract.h + + This is a function to pad whitespace (or user specfied characters) onto the right most end of a string. + + + + + + + + lpad + dlib/string.h + dlib/string/string_abstract.h + + This is a function to pad whitespace (or user specfied characters) onto the left most end of a string. + + + + + + + + pad + dlib/string.h + dlib/string/string_abstract.h + + This is a function to pad whitespace (or user specfied characters) onto the ends of a string. + + + + + + + + rtrim + dlib/string.h + dlib/string/string_abstract.h + + This is a function to remove the whitespace (or user specfied characters) from the right most end of a string. + + + + + + + + ltrim + dlib/string.h + dlib/string/string_abstract.h + + This is a function to remove the whitespace (or user specfied characters) from the left most end of a string. + + + + + + + + trim + dlib/string.h + dlib/string/string_abstract.h + + This is a function to remove the whitespace (or user specfied characters) from the ends of a string. + + + + + + + + narrow + dlib/string.h + dlib/string/string_abstract.h + + This is a function for converting a string of type std::string or std::wstring + to a plain std::string. + + + + + + + + wrap_string + dlib/string.h + dlib/string/string_abstract.h + + wrap_string is a function that takes a string and breaks it into a number of + lines of a given length. You can use this to make a string + fit nicely into a command prompt window for example. + + + + + + + + cast_to_wstring + dlib/string.h + dlib/string/string_abstract.h + + cast_to_string is a templated function which makes it easy to convert arbitrary objects to + std::wstring strings. The types supported are any types that can be written to std::wostream via + operator<<. + + + + + + + + cast_to_string + dlib/string.h + dlib/string/string_abstract.h + + cast_to_string is a templated function which makes it easy to convert arbitrary objects to + std::string strings. The types supported are any types that can be written to std::ostream via + operator<<. + + + + + + + + string_cast + dlib/string.h + dlib/string/string_abstract.h + + string_cast is a templated function which make it easy to convert strings to + other types. The types supported are any types that can be read by the basic_istream operator>>. It + also supports casting between wstring, string, and ustring objects. + + + + + + + + unichar + dlib/unicode.h + dlib/unicode/unicode_abstract.h + + This is a typedef for an unsigned 32bit integer which we use to store + Unicode values. + + + + + + + + basic_utf8_ifstream + dlib/unicode.h + dlib/unicode/unicode_abstract.h + + This object represents an input file stream much like the + normal std::ifstream except that it knows how to read UTF-8 + data. So when you read characters out of this stream it will + automatically convert them from the UTF-8 multibyte encoding + into a fixed width wide character encoding. + +

    + There are also two typedefs of this object. The first is utf8_wifstream which is a + typedef for wchar_t as the wide character to read into. The second is utf8_uifstream + which uses unichar instead of wchar_t. +

    +
    + +
    + + + + + + ustring + dlib/unicode.h + dlib/unicode/unicode_abstract.h + + This is a typedef for a std::basic_string<unichar>. That is, it is a typedef + for a string object that stores unichar Unicode characters. + + + + + + + + is_combining_char + dlib/unicode.h + dlib/unicode/unicode_abstract.h + + This is a global function that can tell you if a character is a Unicode + combining character or not. + + + + + + + + convert_utf8_to_utf32 + dlib/unicode.h + dlib/unicode/unicode_abstract.h + + This is a global function that can convert UTF-8 strings into strings + of 32bit unichar characters. + + + + + + + + base64 + dlib/base64.h + dlib/base64/base64_kernel_abstract.h + + This object allows you to encode and decode data to and from + the Base64 Content-Transfer-Encoding defined in section 6.8 of + rfc2045. + + + + file_to_code_ex.cpp.html + + + + + base64_kernel_1 + dlib/base64/base64_kernel_1.h + + This implementation is done using a lookup table in the obvious way. + + + + + kernel_1a + is a typedef for base64_kernel_1 + + + + + + + + + + + + + cmd_line_parser + dlib/cmd_line_parser.h + dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h + + This object allows you to easily parse a command line. + + + + compress_stream_ex.cpp.html + + + + + cmd_line_parser_kernel_1 + dlib/cmd_line_parser/cmd_line_parser_kernel_1.h + + This implementation uses the map and sequence + containers to keep track of the command line options and arguments. For further details see the above link. + + + + + kernel_1a + is a typedef for cmd_line_parser_kernel_1 that uses map_kernel_1a and sequence_kernel_2a + + + + + + + + + + + cmd_line_parser_check + dlib/cmd_line_parser/cmd_line_parser_check_abstract.h + + This gives a cmd_line_parser object the ability to easily perform various + kinds of validation on the command line input. + + + + cmd_line_parser_check_1 + dlib/cmd_line_parser/cmd_line_parser_check_1.h + This implementation is done in the obvious way. See the source for details + + + check_1a + is a typedef for cmd_line_parser_print_1 extended by cmd_line_parser_check_1 + + + + + + + + cmd_line_parser_print + dlib/cmd_line_parser/cmd_line_parser_print_abstract.h + This extension gives a cmd_line_parser object the ability to print its command line options + in a nice format. + + + cmd_line_parser_print_1 + dlib/cmd_line_parser/cmd_line_parser_print_1.h + This implementation is done by enumerating the options of the parser and printing them. + + + print_1a + is a typedef for cmd_line_parser_kernel_1 extended by cmd_line_parser_print_1 + + + + + + + + + + + + + + config_reader + dlib/config_reader.h + dlib/config_reader/config_reader_kernel_abstract.h + + This object represents something which is intended to be used to read + text configuration files. + + + + + config_reader_kernel_1 + dlib/config_reader/config_reader_kernel_1.h + + This implementation is done using the map object in the obvious way. + + + + + kernel_1a + is a typedef for config_reader_kernel_1 that uses map_kernel_1b + + + + + + + + + + config_reader_thread_safe + dlib/config_reader/config_reader_thread_safe_abstract.h + + This object extends a normal config_reader by simply wrapping all + its member functions inside mutex locks to make it safe to use + in a threaded program. + + + + config_reader_thread_safe_1 + dlib/config_reader/config_reader_thread_safe_1.h + This implementation is done in the obvious way. See the source for details + + + thread_safe_1a + is a typedef for config_reader_kernel_1 extended by config_reader_thread_safe_1 + + + + + + + + + + + + + + cpp_pretty_printer + dlib/cpp_pretty_printer.h + dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_abstract.h + + This object represents an HTML pretty printer for C++ source code. + + + + + cpp_pretty_printer_kernel_1 + dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h + + This is implemented by using the cpp_tokenizer object. + This is the pretty printer I use on all the source in this library. It applies a color scheme, turns + include directives such as #include "file.h" into links to file.h.html and puts HTML anchor points + on function and class declarations. It also looks for comments starting with /*!A and puts an anchor + before the comment using the word following the A as the name of the anchor. + + + + + kernel_1a + is a typedef for cpp_pretty_printer_kernel_1 + + + + + + cpp_pretty_printer_kernel_2 + dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_2.h + + This is implemented by using the cpp_tokenizer object. + It applies a black and white color scheme suitable + for printing on a black and white printer. It also places the document title + prominently at the top of the pretty printed source file. + + + + + kernel_2a + is a typedef for cpp_pretty_printer_kernel_2 + + + + + + + + + + + + + cpp_tokenizer + dlib/cpp_tokenizer.h + dlib/cpp_tokenizer/cpp_tokenizer_kernel_abstract.h + + This object represents a simple tokenizer for C++ source code. + + + + + cpp_tokenizer_kernel_1 + dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h + + This is implemented by using the tokenizer object in the obvious way. + + + + + kernel_1a + is a typedef for cpp_tokenizer_kernel_1 + + + + + + + + + + + + + tokenizer + dlib/tokenizer.h + dlib/tokenizer/tokenizer_kernel_abstract.h + + This object represents a simple tokenizer for textual data. + + + + + tokenizer_kernel_1 + dlib/tokenizer/tokenizer_kernel_1.h + + This is implemented in the obvious way. + + + + + kernel_1a + is a typedef for tokenizer_kernel_1 + + + + + + + + + + + + + xml_parser + dlib/xml_parser.h + dlib/xml_parser/xml_parser_kernel_abstract.h + + + This object represents a simple SAX style event driven XML parser. + It takes its input from an input stream object and sends events to all + registered document_handler and error_handler objects. +

    + + The xml_parser object also uses the interface classes + document_handler + and + error_handler. + Subclasses of these classes are passed to the xml_parser which generates events while it's + parsing and sends them to the appropriate handler. + +
    + + + xml_parser_ex.cpp.html + + + + + xml_parser_kernel_1 + dlib/xml_parser/xml_parser_kernel_1.h + + This implementation is done using a stack (as opposed to recursive descent) to parse + xml documents. It also uses a map to implement the attribute_list interface and + internally uses the sequence object to keep track of all registered document and error + handlers. + + + + + kernel_1a + is a typedef for xml_parser_kernel_1 that uses map_kernel_1a, stack_kernel_1a, and sequence_kernel_2a + + + + + + + +
    + + + + +
    + + + + +
    diff --git a/docs/docs/plus.gif b/docs/docs/plus.gif new file mode 100644 index 0000000000000000000000000000000000000000..2d15c14173d23f664b955cd24f51c82f5f09d91d Binary files /dev/null and b/docs/docs/plus.gif differ diff --git a/docs/docs/release_notes.xml b/docs/docs/release_notes.xml new file mode 100644 index 0000000000000000000000000000000000000000..af1f1943389db107758de966993b2044be7ddf35 --- /dev/null +++ b/docs/docs/release_notes.xml @@ -0,0 +1,1429 @@ + + + + + Release notes + + + + + + + + +New Stuff: + +Non-Backwards Compatible Changes: + +Bug fixes: + +Other: + + + + + +New Stuff: + - Added the vector_to_matrix() function. + - Added a cholesky_decomposition() function. + - Added the toggle_button GUI widget + - Added a default toggle button style as well as check box and + radio button styles. + - Added a single click event to list_box + - Added a save_file_box() and open_existing_file_box() function. + +Non-Backwards Compatible Changes: + - Changed the check_box and radio_button widgets to be specializations of + the new toggle_button object. This is a nearly backwards compatible + change except that the events registered to check_box and radio_button + clicks must now take the form void event(toggle_button&) or + void event(void) instead of the previous void event(check_box&) and + void event(radio_button&). + - Removed the is_mouse_over bool from the button_style::draw_button() + function. + +Bug fixes: + - Fixed a compiler error in mingw. + - Changed the preprocessor checks for the wchar_t overload of + is_built_in_scalar_type so that it works properly with visual studio. + +Other: + - Added a Bayesian Network GUI that allows you to create a network + and serialize it to disk. + + + + + +New Stuff: + - GUI Related + - Added the scrollable_region widget + - Added the text_grid widget + - Added an event to the text_field so you can tell when the + user modifies it. + - Added the fit_to_contents() function to the tabbed_display + widget. + - Bayesian Network Related + - Added the node_first_parent_assignment(), node_next_parent_assignment(), + and node_cpt_filled_out() functions. + +Non-Backwards Compatible Changes: + - Reverted the change in 17.0 where I made drawable::lastx and + drawable::lasty not match the current location of the mouse inside + the on_mouse_move() event. I changed this back to how it was before, + so now lastx and lasty represent the most current record of where + the mouse is in *all* events. + - Changed the functions that control text color in the label and text_field + widgets to use rgb_pixel objects. Also added a function to set the + background color of a text_field. + +Bug fixes: + - Fixed a bug in the bayesian_network_join_tree object that caused it to + compute incorrect results for some networks. + - GUI Related + - Fixed a minor bug in the cursor drawing of the text_field + gui widget. + - Fixed a bug in the compute_cursor_rect() function. It would return an + incorrectly positioned rectangle for 0 length strings. + - Changed the way wchar_t is handled in the serialize.h file. Now + everything should compile correctly in visual studio regardless of how + you set the /Zc:wchar_t compiler option. + - Fixed a bug in the menu_bar widget. One of the members wasn't being + initialized when it needed to be. + - Fixed a bug in the tabbed_display where it didn't redraw itself + correctly after it was moved by set_pos() + +Other: + - Changed the xml parser so that it counts line numbers + from the start of the input stream instead of from the + root tag. + - Changed the xml parser so that you will only get the fatal_error + event once if it occurs. + + + + + +New Stuff: + - Added a zoomable_region widget + - Added a directed_graph_drawer widget + +Non-Backwards Compatible Changes: + - Changed the first_pixel argument of the draw_string() function + to be a rectangle like all the other draw functions now use. + +Bug fixes: + - Fixed a bug in the tooltip widget that was triggered when calling + its member functions without calling set_tooltip_text(). This also + fixed a bug in the button object that triggered when calling some button + functions that referenced the tooltip widget. + - Fixed a problem in the draw_circle and draw_solid_circle functions. + They didn't draw themselves quite correctly in all cases. + +Other: + + + + + +New Stuff: + - Added a png_loader object + - GUI related + - Added a popup_menu widget + - Added a menu_bar widget + - Added a tooltip widget + - Added a user selectable style to the gui button. + - Added the draw_rounded_rectangle() and fill_gradient_rounded() functions + - Added the mouse_over_event object to the base_widgets and made the + button_action inherit from it. + - Added the drawable::next_free_user_event_number() function + - matrix and geometry: + - Added a size() function to matrix_exp and matrix_ref objects. + - Added a class that represents 2D points + - Added the following matrix functions: + - squared(), cubed(), get_rect(), a subm() function that takes + rectangles, and normlize() + - Added the following rectangle functions: + - area(), centered_rect(), translate_rect(), move_rect(), resize_rect(), + resize_rect_height(), resize_rect_width(), and nearest_point() + +Non-Backwards Compatible Changes: + - Renamed atom() to array_to_matrix() + - Moved the rectangle object from the gui_core into a new geometry folder + (only matters if you were directly including the rectangle file) + - Moved the vector object into the geometry folder. Also removed the kernel_1a + stuff. So there is now only one possible vector implementation. + - Changed the default position for a rectangle to (0,0) instead of (1,1) + - Added edge data to the directed_graph. This breaks backwards compatibility + with the previous serialization format for directed_graphs. + - GUI related: + - Changed the base_window::on_keydown event signature so that it now + reports more keyboard modifier keys (e.g. alt) + - Made the functions for drawing on canvas objects take points and pixels + instead of just a bunch of integers. Also changed the order of the + arguments so that the canvas comes first, followed by the location + to draw on, then what to draw. + - Moved the canvas drawing functions into the gui_widgets/canvas_drawing.h + file. + - Modified the drawable_window so that the drawable::lastx and drawable::lasty + fields are updated after calls to on_mouse_move. This way the x and y that + go into the on_mouse_move actually tell you something. + +Bug fixes: + - Fixed a bug in the floating point serialization code. It + didn't handle NaN or infinities correctly. + - Fixed a bug in the win32 version of the gui_core component. It was + possible that calling set_size(), set_pos(), or set_title() could cause + the program to deadlock. + - Made the load_bmp() function more robust in the face of weirdly + written BMP files. + - Modified the draw_circle() and draw_solid_circle() functions so that they + only touch each canvas pixel once. This avoids messing up alpha blending + if an rgb_alpha_pixel is used. + +Other: + - Removed the old win32 only gui code in the dlib/gui folder. + - Changed the default GUI font to a nicer Sans Serif font + + + + + +New Stuff: + - Added another constructor to the thread_function object. + Now it can take proper function objects as well as normal function + pointers. + - Added the probabilistic_decision_function object and svm_nu_train_prob() + function. + +Non-Backwards Compatible Changes: + - Changed the svm train functions so that the cache_size argument + now measures the max number of megabytes of memory to use rather + than number of kernel matrix rows to cache. It's default + value is now 200MB. + - changed the type typedef in the SVM kernel function objects to + be named sample_type instead of type. + +Bug fixes: + - Fixed a bug in the trim, rtrim, and ltrim functions. They + didn't return empty strings when the input string contained all + trim characters. + - Fixed a bug in the decision_function's copy constructor + +Other: + - Added an optimization to the working set selection for the svm training code. + Now the algorithm will prefer to select indices that are in the kernel + matrix cache when possible. + - Fixed a problem with the chm documentation file where many of the links + didn't work. + - Made the support vector functions capable of operating with floats, doubles, + and long doubles instead of just the double type. + + + + + +New Stuff: + - Added aversion of the draw_line() function for images. + - Added the atom(), rowm(), colm(), and subm() matrix functions. + - Added some push/pop_back() functions to the array object that are similar + to the ones in the std::vector. + - Added the std_vector_c class that wraps std::vector and checks its + function's preconditions. + - Added the polynomial_kernel object for use with the svm algorithm. + +Non-Backwards Compatible Changes: + - Changed the svm_nu_cross_validate() function to return a vector + of both the +1 and -1 cross validation accuracies. + +Bug fixes: + - Fixed a bug in the list_box that caused it to not hide itself properly + when told to do so. + - Fixed canvas::fill() gui function so that it should work right + on 64 bit platforms. + +Other: + + + + + +New Stuff: + - Added memory manager support to the matrix object. + +Non-Backwards Compatible Changes: + - Made the assign_pixel() function saturate grayscale values bigger + than the target pixel type can handle. Previously it would just + truncate the numbers. + - Removed rand_kernel_1 and rand_kernel_2 because they gave very + inferior results compared to rand_kernel_3. I then renamed + rand_kernel_3 to rand_kernel_1. + - Renamed rand::get_random_number() to get_random_8bit_number() and also + added a get_random_16bit_number() and get_random_32bit_number() + - Added a checksum to compress_stream_kernel_1 and kernel_2. This + breaks backwards compatibility with the previous versions. That is, + the new implementations will complain that decompression fails if + you give them data compressed with the old non-checksum version of + the compression routines. + - Removed the width() and height() functions from the array2d object. + Now only the equivalent nc() and nr() member functions remain. + - Changed array2d::set_size(width,height) to set_size(num_rows, num_cols). + That is, I switched the order of the two arguments to this function. + The reason for doing this is to make it have the same form as the + set_size() member of the matrix object. This way the usage of the + set_size() member for these two very similar data structures is + the same. Hopefully this will reduce confusion rather than + make things worse. + +Bug fixes: + - Fixed a bug in the image_widget. It didn't repaint the screen + all the way if you gave it a smaller image to display. + - Fixed a bug in the cat() function that caused the state of the queue + to be broken if you called cat with an empty queue. + - Made the queue_sort_1 use a better sorting algorithm. In particular, it + will not sort slowly for nearly sorted data. + - Fixed a bug in the queue_kernel_2 object that caused it to not work + correctly with the non-default memory managers. + +Other: + - Added example code for the member_function_pointer as well as the matrix + object. + - Added some more regression tests and made some of the longer running + ones execute a lot quicker. + - Made the unit test suite easier to use. Now tests just throw an exception + to indicate an error rather than returning an error code. + - Added an example program for the multi-layer perceptron neural network. + + + + +New Stuff: + - Added the is_signed_type and is_unsigned_type templates + - Image Processing stuff + - Added the assign_all_pixels() function + - Added the assign_border_pixels() function + - Added the assign_pixel_intensity() function + - Added the auto_threshold_image() function + - Added the binary_union() function + - Added the edge_orientation() function + - Added the get_histogram() function + - Added the get_pixel_intensity() function + - Added the hysteresis_threshold() function + - Added the sobel_edge_detector() function + - Added the suppress_non_maximum_edges() function + - Added the zero_border_pixels() function + - Changed the pixel_traits structure so that it can support 8, 16, and 32 + bit grayscale pixels. + +Non-Backwards Compatible Changes: + - Added more fields to the pixel_traits template so if you had defined your + own pixel types you will need to update them. + +Bug fixes: + - Fixed some compiler errors in Visual Studio 2008 + +Other: + - Generally tried to clean up the documentation and code in this release + + + + + + +New Stuff: + - Added the randomize_samples() function + - Added the set_main_font() and main_font() functions to the drawable object. + So now the drawable widgets can use a user provided font. + +Non-Backwards Compatible Changes: + - Made the named_rectangle object a little easier to use. It now won't + let you size it so small that it doesn't display its entire name. + +Bug fixes: + - Fixed a bug in the svm_nu_train() function that caused a crash with + some inputs. + - Fixed a compile time error that occurred when compiling the bayesian + network code in Mac OS X. + - Fixed a bug in the compute_cursor_pos() function where it would + return the incorrect value. + +Other: + - Added an example showing how to use the svm functions. + + + + + + +New Stuff: + - Added the left_substr() and right_substr() functions + - Added the zero_extend_cast() function + - Added the unsigned_type template + - Added the uint8 typedef + - Bayesian Network related + - Added the assignment object + - Added the bayes_node object + - Added the joint_probability_table object + - Added the conditional_probability_table object + - Added the bayesian_network_gibbs_sampler object + This object implements an algorithm that performs approximate inference + in a Bayesian Network. + - Added the bayesian_network_join_tree object + This object implements an algorithm that performs exact inference + in a Bayesian Network. + - Set related + - Added the set_intersection_size() function + - Added the set_union() function + - Added the set_intersection() function + - Added the set_difference() function + - Graph related + - Added the graph object + - Added the is_graph template + - Added the is_directed_graph template + - Added the create_moral_graph() function + - Added the triangulate_graph_and_find_cliques() function + - Added the graph_contains_length_one_cycle() function + - Added the find_connected_nodes() function + - Added the graph_is_connected() function + - Added the is_clique() function + - Added the is_maximal_clique() function + - Added the copy_graph_structure() function + - Added the create_join_tree() function + - Added the is_join_tree() function + - Added the edge() function + - GUI related + - Added the base_window::get_display_size() function + - Added message_box_blocking() + - Added the bdf_font object which is capable of loading BDF font files into + the font object used by the gui_widgets + - Better Unicode support + - Added the basic_utf8_ifstream: An input stream that can read UTF-8 files + - Added serialization support for wchar_t and std::wstring + - Added the is_combining_char() function + - Added the convert_utf8_to_utf32() function + - Modified most of the string manipulation functions in dlib/string.h + to work with any kind of character type + - The gui widgets' font object now works with Unicode text (i.e. wchar_t + and unichar strings) as well as with normal char data. + +Non-Backwards Compatible Changes: + - The dlib/all_console.cpp and dlib/all_gui.cpp files have been deprecated + in favor of a new file. Now to build with dlib you simply add + dlib/all/source.cpp to your project regardless of what type of project + you are building. + - The GUI program entry point, winmain(), has been removed. You can now use + the normal main() entry point or some other non-standard entry point + provided by your compiler. + - Renamed directed_graph::node::item to directed_graph::node::data + +Bug fixes: + - Fixed some build issues in gcc 4.2 involving some uses of the std_allocator + - Fixed some build issues in Visual Studio involving the dir_nav component + and buidling with NO_MAKEFILE #defined. + - Moved the #define that disables the old WinSock API into the sockets cpp + file. This should avoid conflicts with people who are using the old WinSock + API. + - Changed the tuple template slightly to avoid a bug in Visual Studio 7.1 + that caused a compile time error in some instances. + +Other: + + + + + + +New Stuff: + - Added a destroy() function to the map, set, hash_map, and hash_set objects. + - Added the tuple object + - Added an overload of connect() that has a timeout + - Added rand_kernel_3 as a random number generator that uses the Mersenne Twister + algorithm. + - Added the directed_graph object + - Added the graph_contains_undirected_cycle() and graph_contains_directed_cycle() + functions. + - Added the std_allocator object. It is a STL style allocator that can use + the dlib memory manager objects. + - std::string manipulation functions: + - Added the cast_to_string() function. + - Added the tolower() function + - Added the toupper() function + - Added the ltrim() function + - Added the rtrim() function + - Added the trim() function + - Added the lpad() function + - Added the rpad() function + - Added the pad() function + +Non-Backwards Compatible Changes: + - Changed the default logging level from LNONE to LERROR + - Renamed the ASSERT macro to DLIB_ASSERT and CASSERT to DLIB_CASSERT. + This rename avoids a conflict with a macro inside MFC. + - Changed the logger so that settings are inherited when a new logger + is instantiated rather than just having the new logger use the + default settings. + - Removed the logger::clear() function since it no longer really + makes sense given the above change. + - Removed the get_main_thread_id() function and replaced it with the + is_dlib_thread() function. + +Bug fixes: + - Pushed some things into cpp files because doing so avoids build and/or + runtime errors on some platforms. + +Other: + - Changed the string_cast() function so that it will recognize the words true + and false as boolean values. Also improved the error message inside the + string_cast_error exception object. + + + + + + +New Stuff: + - Added the covariance() function + - Added the rgb_alpha_pixel pixel type and modified all relevant functions to + support it. + +Non-Backwards Compatible Changes: + - The GUI changes that are non-backwards compatible: + - The alpha parameter is now an unsigned char instead of unsigned int + and its range is now 0 to 255 instead of 0 to 256. + - The image_widget no longer has any member functions dealing with + alpha values. If you want to use alpha blending you just give it an + image that has an alpha channel. The same goes for draw_image(). + - There are now more fields in the pixel_traits template. So if you were + defining your own pixels before you will need to update your pixel_traits + specializations. + +Bug fixes: + - Made some functions non-inline and put some things on the stack + instead of heap. Doing this avoids some problems with certain + kinds of builds in visual studio. + +Other: + - Modified the message_box() function so that it is safe to call end_program() + from within its callback event. + + + + + + +New Stuff: + - Modified the GUI drawing functions to take an alpha argument to allow + alpha blending. + - Added the svm_nu_cross_validate() function to perform k-fold + cross validation using the svm_nu_train() function. + - Added the boost enable_if templates + - Added the rand_float extension to the rand object. + - New matrix features: + - Added the pinv() function + - Changed round_zeros() to use the machine epsilon instead of 1e-6 as + its default epsilon. + - Modified the matrix object so that you can declare them with + a static dimension and a dynamic dimension. E.g. matrix<float,0,10> + is now legal and declares a matrix with a fixed number of columns(10) + and a variable number of rows. + - Added the equal() function to compare two matrices of floating + point numbers for near equality. + - Changed the matrix so that operator(long) works for both + column vectors and now also for row vectors. + - Added a set_size() and constructor that takes a single long for use in + sizing row and column vectors. + - Added the scale_columns() function + +Non-Backwards Compatible Changes: + +Bug fixes: + - Fixed an error in svm_nu_train() where it would incorrectly + complain of incorrect nu values for some datasets. + - Added a missing std:: qualifier at two points in the dlib/vector code that + could cause a compiler error in some instances. + +Other: + - Added a term index to the documentation. + + + + + + +New Stuff: + - Added a nu support vector classifier training function. + - Added a multilayer neural network object. + - Added the "destructive aliasing" checks into the matrix code. Now temporary + matrices are only created during assignment if the right hand side aliases + the left hand side in a destructive way. This removes many of the previous + uses of temporary matrices. + - Made the sum() matrix function be able to sum matrices of matrices + - New matrix functions: + - acos(), asin(), atan(), ceil(), cos(), cosh(), exp(), floor(), log(), + log10(), mean(), norm(), pow(), reciprocal(), round_zeros(), sin(), + sinh(), sqrt(), tan(), tanh(), variance(), and more overloads of + uniform_matrix(). + +Non-Backwards Compatible Changes: + +Bug fixes: + - Added missing nr() and nc() functions to the uniform_matrix() and + identity_matrix() functions. + - Forgot to add a destructor for the dynamically sized matrix resulting in a + memory leak. This is now fixed. + - Fixed various potential compile time errors + +Other: + + + + + + +New Stuff: + - Added a copy of the boost noncopyable base class. + - added some smart pointers: + - added shared_ptr + - added weak_ptr + - added scoped_ptr + +Non-Backwards Compatible Changes: + +Bug fixes: + +Other: + - Cleaned up the assert code and removed the need for the dlib/error.ccp file + - Made the matrix take better advantage of the compile time sized + dimensions when it can. + + + + + + +New Stuff: + - Made it so that command line options have a default conversion to bool + and the bool tells you if they are on the command line or not. + - Added an implicit conversion to a scalar to the matrix object + when it is of dimension 1x1. + - Added the thread_function object + - Added a function to compute the singular value decomposition of a matrix. + +Non-Backwards Compatible Changes: + - Added two new arguments to the on_request() function. They allow you to + see what HTTP headers the client sends you and to control which ones + you send back. + +Bug fixes: + +Other: + + + + + + +New Stuff: + - matrix object additions: + - Added some functions to convert between matrix and pixel objects. + - Added the clamp() function that operates on matrix objects. + - Added the sigmoid function. + - Made the matrix object capable of being sized at runtime in addition + to its original compile time static sizing capability. + - Added 3 and 4 argument versions of pointwise_multiply() + - Added the +=, -=, *= and /= operators to the matrix object. + +Non-Backwards Compatible Changes: + +Bug fixes: + - Fixed the line numbering in the color pretty printer. Wasn't being + done correctly. + - Fixed a bug in the matrix round() function. + - Fixed some miscellaneous compile time errors + - Fixed a bug in the matrix removerc() function. + - Added some missing checks to catch invalid negative index inputs to + matrix objects. + - Fixed a bug in the matrix inv() function. It could sometimes + segfault if used on certain singular matrices + +Other: + - string_cast() can now convert hex strings to integers + - You can now say myarray2d.set_size(0,0) and have it do what + you would naturally expect. + - Added some #pragma statements that tell visual studio + to link the right system libraries automatically. + So now you don't have to add these things in the + project settings anymore. + + + + + + +New Stuff: + - Added the set_all_logging_levels(), set_all_logging_output_streams() + functions + - Added the configure_loggers_from_file() function which allows you to + easily configure all logger objects using a textual configuration + file. + +Non-Backwards Compatible Changes: + +Bug fixes: + - Added a workaround into the code that avoids a potential compilation + error on Mac OS X systems. + +Other: + + + + + + +New Stuff: + +Non-Backwards Compatible Changes: + +Bug fixes: + - Fixed a bug in the POSIX version of the hostname_to_ip() function. It was + screwy if you asked for more than the first IP address (the same address + might be returned more than once). + - Fixed a bug in the pipe object's timeout functions. The timeouts weren't + working correctly. + +Other: + + + + + + +New Stuff: + - Added the wait_for_num_blocked_dequeues(), enable_enqueue(), + disable_enqueue(), and is_enqueue_enabled() functions to the pipe object. + - The pipe object can now be used with a zero length buffer. + +Non-Backwards Compatible Changes: + - There is no longer a pipe::kernel_1a_c typedef since the pipe + no longer has any requirements to check (due to the change of allowing + zero length buffer sizes) + +Bug fixes: + +Other: + - Made the ASSERT and CASSERT macros call dlib_assert_breakpoint() when they + fail. This way you can easily set a breakpoint on them in a debugging + tool by breaking on calls to this new function. + - Fixed some typos and unclear parts of the pipe spec. + + + + + + +New Stuff: + - Added a thread safe version of the config_reader object (in the form of an + extension to the config_reader) + - Added the wait_until_empty() function to the pipe object. + +Non-Backwards Compatible Changes: + - Removed the connection::close() and listener::close() functions. They have + been replaced by destructors. To upgrade old code all you have to do is + replace statements of the form "object->close();" with "delete object;". + Both statements do exactly the same thing. However, for connection objects, + you should probably be using the close_gracefully() function instead. + +Bug fixes: + - Removed a potential compile time error in the dng image format handling code. + - Fixed a bug in the bigint object. The destructor was using "delete" + when it should have been using "delete []" + - Fixed a resource leak in the POSIX version hostname_to_ip() + - Fixed a significant memory leak in memory_manager_kernel_1 + - Fixed a memory leak that could occur in memory_manager_kernel_2 + and memory_manager_kernel_3 when the constructor for the object + being constructed threw an exception. + - Added a missing delete statement to plug a memory leak + in the md5 computation code. + - Fixed an uninitialized variable warning from valgrind + (in lz77_buffer/lz77_buffer_kernel_2.h). I think this could + also potentially result in an error when decoding data but I'm not totally + sure. But either way it is fixed now. + - Changed a call to memcpy to memmove in the sockstreambuf_kernel_2 + implementation since the copy could potentially be of overlapped memory. + +Other: + - Changed the connection::read() and connection::write() functions to take + longs instead of unsigned longs as the buffer sizes. They also now + return longs instead of ints. This should be a backwards compatible change. + - Started using the valgrind tool to check for memory errors in the project and + found a few things. Very nice tool :) + + + + + + +New Stuff: + - Added the multithreaded_object extension to the threads API + - Added the load_dng() and save_dng() functions which can load and store + the DNG lossless compressed image format (which I just made up). + +Non-Backwards Compatible Changes: + - Changed the serialization format for bool to use a 1 byte code rather than 2 + bytes. So this breaks compatibility with the old format. + +Bug fixes: + - The serialization for bool didn't always work right. This is now fixed. + +Other: + + + + + + +New Stuff: + - New faster version of the bigint object (bigint_kernel_2) that uses + the Fast Fourier Transform to perform multiplications. + - The base_window can now be an "undecorated" window. This new type is suitable + for making things like popup menus and the like. + - Added the on_focus_lost() event to the base_window object + - Added the on_focus_gained() event to the base_window object + - Added the on_window_moved() event to the base_window object + - Added the get_pos() function to the base_window object + - Updated the gui_widgets's drawable interface stuff to support the three + new event types and the new window type. + - Added the drawable::draw_rectangle() function + - Added serialization support for std::complex. + - Added the assign_image() function + +Non-Backwards Compatible Changes: + - Removed the color arguments from the drawable_window object's constructor and + added a new boolean argument (if it is an undecorated window or not). This + probably won't break any code but if it does you should get a compiler error + about it. + - Made it so you must disable the events in the destructor for your + drawable gui widgets. Doing so avoids potential race conditions when + destructing drawable objects. + - Made it so that you are required to call close_window() in a window object's + destructor. This avoids a potential race condition. + +Bug fixes: + - Added a workaround for a bug in MinGW that caused the regression test suite + to crash when compiled with -O3. + - Fixed a potential bug in the X Windows version of the gui_core component. + Added an extra XFlush() to end_program() because without it a + program can crash when calling end_program() in certain instances. + - The spec for the pipe object said that objects you enqueue into it + had an "initial value for their type" after the function completes. This + is incorrect, they are swapped into the pipe so they have an undefined + value afterwards. I fixed the spec for the pipe to say this. + - Fixed a bug in the font rendering functions in the gui_widgets + component. It could cause a segmentation fault sometimes. + - Fixed some potential deadlocks in the windows version of the gui_core + component. + - Fixed a bug in the rsignaler object. When you called wait() or + wait_or_timeout() it only unlocked the associated rmutex once (it could be + locked more than once and thus might cause a deadlock since the thread + calling wait() wouldn't actually unlock the mutex in this case). + - Fixed the initialize_array() function in memory_manger_kernel_3 to be + exception safe. Previously if an exception occurred while creating + an array then a resource leak was created. + +Other: + - Changed the package format for the library somewhat. The examples are now + located in their own top level folder. Additionally, the HTML version of the + documentation also comes in the same archive as the source rather than in a + separate download. + - Started using major and minor version numbers rather than just major ones. + + + + + + +New Stuff: + - Added operator<< and operator>> iostream operators to the vector object. + +Non-Backwards Compatible Changes: + - Changed the xml_parser's document_handler interface: + made empty element tags (<like_this/>) trigger the end_element() callback + and removed the is_empty bool from start_element(). + +Bug fixes: + - Fixed a potential race condition between the destruction of the thread pool + and the "program ending handlers" stuff. + +Other: + - Made the xml parser more robust to different types of new line characters. + - Modified the source slightly so that it works with mingw. + + + + + + +New Stuff: + - The config_reader is now enumerable. + - Added the image_widget gui object. + - Added nr() and nc() to the array2d object. + - Added the shutdown_connection() function to the iostream extension + to the server object. + - Added the timer_kernel_2 implementation which is a version of the timer object + that is more efficient in its allocation of threads. + - Added the timeout object. + - There is now a CMakeLists.txt file located in the dlib folder. See + dlib/examples/CMakeLists.txt and dlib/test/CMakeLists.txt for examples + that use CMake to build projects using this library. + - Added the register_program_ending_handler() function to the threading API. + +Non-Backwards Compatible Changes: + - Removed the config_reader::get_blocks() function. Use the + new enumerable interface for the config_reader instead. + - The array2d object now uses longs instead of unsigned longs to report + its dimensions and access its elements. + - Added a uint64 to the on_connect() callback in the iostream + extension to the server object. + - timer::set_delay_time() now throws and timer::start() now may throw + std::bad_alloc. + +Bug fixes: + - Fixed a bug in end_program(). In X Windows it might not cause the + program to end right away if it was called from outside the event + handling thread. + - Fixed a bug in the implementation of the timeout part of the + close_gracefully() function. + +Other: + - The library now works on HP-UX + - The regression test suite now has command line arguments that + enable tests to send debug messages to a file. + + + + + + +New Stuff: + - The http server extension now supports the POST HTTP method. + - The attribute list object in the xml_parser is now enumerable. + - Added the threaded object extension + - Added the uintn.h file which defines fixed sized unsigned integral types. + +Non-Backwards Compatible Changes: + - Renamed the on_get() callback in the http extension to the server object to + on_request() + - Removed the network byte order functions from the sockets api. (They are still + really there though since they come from actual OS header files. But + officially they have been replaced by the byte_orderer component). + - Renamed dlib/uint64.h to dlib/uintn.h + +Bug fixes: + +Other: + - The command line parser will now let you declare long named options with - + characters in them. + - Made it so you can use the COMPILE_TIME_ASSERT macros anywhere rather than + just inside functions. + + + + + + +New Stuff: + - For dlib::matrix + - Added the tmp() function + - Added optimized specializations of inv() and det() for 1x1, 2x2, 3x3 and + 4x4 matrices. + - Added the removerc() function + - Sockets related + - Added the connect() function + - Added the is_ip_address() function. + - Added the close_gracefully() function + - Added the iostream extension to the server object. + - Added the http extension to the server object. + +Non-Backwards Compatible Changes: + - Changed the cpp_tokenizer to not convert characters to their html form. + +Bug fixes: + - Removed some potential compile time errors. See the change log for details. + +Other: + - Improved the web site + - Added some more example code + - Added more colors to cpp_pretty_printer_kernel_1. + + + + + +New Stuff: + - std::map is now serializable + - Added the matrix object and a bunch of supporting code. + - Added the list_box graphical widget + - Added the fill_rect_with_vertical_gradient() function to the + drawable interfaces list of drawing helpers. + - Added the open_file_box() function which provides a simple file chooser. + +Non-Backwards Compatible Changes: + +Bug fixes: + - Made timestamper::get_timestamp() be a const function like it should. Fixes + some compile errors. + - Fixed a bug in the font::draw_string() function. It didn't redraw + multi-line strings right. + - Fixed a bug in the scroll_bar object that would cause a compile + error if you tried to call its width() function. + - Fixed a bug in the array_kernel_1 object. It would cause a segmentation fault + when used sometimes. + +Other: + + + + + +New Stuff: + - Added the following image transformation functions: + - Added the equalize_histogram() function + - Added the spatially_filter_image() function + - Added the threshold_image() function + - Added the binary_dilation() function + - Added the binary_erosion() function + - Added the binary_open() function + - Added the binary_close() function + - Added the binary_intersection() function + - Added the binary_difference() function + - Added the binary_complement() function + - Added the clear(), load_from() and default constructor back into the + config_reader. + - Made the member_function_pointer copyable and also added operator== and != + to it. + +Non-Backwards Compatible Changes: + - Made the vector object templated so you can use types other than double with it. + But now you + have to specify what type you want to use which is slightly different. + - The asc_pair_remover and asc_remover abstract classes now take a third template + argument. I highly doubt this effects any code outside the library but it is + possible. + +Bug fixes: + - Fixed a bug in the base_window::set_size() function. If you specified a size + of (0,0) it caused your program to error out. This has now been fixed. + - Fixed a bug in the scroll_bar widget. + - Fixed a bug in save_bmp(). For some image sizes it would output a goofy + looking skewed image. + +Other: + - Switched everything that used to call operator< directly to instead use + std::less or to take a template argument that provides a compare functor that + defaults to std::less. + + + + + +New Stuff: + - Added the assign_pixel() function + - Added the hsi pixel type + - Added the save_bmp() function + - Added the static_switch template + +Non-Backwards Compatible Changes: + - Changed how the config_reader works. It now has a more powerful syntax and + improved interface. Converting any old code to use the new version should be + simple since the new file syntax is very nearly backwards compatable with the + old syntax. (i.e. You probably won't have to change anything about your + config files) + - Renamed the dlib/image_loader.h file to dlib/image_io.h since it now includes + the image saver stuff. + - Renamed the pixel struct to rgb_pixel + - Renamed pixel_traits::color to pixel_traits::rgb + - Renamed pixel_traits::scalar to pixel_traits::grayscale + +Bug fixes: + - Fixed a bug in the load_bmp() function. It would load 24bit bmp files + incorrectly. + - Changed the logger so that it won't deadlock if you write something similar to + my_log << LINFO << function_that_also_logs();. Although this is a + dumb thing to do. But even so, it shouldn't deadlock. + - Fixed a potential linking problem with the vector object. + +Other: + - I decided I'm not going to support Borland v5.5.1 anymore. There are just too + many bugs in this compiler. It is very old at this point so I don't see this + being a big deal. + - Made the drawable::draw_image() and load_bmp() functions able to handle images + of any type of pixel. + - Pulled the imaging, algorithmic and metaprogramming stuff out of the + miscellaneous section of the web page and gave them all their own sections. + + + + + +New Stuff: + - Added a logger header that prints the date and time. + - Added the LTRACE logging level + - Added a buffered implementation of sockstreambuf. + +Non-Backwards Compatible Changes: + - Changed the specs to say that sockstreambuf may be buffered. + sockstreambuf_kernel_1 is still just as it always has been though. So all old + code will still work just as it always has. But all the same, the specs have + been changed and now allow for an implemenation that is not 100% backwards + compatible. + - rand_kernel_2 now emits a different string of random numbers. + +Bug fixes: + - Changed the logger object's implementation to not try to register + a thread end handler for the main program thread anymore. This was + technically a bug according to the spec but it actually did end up + working the way it was supposed to. But even so, it shouldn't have + been doing that. + - Changed binary_search_tree_kernel_1 so that it avoids a bug in the version of + gcc on SuSE Enterprise Linux 9. + - Fixed a bug in the rand_kernel_2 implementation. It wasn't giving good + random numbers. + +Other: + - Modified the code so that you don't get any warnings when -Wall is used with + GCC. + + + + + +New Stuff: + - Added the ASSERT_ARE_SAME_TYPE macro + - Added the is_same_type template + - Added the get_main_thread_id() function to the threading API + - Added the thread_specific_data extension to the threading API + - Added the logger object. + - Added the auto_unlock object to the threading API. + +Non-Backwards Compatible Changes: + +Bug fixes: + +Other: + - Added an example that is specifically about using threads + - Added two examples about using the logger object + + + + + +New Stuff: + - Added the memory_manager_stateless object and two implementations of it. + - Added the MACOSX macro to dlib/platform.h + - Added a templated version of create_new_thread() that allow you to start + a thread with a member function. + - Added the register_thread_end_handler() function to the threading kernel API. + - Added memory_manager_kernel_3 + +Non-Backwards Compatible Changes: + - Changed the meaning of the memory_manager_global::get_number_of_allocations() + function because the previous definition of it didn't really make sense for + this object. + - Changed the threading API to wait for all outstanding threads to terminate + before allowing the program to end. It used to just let the OS trash those + threads when main() ended but this isn't a safe or portable thing to do. I + used to assume the user would make sure all their threads were done and had + cleaned up whatever they were doing before main() ended but this is too much + of a burden on the end user. So now the library will wait for your threads to + end. You still need to have some way of telling them it is time to stop though. + +Bug fixes: + - Fixed a minor bug in dlib/timer/timer_kernel_1.h. Its implementation was + slightly off according to the specification of a timer object. + +Other: + - The byte_order object is now capable of flipping entire arrays. + - Made it so that the ENABLE_ASSERTS macro is defined whenever ASSERT is + on. + - Made the array container use the memory managers. + + + + + + +New Stuff: + - Added functions to explicitly convert to/from little and big endian to the + byte_order object. + - Added the allocate_array() and deallocate_array() functions to the + memory_manager. + - Created the memory_manager_global object + - Added the remove_last_in_order(), position_enumerator() and + remove_current_element() functions to the binary_search_tree object. + +Non-Backwards Compatible Changes: + - I put an #error directive in the old GUI component to notify anyone + trying to use it that it is deprecated. I will be removing it from the + library in a few months. + - Switched the reference_counter object back to not using the memory_manager. + I realized it isn't safe for this object to use the memory_manager since + it could result in memory_managers freeing each other's allocations. + - I redefined the pixel_traits template. It is now a lot simpler and more + convenient. + +Bug fixes: + - Fixed a minor bug in dlib/rand/rand_kernel_2.cpp + +Other: + - Added some more compile time checks to the byte_orderer object. + - Changed some includes and preprocessor macros around a little so now + everything but the GUI stuff compiles in mac OS X. + - Added inclusion guards to all the .cpp files + - Added the all_gui.cpp and all_console.cpp files. They + include all the .cpp files you need to make gui and + console applications respectively into one file. + - Made more containers use the memory_manager. + + + + + + +New Stuff: + - Added the enqueue_or_timeout() and dequeue_or_timeout() functions + to the pipe object. + - Gave the mouse_tracker the ability to display the mouse position + relative to a user selected point. + - Added the message_box() function to the gui_widgets component. + - Gave the label widget the ability to draw newlines in strings. + - added the close_window() and is_closed() methods to the base_window + object. + - Added the rsignaler extension to the threading API. + - You can now control the thread pool timeout time by setting the + DLIB_THREAD_POOL_TIMEOUT #define. + - Added the get_from_clipboard() and put_on_clipboard() functions + to the gui_core component. + - Added the stop_and_wait() function to the timer object. + - Added the trigger_user_event() function and on_user_event() event + to the base_window object. This new event is also forwarded + to drawable interfaces inside the receiving window. + - Added the wrap_around() function to the named_rectangle widget. + - Added the top(), left(), right(), bottom(), width() and height() + functions to the drawable interface. + +Non-Backwards Compatible Changes: + - Made the radio_button and check_box widgets pass references to themselves + when they call their click handlers. + - Switched the sync_extension to use the rmutex and rsignaler objects + rather than the normal non-reentrant ones. ( Chances are that old + code that used this will still compile fine anyway. ) + - Changed the return type of rand::get_random_number() to be an + unsigned char. I also changed both the implementations of + rand because they weren't very good at all. + - Changed the functions related to drawing strings in the font class. + - Changed the drawable's rectangle to default to being empty + rather than being a single point. Most code should not notice + the difference. + +Bug fixes: + - The event handlers in gui_widgets/drawable.h were private. They + should be protected. This is now fixed. + - Fixed a bug in the way the scroll_bar was drawn when it was + the HORIZONTAL type. + - Changed how the thread pool destructs itself when the program + is ending. Previously it was possible to get an error on + NetBSD when the program was ending. This is now fixed. + - The functions related to setting the jump size in the scroll_bar + widget were private. They are now public. + - There was a bug in the MS Windows version of the gui_core component + where the members of the base_window would not work if called from + within the on_window_close() event. This has now been fixed. + - Made the set_pos() function work right for the mouse_tracker widget. + - Fixed a bug in the base64 object where the string "" could potentially + be decoded incorrectly. + - Made the global swap function for crc32_kernel_1 inline. This fixes a + potential linker error. + - Fixed some potential deadlocking that could occur while using the + gui widgets. + +Other: + - I moved all the regression tests into the dlib/test folder and + made a nice driver program to run all of them. + - I have been using the sourceforge compile farms to test the library + on various platforms. It now works for Solaris and some of the BSDs + in addition to Linux and Windows. + + + + + + + +New Stuff: + - Added the array_expand extension to the array object. + - Added the cmd_line_parser_check extension to the command line parser. + - Added the pipe object. + - All applicable container classes now use the memory_manager component for + their memory allocation. + - New implementations of the memory_manager object. + - Added the copy_functor class. + +Non-Backwards Compatible Changes: + - Moved the wrap_string, narrow, and string_cast functions + to a new file. You now have to include dlib/string.h to get + them. (This makes a bunch of other things work right in gcc 2.95) + - Renamed the _L macro to _dT + - Removed the scopy class + - Simplified the interface to the memory manager. It is basically the same + though. + - Removed the max_size() methods from the hash_table and binary_search_tree + objects. + - Removed the T_is_POD template arguments from the hash_table and + binary_search_tree objects. + - Simplified the template arguments to all checking components and extensions. + They now take the class they are to extend or check as their only template + argument. This only affects you if you haven't been using the kernel_nx + typedefs. + +Bug fixes: + +Other: + - I changed a few things around and now a majority of the library + again compiles under gcc 2.95. But some things don't and I currently + don't plan on making them work because it involves hackish workarounds + of 2.95's bugs. + - Changed the compress_stream_kernel_1 object so that it will detect data + corruptions better. This change will prevent it from correctly decompressing + data that was compressed with a previous version and has an uncompressed size + greater than about 20,000 bytes. + - There is a new cpp file you need to compile: dlib/error.cpp + - Moved all the regression testing stuff into the dlib/test folder and made + a nicer test driver to run them. + + + + + + +New Stuff: + - Created the byte_orderer object. + - Created the mouse_tracker gui widget. + - The sliding_buffer object is now enumerable and serializable. + - Added the get_filesystem_roots() function to the dir_nar component. + - Added the create_directory() function to the misc_api component. + +Non-Backwards Compatible Changes: + - The ASSERT macro is now only enabled if DEBUG or ENABLE_ASSERTS + is defined. + +Bug fixes: + - Fixed a minor bug in the cmd_line_parser object. If you gave + an option such as --option=arg when option didn't take any + arguments it could hang your program. + - Fixed a bug in wait_or_timeout() in the posix version of the threading + api. The time to wait for was being calculated incorrectly and could + result in an excessive number of spurious returns. + - Fixed a minor bug in the on_keydown() event for windows. + I had it set such that the shift and ctrl bools would be false + if they were the actual keys being pressed. This isn't what the + specs say should happen but I had a comment in the windows code + that made it clear that I did it on purpose. Go figure :) + This is now fixed. + +Other: + - Improved the cpp_tokenizer object's ability to recognize numerical + constants. + - Improved the text_field gui widget. + - There are now two assert macros. One called ASSERT + and another CASSERT. They both do the same thing but ASSERT + is only enabled when DEBUG or ENABLE_ASSERTS is defined. + All the old ASSERT statements were changed to CASSERT statements. + + + + + +New Stuff: + - Added array_kernel_2 which is a simple layer on top of a C array. + - Added the tabbed_display GUI widget + - Added the widget_group GUI widget + - Added the named_rectangle GUI widget + - Added the pixel_traits template + +Non-Backwards Compatible Changes: + - The default maximum size for an array object is now 0 rather than + 20,000. +Bug fixes: + +Other: + - made the cpp_pretty_printer a little better about how it handles + C style code. Also added support for /*!A html_anchor_name !*/ + style comments. + + + + + +New Stuff: + - Created the array2d object. + - Created the base64 object. + - Created the pixel struct. + - Created the load_bmp() function which can load a BMP image file + into an array2d object of pixels. + - Created the drawable::draw_image() function + +Non-Backwards Compatible Changes: + - In the drawable interface I made the z order a long rather + than unsigned long. + - The cpp_tokenizer object now has a NUMBER token type. + - removed the get_ prefix from functions in the cmd_line_parser + and cmd_line_parser_option objects. Also changed the + cmd_line_parser_option::operator[] function to a normal member + function called argument(). + +Bug fixes: + +Other: + - cpp_pretty_printer now colors numeric literals a shade of yellow. + + + + + +New Stuff: + - Created the member_function_pointer object. + - Created the button_action object. + - Created the arrow_button object. + - Created the check_box object. + - Created the radio_button object. + - Created the scroll_bar object. + - More drawing functions to draw various things + onto a canvas object. + - Added enable/disable functions to the + drawable interface. + +Non-Backwards Compatible Changes: + - The gui widgets are no longer templated at the + class level. + - The drawable object's constructor now takes a + bit set rather than a bunch of bools to tell it + which events to enable. + - I changed the names of some of the functions in the + gui_widgets component so that they all reflected a + uniform naming style. + +Bug fixes: + - Fixed a minor bug in the cpp_tokenizer. + - Minor bug in the timer object. See change log for + details. + +Other: + - Made the timer object a little more robust + + + + + + + + diff --git a/docs/docs/right.gif b/docs/docs/right.gif new file mode 100644 index 0000000000000000000000000000000000000000..f615e439072c51103798667697266ce5827759e5 Binary files /dev/null and b/docs/docs/right.gif differ diff --git a/docs/docs/stylesheet.xsl b/docs/docs/stylesheet.xsl new file mode 100644 index 0000000000000000000000000000000000000000..d8c99a6cf04e84c0bd5163e5523b2e6e536b6c83 --- /dev/null +++ b/docs/docs/stylesheet.xsl @@ -0,0 +1,895 @@ + + + + + + + + true + main_menu.xml + + + + _LAST_MODIFIED_DATE_ + _CURRENT_RELEASE_ + + + + + + #E3E3E3 + #EDF3EE + 62em + + abcdefghijklmnopqrstuvwxyz + ABCDEFGHIJKLMNOPQRSTUVWXYZ + + + + + + + + + + dlib C++ Library + <xsl:if test="title"> + - <xsl:value-of select="title" /> + </xsl:if> + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    + +

    +
    + +
    + + + +
    + + +
    + + + + + + + + + + +
      + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + +
    + +
    + + + +
  • + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + + + + +
      + + + + + + +
    +
    + + + + + + + + + + +
    + +
    [top]
    +

    +
    +
    + + + +
    + + +
    + Specification: +
    + +
    + Specification: +
    +
    +
    + +
    File to include: +
    + +
    + The body for the component can be found + here: +
    + + + + + + + + +

    +
    + + +
    +
    +

    Extensions to

    +
    + + + +
    :
    + +
    +
    + Specification: + + + + + + +
    +
    +
    +
    + + + +
    +
    + +
    +
    + + +
    Code Examples: + + + + + + + , + + + +
    + + + +

    Implementations: + + + + +
    + : +
    + + + + +
    +
    +
    + +
    + + : + +
    +
    +
    +
    +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    _c
    +
    + is a typedef for that checks its preconditions. +
    +
    +
    + +
    +
    +
    + +
    +
    + + + + +

    Release

    + Release date: +
    + Major Changes in this Release: + + + + + +
    + + + +
    +

    Release

    + + Release date: + +
    + Major Changes in this Release: + + + + + +
    +
    +
    +
    +
    +
    +
    Old Release Notes
    +
    + +
    + + + + + + +

    Release

    + + Release date: + +
    + Major Changes in this Release: + + + + + +
    + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + +

    + +

    +
    + + + +

    + +

    + + + +
    +

    + +

    + + + +

    + +

    +
    + +
    + +
    +
    + +
    +         
    +       
    +
    + +
    + +
    +
    + +
    + + +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + +
  • + +
  • +
    + +
      + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + [A] + [B] + [C] + [D] + [E] + [F] + [G] + [H] + [I] + [J] + [K] + [L] + [M] + [N] + [O] + [P] + [Q] + [R] + [S] + [T] + [U] + [V] + [W] + [X] + [Y] + [Z] +
    + + + +
    + + + + + + + + + + + + + + + + + + Jan + Feb + Mar + Apr + May + Jun + Jul + Aug + Sep + Oct + Nov + Dec + + + , + (:: UTC) + + + + + + + + + + + + + + + + + + + + Revision:
    + Date:
    + + +
    +
    +
    + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + + + + M + Modified + black + + + A + Added + blue + + + D + Deleted + red + + + + +
    +
    + + + + + + + + + + +
    diff --git a/docs/docs/term_index.xml b/docs/docs/term_index.xml new file mode 100644 index 0000000000000000000000000000000000000000..13f4b3862604a00a78ca13d4610614f4327f220f --- /dev/null +++ b/docs/docs/term_index.xml @@ -0,0 +1,662 @@ + + + + + Index + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/htmlify/CMakeLists.txt b/docs/htmlify/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..317f82b655e808d55f3e7801be41bddc4b9121f2 --- /dev/null +++ b/docs/htmlify/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# + + +# create a variable called target_name and set it to the string "htmlify" +set (target_name htmlify) + +PROJECT(${target_name}) + +# add all the cpp files we want to compile to this list. This tells +# cmake that they are part of our target (which is the exectuable named htmlify) +ADD_EXECUTABLE(${target_name} +htmlify.cpp +) + +# add the folder containing the dlib folder to the include path +INCLUDE_DIRECTORIES(../..) + +# There is a CMakeLists.txt file in the dlib source folder that tells cmake +# how to build the dlib library. Tell cmake about that file. +add_subdirectory(../../dlib dlib_build) + +# Tell cmake to link our target executable to the non-gui version of the dlib +# library. +TARGET_LINK_LIBRARIES(${target_name} dlib ) + + + + +INSTALL(TARGETS ${target_name} + RUNTIME DESTINATION bin + ) diff --git a/docs/htmlify/htmlify.cpp b/docs/htmlify/htmlify.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2ecc79b8e4adcae6759436f20375b5fac63cf75 --- /dev/null +++ b/docs/htmlify/htmlify.cpp @@ -0,0 +1,600 @@ +#include +#include +#include + + +#include "dlib/cpp_pretty_printer.h" +#include "dlib/cmd_line_parser.h" +#include "dlib/queue.h" +#include "dlib/misc_api.h" +#include "dlib/dir_nav.h" + + +const char* VERSION = "2.6"; + +using namespace std; +using namespace dlib; + +typedef cpp_pretty_printer::kernel_1a cprinter; +typedef cpp_pretty_printer::kernel_2a bprinter; +typedef cmd_line_parser::check_1a_c clp; +typedef dlib::map::kernel_1a map_string_to_string; +typedef set::kernel_1a set_of_string; +typedef queue::kernel_1a queue_of_files; +typedef queue::kernel_1a queue_of_dirs; + +void print_manual ( +); +/*! + ensures + - prints detailed information about this program. +!*/ + +void htmlify ( + const map_string_to_string& file_map, + bool colored, + bool number_lines, + const std::string& title +); +/*! + ensures + - for all valid out_file: + - the file out_file is the html transformed version of + file_map[out_file] + - if (number_lines) then + - the html version will have numbered lines + - if (colored) then + - the html version will have colors + - title will be the first part of the HTML title in the output file +!*/ + +void htmlify ( + istream& in, + ostream& out, + const std::string& title, + bool colored, + bool number_lines +); +/*! + ensures + - transforms in into html with the given title and writes it to out. + - if (number_lines) then + - the html version of in will have numbered lines + - if (colored) then + - the html version of in will have colors +!*/ + +void add_files ( + const directory& dir, + const std::string& out_dir, + map_string_to_string& file_map, + bool flatten, + bool cat, + const set_of_string& filter, + unsigned long search_depth, + unsigned long cur_depth = 0 +); +/*! + ensures + - searches the directory dir for files matching the filter and adds them + to the file_map. only looks search_depth deep. +!*/ + +int main(int argc, char** argv) +{ + if (argc == 1) + { + cout << "\nTry the -h option for more information.\n"; + return 0; + } + + string file; + try + { + clp parser; + parser.add_option("b","Pretty print in black and white. The default is to pretty print in color."); + parser.add_option("n","Number lines."); + parser.add_option("h","Displays this information."); + parser.add_option("index","Create an index."); + parser.add_option("v","Display version."); + parser.add_option("man","Display the manual."); + parser.add_option("f","Specifies a list of file extensions separated by spaces. The default is \"cpp h c\".",1); + parser.add_option("i","Specifies an input directory.",1); + parser.add_option("cat","Puts all the output into a single html file with the given name.",1); + parser.add_option("depth","Specifies how many directories deep to search when using the i option. The default value is 30.",1); + parser.add_option("o","This option causes all the output files to be created inside the given directory. If this option is not given then all output goes to the current working directory.",1); + parser.add_option("flatten","When this option is given it prevents the input directory structure from being replicated."); + parser.add_option("title","This option specifies a string which is prepended onto the title of the generated HTML",1); + + + parser.parse(argc,argv); + + + parser.check_incompatible_options("cat","o"); + parser.check_incompatible_options("cat","flatten"); + parser.check_incompatible_options("cat","index"); + parser.check_option_arg_type("depth"); + + + const char* singles[] = {"b","n","h","index","v","man","f","cat","depth","o","flatten","title"}; + parser.check_one_time_options(singles); + + const char* i_sub_ops[] = {"f","depth","flatten"}; + parser.check_sub_options("i",i_sub_ops); + + const clp::option_type& b_opt = parser.option("b"); + const clp::option_type& n_opt = parser.option("n"); + const clp::option_type& h_opt = parser.option("h"); + const clp::option_type& index_opt = parser.option("index"); + const clp::option_type& v_opt = parser.option("v"); + const clp::option_type& o_opt = parser.option("o"); + const clp::option_type& man_opt = parser.option("man"); + const clp::option_type& f_opt = parser.option("f"); + const clp::option_type& cat_opt = parser.option("cat"); + const clp::option_type& i_opt = parser.option("i"); + const clp::option_type& flatten_opt = parser.option("flatten"); + const clp::option_type& depth_opt = parser.option("depth"); + const clp::option_type& title_opt = parser.option("title"); + + + string filter = "cpp h c"; + + bool cat = false; + bool color = true; + bool number = false; + unsigned long search_depth = 30; + + string out_dir; // the name of the output directory if the o option is given. "" otherwise + string full_out_dir; // the full name of the output directory if the o option is given. "" otherwise + const char separator = directory::get_separator(); + + bool no_run = false; + if (v_opt) + { + cout << "Htmlify v" << VERSION + << "\nCompiled: " << __TIME__ << " " << __DATE__ + << "\nWritten by Davis King\n"; + cout << "Check for updates at http://dclib.sf.net\n\n"; + no_run = true; + } + + if (h_opt) + { + cout << "This program pretty prints C/C++ source code to HTML.\n"; + cout << "Usage: htmlify [options] [file]...\n"; + parser.print_options(cout); + cout << "\n\n"; + no_run = true; + } + + if (man_opt) + { + print_manual(); + no_run = true; + } + + if (no_run) + return 0; + + if (f_opt) + { + filter = f_opt.argument(); + } + + if (cat_opt) + { + cat = true; + } + + if (depth_opt) + { + search_depth = string_cast(depth_opt.argument()); + } + + if (o_opt) + { + // make sure this directory exists + out_dir = o_opt.argument(); + create_directory(out_dir); + directory dir(out_dir); + full_out_dir = dir.full_name(); + + // make sure the last character of out_dir is a separator + if (out_dir[out_dir.size()-1] != separator) + out_dir += separator; + if (full_out_dir[out_dir.size()-1] != separator) + full_out_dir += separator; + } + + if (b_opt) + color = false; + if (n_opt) + number = true; + + // this is a map of output file names to input file names. + map_string_to_string file_map; + + + // add all the files that are just given on the command line to the + // file_map. + for (unsigned long i = 0; i < parser.number_of_arguments(); ++i) + { + string in_file, out_file; + in_file = parser[i]; + string::size_type pos = in_file.find_last_of(separator); + if (pos != string::npos) + { + out_file = out_dir + in_file.substr(pos+1) + ".html"; + } + else + { + out_file = out_dir + in_file + ".html"; + } + + if (file_map.is_in_domain(out_file)) + { + if (file_map[out_file] != in_file) + { + // there is a file name colision in the output folder. definitly a bad thing + cout << "Error: Two of the input files have the same name and would overwrite each\n"; + cout << "other. They are " << in_file << " and " << file_map[out_file] << ".\n" << endl; + return 1; + } + else + { + continue; + } + } + + file_map.add(out_file,in_file); + } + + // pick out the filter strings + set_of_string sfilter; + istringstream sin(filter); + string temp; + sin >> temp; + while (sin) + { + if (sfilter.is_member(temp) == false) + sfilter.add(temp); + sin >> temp; + } + + // now get all the files given by the i options + for (unsigned long i = 0; i < i_opt.count(); ++i) + { + directory dir(i_opt.argument(0,i)); + add_files(dir, out_dir, file_map, flatten_opt, cat, sfilter, search_depth); + } + + if (cat) + { + file_map.reset(); + ofstream fout(cat_opt.argument().c_str()); + if (!fout) + { + throw error("Error: unable to open file " + cat_opt.argument()); + } + fout << "" << cat_opt.argument() << ""; + + const char separator = directory::get_separator(); + string file; + while (file_map.move_next()) + { + ifstream fin(file_map.element().value().c_str()); + if (!fin) + { + throw error("Error: unable to open file " + file_map.element().value()); + } + + string::size_type pos = file_map.element().value().find_last_of(separator); + if (pos != string::npos) + file = file_map.element().value().substr(pos+1); + else + file = file_map.element().value(); + + std::string title; + if (title_opt) + title = title_opt.argument(); + htmlify(fin, fout, title + file, color, number); + } + + } + else + { + std::string title; + if (title_opt) + title = title_opt.argument(); + htmlify(file_map,color,number,title); + } + + + + if (index_opt) + { + ofstream index((out_dir + "index.html").c_str()); + ofstream menu((out_dir + "menu.html").c_str()); + + if (!index) + { + cout << "Error: unable to create " << out_dir << "index.html\n\n"; + return 0; + } + + if (!menu) + { + cout << "Error: unable to create " << out_dir << "menu.html\n\n"; + return 0; + } + + + index << ""; + index << ""; + index << ""; + + menu << "
    "; + + file_map.reset(); + while (file_map.move_next()) + { + if (o_opt) + { + file = file_map.element().key(); + if (file.find(full_out_dir) != string::npos) + file = file.substr(full_out_dir.size()); + else + file = file.substr(out_dir.size()); + } + else + { + file = file_map.element().key(); + } + // strip the .html from file + file = file.substr(0,file.size()-5); + menu << "" + << file << "
    "; + } + + menu << ""; + + } + + } + catch (ios_base::failure&) + { + cout << "ERROR: unable to write to " << file << endl; + cout << endl; + } + catch (exception& e) + { + cout << e.what() << endl; + cout << "\nTry the -h option for more information.\n"; + cout << endl; + } +} + +// ------------------------------------------------------------------------------------------------- + +void htmlify ( + istream& in, + ostream& out, + const std::string& title, + bool colored, + bool number_lines +) +{ + if (colored) + { + static cprinter cp; + if (number_lines) + { + cp.print_and_number(in,out,title); + } + else + { + cp.print(in,out,title); + } + } + else + { + static bprinter bp; + if (number_lines) + { + bp.print_and_number(in,out,title); + } + else + { + bp.print(in,out,title); + } + } +} + +// ------------------------------------------------------------------------------------------------- + +void htmlify ( + const map_string_to_string& file_map, + bool colored, + bool number_lines, + const std::string& title +) +{ + file_map.reset(); + const char separator = directory::get_separator(); + string file; + while (file_map.move_next()) + { + ifstream fin(file_map.element().value().c_str()); + if (!fin) + { + throw error("Error: unable to open file " + file_map.element().value() ); + } + + ofstream fout(file_map.element().key().c_str()); + + if (!fout) + { + throw error("Error: unable to open file " + file_map.element().key()); + } + + string::size_type pos = file_map.element().value().find_last_of(separator); + if (pos != string::npos) + file = file_map.element().value().substr(pos+1); + else + file = file_map.element().value(); + + htmlify(fin, fout,title + file, colored, number_lines); + } +} + +// ------------------------------------------------------------------------------------------------- + +void add_files ( + const directory& dir, + const std::string& out_dir, + map_string_to_string& file_map, + bool flatten, + bool cat, + const set_of_string& filter, + unsigned long search_depth, + unsigned long cur_depth +) +{ + const char separator = directory::get_separator(); + + queue_of_files files; + queue_of_dirs dirs; + + dir.get_files(files); + + // look though all the files in the current directory and add the + // ones that match the filter to file_map + string name, ext, in_file, out_file; + files.reset(); + while (files.move_next()) + { + name = files.element().name(); + string::size_type pos = name.find_last_of('.'); + if (pos != string::npos && filter.is_member(name.substr(pos+1))) + { + in_file = files.element().full_name(); + + if (flatten) + { + pos = in_file.find_last_of(separator); + } + else + { + // figure out how much of the file's path we need to keep + // for the output file name + pos = in_file.size(); + for (unsigned long i = 0; i <= cur_depth && pos != string::npos; ++i) + { + pos = in_file.find_last_of(separator,pos-1); + } + } + + if (pos != string::npos) + { + out_file = out_dir + in_file.substr(pos+1) + ".html"; + } + else + { + out_file = out_dir + in_file + ".html"; + } + + if (file_map.is_in_domain(out_file)) + { + if (file_map[out_file] != in_file) + { + // there is a file name colision in the output folder. definitly a bad thing + ostringstream sout; + sout << "Error: Two of the input files have the same name and would overwrite each\n"; + sout << "other. They are " << in_file << " and " << file_map[out_file] << "."; + throw error(sout.str()); + } + else + { + continue; + } + } + + file_map.add(out_file,in_file); + + } + } // while (files.move_next()) + files.clear(); + + if (search_depth > cur_depth) + { + // search all the sub directories + dir.get_dirs(dirs); + dirs.reset(); + while (dirs.move_next()) + { + if (!flatten && !cat) + { + string d = dirs.element().full_name(); + + // figure out how much of the directorie's path we need to keep. + string::size_type pos = d.size(); + for (unsigned long i = 0; i <= cur_depth && pos != string::npos; ++i) + { + pos = d.find_last_of(separator,pos-1); + } + + // make sure this directory exists in the output directory tree + d = d.substr(pos+1); + create_directory(out_dir + separator + d); + } + + add_files(dirs.element(), out_dir, file_map, flatten, cat, filter, search_depth, cur_depth+1); + } + } + +} + +// ------------------------------------------------------------------------------------------------- + +void print_manual ( +) +{ + ostringstream sout; + + const unsigned long indent = 2; + + cout << "\n"; + sout << "Htmlify v" << VERSION; + cout << wrap_string(sout.str(),indent,indent); sout.str(""); + + + sout << "This is a fairly simple program that takes source files and pretty prints them " + << "in HTML. There are two pretty printing styles, black and white or color. The " + << "black and white style is meant to look nice when printed out on paper. It looks " + << "a little funny on the screen but on paper it is pretty nice. The color version " + << "on the other hand has nonprintable HTML elements such as links and anchors."; + cout << "\n\n" << wrap_string(sout.str(),indent,indent); sout.str(""); + + + sout << "The colored style puts HTML anchors on class and function names. This means " + << "you can link directly the part of the code that contains these names. For example, " + << "if you had a source file bar.cpp with a function called foo in it you could link " + << "directly to the function with a link address of \"bar.cpp.html#foo\". It is also " + << "possible to instruct Htmlify to place HTML anchors at arbitrary spots by using a " + << "special comment of the form /*!A anchor_name */. You can put other things in the " + << "comment but the important bit is to have it begin with /*!A then some white space " + << "then the anchor name you want then more white space and then you can add whatever " + << "you like. You would then refer to this anchor with a link address of " + << "\"file.html#anchor_name\"."; + cout << "\n\n" << wrap_string(sout.str(),indent,indent); sout.str(""); + + sout << "Htmlify also has the ability to create a simple index of all the files it is given. " + << "The --index option creates a file named index.html with a frame on the left side " + << "that contains links to all the files."; + + + cout << "\n\n" << wrap_string(sout.str(),indent,indent) << "\n\n"; sout.str(""); +} + +// ------------------------------------------------------------------------------------------------- + diff --git a/docs/makedocs b/docs/makedocs new file mode 100755 index 0000000000000000000000000000000000000000..81a4022a83412bf796627e1599ad079f362ca543 --- /dev/null +++ b/docs/makedocs @@ -0,0 +1,180 @@ +#!/bin/bash + +report_failure () +{ + echo " **** failed to complete **** " + exit 1 +} + +htmlify_cmake () +{ + echo "" > $1.html; + echo $1 >> $1.html; + echo "
    " >> $1.html;
    +
    +#  line 1: make comments green
    +#  line 2: add links into the add_subdirectory directives
    +#  line 3: make literal quotes red
    +#  line 4: make the directives show up blue
    +#  line 5: make variable names show up purple
    +    sed -e "s/^\([ ]*#.*\)/\1<\/font>/" \
    +        -e "s/add_subdirectory\([ ]*\)(\([ ]*\)\([^ ]*\)\([ ]*\)\([^ )]*\)/add_subdirectory\1(\2\3\4\5<\/a>/"  \
    +        -e "s/\"\([^\"]*\)\"/\"\1<\/font>\"/g"  \
    +        -e "s/^\([ ]*[^( ]*[ ]*\)(/\1<\/font>(/" \
    +        -e "s/{\([^}]*\)}/\{\1<\/font>}/g"  \
    +        $1 >> $1.html;
    +
    +    echo "
    " >> $1; +} + +makedocs () +{ +#make sure the .docs_last_update_rev file exists + if [ ! -f .docs_last_update_rev ] + then + echo 0 > .docs_last_update_rev + fi; + + + COUNTER_FILE=.current_release_number + MINOR_COUTNER_FILE=.current_minor_release_number + REVNUM_FILE=.logger_revnum + DOCS_LAST_UPDATE_REV=$(cat .docs_last_update_rev) + + + + LOGGER_REVNUM=`cat $REVNUM_FILE` + XSLT_OPTIONS="--nodtdattr --nonet --novalid" + DATE=`date --date= "+%b %d, %Y"`; + + + +# root dlib repository URL + DLIB_REPOS=`svn info | grep Root | awk '{print $3}'` + +# The revision number we are currently at + REVISION=`svn info | grep Revision | awk '{ print $2 }'` + + + if [ "$1" = "snapshot" ] + then + RELEASE="developmental snapshot $REVISION" + else + MAJOR_NUM=`cat $COUNTER_FILE` + MINOR_NUM=`cat $MINOR_COUTNER_FILE` + RELEASE=${MAJOR_NUM}.${MINOR_NUM} + fi; + + +# update the cache of the library files from subversion if they aren't from the current revision + if [ $DOCS_LAST_UPDATE_REV -ne $REVISION ] + then + echo Getting the subversion change logs + svn log $DLIB_REPOS/dlib -v --xml -r$LOGGER_REVNUM:$REVISION > docs/svnlog.txt || report_failure + svn log $DLIB_REPOS/dlib -v --xml -r1000:$LOGGER_REVNUM > docs/old_svnlog.txt || report_failure + + rm -rf docs/cache + + echo $REVISION > .docs_last_update_rev + + echo Getting a copy of the source from subversion + svn export -r $REVISION $DLIB_REPOS/examples docs/cache/examples > /dev/null || report_failure + svn export -r $REVISION $DLIB_REPOS/dlib docs/cache/dlib > /dev/null || report_failure + fi; + + rm -rf docs/web/* + rm -rf docs/chm/docs/* + + echo Creating HTML version of the source + htmlify --title "dlib C++ Library - " -i docs/cache -o htmltemp.$$ + + echo Copying files around... + cp -r htmltemp.$$/dlib docs/web + cp -r htmltemp.$$/dlib docs/chm/docs + cp -r htmltemp.$$/examples/* docs/web + cp -r htmltemp.$$/examples/* docs/chm/docs + rm -rf htmltemp.$$ + + cp docs/cache/dlib/test/makefile docs/web/dlib/test + cp docs/cache/dlib/test/makefile docs/chm/docs/dlib/test + + cp docs/cache/dlib/test/CMakeLists.txt docs/web/dlib/test + cp docs/cache/dlib/test/CMakeLists.txt docs/chm/docs/dlib/test + cp docs/cache/dlib/CMakeLists.txt docs/web/dlib + cp docs/cache/dlib/CMakeLists.txt docs/chm/docs/dlib + mkdir docs/web/examples || report_failure + cp docs/cache/examples/CMakeLists.txt docs/web/examples + mkdir docs/chm/docs/examples || report_failure + cp docs/cache/examples/CMakeLists.txt docs/chm/docs/examples + cp docs/*.gif docs/web + cp docs/*.gif docs/chm/docs + cp docs/*.html docs/web + cp docs/*.html docs/chm/docs + cp docs/*.png docs/web + cp docs/*.png docs/chm/docs + + cd docs/chm/docs || report_failure + htmlify_cmake dlib/CMakeLists.txt; + htmlify_cmake examples/CMakeLists.txt; + htmlify_cmake dlib/test/CMakeLists.txt; + cd ../../.. || report_failure + cd docs/web || report_failure + htmlify_cmake dlib/CMakeLists.txt; + htmlify_cmake examples/CMakeLists.txt; + htmlify_cmake dlib/test/CMakeLists.txt; + cd ../.. || report_failure + + find docs/web docs/chm -name "CMakeLists.txt" | xargs rm + + + + # make the web page version + echo Generate web page from XML and XSLT style sheet + cat docs/stylesheet.xsl | sed -e 's/"is_chm">[^<]*/"is_chm">false/' -e "s/_CURRENT_RELEASE_/$RELEASE/" -e "s/_LAST_MODIFIED_DATE_/$DATE/" \ + > docs/stylesheet.$$.xsl + \ls docs/*.xml | xargs -i echo -o {} docs/stylesheet.$$.xsl {} | \ + sed -e "s/\.xml /\.html /" | sed -e "s/-o docs/-o docs\/web/" | \ + grep -v main_menu. |\ + xargs -l xsltproc $XSLT_OPTIONS + rm docs/stylesheet.$$.xsl + + # make the chm version + echo Generate non-web page version from XML and XSLT style sheet + cat docs/stylesheet.xsl | sed -e 's/"is_chm">[^<]*/"is_chm">true/' -e "s/_CURRENT_RELEASE_/$RELEASE/" -e "s/_LAST_MODIFIED_DATE_/$DATE/" \ + > docs/stylesheet.$$.xsl + \ls docs/*.xml | xargs -i echo -o {} docs/stylesheet.$$.xsl {} | \ + sed -e "s/\.xml /\.html /" | sed -e "s/-o docs/-o docs\/chm\/docs/" | \ + grep -v main_menu. |\ + xargs -l xsltproc $XSLT_OPTIONS + rm docs/stylesheet.$$.xsl + + + FILES=`find docs/chm docs/web -iname "*.html" -type f` + for i in $FILES + do + sed -e '/ temp.$$; + mv temp.$$ ${i}; + done + + + echo Generating sitemap + cd docs/web || report_failure + find . -name "*.html" | awk '{ print "http://dclib.sourceforge.net" substr($1,2)}' > sitemap.txt + cd ../.. +} + + +./testenv || report_failure + + +#echo Update the docs to the newest version in subversion +#svn update || report_failure + + +# build all the html documentation +makedocs $1; + +# now make the table of contents for the chm file +echo Generating the table of contents for the chm file +xsltproc -o docs/chm/Table\ of\ Contents.hhc docs/chm/htmlhelp_stylesheet.xsl docs/chm/toc.xml + diff --git a/docs/makerel b/docs/makerel new file mode 100755 index 0000000000000000000000000000000000000000..4910a61c36c547d510817078fe0559ba3c87c125 --- /dev/null +++ b/docs/makerel @@ -0,0 +1,84 @@ +#!/bin/bash + +# if the first argument to this script is the word major then the +# major version number is updated and the minor is set back to 0 + +report_failure () +{ + echo " **** failed to complete **** " + exit 1 +} + + +./testenv || report_failure + + + +REVNUM_FILE=.logger_revnum +COUNTER_FILE=.current_release_number +MINOR_COUTNER_FILE=.current_minor_release_number + + +RELEASE=`cat $COUNTER_FILE | awk '{ print $1 + 1}'` + +if [ "$1" = "major" ] + then + MAJOR_NUM=`cat $COUNTER_FILE | awk '{print $1 + 1}'` + MINOR_NUM=0 + echo $MAJOR_NUM > $COUNTER_FILE + echo $MINOR_NUM > $MINOR_COUTNER_FILE + ./makedocs major || exit 1 +else + MAJOR_NUM=`cat $COUNTER_FILE` + MINOR_NUM=`cat $MINOR_COUTNER_FILE | awk '{print $1 + 1}'` + echo $MINOR_NUM > $MINOR_COUTNER_FILE + ./makedocs || exit 1 +fi; + +rm -rf release/* || report_failure + +RELEASE=${MAJOR_NUM}.${MINOR_NUM} + + +DLIB_REPOS=`svn info | grep Root | awk '{print $3}'` + + +REVISION=`svn info | grep Revision | awk '{ print $2}'` + +svn log -v -r $REVISION:`cat $REVNUM_FILE` $DLIB_REPOS/dlib > release/change_log.txt || report_failure +flip -m release/change_log.txt + +echo $REVISION | awk '{ print $1 + 1}' > $REVNUM_FILE + +cd release || report_failure +RELDIR=`echo dlib-$RELEASE` +mkdir $RELDIR +cd $RELDIR || report_failure +cp -r ../../docs/cache/dlib . || report_failure +cp -r ../../docs/cache/examples . || report_failure + +echo Version: $RELEASE >> dlib/README.txt +echo Subversion Revision Number: $REVISION >> dlib/README.txt + + + +WEBPAGE=`echo dlib_webpage-$RELEASE.tar` +SOURCE_ZIP=`echo $RELDIR.zip` +SOURCE_TAR=`echo $RELDIR.tar` +tar -C ../../docs/chm -cf - docs/ documentation.html --exclude=".svn" | tar -xf - || report_failure +cd .. || report_failure + +tar -cf $SOURCE_TAR $RELDIR || report_failure +# flip everything to MS-DOS line endings +find $RELDIR -name "*.cpp" -or -name "*.h" -or -name "*.txt" -or -name "*.html" | xargs flip -m + +zip -r9 $SOURCE_ZIP $RELDIR > /dev/null || report_failure +tar -C ../docs -cf $WEBPAGE --exclude=".svn" web || report_failure +bzip2 $SOURCE_TAR || report_failure +bzip2 $WEBPAGE || report_failure + +rm -rf $RELDIR + +wine ../docs/chm/htmlhelp/hhc.exe ../docs/chm/lib.hhp +mv ../docs/chm/help.chm dlib_documentation-$RELEASE.chm || report_failure + diff --git a/docs/makesnapshot b/docs/makesnapshot new file mode 100755 index 0000000000000000000000000000000000000000..48307403bc89294b2dc6b67cd94156267db54eac --- /dev/null +++ b/docs/makesnapshot @@ -0,0 +1,51 @@ +#!/bin/bash + +report_failure () +{ + echo " **** failed to complete **** " + exit 1 +} + + +./testenv || report_failure + +./makedocs snapshot || exit 1 + + + +REVISION=`svn info | grep Revision | awk '{ print $2 }'` + + +DLIB_REPOS=`svn info | grep Root | awk '{print $3}'` + + + +cd release || report_failure +rm -rf * +RELDIR=`echo dlib_snapshot-rev$REVISION` +mkdir $RELDIR +cd $RELDIR || report_failure +cp -r ../../docs/cache/dlib . || report_failure +cp -r ../../docs/cache/examples . || report_failure + +echo This copy of dlib C++ library is a developmental snapshot. >> dlib/README.txt +echo Subversion Revision Number: $REVISION >> dlib/README.txt + + +SOURCE_ZIP=`echo $RELDIR.zip` +SOURCE_TAR=`echo $RELDIR.tar` +tar -C ../../docs/chm -cf - docs/ documentation.html --exclude=".svn" | tar -xf - +cd .. || report_failure + +tar -cf $SOURCE_TAR $RELDIR +# flip everything to MS-DOS line endings +find $RELDIR -name "*.cpp" -or -name "*.h" -or -name "*.txt" -or -name "*.html" | xargs flip -m +zip -r9 $SOURCE_ZIP $RELDIR > /dev/null +bzip2 $SOURCE_TAR + +rm -rf $RELDIR + +wine ../docs/chm/htmlhelp/hhc.exe ../docs/chm/lib.hhp +mv ../docs/chm/help.chm dlib_documentation_snapshot-rev$REVISION.chm + + diff --git a/docs/testenv b/docs/testenv new file mode 100755 index 0000000000000000000000000000000000000000..f8270ddb954fd8e8c936d328f44420ac5bf4b42a --- /dev/null +++ b/docs/testenv @@ -0,0 +1,30 @@ +#/bin/sh +# +#This script checks to make sure all the commands we need are +#present + +return_error() +{ + echo "Error, can't run the $1 command" + exit 1 +} + + +echo Testing environment for needed utilities + +flip -h > /dev/null || return_error "flip"; +echo nothing | awk '{}' > /dev/null || return_error "awk"; +echo | sed -e "s/s/r/" > /dev/null || return_error "sed"; +htmlify > /dev/null || return_error "htmlify"; +echo | xargs > /dev/null || return_error "xargs"; +svn help > /dev/null || return_error "svn"; +xsltproc -V > /dev/null || return_error "xsltproc"; +tar --help > /dev/null || return_error "tar"; +zip -h > /dev/null || return_error "zip"; +bzip2 -h &> /dev/null || return_error "bzip2"; +wine --help &> /dev/null || return_error "wine"; + + +echo All needed utilities found +exit 0 + diff --git a/docs/todo.txt b/docs/todo.txt new file mode 100644 index 0000000000000000000000000000000000000000..1924e844fefa4622e852d35844bea7c5262dff43 --- /dev/null +++ b/docs/todo.txt @@ -0,0 +1,795 @@ + + +make the popup menus from the menu_bar always put themselves on the screen +add toggle menu item styles +improve unicode support in on_keydown() +make widgets take ustring as well as std::string +add a popup menu region sort of like the tooltip widget +make other widgets have a user settable style + + + +find all uses of std::rand() and replace them with rand_kernel_1 + + + + +add a function to display an image in a window. + + + + + + + + + +make the binary search tree's add function return a +pointer to the thing it just added + + + + +add an object that represents an atomic counter so I can make some thread +safe reference counting stuff. Probably use the one from boost. + + + + + + + + +add an option to the logger to send log messages +to a thread instead of writing them directly +to the ostream. Or maybe make a threaded streambuf +that sits on top of a normal stream buffer but +adds a thread for the io... + + + + + + +make the matrix have a template argument that determined if the data is stored +in row_major or column_major order. + + + + + + +maybe add an enable_events() function to base_window + + + + + + +add a toolbar_button that has a picture and text in it. + + +make an ostream_fork object that lets you make an ostream that writes to two +other ostream objects. + + + + +make something that parses strings of the form "key ='value' key2='value'" + + + +add some sha-256 stuff + + + +uulib-threadsafe implementation +http://www.fpx.de/fp/Software/UUDeview/ + + + +add an example that uses the new checking extension for the cmd_line_parser. maybe make a +program that adds numbers and whatnot as an example and have it validate the numbers or something. + + + + + + + + + + + +add some extensions to the dir_nav stuff that know how to pull out various parts of a path. +like the parent directory of a file and such. + + + + + + + + + +make a widget that lets you use the mouse to define geometric shapes on the screen + + + + + + + + + +modify the if in the reference_counter::modify() function so that it works +better with the branch predictor + + + + + + + + + + + +Add a progress bar and password field to the gui_widgets + + + + + + + + + + +make sure constructors that take parameters that need to be checked +get checked *before* they are passed on to the base class constructors. + + + + + + + + + + + + + +make the hashing objects take a normal size rather than expnum + + + + + + + + + + + + + + +make a linear hashing object on top of the array and use a binary search tree +for pathological buckets. + + + + + + + + + + + + + + + + + + +********************************************* + + + + + + + + + + + + + + + + + + + + + + + +make conditioning_class_kernel_3 have a pointer into its array that tells it how many +elements are used. this way it doesn't need to zero everything on construction. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +a command line "percent complete bar". something that uses \r and looks like +|========== | 25% +or something like that. that would be nice. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +some object that abstracts configuration managment. like windows has the registry and +linux and posix stuff has basically nothing except for /etc and ~/.yourprogram sort of crap. +I should make an object that lets you "save" information to disk and then get it later. but +you shouldn't need to know if you are using windows or a posix OS or any of that crap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +the parsing end event in the xml parser should tell you the line number that parsing eneded on + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +an object which can fill an array of unsigned longs with primes + + + + + + + +look for places to remove the use of references to arguments. use a +temporary where appropriate + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +make an implementation of sequence that is just an array with slack on each end + + + + + + + + + + +something that mesures cpu clock ticks + + + + + + + + + + + + + + + + + + + + +something that helps you make pdf files. Just read the PDF standard and think +up cool stuff. :) + + + + + + + +english word set with perfect hashing + + +something that helps you find perfect hash functions for a given data set + + + + + + + + + +make something like the linker object but that has some events that tell you +when data is being sent so you can see what each side is sending. + + + + + + +modify sequence_kernel_1 so that when you access the same element more than once at a time +it takes O(1) time + + + + + + + + + + + + +make some bayesian text categorizer + + + + + + + + + + + + + + +implement the hash table described on comp.programming. the one +that uses an "infinite" array of buckets of sizes that are powers +of two with the watermark. +also change the specs for hash table to say that the num_of_buckets is +an initial suggestion as to the size of the hash table. not an absolute +rule for the implementation. say that it is a guaranteed lower bound or something + + + + + + + + + + + + +an object that makes it easy to save data to the end of an executable file. + + + + + + + + + + +email objects + + +new sockets stuff, UDP sockets, non-blocking sockets, IO multiplexing, negal alg on/off + + + + + + +make a priority queue + + +an echo object for networking shit. holds connections and echos any data from one connection +to all the others + +a broadcast object. holds connections and allows you to send data to all of them easily + + + + + + +file sender function + + + + + + + + + + + + + +an object which represents a file containing many text lines +like an array of strings which represents a file. + + + + + + +make an object that facilitates the creation of a gnutelli like broadcast network. +could be useful for making someting like a distributed server. and that only requires a +few computers so its something actually doable without the support of 100,000 people + +a few ideas about this. when you connect to the first person on the network you then send +out a ping message and the pong messages you get back are from people who want more +connections, the message tells you how many hops away they are and how many connections +they currently have. you pick the one that is the farthest away and then to break any +ties you pick the one with the least number of connections. + + + + + + + + + + + + + + + + + + + + + + + +an object which allows you to replace strings in a file with something else. possibly event driven. +you give it a set of strings to look for and when it finds them you get an event and can write +whatever you want and then it continues on looking for more strings. + + + + + + +an object which will pick out all the links in an html file and any other convenient information from +the file. + + + + + + + + + + + + + + +make numerical stuff like, a big integer, big real, integration stuff, differentiation stuff, +matrix stuff, etc... + + + + + + + + + + + + + +make a framework for creating web page interfaces to a program. have stuff like buttons, +listboxes, dropdown boxes, checkboxes, etc... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +a kind of pop3 proxy that can perform mail filtering. like picking out and taging spam +so that crappy email clients like netscape can put the spam into a folder + +the filter could also buffer stuff it thought as spam for a while. like hold it for a few hours and then let it be passed on. this way all the spam comes wrapped together. and so most of the time you get a flag saying you have mail it won't be spam. only somtimes will it be the packet of spam. + + + + +for the bigint object: +also consider adding a function which returns an unsigned short which contains the two least significant bytes from the bigint + + + + + + + + + + +an object which knows all about the different time zones and what not. it could convert time from GMT to whatever local timezone you are in. and any other useful conversions + + + + + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..247ece74927c80b29a9d73385d63b3900df9deb1 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,55 @@ +# +# This is a CMake makefile. You can find the cmake utility and +# information about it at http://www.cmake.org +# + + +# setting this makes CMake allow normal looking IF ELSE statements +SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +PROJECT(examples) + +# add the folder containing the dlib folder to the include path +INCLUDE_DIRECTORIES(..) + + +# There is a CMakeLists.txt file in the dlib source folder that tells cmake +# how to build the dlib library. Tell cmake about that file. +add_subdirectory(../dlib dlib_build) + + +MACRO(add_example name) + ADD_EXECUTABLE(${name} ${name}.cpp) + TARGET_LINK_LIBRARIES(${name} dlib ) +ENDMACRO() + + +#here we apply our macros +add_example(bayes_net_ex) +add_example(bayes_net_gui_ex) +add_example(bayes_net_from_disk_ex) +add_example(compress_stream_ex) +add_example(dir_nav_ex) +add_example(file_to_code_ex) +add_example(gui_api_ex) +add_example(image_ex) +add_example(logger_ex) +add_example(logger_ex_2) +add_example(matrix_ex) +add_example(member_function_pointer_ex) +add_example(mlp_ex) +add_example(multithreaded_object_ex) +add_example(pipe_ex) +add_example(queue_ex) +add_example(server_http_ex) +add_example(sockets_ex) +add_example(sockets_ex_2) +add_example(sockstreambuf_ex) +add_example(std_allocator_ex) +add_example(svm_ex) +add_example(threaded_object_ex) +add_example(thread_function_ex) +add_example(threads_ex) +add_example(timer_ex) +add_example(xml_parser_ex) + diff --git a/examples/bayes_net_ex.cpp b/examples/bayes_net_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba5961f17b1d52d50bc5edbb6bddb570ce5ac7e3 --- /dev/null +++ b/examples/bayes_net_ex.cpp @@ -0,0 +1,294 @@ +/* + This is an example illustrating the use of the Bayesian Network + inference utilities found in the dlib C++ library. + + + In this example all the nodes in the Bayesian network are + boolean variables. That is, they take on either the value + 0 or the value 1. + + The network contains 4 nodes and looks as follows: + + B C + \\ // + \/ \/ + A + || + \/ + D + + + The probabilities of each node are summarized below. (The probability + of each node being 0 is not listed since it is just P(X=0) = 1-p(X=1) ) + + p(B=1) = 0.01 + + p(C=1) = 0.001 + + p(A=1 | B=0, C=0) = 0.01 + p(A=1 | B=0, C=1) = 0.5 + p(A=1 | B=1, C=0) = 0.9 + p(A=1 | B=1, C=1) = 0.99 + + p(D=1 | A=0) = 0.2 + p(D=1 | A=1) = 0.5 + +*/ + + +#include "dlib/bayes_utils.h" +#include "dlib/graph_utils.h" +#include "dlib/graph.h" +#include "dlib/directed_graph.h" +#include + + +using namespace dlib; +using namespace std; + +// ---------------------------------------------------------------------------------------- + +int main() +{ + // There are many useful convenience functions in this namespace. They all + // perform simple access or modify operations on the nodes of a bayesian network. + // You don't have to use them but they are convenient and they also will check for + // various errors in your bayesian network when your application is built with + // the DEBUG or ENABLE_ASSERTS preprocessor definitions defined. So their use + // is recommended. In fact, most of the global functions used in this example + // program are from this namespace. + using namespace bayes_node_utils; + + // This statement declares a bayesian network called bn. Note that a bayesian network + // in the dlib world is just a directed_graph object that contains a special kind + // of node called a bayes_node. + directed_graph::kernel_1a_c bn; + + // Use an enum to make some more readable names for our nodes. + enum nodes + { + A = 0, + B = 1, + C = 2, + D = 3 + }; + + // The next few blocks of code setup our bayesian network. + + // The first thing we do is tell the bn object how many nodes it has + // and also add the three edges. Again, we are using the network + // shown in ASCII art at the top of this file. + bn.set_number_of_nodes(4); + bn.add_edge(A, D); + bn.add_edge(B, A); + bn.add_edge(C, A); + + + // Now we inform all the nodes in the network that they are binary + // nodes. That is, they only have two possible values. + set_node_num_values(bn, A, 2); + set_node_num_values(bn, B, 2); + set_node_num_values(bn, C, 2); + set_node_num_values(bn, D, 2); + + assignment parent_state; + // Now we will enter all the conditional probability information for each node. + // Each node's conditional probability is dependent on the state of its parents. + // To specify this state we need to use the assignment object. This assignment + // object allows us to specify the state of each nodes parents. + + + // Here we specify that p(B=1) = 0.01 + // parent_state is empty in this case since B is a root node. + set_node_probability(bn, B, 1, parent_state, 0.01); + // Here we specify that p(B=0) = 1-0.01 + set_node_probability(bn, B, 0, parent_state, 1-0.01); + + + // Here we specify that p(C=1) = 0.001 + // parent_state is empty in this case since B is a root node. + set_node_probability(bn, C, 1, parent_state, 0.001); + // Here we specify that p(C=0) = 1-0.001 + set_node_probability(bn, C, 0, parent_state, 1-0.001); + + + // This is our first node that has parents. So we set the parent_state + // object to reflect that A has both B and C as parents. + parent_state.add(B, 1); + parent_state.add(C, 1); + // Here we specify that p(A=1 | B=1, C=1) = 0.99 + set_node_probability(bn, A, 1, parent_state, 0.99); + // Here we specify that p(A=0 | B=1, C=1) = 1-0.99 + set_node_probability(bn, A, 0, parent_state, 1-0.99); + + // Here we use the [] notation because B and C have already + // been added into parent state. + parent_state[B] = 1; + parent_state[C] = 0; + // Here we specify that p(A=1 | B=1, C=0) = 0.9 + set_node_probability(bn, A, 1, parent_state, 0.9); + set_node_probability(bn, A, 0, parent_state, 1-0.9); + + parent_state[B] = 0; + parent_state[C] = 1; + // Here we specify that p(A=1 | B=0, C=1) = 0.5 + set_node_probability(bn, A, 1, parent_state, 0.5); + set_node_probability(bn, A, 0, parent_state, 1-0.5); + + parent_state[B] = 0; + parent_state[C] = 0; + // Here we specify that p(A=1 | B=0, C=0) = 0.01 + set_node_probability(bn, A, 1, parent_state, 0.01); + set_node_probability(bn, A, 0, parent_state, 1-0.01); + + + // Here we set probabilities for node D. + // First we clear out parent state so that it doesn't have any of + // the assignments for the B and C nodes used above. + parent_state.clear(); + parent_state.add(A,1); + // Here we specify that p(D=1 | A=1) = 0.5 + set_node_probability(bn, D, 1, parent_state, 0.5); + set_node_probability(bn, D, 0, parent_state, 1-0.5); + + parent_state[A] = 0; + // Here we specify that p(D=1 | A=0) = 0.2 + set_node_probability(bn, D, 1, parent_state, 0.2); + set_node_probability(bn, D, 0, parent_state, 1-0.2); + + + + // We have now finished setting up our bayesian network. So lets compute some + // probability values. The first thing we will do is compute the prior probability + // of each node in the network. To do this we will use the join tree algorithm which + // is an algorithm for performing exact inference in a bayesian network. + + // First we need to create an undirected graph which contains set objects at each node and + // edge. This long declaration does the trick. + typedef graph::compare_1b_c, set::compare_1b_c>::kernel_1a_c join_tree_type; + join_tree_type join_tree; + + // Now we need populate the join_tree with data from our bayesian network. The next to + // function calls do this. Explaining exactly what they do is outside the scope of this + // example. Just think of them as filling join_tree with information that is useful + // later on for dealing with our bayesian network. + create_moral_graph(bn, join_tree); + create_join_tree(join_tree, join_tree); + + // Now we have a proper join_tree we can use it to obtain a solution to our + // bayesian network. Doing this is as simple as declaring an instance of + // the bayesian_network_join_tree object as follows: + bayesian_network_join_tree solution(bn, join_tree); + + + // now print out the probabilities for each node + cout << "Using the join tree algorithm:\n"; + cout << "p(A=1) = " << solution.probability(A)(1) << endl; + cout << "p(A=0) = " << solution.probability(A)(0) << endl; + cout << "p(B=1) = " << solution.probability(B)(1) << endl; + cout << "p(B=0) = " << solution.probability(B)(0) << endl; + cout << "p(C=1) = " << solution.probability(C)(1) << endl; + cout << "p(C=0) = " << solution.probability(C)(0) << endl; + cout << "p(D=1) = " << solution.probability(D)(1) << endl; + cout << "p(D=0) = " << solution.probability(D)(0) << endl; + cout << "\n\n\n"; + + + // Now to make things more interesting lets say that we have discovered that the C + // node really has a value of 1. That is to say, we now have evidence that + // C is 1. We can represent this in the network using the following two function + // calls. + set_node_value(bn, C, 1); + set_node_as_evidence(bn, C); + + // Now we want to compute the probabilities of all the nodes in the network again + // given that we now know that C is 1. We can do this as follows: + bayesian_network_join_tree solution_with_evidence(bn, join_tree); + + // now print out the probabilities for each node + cout << "Using the join tree algorithm:\n"; + cout << "p(A=1 | C=1) = " << solution_with_evidence.probability(A)(1) << endl; + cout << "p(A=0 | C=1) = " << solution_with_evidence.probability(A)(0) << endl; + cout << "p(B=1 | C=1) = " << solution_with_evidence.probability(B)(1) << endl; + cout << "p(B=0 | C=1) = " << solution_with_evidence.probability(B)(0) << endl; + cout << "p(C=1 | C=1) = " << solution_with_evidence.probability(C)(1) << endl; + cout << "p(C=0 | C=1) = " << solution_with_evidence.probability(C)(0) << endl; + cout << "p(D=1 | C=1) = " << solution_with_evidence.probability(D)(1) << endl; + cout << "p(D=0 | C=1) = " << solution_with_evidence.probability(D)(0) << endl; + cout << "\n\n\n"; + + // Note that when we made our solution_with_evidence object we reused our join_tree object. + // This saves us the time it takes to calculate the join_tree object from scratch. But + // it is important to note that we can only reuse the join_tree object if we haven't changed + // the structure of our bayesian network. That is, if we have added or removed nodes or + // edges from our bayesian network then we must recompute our join_tree. But in this example + // all we did was change the value of a bayes_node object (we made node C be evidence) + // so we are ok. + + + + + + // Next this example will show you how to use the bayesian_network_gibbs_sampler object + // to perform approximate inference in a bayesian network. This is an algorithm + // that doesn't give you an exact solution but it may be necessary to use in some + // instances. For example, the join tree algorithm used above, while fast in many + // instances, has exponential runtime in some cases. Moreover, inference in bayesian + // networks is NP-Hard for general networks so sometimes the best you can do is + // find an approximation. + // However, it should be noted that the gibbs sampler does not compute the correct + // probabilities if the network contains a deterministic node. That is, if any + // of the conditional probability tables in the bayesian network have a probability + // of 1.0 for something the gibbs sampler should not be used. + + + // This Gibbs sampler algorithm works by randomly sampling possibles values of the + // network. So to use it we should set the network to some initial state. + + set_node_value(bn, A, 0); + set_node_value(bn, B, 0); + set_node_value(bn, D, 0); + + // We will leave the C node with a value of 1 and keep it as an evidence node. + + + // First create an instance of the gibbs sampler object + bayesian_network_gibbs_sampler sampler; + + + // To use this algorithm all we do is go into a loop for a certain number of times + // and each time through we sample the bayesian network. Then we count how + // many times a node has a certain state. Then the probability of that node + // having that state is just its count/total times through the loop. + + // The following code illustrates the general procedure. + unsigned long A_count = 0; + unsigned long B_count = 0; + unsigned long C_count = 0; + unsigned long D_count = 0; + + // The more times you let the loop run the more accurate the result will be. Here we loop + // 2000 times. + const long rounds = 2000; + for (long i = 0; i < rounds; ++i) + { + sampler.sample_graph(bn); + + if (node_value(bn, A) == 1) + ++A_count; + if (node_value(bn, B) == 1) + ++B_count; + if (node_value(bn, C) == 1) + ++C_count; + if (node_value(bn, D) == 1) + ++D_count; + } + + cout << "Using the approximate Gibbs Sampler algorithm:\n"; + cout << "p(A=1 | C=1) = " << (double)A_count/(double)rounds << endl; + cout << "p(B=1 | C=1) = " << (double)B_count/(double)rounds << endl; + cout << "p(C=1 | C=1) = " << (double)C_count/(double)rounds << endl; + cout << "p(D=1 | C=1) = " << (double)D_count/(double)rounds << endl; +} + + diff --git a/examples/bayes_net_from_disk_ex.cpp b/examples/bayes_net_from_disk_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27d01e431445de955c57a46ffc4187387009c2d2 --- /dev/null +++ b/examples/bayes_net_from_disk_ex.cpp @@ -0,0 +1,82 @@ +/* + This is an example illustrating the use of the Bayesian Network + inference utilities found in the dlib C++ library. In this example + we load a saved Bayesian Network from disk. +*/ + + +#include "dlib/bayes_utils.h" +#include "dlib/graph_utils.h" +#include "dlib/graph.h" +#include "dlib/directed_graph.h" +#include +#include + + +using namespace dlib; +using namespace std; + +// ---------------------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + try + { + // This statement declares a bayesian network called bn. Note that a bayesian network + // in the dlib world is just a directed_graph object that contains a special kind + // of node called a bayes_node. + directed_graph::kernel_1a_c bn; + + if (argc != 2) + { + cout << "You must supply a file name on the command line. The file should " + << "contain a serialized Bayesian Network" << endl; + return 1; + } + + ifstream fin(argv[1],ios::binary); + + // Note that the saved networks produced by the bayes_net_gui_ex.cpp example can be deserialized + // into a network. So you can make your networks using that GUI if you like. + cout << "Loading the network from disk..." << endl; + deserialize(bn, fin); + + cout << "Number of nodes in the network: " << bn.number_of_nodes() << endl; + + // Lets compute some probability values using the loaded network using the join tree (aka. Junction + // Tree) algorithm. + + // First we need to create an undirected graph which contains set objects at each node and + // edge. This long declaration does the trick. + typedef graph::compare_1b_c, set::compare_1b_c>::kernel_1a_c join_tree_type; + join_tree_type join_tree; + + // Now we need populate the join_tree with data from our bayesian network. The next to + // function calls do this. Explaining exactly what they do is outside the scope of this + // example. Just think of them as filling join_tree with information that is useful + // later on for dealing with our bayesian network. + create_moral_graph(bn, join_tree); + create_join_tree(join_tree, join_tree); + + // Now we have a proper join_tree we can use it to obtain a solution to our + // bayesian network. Doing this is as simple as declaring an instance of + // the bayesian_network_join_tree object as follows: + bayesian_network_join_tree solution(bn, join_tree); + + + // now print out the probabilities for each node + cout << "Using the join tree algorithm:\n"; + for (unsigned long i = 0; i < bn.number_of_nodes(); ++i) + { + // print out the probability distribution for node i. + cout << "p(node " << i <<") = " << solution.probability(i); + } + } + catch (exception& e) + { + cout << "exception thrown: " << e.what() << endl; + return 1; + } +} + + diff --git a/examples/bayes_net_gui_ex.cpp b/examples/bayes_net_gui_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4cc9e4dde04614769de81361661cbf242637bd5 --- /dev/null +++ b/examples/bayes_net_gui_ex.cpp @@ -0,0 +1,985 @@ +/* + This is a rather involved example illustrating the use of the GUI api from + the dlib C++ Library. This program is a fully functional utility for + creating Bayesian Networks. It allows the user to graphically draw the network, + save/load the network to/from disk, and also to calculate the posterior + probability of any node in the network given a set of evidence. + + This is not the first dlib example program you should be looking at. If you + want to see a simpler GUI example please look at the gui_api_ex.cpp or + image_ex.cpp example. + + If you want to understand how to use the Bayesian Network utilities in the library + you should definitely look at the bayes_net_ex.cpp example program. It gives a + comprehensive introduction to creating and manipulating Bayesian Networks. If you + want to see how to load a saved network from disk and use it in a non-GUI application + then look at the bayes_net_from_disk_ex.cpp example. + + + Now all of that being said, if you have already looked at the other relevant + examples and want to see a more in-depth example then by all means, continue reading. :) +*/ + +#include "dlib/gui_widgets.h" +#include +#include +#include "dlib/directed_graph.h" +#include "dlib/string.h" +#include "dlib/bayes_utils.h" +#include "dlib/smart_pointers.h" +#include "dlib/set.h" +#include "dlib/graph_utils.h" +#include "dlib/stl_checked.h" + + +using namespace std; +using namespace dlib; +using namespace dlib::bayes_node_utils; + +// ---------------------------------------------------------------------------- + +typedef directed_graph::kernel_1a_c directed_graph_type; +typedef directed_graph::kernel_1a_c::node_type node_type; +typedef graph::compare_1b_c, set::compare_1b_c>::kernel_1a_c join_tree_type; + +// ---------------------------------------------------------------------------- + +class main_window : public drawable_window +{ + /*! + INITIAL VALUE + This window starts out hidden and with an empty Bayesian Network + + WHAT THIS OBJECT REPRESENTS + This object is the main window of a utility for drawing Bayesian Networks. + It allows you to draw a directed graph and to set the conditional probability + tables up for each node in the network. It also allows you to compute the + posterior probability of each node. And finally, it lets you save and load + networks from file + !*/ +public: + main_window(); + ~main_window(); + +private: + + // Private helper methods + + void initialize_node_cpt_if_necessary ( unsigned long index ); + void load_selected_node_tables_into_cpt_grid (); + void load_selected_node_tables_into_ppt_grid (); + void no_node_selected (); + + + // Event handlers + + void on_cpt_grid_modified(unsigned long row, unsigned long col); + void on_evidence_toggled (); + void on_graph_modified (); + void on_menu_file_open (); + void on_menu_file_quit (); + void on_menu_file_save (); + void on_menu_file_save_as (); + void on_menu_help_about (); + void on_menu_help_help (); + void on_node_deleted (); + void on_node_deselected ( unsigned long n ); + void on_node_selected (unsigned long n); + void on_open_file_selected ( const std::string& file_name); + void on_save_file_selected ( const std::string& file_name); + void on_sel_node_evidence_modified (); + void on_sel_node_num_values_modified (); + void on_sel_node_text_modified (); + void on_window_resized (); + void recalculate_probabilities (); + + // Member data + + const rgb_pixel color_non_evidence; + const rgb_pixel color_default_bg; + const rgb_pixel color_evidence; + const rgb_pixel color_error; + const rgb_pixel color_gray; + bool graph_modified_since_last_recalc; + + button btn_calculate; + check_box sel_node_is_evidence; + directed_graph_drawer graph_drawer; + label sel_node_index; + label sel_node_num_values_label; + label sel_node_text_label; + label sel_node_evidence_label; + menu_bar mbar; + named_rectangle selected_node_rect; + tabbed_display tables; + text_field sel_node_num_values; + text_field sel_node_text; + text_field sel_node_evidence; + text_grid cpt_grid; + text_grid ppt_grid; + unsigned long selected_node_index; + bool node_is_selected; + widget_group cpt_group; + widget_group ppt_group; + + scoped_ptr solution; + join_tree_type join_tree; + // The std_vector_c is an object identical to the std::vector except that it checks + // all its preconditions and throws a dlib::fatal_error if they are violated. + std_vector_c cpt_grid_assignments; + std::string graph_file_name; +}; + +// ---------------------------------------------------------------------------------------- + +int main() +{ + // create our window + main_window my_window; + + // tell our window to put itself on the screen + my_window.show(); + + // wait until the user closes this window before we let the program + // terminate. + my_window.wait_until_closed(); +} + +// ---------------------------------------------------------------------------------------- + +#ifdef WIN32 +// If you use main() as your entry point when building a program on MS Windows then +// there will be a black console window associated with your application. If you +// want your application to not have this console window then you need to build +// using the WinMain() entry point as shown below and also set your compiler to +// produce a "Windows" project instead of a "Console" project. In visual studio +// this can be accomplished by going to project->properties->general configuration-> +// Linker->System->SubSystem and selecting Windows instead of Console. +// +int WINAPI WinMain (HINSTANCE, HINSTANCE, PSTR cmds, int) +{ + main(); +} +#endif + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Methods from the main_window object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +main_window:: +main_window( +) : + color_non_evidence(0,0,0), + color_default_bg(255,255,255), + color_evidence(100,200,100), + color_error(255,0,0), + color_gray(210,210,210), + graph_modified_since_last_recalc(true), + btn_calculate(*this), + sel_node_is_evidence(*this), + graph_drawer(*this), + sel_node_index(*this), + sel_node_num_values_label (*this), + sel_node_text_label(*this), + sel_node_evidence_label(*this), + mbar(*this), + selected_node_rect(*this), + tables(*this), + sel_node_num_values(*this), + sel_node_text(*this), + sel_node_evidence(*this), + cpt_grid(*this), + ppt_grid(*this), + selected_node_index(0), + node_is_selected(false), + cpt_group(*this), + ppt_group(*this) +{ + // Note that all the GUI widgets take a reference to the window that contains them + // as their constructor argument. This is a universal feature of GUI widgets in the + // dlib library. + + set_title("Bayesian Network Utility"); + + // position the widget that is responsible for drawing the directed graph, the graph_drawer, + // just below the mbar (menu bar) widget. + graph_drawer.set_pos(5,mbar.bottom()+5); + set_size(750,400); + + // register the event handlers with their respective widgets + btn_calculate.set_click_handler (*this, &main_window::recalculate_probabilities); + cpt_grid.set_text_modified_handler (*this, &main_window::on_cpt_grid_modified); + graph_drawer.set_graph_modified_handler (*this, &main_window::on_graph_modified); + graph_drawer.set_node_deleted_handler (*this, &main_window::on_node_deleted); + graph_drawer.set_node_deselected_handler (*this, &main_window::on_node_deselected); + graph_drawer.set_node_selected_handler (*this, &main_window::on_node_selected); + sel_node_evidence.set_text_modified_handler (*this, &main_window::on_sel_node_evidence_modified); + sel_node_is_evidence.set_click_handler (*this, &main_window::on_evidence_toggled); + sel_node_num_values.set_text_modified_handler(*this, &main_window::on_sel_node_num_values_modified); + sel_node_text.set_text_modified_handler (*this, &main_window::on_sel_node_text_modified); + + // now let the text of some of our buttons and labels + btn_calculate.set_name("Recalculate posterior probability table"); + selected_node_rect.set_name("Selected node"); + sel_node_evidence_label.set_text("evidence value:"); + sel_node_is_evidence.set_name("is evidence"); + sel_node_num_values_label.set_text("Number of values: "); + sel_node_text_label.set_text("Node label:"); + + // Now setup the tabbed display. It will have two tabs, one for the conditional + // probability table and one for the posterior probability table. + tables.set_number_of_tabs(2); + tables.set_tab_name(0,"Conditional probability table"); + tables.set_tab_name(1,"Posterior probability table"); + cpt_group.add(cpt_grid,0,0); + ppt_group.add(ppt_grid,0,0); + tables.set_tab_group(0,cpt_group); + tables.set_tab_group(1,ppt_group); + + // Now setup the menu bar. We will have two menus. A File and Help menu. + mbar.set_number_of_menus(2); + mbar.set_menu_name(0,"File",'F'); + mbar.set_menu_name(1,"Help",'H'); + + // add the entries to the File menu. + mbar.menu(0).add_menu_item(menu_item_text("Open", *this, &main_window::on_menu_file_open, 'O')); + mbar.menu(0).add_menu_item(menu_item_separator()); + mbar.menu(0).add_menu_item(menu_item_text("Save", *this, &main_window::on_menu_file_save, 'S')); + mbar.menu(0).add_menu_item(menu_item_text("Save As",*this, &main_window::on_menu_file_save_as, 'a')); + mbar.menu(0).add_menu_item(menu_item_separator()); + mbar.menu(0).add_menu_item(menu_item_text("Quit", *this, &main_window::on_menu_file_quit, 'Q')); + + // Add the entries to the Help menu. + mbar.menu(1).add_menu_item(menu_item_text("Help", *this, &main_window::on_menu_help_help, 'e')); + mbar.menu(1).add_menu_item(menu_item_text("About", *this, &main_window::on_menu_help_about, 'A')); + + + // call our helper functions and window resize event to get the widgets + // to all arrange themselves correctly in our window. + no_node_selected(); + on_window_resized(); +} + +// ---------------------------------------------------------------------------------------- + +main_window:: +~main_window( +) +{ + // You should always call close_window() in the destructor of window + // objects to ensure that no events will be sent to this window while + // it is being destructed. + close_window(); +} + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Private methods from the main_window object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +void main_window:: +load_selected_node_tables_into_ppt_grid ( +) +{ + // This function just takes the currently selected graph node and loads + // its posterior probabilities into the ppt_graph widget. + node_type& node = graph_drawer.graph_node(selected_node_index); + ppt_grid.set_grid_size(2,node.data.table().num_values()); + + // load the top row of the table into the grid. This row is the "title bar" row + // that tells you what each column contains. + for (unsigned long col = 0; col < node.data.table().num_values(); ++col) + { + ppt_grid.set_text(0,col,"P(node=" + cast_to_string(col) + ")"); + ppt_grid.set_background_color(0,col,rgb_pixel(150,150,250)); + ppt_grid.set_editable(0,col,false); + } + + // If we have a solution to the network on hand then load the probabilities + // from that into the table + if (solution) + { + // get the probability distribution for the currently selected node out + // of the solution. + const matrix prob = solution->probability(selected_node_index); + + // now load the probabilities into the ppt_grid so the user can see them. + for (unsigned long col = 0; col < node.data.table().num_values(); ++col) + { + ppt_grid.set_text(1,col,cast_to_string(prob(col))); + } + } + + // make the second row of the table non-editable have a color that indicates + // that to the user + for (unsigned long col = 0; col < node.data.table().num_values(); ++col) + { + ppt_grid.set_background_color(1,col,color_gray); + ppt_grid.set_editable(1,col,false); + } +} + +// ---------------------------------------------------------------------------------------- + +void main_window:: +load_selected_node_tables_into_cpt_grid ( +) +{ + // This function just takes the conditional probability table in the + // currently selected graph node and puts it into the cpt_grid widget. + + node_type& node = graph_drawer.graph_node(selected_node_index); + + initialize_node_cpt_if_necessary(selected_node_index); + cpt_grid_assignments.clear(); + + // figure out how many rows there should be in the cpt + unsigned long cpt_rows = 1; + for (unsigned long i = 0; i < node.number_of_parents(); ++i) + { + cpt_rows *= node.parent(i).data.table().num_values(); + } + + unsigned long cpt_cols = node.data.table().num_values(); + + cpt_grid.set_grid_size(cpt_rows+1, cpt_cols+ node.number_of_parents()); + const unsigned long num_cols = cpt_grid.number_of_columns(); + + // fill in the top row of the grid that shows which parent node the left hand columns go with + assignment a(node_first_parent_assignment(graph_drawer.graph(),selected_node_index)); + unsigned long col = 0; + a.reset(); + while (a.move_next()) + { + cpt_grid.set_text(0,col,cast_to_string(a.element().key()) + ": " + graph_drawer.node_label(a.element().key()) ); + cpt_grid.set_background_color(0,col,rgb_pixel(120,210,210)); + cpt_grid.set_editable(0,col,false); + ++col; + } + + // fill in the top row of the grid that shows which probability the right hand columns go with + for (col = node.number_of_parents(); col < num_cols; ++col) + { + cpt_grid.set_text(0,col,"P(node=" + cast_to_string(col-node.number_of_parents()) + ")"); + cpt_grid.set_background_color(0,col,rgb_pixel(150,150,250)); + cpt_grid.set_editable(0,col,false); + } + + // now loop over all the possible parent assignments for this node + const unsigned long num_values = node.data.table().num_values(); + unsigned long row = 1; + do + { + col = 0; + + // fill in the left side of the grid row that shows what the parent assignment is + a.reset(); + while (a.move_next()) + { + cpt_grid.set_text(row,col,cast_to_string(a.element().value())); + cpt_grid.set_background_color(row,col,rgb_pixel(180,255,255)); + cpt_grid.set_editable(row,col,false); + + ++col; + } + + // fill in the right side of the grid row that shows what the conditional probabilities are + for (unsigned long value = 0; value < num_values; ++value) + { + const double prob = node.data.table().probability(value,a); + cpt_grid.set_text(row,col,cast_to_string(prob)); + ++col; + } + + // save this assignment so we can use it later to modify the node's + // conditional probability table if the user modifies the cpt_grid + cpt_grid_assignments.push_back(a); + ++row; + } while (node_next_parent_assignment(graph_drawer.graph(),selected_node_index,a)); + +} + +// ---------------------------------------------------------------------------------------- + +void main_window:: +initialize_node_cpt_if_necessary ( + unsigned long index +) +{ + node_type& node = graph_drawer.graph_node(index); + + // if the cpt for this node isn't properly filled out then lets clear it out + // and populate it with some reasonable default values + if (node_cpt_filled_out(graph_drawer.graph(), index) == false) + { + node.data.table().empty_table(); + + const unsigned long num_values = node.data.table().num_values(); + + // loop over all the possible parent assignments for this node and fill them out + // with reasonable default values + assignment a(node_first_parent_assignment(graph_drawer.graph(), index)); + do + { + // set the first value to have probability 1 + node.data.table().set_probability(0, a, 1.0); + + // set all the other values to have probability 0 + for (unsigned long value = 1; value < num_values; ++value) + node.data.table().set_probability(value, a, 0); + + } while (node_next_parent_assignment(graph_drawer.graph(), index,a)); + } +} + +// ---------------------------------------------------------------------------------------- + +void main_window:: +no_node_selected ( +) +{ + // Make it so that no node is selected on the gui. Do this by disabling things + // and clearing out text fields and so forth. + + + node_is_selected = false; + tables.disable(); + sel_node_evidence.disable(); + sel_node_is_evidence.disable(); + sel_node_index.disable(); + sel_node_evidence_label.disable(); + sel_node_text_label.disable(); + sel_node_text.disable(); + sel_node_index.set_text("index:"); + sel_node_num_values_label.disable(); + sel_node_num_values.disable(); + cpt_grid.set_grid_size(0,0); + ppt_grid.set_grid_size(0,0); + + sel_node_is_evidence.set_unchecked(); + sel_node_text.set_text(""); + sel_node_num_values.set_text(""); + sel_node_evidence.set_text(""); + sel_node_num_values.set_background_color(color_default_bg); + sel_node_evidence.set_background_color(color_default_bg); +} + +// ---------------------------------------------------------------------------------------- + +void main_window:: +recalculate_probabilities ( +) +{ + // clear out the current solution + solution.reset(); + if (graph_is_connected(graph_drawer.graph()) == false) + { + message_box("Error","Your graph has nodes that are completely disconnected from the other nodes.\n" + "You must connect them somehow"); + } + else if (graph_drawer.graph().number_of_nodes() > 0) + { + if (graph_modified_since_last_recalc) + { + // make sure all the cpts are filled out + const unsigned long num_nodes = graph_drawer.graph().number_of_nodes(); + for (unsigned long i = 0; i < num_nodes; ++i) + { + initialize_node_cpt_if_necessary(i); + } + + // remake the join tree for this graph + create_moral_graph(graph_drawer.graph(), join_tree); + create_join_tree(join_tree, join_tree); + graph_modified_since_last_recalc = false; + } + + // create a solution to this bayesian network using the join tree algorithm + solution.reset(new bayesian_network_join_tree(graph_drawer.graph(), join_tree)); + + if (node_is_selected) + { + load_selected_node_tables_into_ppt_grid(); + } + } +} + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// Event handling methods from the main_window object +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects a file with a saved +// bayesian network in it. +void main_window:: +on_open_file_selected ( + const std::string& file_name +) +{ + try + { + no_node_selected(); + ifstream fin(file_name.c_str(), ios::binary); + graph_drawer.load_graph(fin); + graph_file_name = file_name; + set_title("Bayesian Network Utility - " + right_substr(file_name,"\\/")); + } + catch (...) + { + message_box("Error", "Unable to load graph file " + file_name); + } +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects from the menu bar File->Open +void main_window:: +on_menu_file_open ( +) +{ + // display a file chooser window and when the user choses a file + // call the on_open_file_selected() function + open_existing_file_box(*this, &main_window::on_open_file_selected); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects from the menu bar File->Save +void main_window:: +on_menu_file_save ( +) +{ + // if we don't currently have any file name associated with our graph + if (graph_file_name.size() == 0) + { + // display a file chooser window and when the user choses a file + // call the on_save_file_selected() function + save_file_box(*this, &main_window::on_save_file_selected); + } + else + { + // we know what file to open so just do that and save the graph to it + ofstream fout(graph_file_name.c_str(), ios::binary); + graph_drawer.save_graph(fout); + } +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user choses which file to save the graph to +void main_window:: +on_save_file_selected ( + const std::string& file_name +) +{ + ofstream fout(file_name.c_str(), ios::binary); + graph_drawer.save_graph(fout); + graph_file_name = file_name; + set_title("Bayesian Network Utility - " + right_substr(file_name,"\\/")); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects from the menu bar File->Save As +void main_window:: +on_menu_file_save_as ( +) +{ + // display a file chooser window and when the user choses a file + // call the on_save_file_selected() function + save_file_box(*this, &main_window::on_save_file_selected); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects from the menu bar File->Quit +void main_window:: +on_menu_file_quit ( +) +{ + close_window(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects from the menu bar Help->Help +void main_window:: +on_menu_help_help ( +) +{ + message_box("Help", + "To create new nodes right click on the drawing area.\n" + "To create edges select the parent node and then shift+left click on the child node.\n" + "To remove nodes or edges select them by left clicking and then press the delete key."); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user selects from the menu bar Help->About +void main_window:: +on_menu_help_about ( +) +{ + message_box("About","This application is the GUI front end to the dlib C++ Library's\n" + "Bayesian Network inference utilities\n\n" + "See http://dclib.sourceforge.net for updates"); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user modifies the graph_drawer widget. That is, +// when the user adds or removes an edge or node in the graph. +void main_window:: +on_graph_modified ( +) +{ + // make note of the modification + graph_modified_since_last_recalc = true; + // clear out the solution object since we will need to recalculate it + // since the graph changed + solution.reset(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user modifies the evidence value for a node +void main_window:: +on_sel_node_evidence_modified ( +) +{ + // make a reference to the node in the graph that is currently selected + node_type& node = graph_drawer.graph_node(selected_node_index); + unsigned long value; + try + { + // get the numerical value of the new evidence value. Here we are taking + // the string from the text field and casting it to an unsigned long. + value = string_cast(trim(sel_node_evidence.text())); + } + catch (string_cast_error&) + { + // if the user put something that isn't an integer into the + // text field then make it have a different background color + // so that they can easily see this. + sel_node_evidence.set_background_color(color_error); + return; + } + + // validate the input from the user and store it in the selected node + // if it is ok + if (value >= node.data.table().num_values()) + { + sel_node_evidence.set_background_color(color_error); + } + else + { + node.data.set_value(value); + sel_node_evidence.set_background_color(color_default_bg); + } + + // clear out the solution to the graph since we now need + // to recalculate it. + solution.reset(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user modifies the number of evidence values for +// a node. +void main_window:: +on_sel_node_num_values_modified ( +) +{ + // make a reference to the node in the graph that is currently selected + node_type& node = graph_drawer.graph_node(selected_node_index); + + unsigned long num_values; + try + { + // get the number of values out of the text field. + num_values = string_cast(trim(sel_node_num_values.text())); + } + catch (string_cast_error&) + { + sel_node_num_values.set_background_color(color_error); + return; + } + + // validate the input from the user to make sure it is something reasonable + if (num_values < 2 || num_values > 100) + { + sel_node_num_values.set_background_color(color_error); + } + else + { + // update the graph + node.data.table().set_num_values(num_values); + graph_modified_since_last_recalc = true; + sel_node_num_values.set_background_color(color_default_bg); + + on_sel_node_evidence_modified(); + // also make sure the evidence value of this node makes sense still + if (node.data.is_evidence() && node.data.value() >= num_values) + { + // just set it to zero + node.data.set_value(0); + } + + } + + solution.reset(); + + // call these functions so that the conditional and posterior probability + // tables get updated + load_selected_node_tables_into_cpt_grid(); + load_selected_node_tables_into_ppt_grid(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user modifies the cpt_grid (i.e. the conditional +// probability table widget) +void main_window:: +on_cpt_grid_modified(unsigned long row, unsigned long col) +{ + node_type& node = graph_drawer.graph_node(selected_node_index); + solution.reset(); + + double prob; + try + { + // get the new value out of the table + prob = string_cast(cpt_grid.text(row,col)); + } + catch (string_cast_error&) + { + cpt_grid.set_background_color(row,col,color_error); + return; + } + + // validate the value + if (prob < 0 || prob > 1) + { + cpt_grid.set_background_color(row,col,color_error); + return; + } + + // the value of this node that is having its conditional probability + // updated + const unsigned long cur_val = col-node.number_of_parents(); + + node.data.table().set_probability(cur_val, cpt_grid_assignments[row-1], prob); + + // sum the probabilities in the cpt and modify the last one such that they all + // sum to 1. We are excluding either the first or last element from the sum + // because we are going to set it equal to 1-sum below. + double sum = 0; + if (cur_val != node.data.table().num_values()-1) + { + for (unsigned long i = 0; i < node.data.table().num_values()-1; ++i) + sum += node.data.table().probability(i, cpt_grid_assignments[row-1]); + } + else + { + for (unsigned long i = 1; i < node.data.table().num_values(); ++i) + sum += node.data.table().probability(i, cpt_grid_assignments[row-1]); + } + + // make sure all the probabilities sum to 1 + if (sum > 1.0) + { + cpt_grid.set_background_color(row,cpt_grid.number_of_columns()-1,color_error); + } + else + { + // edit one of the other elements in the table to ensure that the probabilities still sum to 1 + if (cur_val == node.data.table().num_values()-1) + { + node.data.table().set_probability(0, cpt_grid_assignments[row-1], 1-sum); + cpt_grid.set_text(row,node.number_of_parents(),cast_to_string(1-sum)); + } + else + { + node.data.table().set_probability(node.data.table().num_values()-1, cpt_grid_assignments[row-1], 1-sum); + cpt_grid.set_text(row,cpt_grid.number_of_columns()-1,cast_to_string(1-sum)); + } + + cpt_grid.set_background_color(row,cpt_grid.number_of_columns()-1,color_default_bg); + cpt_grid.set_background_color(row,col,color_default_bg); + } + +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user resizes the main_window. Note that unlike the other +// events, this event is part of the drawable_window base class that main_window inherits from. +// So you won't see any statements in the constructor that say "register the main_window::on_window_resized function" +void main_window:: +on_window_resized () +{ + // when you override any of the drawable_window events you have to make sure you + // call the drawable_window's version of them because it needs to process + // the events as well. So we do that here. + drawable_window::on_window_resized(); + + // The rest of this function positions the widgets on the window + unsigned long width,height; + get_size(width,height); + + // Don't do anything if the user just made the window too small. That is, leave + // the widgets where they are. + if (width < 500 || height < 350) + return; + + // Set the size of the probability tables and the drawing area for the graph + graph_drawer.set_size(width-370,height-10-mbar.height()); + cpt_grid.set_size((width-graph_drawer.width())-35,height-237); + ppt_grid.set_size((width-graph_drawer.width())-35,height-237); + // tell the tabbed display to make itself just the right size to contain + // the two probability tables. + tables.fit_to_contents(); + + + // Now position all the widgets in the window. Note that much of the positioning + // is relative to other widgets. This part of the code I just figured out by + // trying stuff and rerunning the program to see if it looked nice. + sel_node_index.set_pos(graph_drawer.right()+14,graph_drawer.top()+18); + sel_node_text_label.set_pos(sel_node_index.left(),sel_node_index.bottom()+5); + sel_node_text.set_pos(sel_node_text_label.right()+5,sel_node_index.bottom()); + sel_node_num_values_label.set_pos(sel_node_index.left(), sel_node_text.bottom()+5); + sel_node_num_values.set_pos(sel_node_num_values_label.right(), sel_node_text.bottom()+5); + sel_node_is_evidence.set_pos(sel_node_index.left(),sel_node_num_values.bottom()+5); + sel_node_evidence_label.set_pos(sel_node_index.left(),sel_node_is_evidence.bottom()+5); + sel_node_evidence.set_pos(sel_node_evidence_label.right()+5,sel_node_is_evidence.bottom()); + tables.set_pos(sel_node_index.left(),sel_node_evidence.bottom()+5); + sel_node_evidence.set_width(tables.right()-sel_node_evidence.left()+1); + sel_node_text.set_width(tables.right()-sel_node_text.left()+1); + sel_node_num_values.set_width(tables.right()-sel_node_num_values.left()+1); + + + + // Tell the named rectangle to position itself such that it fits around the + // tabbed display that contains the probability tables and the label at the top of the + // screen. + selected_node_rect.wrap_around(sel_node_index.get_rect()+ + tables.get_rect()); + + // finally set the button to be at the bottom of the named rectangle + btn_calculate.set_pos(selected_node_rect.left(), selected_node_rect.bottom()+5); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called by the graph_drawer widget when the user selects a node +void main_window:: +on_node_selected (unsigned long n) +{ + // make a reference to the selected node + node_type& node = graph_drawer.graph_node(n); + + + // enable all the widgets related to the selected node + selected_node_index = n; + node_is_selected = true; + tables.enable(); + sel_node_is_evidence.enable(); + sel_node_index.enable(); + sel_node_evidence_label.enable(); + sel_node_text_label.enable(); + sel_node_text.enable(); + sel_node_num_values_label.enable(); + sel_node_num_values.enable(); + + // make sure the num_values field of the node's cpt is set to something valid. + // So default it to 2 if it isn't set already. + if (node.data.table().num_values() < 2) + { + node.data.table().set_num_values(2); + graph_modified_since_last_recalc = true; + } + + // setup the evidence check box and input field + sel_node_index.set_text("index: " + cast_to_string(n)); + if (graph_drawer.graph_node(n).data.is_evidence()) + { + sel_node_is_evidence.set_checked(); + sel_node_evidence.enable(); + sel_node_evidence.set_text(cast_to_string(graph_drawer.graph_node(n).data.value())); + } + else + { + sel_node_is_evidence.set_unchecked(); + sel_node_evidence.disable(); + sel_node_evidence.set_text(""); + } + + sel_node_num_values.set_text(cast_to_string(node_num_values(graph_drawer.graph(),n))); + + sel_node_text.set_text(graph_drawer.node_label(n)); + + load_selected_node_tables_into_cpt_grid(); + load_selected_node_tables_into_ppt_grid(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user toggles the "is evidence" check box +void main_window:: +on_evidence_toggled ( +) +{ + if (sel_node_is_evidence.is_checked()) + { + graph_drawer.graph_node(selected_node_index).data.set_as_evidence(); + sel_node_evidence.enable(); + sel_node_evidence.set_text(cast_to_string(graph_drawer.graph_node(selected_node_index).data.value())); + + graph_drawer.set_node_color(selected_node_index, color_evidence); + } + else + { + graph_drawer.graph_node(selected_node_index).data.set_as_nonevidence(); + sel_node_evidence.disable(); + sel_node_evidence.set_text(""); + sel_node_evidence.set_background_color(color_default_bg); + graph_drawer.set_node_color(selected_node_index, color_non_evidence); + } + solution.reset(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user causes no node to be selected +void main_window:: +on_node_deselected ( unsigned long n ) +{ + no_node_selected(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user causes a node to be deleted +void main_window:: +on_node_deleted ( ) +{ + no_node_selected(); +} + +// ---------------------------------------------------------------------------------------- + +// This event is called when the user changes the text in the "node label" text field +void main_window:: +on_sel_node_text_modified ( +) +{ + // set the selected node's text to match whatever the user just typed in + graph_drawer.set_node_label(selected_node_index,sel_node_text.text()); +} + +// ---------------------------------------------------------------------------------------- + diff --git a/examples/compress_stream_ex.cpp b/examples/compress_stream_ex.cpp new file mode 100755 index 0000000000000000000000000000000000000000..94c6a1dec8681ae2d0b3fad9a9a1ec8fff6abb4d --- /dev/null +++ b/examples/compress_stream_ex.cpp @@ -0,0 +1,180 @@ +/* + + This is an example illustrating the use of the compress_stream and + cmd_line_parser components from the dlib C++ Library. + + This example implements a simple command line compression utility. + + + The output from the program when the -h option is given is: + + Usage: dclib_example (-c|-d) --in input_file --out output_file + Options: + -c Indicates that we want to compress a file. + -d Indicates that we want to decompress a file. + -h Display this help message. + --in This option takes one argument which specifies the + name of the file we want to compress/decompress. + --out This option takes one argument which specifies the + name of the output file. + +*/ + + + + +#include "dlib/compress_stream.h" +#include "dlib/cmd_line_parser.h" +#include +#include +#include +#include + +// I am making a typedef for the verson of compress_stream I want to use. +// I have selected kernel_1ec. +typedef dlib::compress_stream::kernel_1ec cs; + +// Here I am making another typedef, this time for the verson of +// cmd_line_parser I want to use. I have selected print_1a_c, +// this is the version of kernel_1a that checks all its +// preconditions (i.e. the debugging version) and is +// extended by print_kernel_1. +typedef dlib::cmd_line_parser::print_1a_c clp; + + +using namespace std; +using namespace dlib; + + +int main(int argc, char** argv) +{ + try + { + clp parser; + cs compressor; + + // first I will define the command line options I want + parser.add_option("c","Indicates that we want to compress a file."); + parser.add_option("d","Indicates that we want to decompress a file."); + parser.add_option("in","This option takes one argument which specifies the name of the file we want to compress/decompress.",1); + parser.add_option("out","This option takes one argument which specifies the name of the output file.",1); + parser.add_option("h","Display this help message."); + + // now I will parse the command line + parser.parse(argc,argv); + + // check if the -h option was given on the command line + if (parser.option("h")) + { + // display all the command line options + cout << "Usage: dclib_example (-c|-d) --in input_file --out output_file\n"; + parser.print_options(cout); // this print_options() function is really + // convenient :) + cout << endl; + return 0; + } + + const clp::option_type& option_c = parser.option("c"); + const clp::option_type& option_d = parser.option("d"); + const clp::option_type& option_in = parser.option("in"); + const clp::option_type& option_out = parser.option("out"); + + if ((option_c.count() != 0 && option_d.count() != 0 ) || + (option_c.count() == 0 && option_d.count() == 0 ) ) + { + cout << "Error in command line:\n You must specify either the c option or the d option.\n"; + cout << "\nTry the -h option for more information." << endl; + return 0; + } + + + string in_file; + string out_file; + + // check if the user told us the input file and if they did then + // get the file name + if (option_in.count() == 1) + { + in_file = option_in.argument(); + } + else if (option_in.count() > 1) + { + cout << "Error in command line:\n You must specify only one input file.\n"; + cout << "\nTry the -h option for more information." << endl; + return 0; + } + else + { + cout << "Error in command line:\n You must specify an input file.\n"; + cout << "\nTry the -h option for more information." << endl; + return 0; + } + + + // check if the user told us the output file and if they did then + // get the file name + if (option_out.count() == 1) + { + out_file = option_out.argument(); + } + else if (option_out.count() > 1) + { + cout << "Error in command line:\n You must specify only one output file.\n"; + cout << "\nTry the -h option for more information." << endl; + return 0; + } + else + { + cout << "Error in command line:\n You must specify an output file.\n"; + cout << "\nTry the -h option for more information." << endl; + return 0; + } + + + ifstream fin(in_file.c_str(),ios::binary); + ofstream fout(out_file.c_str(),ios::binary); + + if (!fin) + { + cout << "Error opening file " << in_file << ".\n"; + return 0; + } + + if (!fout) + { + cout << "Error creating file " << out_file << ".\n"; + return 0; + } + + + + // now perform the actual compression or decompression. + if (option_c) + { + compressor.compress(fin,fout); + } + else + { + compressor.decompress(fin,fout); + } + + + + + } + catch (exception& e) + { + // Note that this will catch any cmd_line_parse_error exceptions and print + // the default message. + cout << e.what() << endl; + } + catch (...) + { + cout << "Some error occurred" << endl; + } +} + + + + + diff --git a/examples/dir_nav_ex.cpp b/examples/dir_nav_ex.cpp new file mode 100755 index 0000000000000000000000000000000000000000..65fbd8a07a1ffd247914a72beb69d6ba49255212 --- /dev/null +++ b/examples/dir_nav_ex.cpp @@ -0,0 +1,87 @@ +/* + + This is an example illustrating the use of the dir_nav component from the dlib C++ Library. + It prints a listing of all directories and files in the users + current working directory or the directory specified on the command line. + +*/ + + +#include +#include +#include "dlib/dir_nav.h" +#include "dlib/queue.h" +#include "dlib/static_set.h" + +using namespace std; +using namespace dlib; + +typedef queue::kernel_2a queue_of_dirs; +typedef queue::kernel_2a queue_of_files; +typedef static_set::kernel_1a set_of_files; +typedef static_set::kernel_1a set_of_dirs; + + +int main(int argc, char** argv) +{ + try + { + string loc; + if (argc == 2) + loc = argv[1]; + else + loc = "."; // if no argument is given then use the current working dir. + + directory test(loc); + + queue_of_dirs dirs; + queue_of_files files; + set_of_dirs sorted_dirs; + set_of_files sorted_files; + + cout << "directory: " << test.name() << endl; + cout << "full path: " << test.full_name() << endl; + cout << "is root: " << ((test.is_root())?"yes":"no") << endl; + + // get all directories and files in test + test.get_dirs(dirs); + test.get_files(files); + + // load the dirs and files into static_sets. This + // seems weird but a static_set can be enumerated in sorted order + // so this way we can print everything in sorted order. This + // static_set also uses a median of three quick sort so the sorting + // should be very fast. + sorted_files.load(files); + sorted_dirs.load(dirs); + + cout << "\n\n\n"; + + // print all the subdirectories + while (sorted_dirs.move_next()) + cout << " " << sorted_dirs.element().name() << "\n"; + + // print all the subfiles + while (sorted_files.move_next()) + cout << setw(13) << sorted_files.element().size() << " " << sorted_files.element().name() << "\n"; + + + cout << "\n\nnumber of dirs: " << sorted_dirs.size() << endl; + cout << "number of files: " << sorted_files.size() << endl; + + } + catch (file::file_not_found e) + { + cout << "file not found or accessable: " << e.info << endl; + } + catch (directory::dir_not_found e) + { + cout << "dir not found or accessable: " << e.info << endl; + } + catch (directory::listing_error e) + { + cout << "listing error: " << e.info << endl; + } +} + + diff --git a/examples/file_to_code_ex.cpp b/examples/file_to_code_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54af8e8b2ba2223b0569650c9db77b19bb4b61cc --- /dev/null +++ b/examples/file_to_code_ex.cpp @@ -0,0 +1,110 @@ +/* + This is an example illustrating the use of the compress_stream and + base64 components from the dlib C++ Library. + + It reads in a file from the disk and compresses it in an in memory buffer and + then converts that buffer into base64 text. The final step is to output to + the screen some C++ code that contains this base64 encoded text and can decompress + it back into its original form. +*/ + + +#include +#include +#include +#include +#include +#include "dlib/compress_stream.h" +#include "dlib/base64.h" + + +using namespace std; +using namespace dlib; + +int main(int argc, char** argv) +{ + if (argc != 2) + { + cout << "You must give a file name as the argument to this program.\n" << endl; + cout << "This program reads in a file from the disk and compresses\n" + << "it in an in memory buffer and then converts that buffer \n" + << "into base64 text. The final step is to output to the screen\n" + << "some C++ code that contains this base64 encoded text and can\n" + << "decompress it back into its original form.\n" << endl; + + return EXIT_FAILURE; + } + + // open the file the user specified on the command line + ifstream fin(argv[1], ios::binary); + if (!fin) { + cout << "can't open file " << argv[1] << endl; + return EXIT_FAILURE; + } + + ostringstream sout; + istringstream sin; + + // this is the object we will use to do the base64 encoding + base64::kernel_1a base64_coder; + // this is the object we will use to do the data compression + compress_stream::kernel_1ea compressor; + + // compress the contents of the file and store the results in the string stream sout + compressor.compress(fin,sout); + sin.str(sout.str()); + sout.clear(); + sout.str(""); + + // now base64 encode the compressed data + base64_coder.encode(sin,sout); + + sin.clear(); + sin.str(sout.str()); + sout.str(""); + + // the following is a little funny looking but all it does is output some C++ code + // that contains the compressed/base64 data and the C++ code that can decode it back + // into its original form. + sout << "#include \n"; + sout << "#include \n"; + sout << "#include \n"; + sout << "\n"; + sout << "// This function returns the contents of the file '" << argv[1] << "'\n"; + sout << "const std::string get_decoded_string()\n"; + sout << "{\n"; + sout << " dlib::base64::kernel_1a base64_coder;\n"; + sout << " dlib::compress_stream::kernel_1ea compressor;\n"; + sout << " std::ostringstream sout;\n"; + sout << " std::istringstream sin;\n\n"; + + + sout << " // The base64 encoded data from the file '" << argv[1] << "' we want to decode and return.\n"; + string temp; + getline(sin,temp); + while (sin && temp.size() > 0) + { + sout << " sout << \"" << temp << "\";\n"; + getline(sin,temp); + } + + sout << "\n"; + sout << " // Put the data into the istream sin\n"; + sout << " sin.str(sout.str());\n"; + sout << " sout.str(\"\");\n\n"; + sout << " // Decode the base64 text into its compressed binary form\n"; + sout << " base64_coder.decode(sin,sout);\n"; + sout << " sin.clear();\n"; + sout << " sin.str(sout.str());\n"; + sout << " sout.str(\"\");\n\n"; + sout << " // Decompress the data into its original form\n"; + sout << " compressor.decompress(sin,sout);\n\n"; + sout << " // Return the decoded and decompressed data\n"; + sout << " return sout.str();\n"; + sout << "}\n"; + + + // finally output our encoded data and its C++ code to the screen + cout << sout.str() << endl; +} + diff --git a/examples/gui_api_ex.cpp b/examples/gui_api_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ce0af407a43393f42a3edfe9381af41d40cf4b2 --- /dev/null +++ b/examples/gui_api_ex.cpp @@ -0,0 +1,220 @@ +/* + + This is an example illustrating the use of the gui api from the dlib C++ Library. + + + This is a pretty simple example. It makes a window with a user + defined widget (a dragable colored box) and a button. You can drag the + box around or click the button which increments a counter. +*/ + + + + +#include "dlib/gui_widgets.h" +#include +#include + + +using namespace std; +using namespace dlib; + +// ---------------------------------------------------------------------------- + +class color_box : public dragable +{ + /* + Here I am defining a custom drawable widget that is a colored box that + you can drag around on the screen. dragable is a special kind of drawable + object that, as the name implies, is dragable by the user via the mouse. + To make my color_box dragable all I need to do is inherit from dragable. + */ + unsigned char red, green,blue; + +public: + color_box ( + drawable_window& w, + rectangle area, + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) : + dragable(w), + red(red_), + green(green_), + blue(blue_) + { + rect = area; + set_dragable_area(rectangle(10,10,400,400)); + + // Whenever you make your own drawable (or inherit from dragable or button_action) + // you have to remember to call this function to enable the events. The idea + // here is that you can perform whatever setup you need to do to get your + // object into a valid state without needing to worry about event handlers + // triggering before you are ready. + enable_events(); + } + + ~color_box ( + ) + { + // Disable all further events for this drawable object. We have to do this + // because we don't want draw() events coming to this object while or after + // it has been destructed. + disable_events(); + + // Tell the parent window to redraw its area that previously contained this + // drawable object. + parent.invalidate_rectangle(rect); + } + +private: + + void draw ( + const canvas& c + ) const + { + // The first thing I usually do is check if the draw call is for part + // of the window that overlaps with my widget. We don't have to do this + // but it is usually good to do as a speed hack. Also, the reason + // I don't have it set to only give you draw calls when it does indeed + // overlap is because you might want to do some drawing outside of your + // widgets rectangle. But usually you don't want to do that :) + rectangle area = c.intersect(rect); + if (area.is_empty() == true) + return; + + // this simple widget is just going to draw a box on the screen. + fill_rect(c,rect,rgb_pixel(red,green,blue)); + } +}; + +// ---------------------------------------------------------------------------- + +class win : public drawable_window +{ + /* + Here I am going to define our window. In general, you can define as + many window types as you like and make as many instances of them as you want. + In this example I am only making one though. + */ +public: + win( + ) : + c(*this), + b(*this), + cb(*this,rectangle(100,100,200,200),0,0,255), // the color_box will be blue and 101 pixels wide and tall + mbar(*this) + { + // tell our button to put itself at the position (10,60). + b.set_pos(10,60); + b.set_name("button"); + + // lets put the label 5 pixels below the button + c.set_pos(b.left(),b.bottom()+5); + + + // set which function should get called when the button gets clicked. In this case we want + // the on_button_clicked member to be called on *this. + b.set_click_handler(*this,&win::on_button_clicked); + + // Lets also make a simple menu bar. + // First we say how many menus we want in our menu bar. In this example we only have 1 + mbar.set_number_of_menus(1); + // Now we set the name of our menu. The 'M' means that the M in Menu will be underlined + // and the user will be able to select it by hitting alt+M + mbar.set_menu_name(0,"Menu",'M'); + + // Now we add some items to the menu. Note that items in a menu are listed in the + // order in which they were added. + + // First lets make a menu item that does the same thing as our button does when it is clicked. + // Again, the 'C' means the C in Click is underlined in the menu. + mbar.menu(0).add_menu_item(menu_item_text("Click Button!",*this,&win::on_button_clicked,'C')); + // lets add a separator (i.e. a horizontal separating line) to the menu + mbar.menu(0).add_menu_item(menu_item_separator()); + // Now lets make a menu item that calls show_about when the user selects it. + mbar.menu(0).add_menu_item(menu_item_text("About",*this,&win::show_about,'A')); + + + // set the size of this window + set_size(430,380); + + counter = 0; + + set_title("dlib gui example"); + show(); + } + + ~win( + ) + { + // You should always call close_window() in the destructor of window + // objects to ensure that no events will be sent to this window while + // it is being destructed. + close_window(); + } + +private: + + void on_button_clicked ( + ) + { + // when someone clicks our button it will increment the counter and + // display it in our label c. + ++counter; + ostringstream sout; + sout << "counter: " << counter; + c.set_text(sout.str()); + } + + void show_about( + ) + { + message_box("About","This is a dlib gui example program"); + } + + unsigned long counter; + label c; + button b; + color_box cb; + menu_bar mbar; +}; + +// ---------------------------------------------------------------------------- + +int main() +{ + // create our window + win my_window; + + + // wait until the user closes this window before we let the program + // terminate. + my_window.wait_until_closed(); +} + +// ---------------------------------------------------------------------------- + +// If you use main() as your entry point when building a program on MS Windows then +// there will be a black console window associated with your application. If you +// want your application to not have this console window then you need to build +// using the WinMain() entry point as shown below and also set your compiler to +// produce a "Windows" project instead of a "Console" project. In visual studio +// this can be accomplished by going to project->properties->general configuration-> +// Linker->System->SubSystem and selecting Windows instead of Console. +// +#ifdef WIN32 +int WINAPI WinMain ( + HINSTANCE, + HINSTANCE, + PSTR cmds, + int +) +{ + main(); +} +#endif + +// ---------------------------------------------------------------------------- + diff --git a/examples/image_ex.cpp b/examples/image_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aaaca7753a7807df397d6fc9d4e18cec8b711300 --- /dev/null +++ b/examples/image_ex.cpp @@ -0,0 +1,126 @@ +/* + + This is an example illustrating the use of the GUI API as well as some + aspects of image manipulation from the dlib C++ Library. + + + This is a pretty simple example. It takes a BMP file on the command line + and opens it up, runs a simple edge detection algorithm on it, and + displays the results on the screen. +*/ + + + +#include "dlib/gui_widgets.h" +#include "dlib/image_io.h" +#include "dlib/image_transforms.h" +#include + + +using namespace std; +using namespace dlib; + +// ---------------------------------------------------------------------------- + +class win : public drawable_window +{ + /* + Here we are making a GUI window that will be capable of displaying + an image. + */ +public: + + template + win( + const image_type& img + ) : + gui_img(*this) + { + // set the size of this window to match the size of the input image + set_size(img.nc(),img.nr()); + + // Now load the image into the image widget so it has something to display. + gui_img.set_image(img); + + set_title("image example"); + + // show this window on the screen + show(); + } + + ~win( + ) + { + // You should always call close_window() in the destructor of window + // objects to ensure that no events will be sent to this window while + // it is being destructed. + close_window(); + } + +private: + + image_widget gui_img; +}; + +// ---------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + try + { + // make sure the user entered an argument to this program + if (argc != 2) + { + cout << "error, you have to enter a BMP file as an argument to this program" << endl; + return 1; + } + + ifstream fin(argv[1],ios::binary); + if (!fin) + { + cout << "error, can't find " << argv[1] << endl; + return 1; + } + + // Here we declare an image object that can store rgb_pixels. Note that in + // dlib there is no explicit image object, just a 2D array and + // various pixel types. + array2d::kernel_1a img; + + // now load the bmp file into our image. If the file isn't really a BMP + // or is corrupted then load_bmp() will throw an exception. + load_bmp(img, fin); + + // Now lets use some image functions. This example is going to perform + // simple edge detection on the image. First lets find the horizontal and + // vertical gradient images. + array2d::kernel_1a horz_gradient, vert_gradient; + array2d::kernel_1a edge_image; + sobel_edge_detector(img,horz_gradient, vert_gradient); + + // now we do the non-maximum edge suppression step so that our edges are nice and thin + suppress_non_maximum_edges(horz_gradient, vert_gradient, edge_image); + + // Now we would like to see what our images look like. So lets use our + // window to display them on the screen. + + + // create a window to display the edge image + win my_window(edge_image); + + // also make a window to display the original image + win my_window2(img); + + // wait until the user closes both windows before we let the program + // terminate. + my_window.wait_until_closed(); + my_window2.wait_until_closed(); + } + catch (exception& e) + { + cout << "exception thrown: " << e.what() << endl; + } +} + +// ---------------------------------------------------------------------------- + diff --git a/examples/logger_ex.cpp b/examples/logger_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ebbdf3c66f88ac78e46ff34e9209f1ba21bd888 --- /dev/null +++ b/examples/logger_ex.cpp @@ -0,0 +1,69 @@ + +/* + + This is a simple example illustrating the use of the logger object from + the dlib C++ Library. + + + The output of this program looks like this: + + 0 INFO [0] example: This is an informational message. + 0 DEBUG [0] example: The integer variable is set to 8 + 0 WARN [0] example: The variable is bigger than 4! Its value is 8 + 0 INFO [0] example: we are going to sleep for half a second. + 503 INFO [0] example: we just woke up + 503 INFO [0] example: program ending + + + The first column shows the number of milliseconds since program start at the time + the message was printed, then the logging level of the message, then the thread that + printed the message, then the logger's name and finally the message itself. + +*/ + + +#include "dlib/logger.h" +#include "dlib/misc_api.h" + +using namespace dlib; + +// Create a logger object somewhere. It is usually convenient to make it at the global scope +// which is what I am doing here. The following statement creates a logger that is named example. +logger dlog("example"); + +int main() +{ + // Every logger has a logging level (given by dlog.level()). Each log message is tagged with a + // level and only levels equal to or higher than dlog.level() will be printed. By default all + // loggers start with level() == LERROR. In this case I'm going to set the lowest level LALL + // which means that dlog will print all logging messages it gets. + dlog.set_level(LALL); + + + // print our first message. It will go to cout because that is the default. + dlog << LINFO << "This is an informational message."; + + // now print a debug message. + int variable = 8; + dlog << LDEBUG << "The integer variable is set to " << variable; + + // the logger can be used pretty much like any ostream object. But you have to give a logging + // level first. But after that you can chain << operators like normal. + + if (variable > 4) + dlog << LWARN << "The variable is bigger than 4! Its value is " << variable; + + + + dlog << LINFO << "we are going to sleep for half a second."; + // sleep for half a second + dlib::sleep(500); + dlog << LINFO << "we just woke up"; + + + + dlog << LINFO << "program ending"; +} + + + diff --git a/examples/logger_ex_2.cpp b/examples/logger_ex_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab57247766f62814b3e538ab23b104babcb8e90d --- /dev/null +++ b/examples/logger_ex_2.cpp @@ -0,0 +1,140 @@ + +/* + + This is a somewhat complex example illustrating the use of the logger object + from the dlib C++ Library. It will demonstrate using multiple loggers and threads. + + + The output of this program looks like this: + 0 INFO [0] example: This is an informational message. + 0 WARN [0] example: The variable is bigger than 4! Its value is 8 + 0 INFO [0] example: make two threads + 0 WARN [0] example.test_class: warning! someone called warning()! + 0 INFO [0] example: we are going to sleep for half a second. + 0 INFO [1] example.thread: entering our thread + 0 WARN [1] example.test_class: warning! someone called warning()! + 0 INFO [2] example.thread: entering our thread + 0 WARN [2] example.test_class: warning! someone called warning()! + 203 INFO [1] example.thread: exiting our thread + 203 INFO [2] example.thread: exiting our thread + 503 INFO [0] example: we just woke up + 503 INFO [0] example: program ending + + +*/ + + +#include "dlib/logger.h" +#include "dlib/misc_api.h" +#include "dlib/threads.h" + +using namespace dlib; + +/* + Here we create three loggers. Note that it is the case that: + - logp.is_child_of(logp) == true + - logt.is_child_of(logp) == true + - logc.is_child_of(logp) == true + + logp is the child of itself because all loggers are their own children :) But the other + two are child loggers of logp because their names start with logp.name() + "." which means + that whenever you set a property on a log it will also set that same property on all of + the log's children. +*/ +logger logp("example"); +logger logt("example.thread"); +logger logc("example.test_class"); + +class test +{ +public: + test () + { + // this message won't get logged because LINFO is too low + logc << LINFO << "constructed a test object"; + } + + ~test () + { + // this message won't get logged because LINFO is too low + logc << LINFO << "destructed a test object"; + } + + void warning () + { + logc << LWARN << "warning! someone called warning()!"; + } +}; + +void thread (void*) +{ + logt << LINFO << "entering our thread"; + + + test mytest; + mytest.warning(); + + dlib::sleep(200); + + logt << LINFO << "exiting our thread"; +} + + +void setup_loggers ( +) +{ + // Create a logger that has the same name as our root logger logp. This isn't very useful in + // this example program but if you had loggers defined in other files then you might not have + // easy access to them when starting up your program and setting log levels. This mechanism + // allows you to manipulate the properties of any logger so long as you know its name. + logger temp_log("example"); + + // For this example I don't want to log debug messages so I'm setting the logging level of + // All our loggers to LINFO. Note that this statement sets all three of our loggers to this + // logging level because they are all children of temp_log. + temp_log.set_level(LINFO); + + + // In addition I only want the example.test_class to print LWARN or higher messages so I'm going + // to set that here too. Note that we set this value after calling temp_log.set_level(). If we + // did it the other way around the set_level() call on temp_log would set logc_temp.level() and + // logc.level() back to LINFO since temp_log is a parent of logc_temp. + logger logc_temp("example.test_class"); + logc_temp.set_level(LWARN); +} + +int main() +{ + setup_loggers(); + + // print our first message. It will go to cout because that is the defaul. + logp << LINFO << "This is an informational message."; + + int variable = 8; + + // here is a debug message. it won't print though because its log level is too low (it is below LINFO). + logp << LDEBUG << "The integer variable is set to " << variable; + + + if (variable > 4) + logp << LWARN << "The variable is bigger than 4! Its value is " << variable; + + logp << LINFO << "make two threads"; + create_new_thread(thread,0); + create_new_thread(thread,0); + + test mytest; + mytest.warning(); + + logp << LINFO << "we are going to sleep for half a second."; + // sleep for half a second + dlib::sleep(500); + logp << LINFO << "we just woke up"; + + + + logp << LINFO << "program ending"; +} + + + diff --git a/examples/matrix_ex.cpp b/examples/matrix_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02b17cffd8b9a72a002feba8fa7ff9544aa27c07 --- /dev/null +++ b/examples/matrix_ex.cpp @@ -0,0 +1,223 @@ + +/* + This is an example illustrating the use of the matrix object + from the dlib C++ Library. + +*/ + + +#include +#include "dlib/matrix.h" + +using namespace dlib; +using namespace std; + +// ---------------------------------------------------------------------------------------- + +int main() +{ + // Lets begin this example by using the library to solve a simple + // linear system. + // + // We will find the value of x such that y = M*x where + // + // 3.5 + // y = 1.2 + // 7.8 + // + // and M is + // + // 54.2 7.4 12.1 + // M = 1 2 3 + // 5.9 0.05 1 + + + // First lets declare these 3 matrices. + // This declares a matrix that contains doubles and has 3 rows and 1 column. + matrix y; + // Make a 3 by 3 matrix of doubles for the M matrix. + matrix M; + // Make a matrix of doubles that has unknown dimensions (the dimensions are + // decided at runtime unlike the above two matrices which are bound at compile + // time). We could declare x the same way as y but I'm doing it differently + // for the purposes of illustration. + matrix x; + + // You may be wondering why someone would want to specify the size of a matrix + // at compile time when you don't have to. The reason is two fold. First, + // there is often a substantial performance improvement, especially for small + // matrices, because the compiler is able to perform loop unrolling if it knows + // the sizes of matrices. Second, the dlib::matrix object checks these compile + // time sizes to ensure that the matrices are being used correctly. For example, + // if you attempt to compile the expression y = M; or x = y*y; you will get + // a compiler error on those lines since those are not legal matrix operations. + // So if you know the size of a matrix at compile time then it is always a good + // idea to let the compiler know about it. + + + + + // now we need to initialize the y and M matrices and we can do so like this: + const double M_data[] = { + 54.2, 7.4, 12.1, + 1, 2, 3, + 5.9, 0.05, 1}; + + const double y_data[] = { + 3.5, + 1.2, + 7.8}; + + // load these matrices up with their data. Note that you can only load a matrix + // with a C style array if the matrix is statically dimensioned as the M and y + // matrices are. You couldn't do it for x since x = M_data would be ambiguous. + // (e.g. should the data be interpreted as a 3x3 matrix or a 9x1 matrix?) + M = M_data; + y = y_data; + + // the solution can be obtained now by multiplying the inverse of M with y + x = inv(M)*y; + + cout << "x: \n" << x << endl; + + // We can check that it really worked by plugging x back into the original equation + // and subtracting y to see if we get a column vector with values all very close + // to zero (Which is what happens. Also, the values may not be exactly zero because + // there may be some numerical error and round off). + cout << "M*x - y: \n" << M*x - y << endl; + + + // The elements of a matrix are accessed using the () operator like so + cout << M(0,1) << endl; + // The above expression prints out the value 7.4. That is, the value of + // the element at row 0 and column 1. + + + // Let's compute the sum of elements in the M matrix. + double M_sum = 0; + // loop over all the rows + for (long r = 0; r < M.nr(); ++r) + { + // loop over all the columns + for (long c = 0; c < M.nc(); ++c) + { + M_sum += M(r,c); + } + } + cout << "sum of all elements in M is " << M_sum << endl; + + // The above code is just to show you how to loop over the elements of a matrix. An + // easier way to find this sum is to do the following: + cout << "sum of all elements in M is " << sum(M) << endl; + + + // If we have a matrix that is a row or column vector. That is, it contains either + // a single row or a single column then we know that any access is always either + // to row 0 or column 0 so we can omit that 0 and use the following syntax. + cout << y(1) << endl; + // The above expression prints out the value 1.2 + + + + // ------------------------- Template Expressions ----------------------------- + // Now I will discuss the "template expressions" technique and how it is + // used in the matrix object. First consider the following expression: + x = y + y; + + /* + Normally this expression results in machine code that looks, at a high + level, like the following: + temp = y + y; + x = temp + + Temp is a temporary matrix returned by the overloaded + operator. + temp then contains the result of adding y to itself. The assignment + operator copies the value of temp into x and temp is then destroyed while + the blissful C++ user never sees any of this. + + This is, however, totally inefficient. In the process described above + you have to pay for the cost of constructing a temporary matrix object + and allocating its memory. Then you pay the additional cost of copying + it over to x. It also gets worse when you have more complex expressions + such as x = y + y + y + M*y which would involve the creation and copying + of 4 temporary matrices. + + All these inefficiencies are removed by using the template expressions + technique. The exact details of how the technique is performed are well + outside the scope of this example but the basic idea is as follows. Instead + of having operators and functions return temporary matrix objects you + return a special object that represents the expression you wish to perform. + + So consider the expression x = y + y again. With dlib::matrix what happens + is the expression y+y returns a matrix_exp object instead of a temporary matrix. + The construction of a matrix_exp does not allocate any memory or perform any + computations. The matrix_exp however has an interface that looks just like a + dlib::matrix object and when you ask it for the value of one of its elements + it computes that value on the spot. Only in the assignment operator does + someone ask the matrix_exp for these values so this avoids the use of any + temporary matrices. Thus the statement x = y + y is equivalent to the following + code: + // loop over all elements in y matrix + for (long r = 0; r < y.nr(); ++r) + for (long c = 0; c < y.nc(); ++c) + x(r,c) = y(r,c) + y(r,c); + + + This technique works for expressions of arbitrary complexity. So if you + typed x = y + y + y + M*y it would involve no temporary matrices being + created at all. Each operator takes and returns only matrix_exp objects. + Thus, no computations are performed until the assignment operator requests + the values from the matrix_exp it receives as input. + + + + + + The is only one caveat in all of this. It is for statements that involve + the multiplication of a complex matrix_exp such as the following: + */ + x = M*(M+M+M+M+M+M+M); + /* + This statement computes the value of M*(M+M+M+M+M+M+M) totally without + any temporary matrix objects. This sounds good but we should take + a closer look. Consider that the + operator is invoked 6 times. This + means we have something like this: + + x = M * (matrix_exp representing M+M+M+M+M+M+M); + + M is being multiplied with a quite complex matrix_exp. Now recall that when + you ask a matrix_exp what the value of any of its elements are it computes + their values *right then*. + + If you think on what is involved in performing a matrix multiply you will + realize that each element of a matrix is accessed M.nr() times. In the + case of our above expression the cost of accessing an element of the + matrix_exp on the right hand side is the cost of doing 6 addition operations. + + Thus, it would be faster to assign M+M+M+M+M+M+M to a real matrix and then + multiply that by M. + + So do something like this: + */ + matrix Mtemp; + Mtemp = M+M+M+M+M+M+M; + x = M*Mtemp; + + // Or alternatively you can use the tmp() function like so. + x = M*tmp(M+M+M+M+M+M+M); + /* + tmp() just evaluates a matrix_exp and returns a real matrix object. So it + does the same thing as the above code that uses Mtemp. + + Anyway, the point of the above discussion is that you shouldn't multiply + complex matrix expressions. You should instead assign the expression to + a matrix object and then use that object in the multiply. This will ensure + that your multiplies are always fast. + */ + + +} + +// ---------------------------------------------------------------------------------------- + + diff --git a/examples/member_function_pointer_ex.cpp b/examples/member_function_pointer_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04ea79a2e445ec256573ab534f6ee11ebbe3bdac --- /dev/null +++ b/examples/member_function_pointer_ex.cpp @@ -0,0 +1,77 @@ + +/* + This is an example illustrating the use of the member_function_pointer object + from the dlib C++ Library. + +*/ + + +#include +#include "dlib/member_function_pointer.h" + +using namespace dlib; +using namespace std; + +// ---------------------------------------------------------------------------------------- + +class example_object +{ +public: + + void do_something ( + ) + { + cout << "hello world" << endl; + } + + void print_this_number ( + int num + ) + { + cout << "number you gave me = " << num << endl; + } + +}; + +// ---------------------------------------------------------------------------------------- + +int main() +{ + // create a pointer that can point to member functions that take no arguments + member_function_pointer<>::kernel_1a_c mfp1; + + // create a pointer that can point to member functions that take a single int argument + member_function_pointer::kernel_1a_c mfp2; + + example_object obj; + + // now we set the mfp1 pointer to point to the member function do_something() + // on the obj object. + mfp1.set(obj, &example_object::do_something); + + + // now we set the mfp1 pointer to point to the member function print_this_number() + // on the obj object. + mfp2.set(obj, &example_object::print_this_number); + + + // Now we can call the function this pointer points to. This calls the function + // obj.do_something() via our member function pointer. + mfp1(); + + // Now we can call the function this pointer points to. This calls the function + // obj.print_this_number(5) via our member function pointer. + mfp2(5); + + + // The above example shows a very simple use of the member_function_pointer. + // A more interesting use of the member_function_pointer is in the implementation + // of callbacks or event handlers. For example, when you register an event + // handler for a dlib::button click it uses a member_function_pointer + // internally to save and later call your event handler. +} + +// ---------------------------------------------------------------------------------------- + + + diff --git a/examples/mlp_ex.cpp b/examples/mlp_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4521dd9089910ab9ea372354cf350127773c776c --- /dev/null +++ b/examples/mlp_ex.cpp @@ -0,0 +1,85 @@ +/* + + This is an example illustrating the use of the multilayer perceptron + from the dlib C++ Library. + + This example creates a simple set of data to train on and shows + you how to train a mlp object on that data. + + + The data used in this example will be 2 dimensional data and will + come from a distribution where points with a distance less than 10 + from the origin are labeled 1 and all other points are labeled + as 0. + +*/ + + +#include +#include "dlib/mlp.h" + +using namespace std; +using namespace dlib; + + +int main() +{ + // The mlp takes column vectors as input and gives column vectors as output. The dlib::matrix + // object is used to represent the column vectors. So the first thing we do here is declare + // a convenient typedef for the matrix object we will be using. + + // This typedef declares a matrix with 2 rows and 1 column. It will be the + // object that contains each of our 2 dimensional samples. (Note that if you wanted + // more than 2 features in this vector you can simply change the 2 to something else) + typedef matrix sample_type; + + + // make an instance of a sample matrix so we can use it below + sample_type sample; + + // Create a multi-layer perceptron network. This network has 2 nodes on the input layer + // (which means it takes column vectors of length 2 as input) and 5 nodes in the first + // hidden layer. Note that the other 4 variables in the mlp's constructor are left at + // their default values. + mlp::kernel_1a_c net(2,5); + + // Now lets put some data into our sample and train on it. We do this + // by looping over 41*41 points and labeling them according to their + // distance from the origin. + for (int i = 0; i < 1000; ++i) + { + for (int r = -20; r <= 20; ++r) + { + for (int c = -20; c <= 20; ++c) + { + sample(0) = r; + sample(1) = c; + + // if this point is less than 10 from the origin + if (sqrt((double)r*r + c*c) <= 10) + net.train(sample,1); + else + net.train(sample,0); + } + } + } + + // Now we have trained our mlp. Lets see how well it did. + // Note that if you run this program multiple times you will get different results. This + // is because the mlp network is randomly initialized. + + // each of these statements prints out the output of the network given a particular sample. + + sample(0) = 3.123; + sample(1) = 4; + cout << "This sample should close to 1 and it is classified as a " << net(sample) << endl; + + sample(0) = 13.123; + sample(1) = 9.3545; + cout << "This sample should close to 0 and it is classified as a " << net(sample) << endl; + + sample(0) = 13.123; + sample(1) = 0; + cout << "This sample should close to 0 and it is classified as a " << net(sample) << endl; +} + diff --git a/examples/multithreaded_object_ex.cpp b/examples/multithreaded_object_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6dd06e330f39625809e0ca165b5e52e6acf940ae --- /dev/null +++ b/examples/multithreaded_object_ex.cpp @@ -0,0 +1,137 @@ +/* + + This is an example illustrating the use of the multithreaded_object. + + This is a very simple example. It creates 3 threads that + just print messages to the screen. + + + + Example program output: + 0 INFO [1] mto: thread1(): hurray threads! + 0 INFO [2] mto: thread2(): hurray threads! + 0 INFO [3] mto: thread2(): hurray threads! + 700 INFO [1] mto: thread1(): hurray threads! + 800 INFO [2] mto: thread2(): hurray threads! + 801 INFO [3] mto: thread2(): hurray threads! + 1400 INFO [1] mto: thread1(): hurray threads! + 1604 INFO [2] mto: thread2(): hurray threads! + 1605 INFO [3] mto: thread2(): hurray threads! + 2100 INFO [1] mto: thread1(): hurray threads! + 2409 INFO [2] mto: thread2(): hurray threads! + 2409 INFO [3] mto: thread2(): hurray threads! + 2801 INFO [1] mto: thread1(): hurray threads! + 3001 INFO [0] mto: paused threads + 6001 INFO [0] mto: starting threads back up from paused state + 6001 INFO [2] mto: thread2(): hurray threads! + 6001 INFO [1] mto: thread1(): hurray threads! + 6001 INFO [3] mto: thread2(): hurray threads! + 6705 INFO [1] mto: thread1(): hurray threads! + 6805 INFO [2] mto: thread2(): hurray threads! + 6805 INFO [3] mto: thread2(): hurray threads! + 7405 INFO [1] mto: thread1(): hurray threads! + 7609 INFO [2] mto: thread2(): hurray threads! + 7609 INFO [3] mto: thread2(): hurray threads! + 8105 INFO [1] mto: thread1(): hurray threads! + 8413 INFO [2] mto: thread2(): hurray threads! + 8413 INFO [3] mto: thread2(): hurray threads! + 8805 INFO [1] mto: thread1(): hurray threads! + + The first column is the number of milliseconds since program start, the second + column is the logging level, the third column is the thread id, and the rest + is the log message. +*/ + + +#include +#include "dlib/threads.h" +#include "dlib/misc_api.h" // for dlib::sleep +#include "dlib/logger.h" + +using namespace std; +using namespace dlib; + +logger dlog("mto"); + +class my_object : public multithreaded_object +{ +public: + my_object() + { + // register which functions we want to run as threads. We want one thread running + // thread1() and two threads to run thread2(). So we will have a total of 3 threads + // running. + register_thread(*this,&my_object::thread1); + register_thread(*this,&my_object::thread2); + register_thread(*this,&my_object::thread2); + + // start all our registered threads going by calling the start() function + start(); + } + + ~my_object() + { + // Tell the thread() function to stop. This will cause should_stop() to + // return true so the thread knows what to do. + stop(); + + // Wait for the threads to stop before letting this object destruct itself. + // Also note, you are *required* to wait for the threads to end before + // letting this object destruct itself. + wait(); + } + +private: + + void thread1() + { + // This is a thread. It will loop until it is told that it should terminate. + while (should_stop() == false) + { + dlog << LINFO << "thread1(): hurray threads!"; + dlib::sleep(700); + } + } + + void thread2() + { + // This is a thread. It will loop until it is told that it should terminate. + while (should_stop() == false) + { + dlog << LINFO << "thread2(): hurray threads!"; + dlib::sleep(800); + } + } + +}; + +int main() +{ + // tell the logger to output all messages + dlog.set_level(LALL); + + // Create an instance of our multi-threaded object. + my_object t; + + dlib::sleep(3000); + + // Tell the multi-threaded object to pause its threads. This causes the + // threads to block on their next calls to should_stop(). + t.pause(); + dlog << LINFO << "paused threads"; + + dlib::sleep(3000); + dlog << LINFO << "starting threads back up from paused state"; + + // Tell the threads to unpause themselves. This causes should_stop() to unblock + // and to let the threads continue. + t.start(); + + dlib::sleep(3000); + + // Let the program end. When t is destructed it will gracefully terminate your + // threads because we have set the destructor up to do so. +} + + + diff --git a/examples/pipe_ex.cpp b/examples/pipe_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d49266e509b8054c3d4aa252d4102f41498f6a0c --- /dev/null +++ b/examples/pipe_ex.cpp @@ -0,0 +1,162 @@ + + +/* + This is an example illustrating the use of the threading API and pipe object + from the dlib C++ Library. + + In this example we will create three threads that will read "jobs" off the end of + a pipe object and process them. It shows you how you can use the pipe object + to communicate between threads. + + + Example program output: + 0 INFO [0] pipe_example: Add job 0 to pipe + 0 INFO [0] pipe_example: Add job 1 to pipe + 0 INFO [0] pipe_example: Add job 2 to pipe + 0 INFO [0] pipe_example: Add job 3 to pipe + 0 INFO [0] pipe_example: Add job 4 to pipe + 0 INFO [0] pipe_example: Add job 5 to pipe + 0 INFO [1] pipe_example: got job 0 + 0 INFO [0] pipe_example: Add job 6 to pipe + 0 INFO [2] pipe_example: got job 1 + 0 INFO [0] pipe_example: Add job 7 to pipe + 0 INFO [3] pipe_example: got job 2 + 103 INFO [0] pipe_example: Add job 8 to pipe + 103 INFO [1] pipe_example: got job 3 + 103 INFO [0] pipe_example: Add job 9 to pipe + 103 INFO [2] pipe_example: got job 4 + 103 INFO [0] pipe_example: Add job 10 to pipe + 103 INFO [3] pipe_example: got job 5 + 207 INFO [0] pipe_example: Add job 11 to pipe + 207 INFO [1] pipe_example: got job 6 + 207 INFO [0] pipe_example: Add job 12 to pipe + 207 INFO [2] pipe_example: got job 7 + 207 INFO [0] pipe_example: Add job 13 to pipe + 207 INFO [3] pipe_example: got job 8 + 311 INFO [1] pipe_example: got job 9 + 311 INFO [2] pipe_example: got job 10 + 311 INFO [3] pipe_example: got job 11 + 311 INFO [0] pipe_example: Add job 14 to pipe + 311 INFO [0] pipe_example: main ending + 311 INFO [0] pipe_example: destructing pipe object: wait for job_pipe to be empty + 415 INFO [1] pipe_example: got job 12 + 415 INFO [2] pipe_example: got job 13 + 415 INFO [3] pipe_example: got job 14 + 415 INFO [0] pipe_example: destructing pipe object: job_pipe is empty + 519 INFO [1] pipe_example: thread ending + 519 INFO [2] pipe_example: thread ending + 519 INFO [3] pipe_example: thread ending + 519 INFO [0] pipe_example: destructing pipe object: all threads have ended + + + The first column is the number of milliseconds since program start, the second + column is the logging level, the third column is the thread id, and the rest + is the log message. +*/ + + +#include "dlib/threads.h" +#include "dlib/misc_api.h" // for dlib::sleep +#include "dlib/pipe.h" +#include "dlib/logger.h" + +using namespace dlib; + +struct job +{ + /* + This object represents the jobs we are going to send out to our threads. + */ + int id; +}; + +dlib::logger dlog("pipe_example"); + +// ---------------------------------------------------------------------------------------- + +class pipe_example : private multithreaded_object +{ +public: + pipe_example( + ) : + job_pipe(4) // This 4 here is the size of our job_pipe. The significance is that + // if you try to enqueue more than 4 jobs onto the pipe then enqueue() will + // block until there is room. + { + // register 3 threads + register_thread(*this,&pipe_example::thread); + register_thread(*this,&pipe_example::thread); + register_thread(*this,&pipe_example::thread); + + // start the 3 threads we registered above + start(); + } + + ~pipe_example ( + ) + { + dlog << LINFO << "destructing pipe object: wait for job_pipe to be empty"; + // wait for all the jobs to be processed + job_pipe.wait_until_empty(); + + dlog << LINFO << "destructing pipe object: job_pipe is empty"; + + // now disable the job_pipe. doing this will cause all calls to + // job_pipe.dequeue() to return false so our threads will terminate + job_pipe.disable(); + + // now block until all the threads have terminated + wait(); + dlog << LINFO << "destructing pipe object: all threads have ended"; + } + + // Here we declare our pipe object. It will contain our job objects. + // There are only two requirements on the type of objects you can use in a + // pipe, first they must have a default constructor and second they must + // be swappable by a global swap(). + dlib::pipe::kernel_1a job_pipe; + +private: + void thread () + { + job j; + // Here we loop on jobs from the job_pipe. + while (job_pipe.dequeue(j)) + { + // process our job j in some way. + dlog << LINFO << "got job " << j.id; + + // sleep for 0.1 seconds + dlib::sleep(100); + } + dlog << LINFO << "thread ending"; + } + +}; + +// ---------------------------------------------------------------------------------------- + +int main() +{ + // Set the dlog object so that it logs everything. + dlog.set_level(LALL); + + pipe_example pe; + + for (int i = 0; i < 15; ++i) + { + dlog << LINFO << "Add job " << i << " to pipe"; + job j; + j.id = i; + // Add this job to the pipe. One of our three threads will get it and process it + pe.job_pipe.enqueue(j); + } + + dlog << LINFO << "main ending"; + + // the main function won't really terminate here. It will call the destructor for pe + // which will block until all the jobs have been processed. +} + +// ---------------------------------------------------------------------------------------- + diff --git a/examples/queue_ex.cpp b/examples/queue_ex.cpp new file mode 100755 index 0000000000000000000000000000000000000000..0d6a7272f11ea31cb00059bcd230bc88a4b74006 --- /dev/null +++ b/examples/queue_ex.cpp @@ -0,0 +1,77 @@ +/* + + This is an example illustrating the use of the queue component (and + to some degree the generial idea behind most of the other container + classes) from the dlib C++ Library. + + It loads a queue with 20 random numbers. Then it uses the enumerable + interface to print them all to the screen. Then it sorts the numbers and + prints them to the screen. +*/ + + + + +#include "dlib/queue.h" +#include +#include +#include +#include + + +// I'm picking the version of the queue that is kernel_2a extended by +// the queue sorting extension. This is just a normal queue but with the +// added member function sort() which sorts the queue. +typedef dlib::queue::sort_1b_c queue_of_int; + + +using namespace std; +using namespace dlib; + + +int main() +{ + queue_of_int q; + + // initialize rand() + srand(time(0)); + + for (int i = 0; i < 20; ++i) + { + int a = rand()&0xFF; + + // note that adding a to the queue "consumes" the value of a because + // all container classes move values around by swapping them rather + // than copying them. So a is swapped into the queue which results + // in a having an initial value for its type (for int types that value + // is just some undefined value. ) + q.enqueue(a); + + } + + + cout << "The contents of the queue are:\n"; + while (q.move_next()) + cout << q.element() << " "; + + cout << "\n\nNow we sort the queue and its contents are:\n"; + q.sort(); // note that we don't have to call q.reset() to put the enumerator + // back at the start of the queue because calling sort() does + // that automatically for us. (In general, modifying a container + // will reset the enumerator). + while (q.move_next()) + cout << q.element() << " "; + + + cout << "\n\nNow we remove the numbers from the queue:\n"; + while (q.size() > 0) + { + int a; + q.dequeue(a); + cout << a << " "; + } + + + cout << endl; +} + diff --git a/examples/server_http_ex.cpp b/examples/server_http_ex.cpp new file mode 100755 index 0000000000000000000000000000000000000000..4d85f0c45cfea92f9014e54b18ee01e7164ae9f4 --- /dev/null +++ b/examples/server_http_ex.cpp @@ -0,0 +1,130 @@ +/* + + This example illustrates the use of the HTTP extension to the server object + from the dlib C++ Library. + It creates a server that always responds with a simple HTML form. + + To view the page this program displays you should go to http://localhost:5000 + +*/ + +#include +#include +#include +#include "dlib/server.h" + +using namespace dlib; +using namespace std; + +class web_server : public server::http_1a_c +{ + void on_request ( + const std::string& path, + std::string& result, + const map_type& queries, + const map_type& cookies, + queue_type& new_cookies, + const map_type& incoming_headers, + map_type& response_headers, + const std::string& foreign_ip, + const std::string& local_ip, + unsigned short foreign_port, + unsigned short local_port + ) + { + try + { + ostringstream sout; + // We are going to send back a page that contains an HTML form with two text input fields. + // One field called name. The HTML form uses the post method but could also use the get + // method (just change method='post' to method='get'). + sout << " " + << "
    " + << "User Name:
    " + << "User password: " + << "
    "; + + sout << "
    path = " << path << endl; + sout << "
    foreign_ip = " << foreign_ip << endl; + sout << "
    foreign_port = " << foreign_port << endl; + sout << "
    local_ip = " << local_ip << endl; + sout << "
    local_port = " << local_port << endl; + + + // If this request is the result of the user submitting the form then echo back + // the submission. + if (path == "/form_handler") + { + sout << "

    Stuff from the query string

    " << endl; + sout << "
    user = " << queries["user"] << endl; + sout << "
    pass = " << queries["pass"] << endl; + + // save these form submissions as cookies. + string cookie; + cookie = "user=" + queries["user"]; + new_cookies.enqueue(cookie); + cookie = "pass=" + queries["pass"]; + new_cookies.enqueue(cookie); + } + + + // Echo any cookies back to the client browser + sout << "

    Cookies we got back from the server

    "; + cookies.reset(); + while (cookies.move_next()) + { + sout << "
    " << cookies.element().key() << " = " << cookies.element().value() << endl; + } + + sout << "

    "; + + sout << "

    HTTP Headers we sent to the server

    "; + // Echo out all the HTTP headers we received from the client web browser + incoming_headers.reset(); + while (incoming_headers.move_next()) + { + sout << "
    " << incoming_headers.element().key() << ": " << incoming_headers.element().value() << endl; + } + + + sout << " "; + + result = sout.str(); + } + catch (exception& e) + { + cout << e.what() << endl; + } + } + +}; + +// create an instance of our web server +web_server our_web_server; + +void thread() +{ + cout << "Press enter to end this program" << endl; + cin.get(); + // this will cause the server to shut down which will in turn cause + // our_web_server.start() to unblock and thus the main() function will terminate. + our_web_server.clear(); +} + +int main() +{ + try + { + // create a thread that will listen for the user to end this program + thread_function t(thread); + + // make it listen on port 5000 + our_web_server.set_listening_port(5000); + our_web_server.start(); + } + catch (exception& e) + { + cout << e.what() << endl; + } +} + diff --git a/examples/sockets_ex.cpp b/examples/sockets_ex.cpp new file mode 100755 index 0000000000000000000000000000000000000000..b4840224fb1b56d4b5dd76233aa70c5d96a9e656 --- /dev/null +++ b/examples/sockets_ex.cpp @@ -0,0 +1,81 @@ +/* + + This is an example illustrating the use of the sockets and + server components from the dlib C++ Library. + + This is a simple echo server. It listens on port 1234 for incoming + connections and just echos back any data it receives. + +*/ + + + + +#include "dlib/sockets.h" +#include "dlib/server.h" +#include + +using namespace dlib; +using namespace std; + + + +class serv : public server::kernel_1a_c +{ + + void on_connect ( + connection& con + ) + { + char ch; + while (con.read(&ch,1) > 0) + { + // we are just reading one char at a time and writing it back + // to the connection. If there is some problem writing the char + // then we quit the loop. + if (con.write(&ch,1) != 1) + break; + } + } + +}; + +serv our_server; + +void thread() +{ + cout << "Press enter to end this program" << endl; + cin.get(); + // this will cause the server to shut down which will in turn cause + // our_server.start() to unblock and thus the main() function will terminate. + our_server.clear(); +} + + + +int main() +{ + try + { + // create a thread that will listen for the user to end this program + thread_function t(thread); + + + // set up the server object we have made + our_server.set_listening_port(1234); + our_server.set_max_connections(1000); + + // start the server + our_server.start(); + + } + catch (exception& e) + { + cout << e.what() << endl; + } + catch (...) + { + cout << "Some error occurred" << endl; + } +} + diff --git a/examples/sockets_ex_2.cpp b/examples/sockets_ex_2.cpp new file mode 100755 index 0000000000000000000000000000000000000000..07baf5a613f28ac12418876a29d269f23ea3fc8d --- /dev/null +++ b/examples/sockets_ex_2.cpp @@ -0,0 +1,71 @@ +/* + + This is an example illustrating the use of the sockets and + sockstreambuf components from the dlib C++ Library. + + This program simply connects to www.google.com at port 80 and requests the + main Google web page. It then prints what it gets back from Google to the + screen. + + + For those of you curious about HTTP check out the excellent introduction at + http://www.jmarshall.com/easy/http/ +*/ + +#include "dlib/sockets.h" +#include "dlib/sockstreambuf.h" +#include + +using namespace std; +using namespace dlib; + +int main() +{ + try + { + // Connect to Google's web server which listens on port 80. If this + // fails it will throw a dlib::socket_error exception. + connection* con = connect("www.google.com",80); + + + { + // create a stream buffer for our connection + sockstreambuf::kernel_2a buf(con); + // now stick that stream buffer into an iostream object + iostream stream(&buf); + // this command causes the iostream to flush its output buffers + // whenever someone makes a read request. + stream.tie(&stream); + + // now we make the HTTP GET request for the main Google page. + stream << "GET / HTTP/1.0\r\n" + << "\r\n"; + + // Here we print each character we get back one at a time. + int ch = stream.get(); + while (ch != EOF) + { + cout << (char)ch; + ch = stream.get(); + } + + // at the end of this scope buf will be destructed and flush + // anything it still contains to the connection. Thus putting + // this scope here makes it safe to call close_gracefully() next. + // If we just called close_gracefully() before buf was destructed + // then buf would try to flush its data to a closed connection + // which would be an error. + } + + // Don't forget to close the connection. Not doing so will + // cause a resource leak. And once it is closed the con pointer + // is invalid so don't touch it. + close_gracefully(con); + } + catch (exception& e) + { + cout << e.what() << endl; + } +} + + diff --git a/examples/sockstreambuf_ex.cpp b/examples/sockstreambuf_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..867576ac810baa046effa4ca0fe61ef5567e4e34 --- /dev/null +++ b/examples/sockstreambuf_ex.cpp @@ -0,0 +1,106 @@ +/* + + This is an example illustrating the use of the sockets, + server and sockstreambuf components from the dlib C++ Library. + + This is a simple echo server. It listens on port 1234 for incoming + connections and just echos back any text it receives but in upper case. + So basically it is the same as the other sockets example except it + uses stream buffers. + + To test it out you can just open a command prompt and type: + telnet localhost 1234 + + Then you can type away. + + + Also note that a good reference on the standard C++ iostream library can be + found at http://www.cplusplus.com/ref/iostream/ +*/ + + + + +#include "dlib/sockets.h" +#include "dlib/server.h" +#include "dlib/sockstreambuf.h" +#include + +using namespace dlib; +using namespace std; + + + +class serv : public server::kernel_1a_c +{ + + void on_connect ( + connection& con + ) + { + // create a sockstreambuf that reads/writes on our connection. I'm using the + // kernel_2a version here because it is generally the faster of the two versions in the + // library. + sockstreambuf::kernel_2a buf(&con); + + // Now we make an iostream object that reads/writes to our streambuffer. A lot of people + // don't seem to know that the C++ iostreams are as powerful as they are. So what I'm doing + // here isn't anything special and is totally portable. You will be able to use this stream + // object just as you would any iostream from the standard library. + iostream stream(&buf); + + // This command causes our stream to flush its output buffers whenever you ask it for more + // data. + stream.tie(&stream); + + char ch; + while (stream.good()) + { + // get the next character from the client + ch = stream.get(); + + // now echo it back to them + stream << (char)toupper(ch); + } + } + +}; + +serv our_server; + +void thread() +{ + cout << "Press enter to end this program" << endl; + cin.get(); + // this will cause the server to shut down which will in turn cause + // our_server.start() to unblock and thus the main() function will terminate. + our_server.clear(); +} + +int main() +{ + try + { + // create a thread that will listen for the user to end this program + thread_function t(thread); + + + // set up the server object we have made + our_server.set_listening_port(1234); + our_server.set_max_connections(1000); + + // start the server + our_server.start(); + + } + catch (exception& e) + { + cout << e.what() << endl; + } + catch (...) + { + cout << "Some error occurred" << endl; + } +} + + diff --git a/examples/std_allocator_ex.cpp b/examples/std_allocator_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60e999ec685f6526640e0e9950b6f5c95aae9bb9 --- /dev/null +++ b/examples/std_allocator_ex.cpp @@ -0,0 +1,56 @@ +/* + This is an example illustrating the use of the dlib::std_allocator object. + + In this example we will create the necessary typedefs to give the + dlib::std_allocator object to the standard string and vector objects + in the STL. Thus we will create versions of std::string and std::vector + that perform all their memory allocations and deallocations via one of + the dlib memory manager objects. +*/ + + +// include everything we need for this example +#include +#include +#include +#include "dlib/std_allocator.h" +#include "dlib/memory_manager.h" +#include "dlib/memory_manager_stateless.h" + +using namespace std; +using namespace dlib; + + +int main() +{ + // Make a typedef for an allocator that uses the thread safe memory_manager_stateless object with a + // global memory pool. This version of the memory_manager_stateless object keeps everything it allocates + // in a global memory pool and doesn't release any memory until the program terminates. + typedef std_allocator::kernel_2_3a> alloc_char_with_global_memory_pool; + + // Now make a typedef for a C++ standard string that uses our new allocator type + typedef std::basic_string, alloc_char_with_global_memory_pool > dstring; + + + // typedef another allocator for dstring objects + typedef std_allocator::kernel_2_3a> alloc_dstring_with_global_memory_pool; + + // Now make a typedef for a C++ standard vector that uses our new allocator type and also contains the new dstring + typedef std::vector dvector; + + // Now we can use the string and vector we have as we normally would. So for example, I can make a + // dvector and add 4 strings into it like so: + dvector v; + v.push_back("one"); + v.push_back("two"); + v.push_back("three"); + v.push_back("four"); + + // And now we print out the contents of our vector + for (unsigned long i = 0; i < v.size(); ++i) + { + cout << v[i] << endl; + } + +} + diff --git a/examples/svm_ex.cpp b/examples/svm_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64efb8758c011f2b31a1ce7fad45cf5b5e82f09d --- /dev/null +++ b/examples/svm_ex.cpp @@ -0,0 +1,170 @@ +/* + + This is an example illustrating the use of the support vector machine + utilities from the dlib C++ Library. + + This example creates a simple set of data to train on and then shows + you how to use the cross validation and svm training functions + to find a good decision function that can classify examples in our + data set. + + + The data used in this example will be 2 dimensional data and will + come from a distribution where points with a distance less than 10 + from the origin are labeled +1 and all other points are labeled + as -1. + +*/ + + +#include +#include "dlib/svm.h" + +using namespace std; +using namespace dlib; + + +int main() +{ + // The svm functions use column vectors to contain a lot of the data they operate on + // So the first thing we do here is declare some convenient typedefs for matrix objects + // we will be using. + + // This first typedef declares a matrix with 2 rows and 1 column. It will be the + // object that contains each of our 2 dimensional samples. (Note that if you wanted + // more than 2 features in this vector you can simply change the 2 to something else) + typedef matrix sample_type; + + // This is a typedef for a column vector of unknown length that contains our + // sample_type objects. Instances of this object will contain our sample data. + typedef matrix samples_type; + + // This is a typedef for the type of kernel we are going to use in this example. + // In this case I have selected the radial basis kernel that can operate on our + // 2D sample_type objects + typedef radial_basis_kernel kernel_type; + + + // Now we make a samples_type object as well as a column vector to + // store the label for each sample in samples. + samples_type samples; + matrix labels; + + + // Now lets put some data into our samples and labels objects. We do this + // by looping over 41*41 points and labeling them according to their + // distance from the origin. + samples.set_size(41*41); + labels.set_size(41*41); + int count = 0; + for (int r = -20; r <= 20; ++r) + { + for (int c = -20; c <= 20; ++c) + { + samples(count)(0) = r; + samples(count)(1) = c; + + // if this point is less than 10 from the origin + if (sqrt((double)r*r + c*c) <= 10) + labels(count) = +1; + else + labels(count) = -1; + + ++count; + } + } + + + // Now that we have some data we want to train on it. However, there are two parameters to the + // training. These are the nu and gamma parameters. Our choice for these parameters will + // influence how good the resulting decision function is. To test how good a particular choice + // of these parameters are we can use the svm_nu_cross_validate() function to perform n-fold cross + // validation on our training data. However, there is a problem with the way we have sampled + // our distribution above. The problem is that there is a definite ordering to the samples. + // That is, the first half of the samples look like they are from a different distribution + // than the second half do. This would screw up the cross validation process but we can + // fix it by randomizing the order of the samples with the following function call. + randomize_samples(samples, labels); + + + // The nu parameter has a maximum value that is dependent on the ratio of the +1 to -1 + // labels in the training data. This function finds that value. + const double max_nu = maximum_nu(labels); + + // Now we loop over some different nu and gamma values to see how good they are. Note + // that this is just a simple brute force way to try out a few possible parameter + // choices. You may want to investigate more sophisticated strategies for determining + // good parameter choices. + cout << "doing cross validation" << endl; + for (double gamma = 0.00001; gamma <= 1; gamma += 0.1) + { + for (double nu = 0.00001; nu < max_nu; nu += 0.1) + { + cout << "gamma: " << gamma << " nu: " << nu; + // Print out the cross validation accuracy for 3-fold cross validation using the current gamma and nu. + // svm_nu_cross_validate() returns a column vector. The first element of the vector is the fraction + // of +1 training examples correctly classified and the second number is the fraction of -1 training + // examples correctly classified. + cout << " cross validation accuracy: " << svm_nu_cross_validate(samples, labels, kernel_type(gamma), nu, 3); + } + } + + + // From looking at the output of the above loop it turns out that a good value for + // nu and gamma for this problem is 0.1 for both. So that is what we will use. + + // Now we train on the full set of data and obtain the resulting decision function. We use the + // value of 0.1 for nu and gamma. The decision function will return values >= 0 for samples it predicts + // are in the +1 class and numbers < 0 for samples it predicts to be in the -1 class. + decision_function learned_decision_function = svm_nu_train(samples, labels, kernel_type(0.1), 0.1); + + // print out the number of support vectors in the resulting decision function + cout << "\nnumber of support vectors in our learned_decision_function is " << learned_decision_function.support_vectors.nr() << endl; + + // now lets try this decision_function on some samples we haven't seen before + sample_type sample; + + sample(0) = 3.123; + sample(1) = 2; + cout << "This sample should be >= 0 and it is classified as a " << learned_decision_function(sample) << endl; + + sample(0) = 3.123; + sample(1) = 9.3545; + cout << "This sample should be >= 0 and it is classified as a " << learned_decision_function(sample) << endl; + + sample(0) = 13.123; + sample(1) = 9.3545; + cout << "This sample should be < 0 and it is classified as a " << learned_decision_function(sample) << endl; + + sample(0) = 13.123; + sample(1) = 0; + cout << "This sample should be < 0 and it is classified as a " << learned_decision_function(sample) << endl; + + + // We can also train a decision function that reports a well conditioned probability instead of just a number + // > 0 for the +1 class and < 0 for the -1 class. An example of doing that follows: + probabilistic_decision_function learned_probabilistic_decision_function = svm_nu_train_prob(samples, labels, kernel_type(0.1), 0.1, 3); + + // print out the number of support vectors in the resulting decision function. (it should be the same as in the one above) + cout << "\nnumber of support vectors in our learned_probabilistic_decision_function is " + << learned_probabilistic_decision_function.decision_funct.support_vectors.nr() << endl; + + sample(0) = 3.123; + sample(1) = 2; + cout << "This +1 example should have high probability. It's probability is: " << learned_probabilistic_decision_function(sample) << endl; + + sample(0) = 3.123; + sample(1) = 9.3545; + cout << "This +1 example should have high probability. It's probability is: " << learned_probabilistic_decision_function(sample) << endl; + + sample(0) = 13.123; + sample(1) = 9.3545; + cout << "This -1 example should have low probability. It's probability is: " << learned_probabilistic_decision_function(sample) << endl; + + sample(0) = 13.123; + sample(1) = 0; + cout << "This -1 example should have low probability. It's probability is: " << learned_probabilistic_decision_function(sample) << endl; + + +} + diff --git a/examples/thread_function_ex.cpp b/examples/thread_function_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..068621c8ae5e265413ad9d7c666c19c0d427dd81 --- /dev/null +++ b/examples/thread_function_ex.cpp @@ -0,0 +1,52 @@ +/* + This is a very simple example that illustrates the use of the + thread_function object from the dlib C++ Library. + + The output of the programs should look like this: + + 45.6 + 9.999 + I have no args! +*/ + + +#include +#include "dlib/threads.h" + +using namespace dlib; +using namespace std; + +void thread_1(double a) +{ + cout << a << endl; +} + +void thread_2 () +{ + cout << "I have no args!" << endl; +} + +int main() +{ + // create a thread that will call thread_1(45.6) + thread_function t1(thread_1,45.6); + // wait for the t1 thread to end + t1.wait(); + + + // create a thread that will call thread_1(9.999) + thread_function t2(thread_1,9.999); + // wait for the t2 thread to end + t2.wait(); + + + // create a thread that will call thread_2() + thread_function t3(thread_2); + + + + // we will wait for t3 to end here because the destructor for + // thread_function objects always waits for their thread to end +} + + diff --git a/examples/threaded_object_ex.cpp b/examples/threaded_object_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f58f861391ffb5cb2ba474c889097933e46632c3 --- /dev/null +++ b/examples/threaded_object_ex.cpp @@ -0,0 +1,78 @@ +/* + + This is an example illustrating the use of the threaded_object + from the dlib C++ Library. + + + This is a very simple example. It creates a single thread that + just prints messages to the screen. +*/ + + +#include +#include "dlib/threads.h" +#include "dlib/misc_api.h" // for dlib::sleep + +using namespace std; +using namespace dlib; + +class my_object : public threaded_object +{ +public: + my_object() + { + // Start our thread going in the thread() function + start(); + } + + ~my_object() + { + // Tell the thread() function to stop. This will cause should_stop() to + // return true so the thread knows what to do. + stop(); + + // Wait for the thread to stop before letting this object destruct itself. + // Also note, you are *required* to wait for the thread to end before + // letting this object destruct itself. + wait(); + } + +private: + + void thread() + { + // This is our thread. It will loop until it is told that it should terminate. + while (should_stop() == false) + { + cout << "hurray threads!" << endl; + dlib::sleep(500); + } + } +}; + +int main() +{ + // Create an instance of our threaded object. + my_object t; + + dlib::sleep(4000); + + // Tell the threaded object to pause its thread. This causes the + // thread to block on its next call to should_stop(). + t.pause(); + + dlib::sleep(3000); + cout << "starting thread back up from paused state" << endl; + + // Tell the thread to unpause itself. This causes should_stop() to unblock + // and to let the thread continue. + t.start(); + + dlib::sleep(4000); + + // Let the program end. When t is destructed it will gracefully terminate your + // thread because we have set the destructor up to do so. +} + + + diff --git a/examples/threads_ex.cpp b/examples/threads_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4fce98bea403c92201e3048169d1ef6d11053d39 --- /dev/null +++ b/examples/threads_ex.cpp @@ -0,0 +1,88 @@ + +/* + + This is an example illustrating the use of the threading api from the + dlib C++ Library. + + + This is a very simple example. It makes some threads and just waits for + them to terminate. +*/ + + +#include +#include "dlib/threads.h" +#include "dlib/misc_api.h" // for dlib::sleep + +using namespace std; +using namespace dlib; + +int thread_count = 10; +mutex count_mutex; // This is a mutex we will use to guard the thread_count variable. Note that the mutex doesn't know + // anything about the thread_count variable. Only our usage of a mutex determines what it guards. + // In this case we are going to make sure this mutex is always locked before we touch the + // thread_count variable. + +signaler count_signaler(count_mutex); // This is a signaler we will use to signal when + // the thread_count variable is changed. Note that it is + // associated with the count_mutex. This means that + // when you call count_signaler.wait() it will automatically + // unlock count_mutex for you. + + +void thread (void*) +{ + // just sleep for a second + dlib::sleep(1000); + + // Now signal that this thread is ending. First we should get a lock on the + // count_mutex so we can safely mess with thread_count. A convenient way to do this + // is to use an auto_mutex object. Its constructor takes a mutex object and locks + // it right away, it then unlocks the mutex when the auto_mutex object is destructed. + // Note that this happens even if an exception is thrown. So it ensures that you + // don't somehow quit your function without unlocking your mutex. + auto_mutex locker(count_mutex); + --thread_count; + // Now we signal this change. This will cause one thread that is currently waiting + // on a call to count_signaler.wait() to unblock. + count_signaler.signal(); + + // At the end of this function locker goes out of scope and gets destructed, thus + // unlocking count_mutex for us. +} + +int main() +{ + + cout << "Create some threads" << endl; + for (int i = 0; i < thread_count; ++i) + { + // Create some threads. This 0 we are passing in here is the argument that gets + // passed to the thread function (a void pointer) but we aren't using it in this + // example program so i'm just using 0. + create_new_thread(thread,0); + } + cout << "Done creating threads, now we wait for them to end" << endl; + + + // Again we use an auto_mutex to get a lock. We don't have to do it this way + // but it is convenient. Also note that we can name the auto_mutex object anything. + auto_mutex some_random_unused_name(count_mutex); + + // Now we wait in a loop for thread_count to be 0. Note that it is important to do this in a + // loop because it is possible to get spurious wakeups from calls to wait() on some + // platforms. So this guards against that and it also makes the code easy to understand. + while (thread_count > 0) + count_signaler.wait(); // This puts this thread to sleep until we get a signal to look at the + // thread_count variable. It also unlocks the count_mutex before it + // goes to sleep and then relocks it when it wakes back up. Again, + // note that it is possible for wait() to return even if no one signals you. + // This is just weird junk you have to deal with on some platforms. So + // don't try to be clever and write code that depends on the number of + // times wait() returns because it won't always work. + + + cout << "All threads done, ending program" << endl; +} + + diff --git a/examples/timer_ex.cpp b/examples/timer_ex.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39af39eeec9b6e829a3e0fa585c14b5d6121b2f6 --- /dev/null +++ b/examples/timer_ex.cpp @@ -0,0 +1,60 @@ + + +/* + This is an example illustrating the use of the timer object. + + The timer object is an object that calls some user specified member function + in its own thread at regular intervals. +*/ + + +#include "dlib/timer.h" +#include "dlib/misc_api.h" // for dlib::sleep +#include + +using namespace dlib; +using namespace std; + +// ---------------------------------------------------------------------------------------- + +class timer_example +{ +public: + timer_example( + ) : + // Here we construct our timer object. It needs two things. The second argument is + // the member function it is going to call at regular intervals and the first + // argument is the object instance it will call that member function on. + t(*this,&timer_example::action_function) + { + // set the timer object to trigger every second + t.set_delay_time(1000); + + // start the timer. It will start calling the action function + // 1 second from this call to start. + t.start(); + } + +private: + + timer::kernel_1a t; + + void action_function() + { + // print out a message so we can see that this function is being triggered + cout << "action_function() called" << endl; + } +}; + +// ---------------------------------------------------------------------------------------- + +int main() +{ + timer_example e; + + // sleep for 10 seconds before letting the program end + dlib::sleep(10000); +} + +// ---------------------------------------------------------------------------------------- + diff --git a/examples/xml_parser_ex.cpp b/examples/xml_parser_ex.cpp new file mode 100755 index 0000000000000000000000000000000000000000..3a4f41d7248c1ab020896c2db7d33bd0a13e2abb --- /dev/null +++ b/examples/xml_parser_ex.cpp @@ -0,0 +1,146 @@ +/* + + This is an example illustrating the use of the xml_parser component in + the dlib C++ Library. + + This example simply reads in an xml file and prints the parsing events + to the screen. +*/ + + + + +#include "dlib/xml_parser.h" +#include +#include + + +using namespace std; +using namespace dlib; + +// ---------------------------------------------------------------------------------------- + +class doc_handler : public document_handler +{ + /* + As the parser runs it generates events when it encounters tags and + data in an XML file. To be able to receive these events all you have to + do is make a class that inherits from dlib::document_handler and + implements its virtual methods. Then you simply associate an + instance of your class with the xml_parser. + + So this class is a simple example document handler that just prints + all the events to the screen. + */ +public: + + virtual void start_document ( + ) + { + cout << "parsing begins" << endl; + } + + virtual void end_document ( + ) + { + cout << "Parsing done" << endl; + } + + virtual void start_element ( + const unsigned long line_number, + const std::string& name, + const dlib::attribute_list& atts + ) + { + cout << "on line " << line_number << " we hit the <" << name << "> tag" << endl; + + // print all the tag's attributes + atts.reset(); + while (atts.move_next()) + { + cout << "\tattribute: " << atts.element().key() << " = " << atts.element().value() << endl; + } + } + + virtual void end_element ( + const unsigned long line_number, + const std::string& name + ) + { + cout << "on line " << line_number << " we hit the closing tag " << endl; + } + + virtual void characters ( + const std::string& data + ) + { + cout << "Got some data between tags and it is:\n" << data << endl; + } + + virtual void processing_instruction ( + const unsigned long line_number, + const std::string& target, + const std::string& data + ) + { + cout << "on line " << line_number << " we hit a processing instruction with a target of '" + << target << "' and data '" << data << "'" << endl; + } +}; + +// ---------------------------------------------------------------------------------------- + +class xml_error_handler : public error_handler +{ + /* + This class handles error events that occur during parsing. + + Just like the document_handler class above it just prints the events to the screen. + */ + +public: + virtual void error ( + const unsigned long line_number + ) + { + cout << "There is a non-fatal error on line " << line_number << " in the file we are parsing." << endl; + } + + virtual void fatal_error ( + const unsigned long line_number + ) + { + cout << "There is a fatal error on line " << line_number << " so parsing will now halt" << endl; + } +}; + +// ---------------------------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + // Check if the user entered an argument to this application. + if (argc != 2) + { + cout << "Please enter an xml file to parse on the command line" << endl; + return 1; + } + + // Try to open the file given on the command line + ifstream fin(argv[1]); + if (!fin) + { + cout << "unable to open file: " << argv[1] << endl; + return 1; + } + + // now make the xml parser and our document and error handlers + xml_parser::kernel_1a_c parser; + doc_handler dh; + xml_error_handler eh; + + // now associate the handlers with the parser and tell it to parse + parser.add_document_handler(dh); + parser.add_error_handler(eh); + parser.parse(fin); +} +