From 754da0ef3ceb598b2e708f1498f6d22c92b290d7 Mon Sep 17 00:00:00 2001 From: Davis King Date: Fri, 2 May 2008 14:19:38 +0000 Subject: [PATCH] Properly organized the svn repository. Finally. --HG-- extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402199 --- dlib/CMakeLists.txt | 151 + dlib/LICENSE.txt | 23 + dlib/README.txt | 38 + dlib/algs.h | 503 ++ dlib/all/source.cpp | 65 + dlib/all_console.cpp | 9 + dlib/all_gui.cpp | 9 + dlib/array.h | 106 + dlib/array/array_expand_1.h | 170 + dlib/array/array_expand_abstract.h | 126 + dlib/array/array_expand_c.h | 139 + dlib/array/array_kernel_1.h | 652 ++ dlib/array/array_kernel_2.h | 492 ++ dlib/array/array_kernel_abstract.h | 197 + dlib/array/array_kernel_c.h | 170 + dlib/array/array_sort_1.h | 77 + dlib/array/array_sort_2.h | 65 + dlib/array/array_sort_abstract.h | 58 + dlib/array2d.h | 43 + dlib/array2d/array2d_kernel_1.h | 381 + dlib/array2d/array2d_kernel_abstract.h | 242 + dlib/array2d/array2d_kernel_c.h | 382 + dlib/assert.h | 110 + dlib/base64.h | 35 + dlib/base64/base64_kernel_1.cpp | 364 + dlib/base64/base64_kernel_1.h | 74 + dlib/base64/base64_kernel_abstract.h | 95 + dlib/bayes_utils.h | 11 + dlib/bayes_utils/bayes_utils.h | 1675 +++++ dlib/bayes_utils/bayes_utils_abstract.h | 1041 +++ dlib/bigint.h | 43 + dlib/bigint/bigint_kernel_1.cpp | 1724 +++++ dlib/bigint/bigint_kernel_1.h | 541 ++ dlib/bigint/bigint_kernel_2.cpp | 1949 ++++++ dlib/bigint/bigint_kernel_2.h | 567 ++ dlib/bigint/bigint_kernel_abstract.h | 667 ++ dlib/bigint/bigint_kernel_c.h | 1130 +++ dlib/binary_search_tree.h | 50 + .../binary_search_tree_kernel_1.h | 2064 ++++++ .../binary_search_tree_kernel_2.h | 1897 +++++ .../binary_search_tree_kernel_abstract.h | 308 + .../binary_search_tree_kernel_c.h | 253 + dlib/bit_stream.h | 42 + dlib/bit_stream/bit_stream_kernel_1.cpp | 200 + dlib/bit_stream/bit_stream_kernel_1.h | 120 + dlib/bit_stream/bit_stream_kernel_abstract.h | 185 + dlib/bit_stream/bit_stream_kernel_c.h | 172 + dlib/bit_stream/bit_stream_multi_1.h | 103 + dlib/bit_stream/bit_stream_multi_abstract.h | 77 + dlib/bit_stream/bit_stream_multi_c.h | 101 + dlib/byte_orderer.h | 35 + dlib/byte_orderer/byte_orderer_kernel_1.h | 183 + .../byte_orderer_kernel_abstract.h | 156 + dlib/cassert | 1 + dlib/cmd_line_parser.h | 63 + .../cmd_line_parser/cmd_line_parser_check_1.h | 545 ++ .../cmd_line_parser_check_abstract.h | 323 + .../cmd_line_parser/cmd_line_parser_check_c.h | 424 ++ .../cmd_line_parser_kernel_1.h | 764 ++ .../cmd_line_parser_kernel_abstract.h | 314 + .../cmd_line_parser_kernel_c.h | 203 + .../cmd_line_parser/cmd_line_parser_print_1.h | 162 + .../cmd_line_parser_print_abstract.h | 65 + dlib/compress_stream.h | 133 + .../compress_stream_kernel_1.h | 245 + .../compress_stream_kernel_2.h | 419 ++ .../compress_stream_kernel_3.h | 375 + .../compress_stream_kernel_abstract.h | 94 + dlib/conditioning_class.h | 80 + .../conditioning_class_kernel_1.h | 333 + .../conditioning_class_kernel_2.h | 500 ++ .../conditioning_class_kernel_3.h | 438 ++ .../conditioning_class_kernel_4.h | 533 ++ .../conditioning_class_kernel_abstract.h | 228 + .../conditioning_class_kernel_c.h | 162 + dlib/config_reader.h | 64 + dlib/config_reader/config_reader_kernel_1.h | 715 ++ .../config_reader_kernel_abstract.h | 265 + .../config_reader_thread_safe_1.h | 590 ++ .../config_reader_thread_safe_abstract.h | 51 + dlib/cpp_pretty_printer.h | 39 + .../cpp_pretty_printer_kernel_1.h | 583 ++ .../cpp_pretty_printer_kernel_2.h | 520 ++ .../cpp_pretty_printer_kernel_abstract.h | 88 + dlib/cpp_tokenizer.h | 40 + dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h | 674 ++ .../cpp_tokenizer_kernel_abstract.h | 224 + dlib/cpp_tokenizer/cpp_tokenizer_kernel_c.h | 137 + dlib/crc32.h | 35 + dlib/crc32/crc32_kernel_1.h | 158 + dlib/crc32/crc32_kernel_abstract.h | 105 + dlib/cstring | 1 + dlib/dir_nav.h | 20 + dlib/dir_nav/dir_nav_kernel_1.cpp | 256 + dlib/dir_nav/dir_nav_kernel_1.h | 523 ++ dlib/dir_nav/dir_nav_kernel_2.cpp | 252 + dlib/dir_nav/dir_nav_kernel_2.h | 564 ++ dlib/dir_nav/dir_nav_kernel_abstract.h | 418 ++ dlib/dir_nav/posix.h | 6 + dlib/dir_nav/windows.h | 6 + dlib/directed_graph.h | 37 + dlib/directed_graph/directed_graph_kernel_1.h | 704 ++ .../directed_graph_kernel_abstract.h | 379 + dlib/dlib_include_path_tutorial.txt | 20 + dlib/enable_if.h | 140 + dlib/entropy_decoder.h | 44 + .../entropy_decoder_kernel_1.cpp | 220 + .../entropy_decoder_kernel_1.h | 132 + .../entropy_decoder_kernel_2.cpp | 224 + .../entropy_decoder_kernel_2.h | 127 + .../entropy_decoder_kernel_abstract.h | 207 + .../entropy_decoder_kernel_c.h | 123 + dlib/entropy_decoder_model.h | 108 + .../entropy_decoder_model_kernel_1.h | 173 + .../entropy_decoder_model_kernel_2.h | 245 + .../entropy_decoder_model_kernel_3.h | 335 + .../entropy_decoder_model_kernel_4.h | 622 ++ .../entropy_decoder_model_kernel_5.h | 793 +++ .../entropy_decoder_model_kernel_6.h | 131 + .../entropy_decoder_model_kernel_abstract.h | 116 + dlib/entropy_encoder.h | 43 + .../entropy_encoder_kernel_1.cpp | 239 + .../entropy_encoder_kernel_1.h | 119 + .../entropy_encoder_kernel_2.cpp | 233 + .../entropy_encoder_kernel_2.h | 112 + .../entropy_encoder_kernel_abstract.h | 161 + .../entropy_encoder_kernel_c.h | 112 + dlib/entropy_encoder_model.h | 146 + .../entropy_encoder_model_kernel_1.h | 167 + .../entropy_encoder_model_kernel_2.h | 246 + .../entropy_encoder_model_kernel_3.h | 341 + .../entropy_encoder_model_kernel_4.h | 553 ++ .../entropy_encoder_model_kernel_5.h | 817 +++ .../entropy_encoder_model_kernel_6.h | 127 + .../entropy_encoder_model_kernel_abstract.h | 118 + .../entropy_encoder_model_kernel_c.h | 65 + dlib/error.h | 355 + dlib/fstream | 1 + dlib/general_hash/general_hash.h | 84 + dlib/geometry.h | 11 + dlib/geometry/rectangle.h | 491 ++ dlib/geometry/rectangle_abstract.h | 574 ++ dlib/geometry/vector.h | 728 ++ dlib/geometry/vector_abstract.h | 557 ++ dlib/graph.h | 37 + dlib/graph/graph_kernel_1.h | 629 ++ dlib/graph/graph_kernel_abstract.h | 325 + dlib/graph_utils.h | 10 + dlib/graph_utils/graph_utils.h | 1071 +++ dlib/graph_utils/graph_utils_abstract.h | 373 + dlib/gui_core.h | 20 + dlib/gui_core/gui_core_kernel_1.cpp | 2002 ++++++ dlib/gui_core/gui_core_kernel_1.h | 378 + dlib/gui_core/gui_core_kernel_2.cpp | 1733 +++++ dlib/gui_core/gui_core_kernel_2.h | 379 + dlib/gui_core/gui_core_kernel_abstract.h | 738 ++ dlib/gui_core/windows.h | 6 + dlib/gui_core/xlib.h | 6 + dlib/gui_widgets.h | 13 + dlib/gui_widgets/base_widgets.cpp | 1372 ++++ dlib/gui_widgets/base_widgets.h | 3023 ++++++++ dlib/gui_widgets/base_widgets_abstract.h | 1735 +++++ dlib/gui_widgets/canvas_drawing.cpp | 101 + dlib/gui_widgets/canvas_drawing.h | 687 ++ dlib/gui_widgets/canvas_drawing_abstract.h | 312 + dlib/gui_widgets/drawable.cpp | 506 ++ dlib/gui_widgets/drawable.h | 510 ++ dlib/gui_widgets/drawable_abstract.h | 697 ++ dlib/gui_widgets/fonts.cpp | 665 ++ dlib/gui_widgets/fonts.h | 616 ++ dlib/gui_widgets/fonts_abstract.h | 486 ++ dlib/gui_widgets/style.cpp | 589 ++ dlib/gui_widgets/style.h | 351 + dlib/gui_widgets/style_abstract.h | 230 + dlib/gui_widgets/widgets.cpp | 2613 +++++++ dlib/gui_widgets/widgets.h | 3816 ++++++++++ dlib/gui_widgets/widgets_abstract.h | 1860 +++++ dlib/hash_map.h | 63 + dlib/hash_map/hash_map_kernel_1.h | 461 ++ dlib/hash_map/hash_map_kernel_abstract.h | 244 + dlib/hash_map/hash_map_kernel_c.h | 276 + dlib/hash_set.h | 63 + dlib/hash_set/hash_set_kernel_1.h | 392 ++ dlib/hash_set/hash_set_kernel_abstract.h | 204 + dlib/hash_set/hash_set_kernel_c.h | 190 + dlib/hash_table.h | 60 + dlib/hash_table/hash_table_kernel_1.h | 820 +++ dlib/hash_table/hash_table_kernel_2.h | 613 ++ dlib/hash_table/hash_table_kernel_abstract.h | 250 + dlib/hash_table/hash_table_kernel_c.h | 212 + dlib/image_io.h | 11 + dlib/image_loader/image_loader.h | 688 ++ dlib/image_loader/image_loader_abstract.h | 91 + dlib/image_loader/png_loader.cpp | 164 + dlib/image_loader/png_loader.h | 89 + dlib/image_loader/png_loader_abstract.h | 123 + dlib/image_saver/dng_shared.h | 302 + dlib/image_saver/image_saver.h | 534 ++ dlib/image_saver/image_saver_abstract.h | 84 + dlib/image_transforms.h | 15 + dlib/image_transforms/assign_image.h | 138 + dlib/image_transforms/assign_image_abstract.h | 115 + dlib/image_transforms/draw.h | 154 + dlib/image_transforms/draw_abstract.h | 42 + dlib/image_transforms/edge_detector.h | 270 + .../image_transforms/edge_detector_abstract.h | 103 + dlib/image_transforms/equalize_histogram.h | 115 + .../equalize_histogram_abstract.h | 65 + .../morphological_operations.h | 615 ++ .../morphological_operations_abstract.h | 287 + dlib/image_transforms/spatial_filtering.h | 115 + .../spatial_filtering_abstract.h | 58 + dlib/image_transforms/thresholding.h | 307 + dlib/image_transforms/thresholding_abstract.h | 106 + dlib/interfaces/cmd_line_parser_option.h | 99 + dlib/interfaces/enumerable.h | 130 + dlib/interfaces/map_pair.h | 74 + dlib/interfaces/remover.h | 220 + dlib/iomanip | 1 + dlib/iosfwd | 1 + dlib/iostream | 1 + dlib/is_kind.h | 62 + dlib/istream | 1 + dlib/linker.h | 37 + dlib/linker/linker_kernel_1.cpp | 325 + dlib/linker/linker_kernel_1.h | 132 + dlib/linker/linker_kernel_abstract.h | 128 + dlib/linker/linker_kernel_c.h | 63 + dlib/locale | 1 + dlib/logger.h | 11 + dlib/logger/extra_logger_headers.cpp | 40 + dlib/logger/extra_logger_headers.h | 41 + dlib/logger/logger_config_file.cpp | 203 + dlib/logger/logger_config_file.h | 112 + dlib/logger/logger_kernel_1.cpp | 414 ++ dlib/logger/logger_kernel_1.h | 476 ++ dlib/logger/logger_kernel_abstract.h | 313 + dlib/lz77_buffer.h | 47 + dlib/lz77_buffer/lz77_buffer_kernel_1.h | 263 + dlib/lz77_buffer/lz77_buffer_kernel_2.h | 504 ++ .../lz77_buffer/lz77_buffer_kernel_abstract.h | 210 + dlib/lz77_buffer/lz77_buffer_kernel_c.h | 169 + dlib/lzp_buffer.h | 46 + dlib/lzp_buffer/lzp_buffer_kernel_1.h | 236 + dlib/lzp_buffer/lzp_buffer_kernel_2.h | 319 + dlib/lzp_buffer/lzp_buffer_kernel_abstract.h | 130 + dlib/lzp_buffer/lzp_buffer_kernel_c.h | 101 + dlib/map.h | 59 + dlib/map/map_kernel_1.h | 437 ++ dlib/map/map_kernel_abstract.h | 232 + dlib/map/map_kernel_c.h | 266 + dlib/matrix.h | 12 + dlib/matrix/matrix.h | 2086 ++++++ dlib/matrix/matrix_abstract.h | 802 +++ dlib/matrix/matrix_math_functions.h | 418 ++ dlib/matrix/matrix_math_functions_abstract.h | 515 ++ dlib/matrix/matrix_utilities.h | 2888 ++++++++ dlib/matrix/matrix_utilities_abstract.h | 659 ++ dlib/md5.h | 3 + dlib/md5/md5_kernel_1.cpp | 583 ++ dlib/md5/md5_kernel_1.h | 50 + dlib/md5/md5_kernel_abstract.h | 83 + dlib/member_function_pointer.h | 38 + .../member_function_pointer_kernel_1.h | 821 +++ .../member_function_pointer_kernel_abstract.h | 422 ++ .../member_function_pointer_kernel_c.h | 279 + dlib/memory_manager.h | 73 + dlib/memory_manager/memory_manager_kernel_1.h | 305 + dlib/memory_manager/memory_manager_kernel_2.h | 253 + dlib/memory_manager/memory_manager_kernel_3.h | 385 + .../memory_manager_kernel_abstract.h | 146 + dlib/memory_manager_global.h | 38 + .../memory_manager_global_kernel_1.h | 113 + .../memory_manager_global_kernel_abstract.h | 182 + dlib/memory_manager_stateless.h | 72 + .../memory_manager_stateless_kernel_1.h | 87 + .../memory_manager_stateless_kernel_2.h | 119 + ...memory_manager_stateless_kernel_abstract.h | 142 + dlib/misc_api.h | 18 + dlib/misc_api/misc_api_kernel_1.cpp | 104 + dlib/misc_api/misc_api_kernel_1.h | 96 + dlib/misc_api/misc_api_kernel_2.cpp | 111 + dlib/misc_api/misc_api_kernel_2.h | 67 + dlib/misc_api/misc_api_kernel_abstract.h | 101 + dlib/misc_api/posix.h | 6 + dlib/misc_api/windows.h | 6 + dlib/mlp.h | 30 + dlib/mlp/mlp_kernel_1.h | 380 + dlib/mlp/mlp_kernel_abstract.h | 221 + dlib/mlp/mlp_kernel_c.h | 151 + dlib/noncopyable.h | 47 + dlib/ostream | 1 + dlib/pipe.h | 32 + dlib/pipe/pipe_kernel_1.h | 691 ++ dlib/pipe/pipe_kernel_abstract.h | 275 + dlib/pixel.cpp | 219 + dlib/pixel.h | 929 +++ dlib/platform.h | 60 + dlib/queue.h | 84 + dlib/queue/queue_kernel_1.h | 555 ++ dlib/queue/queue_kernel_2.h | 601 ++ dlib/queue/queue_kernel_abstract.h | 193 + dlib/queue/queue_kernel_c.h | 187 + dlib/queue/queue_sort_1.h | 162 + dlib/queue/queue_sort_abstract.h | 74 + dlib/rand.h | 40 + dlib/rand/mersenne_twister.h | 191 + dlib/rand/rand_float_1.h | 98 + dlib/rand/rand_float_abstract.h | 64 + dlib/rand/rand_kernel_1.h | 122 + dlib/rand/rand_kernel_abstract.h | 127 + dlib/reference_counter.h | 31 + .../reference_counter_kernel_1.h | 298 + .../reference_counter_kernel_abstract.h | 138 + dlib/sequence.h | 83 + dlib/sequence/sequence_compare_1.h | 102 + dlib/sequence/sequence_compare_abstract.h | 75 + dlib/sequence/sequence_kernel_1.h | 1341 ++++ dlib/sequence/sequence_kernel_2.h | 683 ++ dlib/sequence/sequence_kernel_abstract.h | 196 + dlib/sequence/sequence_kernel_c.h | 253 + dlib/sequence/sequence_sort_1.h | 182 + dlib/sequence/sequence_sort_2.h | 65 + dlib/sequence/sequence_sort_abstract.h | 65 + dlib/serialize.h | 916 +++ dlib/server.h | 65 + dlib/server/server_http_1.h | 356 + dlib/server/server_http_abstract.h | 118 + dlib/server/server_iostream_1.h | 164 + dlib/server/server_iostream_abstract.h | 90 + dlib/server/server_kernel_1.h | 699 ++ dlib/server/server_kernel_abstract.h | 264 + dlib/server/server_kernel_c.h | 193 + dlib/set.h | 74 + dlib/set/set_compare_1.h | 122 + dlib/set/set_compare_abstract.h | 93 + dlib/set/set_kernel_1.h | 373 + dlib/set/set_kernel_abstract.h | 192 + dlib/set/set_kernel_c.h | 194 + dlib/set_utils.h | 11 + dlib/set_utils/set_utils.h | 267 + dlib/set_utils/set_utils_abstract.h | 98 + dlib/sliding_buffer.h | 37 + dlib/sliding_buffer/sliding_buffer_kernel_1.h | 227 + .../sliding_buffer_kernel_abstract.h | 202 + dlib/sliding_buffer/sliding_buffer_kernel_c.h | 222 + dlib/smart_pointers.h | 12 + dlib/smart_pointers/scoped_ptr.h | 99 + dlib/smart_pointers/scoped_ptr_abstract.h | 115 + dlib/smart_pointers/shared_ptr.h | 519 ++ dlib/smart_pointers/shared_ptr_abstract.h | 403 ++ dlib/smart_pointers/weak_ptr.h | 225 + dlib/smart_pointers/weak_ptr_abstract.h | 193 + dlib/sockets.h | 20 + dlib/sockets/posix.h | 6 + dlib/sockets/sockets_extensions.cpp | 234 + dlib/sockets/sockets_extensions.h | 50 + dlib/sockets/sockets_extensions_abstract.h | 95 + dlib/sockets/sockets_kernel_1.cpp | 822 +++ dlib/sockets/sockets_kernel_1.h | 300 + dlib/sockets/sockets_kernel_2.cpp | 858 +++ dlib/sockets/sockets_kernel_2.h | 348 + dlib/sockets/sockets_kernel_abstract.h | 403 ++ dlib/sockets/windows.h | 6 + dlib/sockstreambuf.h | 36 + dlib/sockstreambuf/sockstreambuf_kernel_1.cpp | 167 + dlib/sockstreambuf/sockstreambuf_kernel_1.h | 98 + dlib/sockstreambuf/sockstreambuf_kernel_2.cpp | 158 + dlib/sockstreambuf/sockstreambuf_kernel_2.h | 132 + .../sockstreambuf_kernel_abstract.h | 86 + dlib/sort.h | 490 ++ dlib/sstream | 1 + dlib/stack.h | 34 + dlib/stack/stack_kernel_1.h | 505 ++ dlib/stack/stack_kernel_abstract.h | 177 + dlib/stack/stack_kernel_c.h | 189 + dlib/static_map.h | 43 + dlib/static_map/static_map_kernel_1.h | 756 ++ dlib/static_map/static_map_kernel_abstract.h | 178 + dlib/static_map/static_map_kernel_c.h | 89 + dlib/static_set.h | 49 + dlib/static_set/static_set_compare_1.h | 122 + dlib/static_set/static_set_compare_abstract.h | 93 + dlib/static_set/static_set_kernel_1.h | 446 ++ dlib/static_set/static_set_kernel_abstract.h | 151 + dlib/static_set/static_set_kernel_c.h | 88 + dlib/std_allocator.h | 186 + dlib/stl_checked.h | 10 + dlib/stl_checked/std_vector_c.h | 346 + dlib/stl_checked/std_vector_c_abstract.h | 507 ++ dlib/string.h | 9 + dlib/string/string.h | 624 ++ dlib/string/string_abstract.h | 437 ++ dlib/svm.h | 10 + dlib/svm/svm.h | 1560 +++++ dlib/svm/svm_abstract.h | 687 ++ dlib/sync_extension.h | 31 + dlib/sync_extension/sync_extension_kernel_1.h | 67 + .../sync_extension_kernel_abstract.h | 190 + dlib/test/CMakeLists.txt | 90 + dlib/test/array.cpp | 653 ++ dlib/test/array2d.cpp | 414 ++ dlib/test/base64.cpp | 208 + dlib/test/bayes_nets.cpp | 411 ++ dlib/test/bigint.cpp | 513 ++ dlib/test/binary_search_tree.h | 889 +++ dlib/test/binary_search_tree_kernel_1a.cpp | 47 + dlib/test/binary_search_tree_kernel_2a.cpp | 45 + dlib/test/binary_search_tree_mm1.cpp | 66 + dlib/test/binary_search_tree_mm2.cpp | 48 + dlib/test/cmd_line_parser.cpp | 40 + dlib/test/cmd_line_parser.h | 900 +++ dlib/test/cmd_line_parser_wchar_t.cpp | 40 + dlib/test/compress_stream.cpp | 306 + dlib/test/conditioning_class.cpp | 86 + dlib/test/conditioning_class.h | 841 +++ dlib/test/conditioning_class_c.cpp | 87 + dlib/test/config_reader.cpp | 374 + dlib/test/directed_graph.cpp | 479 ++ dlib/test/entropy_coder.cpp | 587 ++ dlib/test/entropy_encoder_model.cpp | 198 + dlib/test/example.cpp | 69 + dlib/test/example_args.cpp | 75 + dlib/test/geometry.cpp | 131 + dlib/test/graph.cpp | 359 + dlib/test/gui/CMakeLists.txt | 25 + dlib/test/gui/main.cpp | 737 ++ dlib/test/hash_map.cpp | 450 ++ dlib/test/hash_set.cpp | 387 + dlib/test/hash_table.cpp | 663 ++ dlib/test/image.cpp | 420 ++ dlib/test/lz77_buffer.cpp | 569 ++ dlib/test/main.cpp | 193 + dlib/test/makefile | 6216 +++++++++++++++++ dlib/test/map.cpp | 441 ++ dlib/test/matrix.cpp | 1206 ++++ dlib/test/md5.cpp | 61 + dlib/test/member_function_pointer.cpp | 402 ++ dlib/test/metaprogramming.cpp | 94 + dlib/test/multithreaded_object.cpp | 311 + dlib/test/pipe.cpp | 541 ++ dlib/test/pixel.cpp | 305 + dlib/test/queue.cpp | 426 ++ dlib/test/rand.cpp | 182 + dlib/test/reference_counter.cpp | 122 + dlib/test/sequence.cpp | 312 + dlib/test/serialize.cpp | 521 ++ dlib/test/set.cpp | 464 ++ dlib/test/sliding_buffer.cpp | 330 + dlib/test/smart_pointers.cpp | 393 ++ dlib/test/sockets.cpp | 231 + dlib/test/sockstreambuf.cpp | 250 + dlib/test/stack.cpp | 294 + dlib/test/static_map.cpp | 323 + dlib/test/static_set.cpp | 206 + dlib/test/string.cpp | 202 + dlib/test/tester.cpp | 126 + dlib/test/tester.h | 136 + dlib/test/threads.cpp | 125 + dlib/test/timer.cpp | 282 + dlib/test/tokenizer.cpp | 378 + dlib/test/tuple.cpp | 184 + dlib/threads.h | 19 + dlib/threads/auto_mutex_extension.h | 74 + dlib/threads/auto_mutex_extension_abstract.h | 64 + dlib/threads/auto_unlock_extension.h | 71 + dlib/threads/auto_unlock_extension_abstract.h | 66 + dlib/threads/create_new_thread_extension.h | 46 + .../create_new_thread_extension_abstract.h | 33 + .../multithreaded_object_extension.cpp | 245 + dlib/threads/multithreaded_object_extension.h | 144 + .../multithreaded_object_extension_abstract.h | 186 + dlib/threads/posix.h | 6 + dlib/threads/rmutex_extension.h | 109 + dlib/threads/rmutex_extension_abstract.h | 107 + dlib/threads/rsignaler_extension.h | 91 + dlib/threads/rsignaler_extension_abstract.h | 123 + dlib/threads/thread_function_extension.h | 150 + .../thread_function_extension_abstract.h | 107 + dlib/threads/thread_specific_data_extension.h | 116 + .../thread_specific_data_extension_abstract.h | 87 + dlib/threads/threaded_object_extension.cpp | 201 + dlib/threads/threaded_object_extension.h | 111 + .../threaded_object_extension_abstract.h | 156 + dlib/threads/threads_kernel.h | 18 + dlib/threads/threads_kernel_1.cpp | 83 + dlib/threads/threads_kernel_1.h | 277 + dlib/threads/threads_kernel_2.cpp | 75 + dlib/threads/threads_kernel_2.h | 180 + dlib/threads/threads_kernel_abstract.h | 338 + dlib/threads/threads_kernel_shared.cpp | 287 + dlib/threads/threads_kernel_shared.h | 229 + dlib/threads/windows.h | 6 + dlib/time_this.h | 76 + dlib/timeout.h | 29 + dlib/timeout/timeout_kernel_1.h | 166 + dlib/timeout/timeout_kernel_abstract.h | 154 + dlib/timer.h | 38 + dlib/timer/timer_kernel_1.h | 380 + dlib/timer/timer_kernel_2.cpp | 218 + dlib/timer/timer_kernel_2.h | 422 ++ dlib/timer/timer_kernel_abstract.h | 190 + dlib/tokenizer.h | 33 + dlib/tokenizer/tokenizer_kernel_1.cpp | 294 + dlib/tokenizer/tokenizer_kernel_1.h | 155 + dlib/tokenizer/tokenizer_kernel_abstract.h | 289 + dlib/tokenizer/tokenizer_kernel_c.h | 167 + dlib/tuple.h | 10 + dlib/tuple/tuple.h | 410 ++ dlib/tuple/tuple_abstract.h | 302 + dlib/uintn.h | 79 + dlib/unicode.h | 9 + dlib/unicode/unicode.h | 494 ++ dlib/unicode/unicode_abstract.h | 131 + dlib/windows_magic.h | 30 + dlib/xml_parser.h | 51 + dlib/xml_parser/xml_parser_kernel_1.h | 1463 ++++ dlib/xml_parser/xml_parser_kernel_abstract.h | 155 + dlib/xml_parser/xml_parser_kernel_c.h | 64 + .../xml_parser/xml_parser_kernel_interfaces.h | 229 + docs/.current_minor_release_number | 1 + docs/.current_release_number | 1 + docs/.logger_revnum | 1 + docs/docs/algorithms.xml | 1249 ++++ docs/docs/api.xml | 1089 +++ docs/docs/boost.png | Bin 0 -> 6308 bytes docs/docs/change_log.xml | 11 + ...ME. DO NOT EDIT THE TABLE OF CONTENTS FILE | 0 ...E. DO NOT EDIT THE TABLE OF CONTENTS FILE2 | 0 ...E. DO NOT EDIT THE TABLE OF CONTENTS FILE3 | 0 docs/docs/chm/README.txt | 5 + docs/docs/chm/documentation.html | 20 + docs/docs/chm/htmlhelp/hha.dll | Bin 0 -> 837904 bytes docs/docs/chm/htmlhelp/hhc.exe | Bin 0 -> 51472 bytes docs/docs/chm/htmlhelp/htmlhelp.reg | 5 + docs/docs/chm/htmlhelp/itcc.dll | Bin 0 -> 154352 bytes docs/docs/chm/htmlhelp/itircl.dll | Bin 0 -> 155552 bytes docs/docs/chm/htmlhelp/itss.dll | Bin 0 -> 138048 bytes docs/docs/chm/htmlhelp/setup_htmlhelp.sh | 8 + docs/docs/chm/htmlhelp_stylesheet.xsl | 223 + docs/docs/chm/lib.hhp | 52 + docs/docs/chm/toc.xml | 10 + docs/docs/compile.xml | 230 + docs/docs/compression.xml | 882 +++ docs/docs/containers.xml | 1345 ++++ docs/docs/down.gif | Bin 0 -> 101 bytes docs/docs/enable_if.html | 387 + docs/docs/imaging.xml | 544 ++ docs/docs/index.xml | 171 + docs/docs/intro.xml | 400 ++ docs/docs/kernel_1a.txt | 78 + docs/docs/kernel_1a.xml | 8 + docs/docs/kernel_1b.txt | 77 + docs/docs/kernel_1b.xml | 8 + docs/docs/kernel_1c.txt | 78 + docs/docs/kernel_1c.xml | 8 + docs/docs/kernel_1da.txt | 78 + docs/docs/kernel_1da.xml | 8 + docs/docs/kernel_1db.txt | 78 + docs/docs/kernel_1db.xml | 8 + docs/docs/kernel_1ea.txt | 78 + docs/docs/kernel_1ea.xml | 8 + docs/docs/kernel_1eb.txt | 78 + docs/docs/kernel_1eb.xml | 8 + docs/docs/kernel_1ec.txt | 78 + docs/docs/kernel_1ec.xml | 8 + docs/docs/kernel_2a.txt | 78 + docs/docs/kernel_2a.xml | 8 + docs/docs/kernel_3a.txt | 78 + docs/docs/kernel_3a.xml | 8 + docs/docs/kernel_3b.txt | 78 + docs/docs/kernel_3b.xml | 8 + docs/docs/license.xml | 36 + docs/docs/main_menu.xml | 259 + docs/docs/metaprogramming.xml | 419 ++ docs/docs/minus.gif | Bin 0 -> 56 bytes docs/docs/network.xml | 251 + docs/docs/old_change_log.xml | 7 + docs/docs/old_release_notes.xml | 10 + docs/docs/other.xml | 853 +++ docs/docs/parsing.xml | 686 ++ docs/docs/plus.gif | Bin 0 -> 59 bytes docs/docs/release_notes.xml | 1429 ++++ docs/docs/right.gif | Bin 0 -> 102 bytes docs/docs/stylesheet.xsl | 895 +++ docs/docs/term_index.xml | 662 ++ docs/htmlify/CMakeLists.txt | 34 + docs/htmlify/htmlify.cpp | 600 ++ docs/makedocs | 180 + docs/makerel | 84 + docs/makesnapshot | 51 + docs/testenv | 30 + docs/todo.txt | 795 +++ examples/CMakeLists.txt | 55 + examples/bayes_net_ex.cpp | 294 + examples/bayes_net_from_disk_ex.cpp | 82 + examples/bayes_net_gui_ex.cpp | 985 +++ examples/compress_stream_ex.cpp | 180 + examples/dir_nav_ex.cpp | 87 + examples/file_to_code_ex.cpp | 110 + examples/gui_api_ex.cpp | 220 + examples/image_ex.cpp | 126 + examples/logger_ex.cpp | 69 + examples/logger_ex_2.cpp | 140 + examples/matrix_ex.cpp | 223 + examples/member_function_pointer_ex.cpp | 77 + examples/mlp_ex.cpp | 85 + examples/multithreaded_object_ex.cpp | 137 + examples/pipe_ex.cpp | 162 + examples/queue_ex.cpp | 77 + examples/server_http_ex.cpp | 130 + examples/sockets_ex.cpp | 81 + examples/sockets_ex_2.cpp | 71 + examples/sockstreambuf_ex.cpp | 106 + examples/std_allocator_ex.cpp | 56 + examples/svm_ex.cpp | 170 + examples/thread_function_ex.cpp | 52 + examples/threaded_object_ex.cpp | 78 + examples/threads_ex.cpp | 88 + examples/timer_ex.cpp | 60 + examples/xml_parser_ex.cpp | 146 + 621 files changed, 181200 insertions(+) create mode 100644 dlib/CMakeLists.txt create mode 100644 dlib/LICENSE.txt create mode 100644 dlib/README.txt create mode 100644 dlib/algs.h create mode 100644 dlib/all/source.cpp create mode 100644 dlib/all_console.cpp create mode 100644 dlib/all_gui.cpp create mode 100644 dlib/array.h create mode 100644 dlib/array/array_expand_1.h create mode 100644 dlib/array/array_expand_abstract.h create mode 100644 dlib/array/array_expand_c.h create mode 100644 dlib/array/array_kernel_1.h create mode 100644 dlib/array/array_kernel_2.h create mode 100644 dlib/array/array_kernel_abstract.h create mode 100644 dlib/array/array_kernel_c.h create mode 100644 dlib/array/array_sort_1.h create mode 100644 dlib/array/array_sort_2.h create mode 100644 dlib/array/array_sort_abstract.h create mode 100644 dlib/array2d.h create mode 100644 dlib/array2d/array2d_kernel_1.h create mode 100644 dlib/array2d/array2d_kernel_abstract.h create mode 100644 dlib/array2d/array2d_kernel_c.h create mode 100644 dlib/assert.h create mode 100644 dlib/base64.h create mode 100644 dlib/base64/base64_kernel_1.cpp create mode 100644 dlib/base64/base64_kernel_1.h create mode 100644 dlib/base64/base64_kernel_abstract.h create mode 100644 dlib/bayes_utils.h create mode 100644 dlib/bayes_utils/bayes_utils.h create mode 100644 dlib/bayes_utils/bayes_utils_abstract.h create mode 100644 dlib/bigint.h create mode 100644 dlib/bigint/bigint_kernel_1.cpp create mode 100644 dlib/bigint/bigint_kernel_1.h create mode 100644 dlib/bigint/bigint_kernel_2.cpp create mode 100644 dlib/bigint/bigint_kernel_2.h create mode 100644 dlib/bigint/bigint_kernel_abstract.h create mode 100644 dlib/bigint/bigint_kernel_c.h create mode 100644 dlib/binary_search_tree.h create mode 100644 dlib/binary_search_tree/binary_search_tree_kernel_1.h create mode 100644 dlib/binary_search_tree/binary_search_tree_kernel_2.h create mode 100644 dlib/binary_search_tree/binary_search_tree_kernel_abstract.h create mode 100644 dlib/binary_search_tree/binary_search_tree_kernel_c.h create mode 100644 dlib/bit_stream.h create mode 100644 dlib/bit_stream/bit_stream_kernel_1.cpp create mode 100644 dlib/bit_stream/bit_stream_kernel_1.h create mode 100644 dlib/bit_stream/bit_stream_kernel_abstract.h create mode 100644 dlib/bit_stream/bit_stream_kernel_c.h create mode 100644 dlib/bit_stream/bit_stream_multi_1.h create mode 100644 dlib/bit_stream/bit_stream_multi_abstract.h create mode 100644 dlib/bit_stream/bit_stream_multi_c.h create mode 100644 dlib/byte_orderer.h create mode 100644 dlib/byte_orderer/byte_orderer_kernel_1.h create mode 100644 dlib/byte_orderer/byte_orderer_kernel_abstract.h create mode 100644 dlib/cassert create mode 100644 dlib/cmd_line_parser.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_check_1.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_check_abstract.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_check_c.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_kernel_1.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_kernel_c.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_print_1.h create mode 100644 dlib/cmd_line_parser/cmd_line_parser_print_abstract.h create mode 100644 dlib/compress_stream.h create mode 100644 dlib/compress_stream/compress_stream_kernel_1.h create mode 100644 dlib/compress_stream/compress_stream_kernel_2.h create mode 100644 dlib/compress_stream/compress_stream_kernel_3.h create mode 100644 dlib/compress_stream/compress_stream_kernel_abstract.h create mode 100644 dlib/conditioning_class.h create mode 100644 dlib/conditioning_class/conditioning_class_kernel_1.h create mode 100644 dlib/conditioning_class/conditioning_class_kernel_2.h create mode 100644 dlib/conditioning_class/conditioning_class_kernel_3.h create mode 100644 dlib/conditioning_class/conditioning_class_kernel_4.h create mode 100644 dlib/conditioning_class/conditioning_class_kernel_abstract.h create mode 100644 dlib/conditioning_class/conditioning_class_kernel_c.h create mode 100644 dlib/config_reader.h create mode 100644 dlib/config_reader/config_reader_kernel_1.h create mode 100644 dlib/config_reader/config_reader_kernel_abstract.h create mode 100644 dlib/config_reader/config_reader_thread_safe_1.h create mode 100644 dlib/config_reader/config_reader_thread_safe_abstract.h create mode 100644 dlib/cpp_pretty_printer.h create mode 100644 dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h create mode 100644 dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_2.h create mode 100644 dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_abstract.h create mode 100644 dlib/cpp_tokenizer.h create mode 100644 dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h create mode 100644 dlib/cpp_tokenizer/cpp_tokenizer_kernel_abstract.h create mode 100644 dlib/cpp_tokenizer/cpp_tokenizer_kernel_c.h create mode 100644 dlib/crc32.h create mode 100644 dlib/crc32/crc32_kernel_1.h create mode 100644 dlib/crc32/crc32_kernel_abstract.h create mode 100644 dlib/cstring create mode 100644 dlib/dir_nav.h create mode 100644 dlib/dir_nav/dir_nav_kernel_1.cpp create mode 100644 dlib/dir_nav/dir_nav_kernel_1.h create mode 100644 dlib/dir_nav/dir_nav_kernel_2.cpp create mode 100644 dlib/dir_nav/dir_nav_kernel_2.h create mode 100644 dlib/dir_nav/dir_nav_kernel_abstract.h create mode 100644 dlib/dir_nav/posix.h create mode 100644 dlib/dir_nav/windows.h create mode 100644 dlib/directed_graph.h create mode 100644 dlib/directed_graph/directed_graph_kernel_1.h create mode 100644 dlib/directed_graph/directed_graph_kernel_abstract.h create mode 100644 dlib/dlib_include_path_tutorial.txt create mode 100644 dlib/enable_if.h create mode 100644 dlib/entropy_decoder.h create mode 100644 dlib/entropy_decoder/entropy_decoder_kernel_1.cpp create mode 100644 dlib/entropy_decoder/entropy_decoder_kernel_1.h create mode 100644 dlib/entropy_decoder/entropy_decoder_kernel_2.cpp create mode 100644 dlib/entropy_decoder/entropy_decoder_kernel_2.h create mode 100644 dlib/entropy_decoder/entropy_decoder_kernel_abstract.h create mode 100644 dlib/entropy_decoder/entropy_decoder_kernel_c.h create mode 100644 dlib/entropy_decoder_model.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h create mode 100644 dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h create mode 100644 dlib/entropy_encoder.h create mode 100644 dlib/entropy_encoder/entropy_encoder_kernel_1.cpp create mode 100644 dlib/entropy_encoder/entropy_encoder_kernel_1.h create mode 100644 dlib/entropy_encoder/entropy_encoder_kernel_2.cpp create mode 100644 dlib/entropy_encoder/entropy_encoder_kernel_2.h create mode 100644 dlib/entropy_encoder/entropy_encoder_kernel_abstract.h create mode 100644 dlib/entropy_encoder/entropy_encoder_kernel_c.h create mode 100644 dlib/entropy_encoder_model.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h create mode 100644 dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h create mode 100644 dlib/error.h create mode 100644 dlib/fstream create mode 100644 dlib/general_hash/general_hash.h create mode 100644 dlib/geometry.h create mode 100644 dlib/geometry/rectangle.h create mode 100644 dlib/geometry/rectangle_abstract.h create mode 100644 dlib/geometry/vector.h create mode 100644 dlib/geometry/vector_abstract.h create mode 100644 dlib/graph.h create mode 100644 dlib/graph/graph_kernel_1.h create mode 100644 dlib/graph/graph_kernel_abstract.h create mode 100644 dlib/graph_utils.h create mode 100644 dlib/graph_utils/graph_utils.h create mode 100644 dlib/graph_utils/graph_utils_abstract.h create mode 100644 dlib/gui_core.h create mode 100644 dlib/gui_core/gui_core_kernel_1.cpp create mode 100644 dlib/gui_core/gui_core_kernel_1.h create mode 100644 dlib/gui_core/gui_core_kernel_2.cpp create mode 100644 dlib/gui_core/gui_core_kernel_2.h create mode 100644 dlib/gui_core/gui_core_kernel_abstract.h create mode 100644 dlib/gui_core/windows.h create mode 100644 dlib/gui_core/xlib.h create mode 100644 dlib/gui_widgets.h create mode 100644 dlib/gui_widgets/base_widgets.cpp create mode 100644 dlib/gui_widgets/base_widgets.h create mode 100644 dlib/gui_widgets/base_widgets_abstract.h create mode 100644 dlib/gui_widgets/canvas_drawing.cpp create mode 100644 dlib/gui_widgets/canvas_drawing.h create mode 100644 dlib/gui_widgets/canvas_drawing_abstract.h create mode 100644 dlib/gui_widgets/drawable.cpp create mode 100644 dlib/gui_widgets/drawable.h create mode 100644 dlib/gui_widgets/drawable_abstract.h create mode 100644 dlib/gui_widgets/fonts.cpp create mode 100644 dlib/gui_widgets/fonts.h create mode 100644 dlib/gui_widgets/fonts_abstract.h create mode 100644 dlib/gui_widgets/style.cpp create mode 100644 dlib/gui_widgets/style.h create mode 100644 dlib/gui_widgets/style_abstract.h create mode 100644 dlib/gui_widgets/widgets.cpp create mode 100644 dlib/gui_widgets/widgets.h create mode 100644 dlib/gui_widgets/widgets_abstract.h create mode 100644 dlib/hash_map.h create mode 100644 dlib/hash_map/hash_map_kernel_1.h create mode 100644 dlib/hash_map/hash_map_kernel_abstract.h create mode 100644 dlib/hash_map/hash_map_kernel_c.h create mode 100644 dlib/hash_set.h create mode 100644 dlib/hash_set/hash_set_kernel_1.h create mode 100644 dlib/hash_set/hash_set_kernel_abstract.h create mode 100644 dlib/hash_set/hash_set_kernel_c.h create mode 100644 dlib/hash_table.h create mode 100644 dlib/hash_table/hash_table_kernel_1.h create mode 100644 dlib/hash_table/hash_table_kernel_2.h create mode 100644 dlib/hash_table/hash_table_kernel_abstract.h create mode 100644 dlib/hash_table/hash_table_kernel_c.h create mode 100644 dlib/image_io.h create mode 100644 dlib/image_loader/image_loader.h create mode 100644 dlib/image_loader/image_loader_abstract.h create mode 100644 dlib/image_loader/png_loader.cpp create mode 100644 dlib/image_loader/png_loader.h create mode 100644 dlib/image_loader/png_loader_abstract.h create mode 100644 dlib/image_saver/dng_shared.h create mode 100644 dlib/image_saver/image_saver.h create mode 100644 dlib/image_saver/image_saver_abstract.h create mode 100644 dlib/image_transforms.h create mode 100644 dlib/image_transforms/assign_image.h create mode 100644 dlib/image_transforms/assign_image_abstract.h create mode 100644 dlib/image_transforms/draw.h create mode 100644 dlib/image_transforms/draw_abstract.h create mode 100644 dlib/image_transforms/edge_detector.h create mode 100644 dlib/image_transforms/edge_detector_abstract.h create mode 100644 dlib/image_transforms/equalize_histogram.h create mode 100644 dlib/image_transforms/equalize_histogram_abstract.h create mode 100644 dlib/image_transforms/morphological_operations.h create mode 100644 dlib/image_transforms/morphological_operations_abstract.h create mode 100644 dlib/image_transforms/spatial_filtering.h create mode 100644 dlib/image_transforms/spatial_filtering_abstract.h create mode 100644 dlib/image_transforms/thresholding.h create mode 100644 dlib/image_transforms/thresholding_abstract.h create mode 100644 dlib/interfaces/cmd_line_parser_option.h create mode 100644 dlib/interfaces/enumerable.h create mode 100644 dlib/interfaces/map_pair.h create mode 100644 dlib/interfaces/remover.h create mode 100644 dlib/iomanip create mode 100644 dlib/iosfwd create mode 100644 dlib/iostream create mode 100644 dlib/is_kind.h create mode 100644 dlib/istream create mode 100644 dlib/linker.h create mode 100644 dlib/linker/linker_kernel_1.cpp create mode 100644 dlib/linker/linker_kernel_1.h create mode 100644 dlib/linker/linker_kernel_abstract.h create mode 100644 dlib/linker/linker_kernel_c.h create mode 100644 dlib/locale create mode 100644 dlib/logger.h create mode 100644 dlib/logger/extra_logger_headers.cpp create mode 100644 dlib/logger/extra_logger_headers.h create mode 100644 dlib/logger/logger_config_file.cpp create mode 100644 dlib/logger/logger_config_file.h create mode 100644 dlib/logger/logger_kernel_1.cpp create mode 100644 dlib/logger/logger_kernel_1.h create mode 100644 dlib/logger/logger_kernel_abstract.h create mode 100644 dlib/lz77_buffer.h create mode 100644 dlib/lz77_buffer/lz77_buffer_kernel_1.h create mode 100644 dlib/lz77_buffer/lz77_buffer_kernel_2.h create mode 100644 dlib/lz77_buffer/lz77_buffer_kernel_abstract.h create mode 100644 dlib/lz77_buffer/lz77_buffer_kernel_c.h create mode 100644 dlib/lzp_buffer.h create mode 100644 dlib/lzp_buffer/lzp_buffer_kernel_1.h create mode 100644 dlib/lzp_buffer/lzp_buffer_kernel_2.h create mode 100644 dlib/lzp_buffer/lzp_buffer_kernel_abstract.h create mode 100644 dlib/lzp_buffer/lzp_buffer_kernel_c.h create mode 100644 dlib/map.h create mode 100644 dlib/map/map_kernel_1.h create mode 100644 dlib/map/map_kernel_abstract.h create mode 100644 dlib/map/map_kernel_c.h create mode 100644 dlib/matrix.h create mode 100644 dlib/matrix/matrix.h create mode 100644 dlib/matrix/matrix_abstract.h create mode 100644 dlib/matrix/matrix_math_functions.h create mode 100644 dlib/matrix/matrix_math_functions_abstract.h create mode 100644 dlib/matrix/matrix_utilities.h create mode 100644 dlib/matrix/matrix_utilities_abstract.h create mode 100644 dlib/md5.h create mode 100644 dlib/md5/md5_kernel_1.cpp create mode 100644 dlib/md5/md5_kernel_1.h create mode 100644 dlib/md5/md5_kernel_abstract.h create mode 100644 dlib/member_function_pointer.h create mode 100644 dlib/member_function_pointer/member_function_pointer_kernel_1.h create mode 100644 dlib/member_function_pointer/member_function_pointer_kernel_abstract.h create mode 100644 dlib/member_function_pointer/member_function_pointer_kernel_c.h create mode 100644 dlib/memory_manager.h create mode 100644 dlib/memory_manager/memory_manager_kernel_1.h create mode 100644 dlib/memory_manager/memory_manager_kernel_2.h create mode 100644 dlib/memory_manager/memory_manager_kernel_3.h create mode 100644 dlib/memory_manager/memory_manager_kernel_abstract.h create mode 100644 dlib/memory_manager_global.h create mode 100644 dlib/memory_manager_global/memory_manager_global_kernel_1.h create mode 100644 dlib/memory_manager_global/memory_manager_global_kernel_abstract.h create mode 100644 dlib/memory_manager_stateless.h create mode 100644 dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h create mode 100644 dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h create mode 100644 dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h create mode 100644 dlib/misc_api.h create mode 100644 dlib/misc_api/misc_api_kernel_1.cpp create mode 100644 dlib/misc_api/misc_api_kernel_1.h create mode 100644 dlib/misc_api/misc_api_kernel_2.cpp create mode 100644 dlib/misc_api/misc_api_kernel_2.h create mode 100644 dlib/misc_api/misc_api_kernel_abstract.h create mode 100644 dlib/misc_api/posix.h create mode 100644 dlib/misc_api/windows.h create mode 100644 dlib/mlp.h create mode 100644 dlib/mlp/mlp_kernel_1.h create mode 100644 dlib/mlp/mlp_kernel_abstract.h create mode 100644 dlib/mlp/mlp_kernel_c.h create mode 100644 dlib/noncopyable.h create mode 100644 dlib/ostream create mode 100644 dlib/pipe.h create mode 100644 dlib/pipe/pipe_kernel_1.h create mode 100644 dlib/pipe/pipe_kernel_abstract.h create mode 100644 dlib/pixel.cpp create mode 100644 dlib/pixel.h create mode 100644 dlib/platform.h create mode 100644 dlib/queue.h create mode 100644 dlib/queue/queue_kernel_1.h create mode 100644 dlib/queue/queue_kernel_2.h create mode 100644 dlib/queue/queue_kernel_abstract.h create mode 100644 dlib/queue/queue_kernel_c.h create mode 100644 dlib/queue/queue_sort_1.h create mode 100644 dlib/queue/queue_sort_abstract.h create mode 100644 dlib/rand.h create mode 100644 dlib/rand/mersenne_twister.h create mode 100644 dlib/rand/rand_float_1.h create mode 100644 dlib/rand/rand_float_abstract.h create mode 100644 dlib/rand/rand_kernel_1.h create mode 100644 dlib/rand/rand_kernel_abstract.h create mode 100644 dlib/reference_counter.h create mode 100644 dlib/reference_counter/reference_counter_kernel_1.h create mode 100644 dlib/reference_counter/reference_counter_kernel_abstract.h create mode 100644 dlib/sequence.h create mode 100644 dlib/sequence/sequence_compare_1.h create mode 100644 dlib/sequence/sequence_compare_abstract.h create mode 100644 dlib/sequence/sequence_kernel_1.h create mode 100644 dlib/sequence/sequence_kernel_2.h create mode 100644 dlib/sequence/sequence_kernel_abstract.h create mode 100644 dlib/sequence/sequence_kernel_c.h create mode 100644 dlib/sequence/sequence_sort_1.h create mode 100644 dlib/sequence/sequence_sort_2.h create mode 100644 dlib/sequence/sequence_sort_abstract.h create mode 100644 dlib/serialize.h create mode 100644 dlib/server.h create mode 100644 dlib/server/server_http_1.h create mode 100644 dlib/server/server_http_abstract.h create mode 100644 dlib/server/server_iostream_1.h create mode 100644 dlib/server/server_iostream_abstract.h create mode 100644 dlib/server/server_kernel_1.h create mode 100644 dlib/server/server_kernel_abstract.h create mode 100644 dlib/server/server_kernel_c.h create mode 100644 dlib/set.h create mode 100644 dlib/set/set_compare_1.h create mode 100644 dlib/set/set_compare_abstract.h create mode 100644 dlib/set/set_kernel_1.h create mode 100644 dlib/set/set_kernel_abstract.h create mode 100644 dlib/set/set_kernel_c.h create mode 100644 dlib/set_utils.h create mode 100644 dlib/set_utils/set_utils.h create mode 100644 dlib/set_utils/set_utils_abstract.h create mode 100644 dlib/sliding_buffer.h create mode 100644 dlib/sliding_buffer/sliding_buffer_kernel_1.h create mode 100644 dlib/sliding_buffer/sliding_buffer_kernel_abstract.h create mode 100644 dlib/sliding_buffer/sliding_buffer_kernel_c.h create mode 100644 dlib/smart_pointers.h create mode 100644 dlib/smart_pointers/scoped_ptr.h create mode 100644 dlib/smart_pointers/scoped_ptr_abstract.h create mode 100644 dlib/smart_pointers/shared_ptr.h create mode 100644 dlib/smart_pointers/shared_ptr_abstract.h create mode 100644 dlib/smart_pointers/weak_ptr.h create mode 100644 dlib/smart_pointers/weak_ptr_abstract.h create mode 100644 dlib/sockets.h create mode 100644 dlib/sockets/posix.h create mode 100644 dlib/sockets/sockets_extensions.cpp create mode 100644 dlib/sockets/sockets_extensions.h create mode 100644 dlib/sockets/sockets_extensions_abstract.h create mode 100644 dlib/sockets/sockets_kernel_1.cpp create mode 100644 dlib/sockets/sockets_kernel_1.h create mode 100644 dlib/sockets/sockets_kernel_2.cpp create mode 100644 dlib/sockets/sockets_kernel_2.h create mode 100644 dlib/sockets/sockets_kernel_abstract.h create mode 100644 dlib/sockets/windows.h create mode 100644 dlib/sockstreambuf.h create mode 100644 dlib/sockstreambuf/sockstreambuf_kernel_1.cpp create mode 100644 dlib/sockstreambuf/sockstreambuf_kernel_1.h create mode 100644 dlib/sockstreambuf/sockstreambuf_kernel_2.cpp create mode 100644 dlib/sockstreambuf/sockstreambuf_kernel_2.h create mode 100644 dlib/sockstreambuf/sockstreambuf_kernel_abstract.h create mode 100644 dlib/sort.h create mode 100644 dlib/sstream create mode 100644 dlib/stack.h create mode 100644 dlib/stack/stack_kernel_1.h create mode 100644 dlib/stack/stack_kernel_abstract.h create mode 100644 dlib/stack/stack_kernel_c.h create mode 100644 dlib/static_map.h create mode 100644 dlib/static_map/static_map_kernel_1.h create mode 100644 dlib/static_map/static_map_kernel_abstract.h create mode 100644 dlib/static_map/static_map_kernel_c.h create mode 100644 dlib/static_set.h create mode 100644 dlib/static_set/static_set_compare_1.h create mode 100644 dlib/static_set/static_set_compare_abstract.h create mode 100644 dlib/static_set/static_set_kernel_1.h create mode 100644 dlib/static_set/static_set_kernel_abstract.h create mode 100644 dlib/static_set/static_set_kernel_c.h create mode 100644 dlib/std_allocator.h create mode 100644 dlib/stl_checked.h create mode 100644 dlib/stl_checked/std_vector_c.h create mode 100644 dlib/stl_checked/std_vector_c_abstract.h create mode 100644 dlib/string.h create mode 100644 dlib/string/string.h create mode 100644 dlib/string/string_abstract.h create mode 100644 dlib/svm.h create mode 100644 dlib/svm/svm.h create mode 100644 dlib/svm/svm_abstract.h create mode 100644 dlib/sync_extension.h create mode 100644 dlib/sync_extension/sync_extension_kernel_1.h create mode 100644 dlib/sync_extension/sync_extension_kernel_abstract.h create mode 100644 dlib/test/CMakeLists.txt create mode 100644 dlib/test/array.cpp create mode 100644 dlib/test/array2d.cpp create mode 100644 dlib/test/base64.cpp create mode 100644 dlib/test/bayes_nets.cpp create mode 100644 dlib/test/bigint.cpp create mode 100644 dlib/test/binary_search_tree.h create mode 100644 dlib/test/binary_search_tree_kernel_1a.cpp create mode 100644 dlib/test/binary_search_tree_kernel_2a.cpp create mode 100644 dlib/test/binary_search_tree_mm1.cpp create mode 100644 dlib/test/binary_search_tree_mm2.cpp create mode 100644 dlib/test/cmd_line_parser.cpp create mode 100644 dlib/test/cmd_line_parser.h create mode 100644 dlib/test/cmd_line_parser_wchar_t.cpp create mode 100644 dlib/test/compress_stream.cpp create mode 100644 dlib/test/conditioning_class.cpp create mode 100644 dlib/test/conditioning_class.h create mode 100644 dlib/test/conditioning_class_c.cpp create mode 100644 dlib/test/config_reader.cpp create mode 100644 dlib/test/directed_graph.cpp create mode 100644 dlib/test/entropy_coder.cpp create mode 100644 dlib/test/entropy_encoder_model.cpp create mode 100644 dlib/test/example.cpp create mode 100644 dlib/test/example_args.cpp create mode 100644 dlib/test/geometry.cpp create mode 100644 dlib/test/graph.cpp create mode 100644 dlib/test/gui/CMakeLists.txt create mode 100644 dlib/test/gui/main.cpp create mode 100644 dlib/test/hash_map.cpp create mode 100644 dlib/test/hash_set.cpp create mode 100644 dlib/test/hash_table.cpp create mode 100644 dlib/test/image.cpp create mode 100644 dlib/test/lz77_buffer.cpp create mode 100644 dlib/test/main.cpp create mode 100644 dlib/test/makefile create mode 100644 dlib/test/map.cpp create mode 100644 dlib/test/matrix.cpp create mode 100644 dlib/test/md5.cpp create mode 100644 dlib/test/member_function_pointer.cpp create mode 100644 dlib/test/metaprogramming.cpp create mode 100644 dlib/test/multithreaded_object.cpp create mode 100644 dlib/test/pipe.cpp create mode 100644 dlib/test/pixel.cpp create mode 100644 dlib/test/queue.cpp create mode 100644 dlib/test/rand.cpp create mode 100644 dlib/test/reference_counter.cpp create mode 100644 dlib/test/sequence.cpp create mode 100644 dlib/test/serialize.cpp create mode 100644 dlib/test/set.cpp create mode 100644 dlib/test/sliding_buffer.cpp create mode 100644 dlib/test/smart_pointers.cpp create mode 100644 dlib/test/sockets.cpp create mode 100644 dlib/test/sockstreambuf.cpp create mode 100644 dlib/test/stack.cpp create mode 100644 dlib/test/static_map.cpp create mode 100644 dlib/test/static_set.cpp create mode 100644 dlib/test/string.cpp create mode 100644 dlib/test/tester.cpp create mode 100644 dlib/test/tester.h create mode 100644 dlib/test/threads.cpp create mode 100644 dlib/test/timer.cpp create mode 100644 dlib/test/tokenizer.cpp create mode 100644 dlib/test/tuple.cpp create mode 100644 dlib/threads.h create mode 100644 dlib/threads/auto_mutex_extension.h create mode 100644 dlib/threads/auto_mutex_extension_abstract.h create mode 100644 dlib/threads/auto_unlock_extension.h create mode 100644 dlib/threads/auto_unlock_extension_abstract.h create mode 100644 dlib/threads/create_new_thread_extension.h create mode 100644 dlib/threads/create_new_thread_extension_abstract.h create mode 100644 dlib/threads/multithreaded_object_extension.cpp create mode 100644 dlib/threads/multithreaded_object_extension.h create mode 100644 dlib/threads/multithreaded_object_extension_abstract.h create mode 100644 dlib/threads/posix.h create mode 100644 dlib/threads/rmutex_extension.h create mode 100644 dlib/threads/rmutex_extension_abstract.h create mode 100644 dlib/threads/rsignaler_extension.h create mode 100644 dlib/threads/rsignaler_extension_abstract.h create mode 100644 dlib/threads/thread_function_extension.h create mode 100644 dlib/threads/thread_function_extension_abstract.h create mode 100644 dlib/threads/thread_specific_data_extension.h create mode 100644 dlib/threads/thread_specific_data_extension_abstract.h create mode 100644 dlib/threads/threaded_object_extension.cpp create mode 100644 dlib/threads/threaded_object_extension.h create mode 100644 dlib/threads/threaded_object_extension_abstract.h create mode 100644 dlib/threads/threads_kernel.h create mode 100644 dlib/threads/threads_kernel_1.cpp create mode 100644 dlib/threads/threads_kernel_1.h create mode 100644 dlib/threads/threads_kernel_2.cpp create mode 100644 dlib/threads/threads_kernel_2.h create mode 100644 dlib/threads/threads_kernel_abstract.h create mode 100644 dlib/threads/threads_kernel_shared.cpp create mode 100644 dlib/threads/threads_kernel_shared.h create mode 100644 dlib/threads/windows.h create mode 100644 dlib/time_this.h create mode 100644 dlib/timeout.h create mode 100644 dlib/timeout/timeout_kernel_1.h create mode 100644 dlib/timeout/timeout_kernel_abstract.h create mode 100644 dlib/timer.h create mode 100644 dlib/timer/timer_kernel_1.h create mode 100644 dlib/timer/timer_kernel_2.cpp create mode 100644 dlib/timer/timer_kernel_2.h create mode 100644 dlib/timer/timer_kernel_abstract.h create mode 100644 dlib/tokenizer.h create mode 100644 dlib/tokenizer/tokenizer_kernel_1.cpp create mode 100644 dlib/tokenizer/tokenizer_kernel_1.h create mode 100644 dlib/tokenizer/tokenizer_kernel_abstract.h create mode 100644 dlib/tokenizer/tokenizer_kernel_c.h create mode 100644 dlib/tuple.h create mode 100644 dlib/tuple/tuple.h create mode 100644 dlib/tuple/tuple_abstract.h create mode 100644 dlib/uintn.h create mode 100644 dlib/unicode.h create mode 100644 dlib/unicode/unicode.h create mode 100644 dlib/unicode/unicode_abstract.h create mode 100644 dlib/windows_magic.h create mode 100644 dlib/xml_parser.h create mode 100644 dlib/xml_parser/xml_parser_kernel_1.h create mode 100644 dlib/xml_parser/xml_parser_kernel_abstract.h create mode 100644 dlib/xml_parser/xml_parser_kernel_c.h create mode 100644 dlib/xml_parser/xml_parser_kernel_interfaces.h create mode 100644 docs/.current_minor_release_number create mode 100644 docs/.current_release_number create mode 100644 docs/.logger_revnum create mode 100644 docs/docs/algorithms.xml create mode 100644 docs/docs/api.xml create mode 100644 docs/docs/boost.png create mode 100644 docs/docs/change_log.xml create mode 100644 docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE create mode 100644 docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE2 create mode 100644 docs/docs/chm/READ THE README. DO NOT EDIT THE TABLE OF CONTENTS FILE3 create mode 100644 docs/docs/chm/README.txt create mode 100644 docs/docs/chm/documentation.html create mode 100644 docs/docs/chm/htmlhelp/hha.dll create mode 100644 docs/docs/chm/htmlhelp/hhc.exe create mode 100644 docs/docs/chm/htmlhelp/htmlhelp.reg create mode 100644 docs/docs/chm/htmlhelp/itcc.dll create mode 100644 docs/docs/chm/htmlhelp/itircl.dll create mode 100644 docs/docs/chm/htmlhelp/itss.dll create mode 100755 docs/docs/chm/htmlhelp/setup_htmlhelp.sh create mode 100644 docs/docs/chm/htmlhelp_stylesheet.xsl create mode 100644 docs/docs/chm/lib.hhp create mode 100644 docs/docs/chm/toc.xml create mode 100644 docs/docs/compile.xml create mode 100644 docs/docs/compression.xml create mode 100644 docs/docs/containers.xml create mode 100644 docs/docs/down.gif create mode 100644 docs/docs/enable_if.html create mode 100644 docs/docs/imaging.xml create mode 100644 docs/docs/index.xml create mode 100644 docs/docs/intro.xml create mode 100644 docs/docs/kernel_1a.txt create mode 100644 docs/docs/kernel_1a.xml create mode 100644 docs/docs/kernel_1b.txt create mode 100644 docs/docs/kernel_1b.xml create mode 100644 docs/docs/kernel_1c.txt create mode 100644 docs/docs/kernel_1c.xml create mode 100644 docs/docs/kernel_1da.txt create mode 100644 docs/docs/kernel_1da.xml create mode 100644 docs/docs/kernel_1db.txt create mode 100644 docs/docs/kernel_1db.xml create mode 100644 docs/docs/kernel_1ea.txt create mode 100644 docs/docs/kernel_1ea.xml create mode 100644 docs/docs/kernel_1eb.txt create mode 100644 docs/docs/kernel_1eb.xml create mode 100644 docs/docs/kernel_1ec.txt create mode 100644 docs/docs/kernel_1ec.xml create mode 100644 docs/docs/kernel_2a.txt create mode 100644 docs/docs/kernel_2a.xml create mode 100644 docs/docs/kernel_3a.txt create mode 100644 docs/docs/kernel_3a.xml create mode 100644 docs/docs/kernel_3b.txt create mode 100644 docs/docs/kernel_3b.xml create mode 100644 docs/docs/license.xml create mode 100644 docs/docs/main_menu.xml create mode 100644 docs/docs/metaprogramming.xml create mode 100644 docs/docs/minus.gif create mode 100644 docs/docs/network.xml create mode 100644 docs/docs/old_change_log.xml create mode 100644 docs/docs/old_release_notes.xml create mode 100644 docs/docs/other.xml create mode 100644 docs/docs/parsing.xml create mode 100644 docs/docs/plus.gif create mode 100644 docs/docs/release_notes.xml create mode 100644 docs/docs/right.gif create mode 100644 docs/docs/stylesheet.xsl create mode 100644 docs/docs/term_index.xml create mode 100644 docs/htmlify/CMakeLists.txt create mode 100644 docs/htmlify/htmlify.cpp create mode 100755 docs/makedocs create mode 100755 docs/makerel create mode 100755 docs/makesnapshot create mode 100755 docs/testenv create mode 100644 docs/todo.txt create mode 100644 examples/CMakeLists.txt create mode 100644 examples/bayes_net_ex.cpp create mode 100644 examples/bayes_net_from_disk_ex.cpp create mode 100644 examples/bayes_net_gui_ex.cpp create mode 100755 examples/compress_stream_ex.cpp create mode 100755 examples/dir_nav_ex.cpp create mode 100644 examples/file_to_code_ex.cpp create mode 100644 examples/gui_api_ex.cpp create mode 100644 examples/image_ex.cpp create mode 100644 examples/logger_ex.cpp create mode 100644 examples/logger_ex_2.cpp create mode 100644 examples/matrix_ex.cpp create mode 100644 examples/member_function_pointer_ex.cpp create mode 100644 examples/mlp_ex.cpp create mode 100644 examples/multithreaded_object_ex.cpp create mode 100644 examples/pipe_ex.cpp create mode 100755 examples/queue_ex.cpp create mode 100755 examples/server_http_ex.cpp create mode 100755 examples/sockets_ex.cpp create mode 100755 examples/sockets_ex_2.cpp create mode 100644 examples/sockstreambuf_ex.cpp create mode 100644 examples/std_allocator_ex.cpp create mode 100644 examples/svm_ex.cpp create mode 100644 examples/thread_function_ex.cpp create mode 100644 examples/threaded_object_ex.cpp create mode 100644 examples/threads_ex.cpp create mode 100644 examples/timer_ex.cpp create mode 100755 examples/xml_parser_ex.cpp diff --git a/dlib/CMakeLists.txt b/dlib/CMakeLists.txt new file mode 100644 index 00000000..aa1901fb --- /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 00000000..127a5bc3 --- /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 00000000..c2091d47 --- /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 00000000..fec92756 --- /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 00000000..4087257c --- /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 00000000..bbcad1bf --- /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 00000000..cb14e09d --- /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 00000000..99a77d5a --- /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 00000000..5e153038 --- /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 00000000..c6256ada --- /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 00000000..14aa6eb6 --- /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 00000000..e69a96e7 --- /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 00000000..05e39577 --- /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 00000000..555085ef --- /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 00000000..88e6cc92 --- /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 00000000..78cc9613 --- /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 00000000..f56b61ea --- /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 00000000..ddacca7c --- /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 00000000..5366c57a --- /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 00000000..c311c8e0 --- /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 00000000..223acb39 --- /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 00000000..0a8ca810 --- /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 00000000..091cbca9 --- /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 00000000..4173465b --- /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 00000000..523c4134 --- /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 00000000..63f7738f --- /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 00000000..e1cb72c1 --- /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 00000000..a88ee056 --- /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 00000000..8da29652 --- /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 00000000..0c89e567 --- /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 00000000..eab59868 --- /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 00000000..90648205 --- /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 00000000..3facf8f6 --- /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 00000000..4046144b --- /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 00000000..fa72d7e4 --- /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 00000000..e8323d86 --- /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 00000000..15cbf8ab --- /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 00000000..ec9ef81f --- /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 00000000..4efc859d --- /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 00000000..f54d32bf --- /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 00000000..c6e94b5a --- /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 00000000..1ff67f0e --- /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 00000000..fe0cf3b2 --- /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 00000000..777119c3 --- /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 00000000..96c80f40 --- /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 00000000..3b271a01 --- /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 00000000..17fee194 --- /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 00000000..42c35890 --- /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 00000000..6e18423d --- /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 00000000..cb413df7 --- /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 00000000..092ff6a9 --- /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 00000000..71e2ad62 --- /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 00000000..2096e628 --- /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 00000000..eb0e59e4 --- /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 00000000..ba0d7292 --- /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 00000000..d045c8d0 --- /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 00000000..084cbc8e --- /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 00000000..d74dccdc --- /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 00000000..92fd18c9 --- /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 00000000..f018ef59 --- /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 00000000..6270adde --- /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 00000000..23dea79f --- /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 00000000..121215bd --- /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 00000000..5ae5bb93 --- /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 00000000..dbeed342 --- /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 00000000..833b43e6 --- /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 00000000..5df6d08c --- /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 00000000..f14b501b --- /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 00000000..91f82c52 --- /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 00000000..d7dfa74f --- /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 00000000..9d46d4bd --- /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 00000000..41b5f780 --- /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 00000000..9ee6ca50 --- /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 00000000..bb3ca9a3 --- /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 00000000..00bcb843 --- /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 00000000..de4b9794 --- /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 00000000..57aba598 --- /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 00000000..ef645a5d --- /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 00000000..e996e01a --- /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 00000000..dd49b637 --- /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 00000000..e4b8ba81 --- /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 00000000..e83c4780 --- /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 00000000..a2f490c3 --- /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 00000000..ee93a0bf --- /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 00000000..fb9f2362 --- /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 00000000..de7bf2f6 --- /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 00000000..77213c1a --- /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 00000000..d8f3ba72 --- /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 00000000..f9d9b493 --- /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 00000000..88a553bb --- /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 00000000..c7ade07b --- /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 00000000..eb0e59e4 --- /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 00000000..e2418a21 --- /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 00000000..d1477bc2 --- /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 00000000..a9fae23b --- /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 00000000..d3101750 --- /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 00000000..7b511d4f --- /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 00000000..c55211ec --- /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 00000000..76492f30 --- /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 00000000..25e5cdd5 --- /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 00000000..f5f44085 --- /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 00000000..f813a7ff --- /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 00000000..95bfc4bb --- /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 00000000..b73a0d64 --- /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 00000000..d72ae57b --- /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 00000000..dedf5170 --- /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 00000000..5b149880 --- /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 00000000..c3536d36 --- /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 00000000..c0ab82f9 --- /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 00000000..5332b62f --- /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 00000000..b277d2c7 --- /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 00000000..5271d9f1 --- /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 00000000..4120ba80 --- /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 00000000..86b864e9 --- /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 00000000..b6781fe4 --- /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 00000000..f98cb3be --- /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 00000000..23442ff2 --- /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 00000000..1243b352 --- /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 00000000..5004d721 --- /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 00000000..e9c595b3 --- /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 00000000..df068cd5 --- /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 00000000..92e34252 --- /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 00000000..fc343d39 --- /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 00000000..5009c263 --- /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 00000000..16505b67 --- /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 00000000..9037538a --- /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 00000000..c5687911 --- /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 00000000..7fe4dd5d --- /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 00000000..d4404e4e --- /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 00000000..c72736ba --- /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 00000000..05d0fcc5 --- /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 00000000..3a9fec40 --- /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 00000000..2c0cf70d --- /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 00000000..f4e9b66f --- /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 00000000..449d14c0 --- /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 00000000..6165f415 --- /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 00000000..8def61a7 --- /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 00000000..eb0e59e4 --- /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 00000000..a5c80d02 --- /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 00000000..0ebae9a7 --- /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 00000000..e14ef1d8 --- /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 00000000..b8ecd413 --- /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 00000000..47cc86e3 --- /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 00000000..3be990fd --- /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 00000000..558b8ef9 --- /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 00000000..e5fb28f8 --- /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 00000000..c8662f9a --- /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 00000000..47177927 --- /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 00000000..f5390bb7 --- /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 00000000..991a8caf --- /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 00000000..d7d2efdf --- /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 00000000..241cc180 --- /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 00000000..6414fd28 --- /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 00000000..e085b3cc --- /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 00000000..a525a49c --- /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 00000000..c79c37b8 --- /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 00000000..d9bba7d4 --- /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 00000000..5f9de962 --- /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 00000000..ddc4db9e --- /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 00000000..37cc6d17 --- /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 00000000..f21725af --- /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 00000000..5f2b5d8d --- /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 00000000..cd0860d1 --- /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 00000000..79db9191 --- /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 00000000..9741a36e --- /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 00000000..7618b709 --- /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 00000000..ee3e722d --- /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 00000000..3adba796 --- /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 00000000..5b818956 --- /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 00000000..9c60bc37 --- /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 00000000..58f3de93 --- /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 00000000..03bb5c8c --- /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 00000000..5861ea2f --- /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 00000000..8791de87 --- /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 00000000..9297c56a --- /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 00000000..e70ed858 --- /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 00000000..32fcba97 --- /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 00000000..a61bc529 --- /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 00000000..c14f20a3 --- /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 00000000..4ddeabfc --- /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 00000000..677160e4 --- /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 00000000..a08b3d54 --- /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 00000000..0dcb8c7f --- /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 00000000..be322f20 --- /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 00000000..cf8138a5 --- /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 00000000..6d3831ab --- /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 00000000..835d85a2 --- /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 00000000..5c7c07c3 --- /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 00000000..c16c98f6 --- /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 00000000..f3502b63 --- /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 00000000..4a7d6e6e --- /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 00000000..744dd09e --- /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 00000000..3594b4b8 --- /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 00000000..b7a9d9f3 --- /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 00000000..14894e5e --- /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 00000000..55c85d2e --- /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 00000000..ae497ee3 --- /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 00000000..4f3c5f08 --- /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 00000000..353bd541 --- /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 00000000..22f493be --- /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 00000000..96641245 --- /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 00000000..98f911ad --- /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 00000000..2b1961c9 --- /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 00000000..7c7f95d1 --- /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 00000000..edba2b34 --- /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 00000000..ecb58ee0 --- /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 00000000..fb72f6cd --- /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 00000000..a6bf83ba --- /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 00000000..368e1663 --- /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 00000000..1cc3312e --- /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 00000000..abb66ced --- /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 00000000..1379063e --- /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 00000000..cfcab716 --- /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 00000000..32a47aea --- /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 00000000..892b6426 --- /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 00000000..f5f688a3 --- /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 00000000..6e85ed61 --- /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 00000000..eb0e59e4 --- /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 00000000..eb0e59e4 --- /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 00000000..eb0e59e4 --- /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 00000000..4a5a6ed8 --- /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 00000000..eb0e59e4 --- /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 00000000..98532d43 --- /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 00000000..4aea7bd7 --- /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 00000000..23b953de --- /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 00000000..c50dd718 --- /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 00000000..3f2ec445 --- /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 00000000..eb0e59e4 --- /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 00000000..35b40fab --- /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 00000000..05ee4258 --- /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 00000000..4126d010 --- /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 00000000..96074e8e --- /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 00000000..c5be137f --- /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 00000000..dae6e69b --- /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 00000000..25d4b54a --- /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 00000000..0005e18d --- /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 00000000..f6788d34 --- /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 00000000..ceaf53ee --- /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 00000000..22b3b4b0 --- /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 00000000..181201a5 --- /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 00000000..7411927a --- /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 00000000..4c838843 --- /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 00000000..0eb6f163 --- /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 00000000..d1304417 --- /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 00000000..71e5994f --- /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 00000000..4edd439e --- /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 00000000..095269a4 --- /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 00000000..d0ce308a --- /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 00000000..d4c365ee --- /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 00000000..b1c7aed9 --- /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 00000000..09a74564 --- /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 00000000..4a5e83c8 --- /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 00000000..41bf38ac --- /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 00000000..8f7f67fe --- /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 00000000..b94ad3fd --- /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 00000000..f9f6de0f --- /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 00000000..a0c4f2a7 --- /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 00000000..a3b50ce5 --- /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 00000000..62087a22 --- /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 00000000..2387b63a --- /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 00000000..78d0dd03 --- /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 00000000..21a83275 --- /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 00000000..f934844d --- /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 00000000..b6b6c445 --- /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 00000000..5d9c7ff1 --- /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 00000000..d025c1d3 --- /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 00000000..cca5db37 --- /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 00000000..56e62870 --- /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 00000000..b1e63045 --- /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 00000000..ba426713 --- /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 00000000..09ec8d2c --- /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 00000000..017e1eee --- /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 00000000..dc4ca820 --- /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 00000000..99748d5a --- /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 00000000..ff30c94f --- /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 00000000..07503a44 --- /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 00000000..bd42881d --- /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 00000000..b7faaa08 --- /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 00000000..621466de --- /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 00000000..3eea5406 --- /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 00000000..d9473164 --- /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 00000000..51acd514 --- /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 00000000..203c2c7b --- /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 00000000..51b03065 --- /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 00000000..5cb936b4 --- /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 00000000..32cdea96 --- /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 00000000..8d36ebd4 --- /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 00000000..da65fdf4 --- /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 00000000..36ec4119 --- /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 00000000..04e6c72b --- /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 00000000..eb0e59e4 --- /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 00000000..2f13d242 --- /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 00000000..c60c4049 --- /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 00000000..c71755ad --- /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 00000000..b81dac0b --- /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 00000000..6e732c58 --- /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 00000000..2466ea33 --- /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 00000000..cc96e222 --- /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 00000000..52153935 --- /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 00000000..572f5678 --- /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 00000000..f21ab4ee --- /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 00000000..fc67dc46 --- /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 00000000..f1f009f3 --- /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 00000000..75a18cc3 --- /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 00000000..64800b4d --- /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 00000000..4ad48416 --- /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 00000000..f9117c0d --- /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 00000000..b745e80c --- /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 00000000..3dc1c080 --- /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 00000000..8e52ba4d --- /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 00000000..5efc9fad --- /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 00000000..093151cc --- /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 00000000..b5c7a4af --- /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 00000000..2afff023 --- /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 00000000..82bb417b --- /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 00000000..0a0446ab --- /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 00000000..4eb8b1ac --- /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 00000000..e7dcc01d --- /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 00000000..4bee603d --- /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 00000000..3db99fd3 --- /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 00000000..f81e78ce --- /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 00000000..88f270b3 --- /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 00000000..65a5f916 --- /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 00000000..2d7218db --- /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 00000000..dd61b1a3 --- /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 00000000..53d44448 --- /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 00000000..6ec3edb5 --- /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 00000000..422034d9 --- /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 00000000..311efcc4 --- /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 00000000..81e8d5d8 --- /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 00000000..e23ed428 --- /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 00000000..1d8a433d --- /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 00000000..7c606342 --- /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 00000000..0d84987d --- /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 00000000..a7bbc848 --- /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 00000000..b06a183f --- /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 00000000..8ec0bb12 --- /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 00000000..8075c153 --- /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 00000000..a60c21a1 --- /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 00000000..0a86132c --- /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 00000000..785c5be5 --- /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 00000000..241d61cd --- /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 00000000..126fb8e6 --- /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 00000000..b1390b37 --- /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 00000000..7dacb91f --- /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 00000000..8b0de411 --- /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 00000000..833f07f2 --- /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 00000000..806a8a70 --- /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 00000000..7efe2920 --- /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 00000000..9ad684f4 --- /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 00000000..9120bff3 --- /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 00000000..12cd4ba1 --- /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 00000000..6dd6897e --- /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 00000000..5fff80cd --- /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 00000000..705a0e20 --- /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 00000000..e52be3df --- /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 00000000..f8061216 --- /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 00000000..f6292767 --- /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 00000000..d5cecb18 --- /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 00000000..e5a8e661 --- /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 00000000..f9c341f1 --- /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 00000000..9937310c --- /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 00000000..cab8d529 --- /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 00000000..382ebe41 --- /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 00000000..2d643e88 --- /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 00000000..2926103d --- /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 00000000..cb137c75 --- /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 00000000..06a8a0d9 --- /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 00000000..dd6a483f --- /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 00000000..c73f280f --- /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 00000000..eb0e59e4 --- /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 00000000..a60a395f --- /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 00000000..e9630275 --- /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 00000000..49d144ff --- /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 00000000..582d72e1 --- /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 00000000..4eb15441 --- /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 00000000..584c4a13 --- /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 00000000..a9274965 --- /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 00000000..c446c01d --- /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 00000000..ecdbb610 --- /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 00000000..0d5976c7 --- /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 00000000..179fd15b --- /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 00000000..d60a9422 --- /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 00000000..1fa8e11a --- /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 00000000..1de2132a --- /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 00000000..f5985b31 --- /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 00000000..c1880027 --- /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 00000000..c16428e2 --- /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 00000000..7a2e2397 --- /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 00000000..31cd5820 --- /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 00000000..16ad6ef9 --- /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 00000000..a40d54db --- /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 00000000..0601cbb2 --- /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 00000000..fb65c5a2 --- /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 00000000..e32d7c63 --- /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 00000000..d688e177 --- /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 00000000..6997a21d --- /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 00000000..b00f6e8d --- /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 00000000..a613050f --- /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 00000000..e86e00c6 --- /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 00000000..734f67bd --- /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 00000000..d269924c --- /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 00000000..06bca668 --- /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 00000000..348a39f5 --- /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 00000000..0c8a7f42 --- /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 00000000..bd6ff621 --- /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 00000000..fecb0e37 --- /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 00000000..9b106a1a --- /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 00000000..4712a3eb --- /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 00000000..9d2fbbc9 --- /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 00000000..80f3063c --- /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 00000000..ffa005f7 --- /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 00000000..400f7257 --- /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 00000000..096e6bae --- /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 00000000..87bb0b50 --- /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 00000000..e312600f --- /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 00000000..04bd36c8 --- /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 00000000..dd13c1cd --- /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 00000000..83c22954 --- /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 00000000..ebf6a24c --- /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 00000000..c72f4b8d --- /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 00000000..18fb3170 --- /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 00000000..ef591462 --- /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 00000000..2f5f22c9 --- /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 00000000..d3149f88 --- /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 00000000..24a17f4d --- /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 00000000..0c7c7c4f --- /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 00000000..6c870b9d --- /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 00000000..349e8910 --- /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 00000000..bfed9208 --- /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 00000000..fd0abaa3 --- /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 00000000..3164a19e --- /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 00000000..0abe2af2 --- /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 00000000..62a38b74 --- /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 00000000..da920d19 --- /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 00000000..aa09e94a --- /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 00000000..843c06e7 --- /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 00000000..9078a52a --- /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 00000000..e27125a4 --- /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 00000000..699ae979 --- /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 00000000..b342b118 --- /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 00000000..8c3d46d4 --- /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 00000000..8f0ee4be --- /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 00000000..99c86e49 --- /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 00000000..6bfb405d --- /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 00000000..b22edb80 --- /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 00000000..f0218b7b --- /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 00000000..b8e03ae1 --- /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 00000000..0fd0d971 --- /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 00000000..264f0cf6 --- /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 00000000..115f2e6a --- /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 00000000..c64feb08 --- /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 00000000..76ed41c4 --- /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 00000000..99009522 --- /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 00000000..437efa07 --- /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 00000000..4fd848f4 --- /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 00000000..ba32b009 --- /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 00000000..5855f1fe --- /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 00000000..439b0515 --- /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 00000000..92c3f3e5 --- /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 00000000..bbb6b39b --- /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 00000000..e91cb06c --- /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 00000000..0aad959d --- /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 00000000..6c567f56 --- /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 00000000..25944633 --- /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 00000000..d4d11df4 --- /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 00000000..1c45b4d5 --- /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 00000000..cf15b346 --- /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 00000000..1f7cf647 --- /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 00000000..7c90e03c --- /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 00000000..102b1db0 --- /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 00000000..113e66ae --- /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 00000000..589db252 --- /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 00000000..d00eaa29 --- /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 00000000..0da988de --- /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 00000000..b7b26cf2 --- /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 00000000..8c7db8fb --- /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 00000000..ddd489f8 --- /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 00000000..dfeaeeb9 --- /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 00000000..2796c322 --- /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 00000000..9091bdaa --- /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 00000000..c068753a --- /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 00000000..0fbb3555 --- /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 00000000..cd667233 --- /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 00000000..1ad925e1 --- /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 00000000..9090a11f --- /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 00000000..fe1f5f5f --- /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 00000000..9753ad88 --- /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 00000000..587ff5e4 --- /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 00000000..e0687f47 --- /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 00000000..1f8af501 --- /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 00000000..434ef801 --- /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 00000000..df7fb659 --- /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 00000000..b2c89630 --- /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 00000000..ab0e579e --- /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 00000000..d0389a5e --- /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 00000000..d34724b5 --- /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 00000000..ec32a3f0 --- /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 00000000..7444f4a8 --- /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 00000000..c884c2a3 --- /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 00000000..5b0a71a6 --- /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 00000000..a35aa4a8 --- /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 00000000..6c5800c3 --- /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 00000000..c1987ba5 --- /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 00000000..e1e273d0 --- /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 00000000..9f7a7944 --- /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 00000000..5a2fc16f --- /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 00000000..8ec62ddf --- /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 00000000..62d0b4e3 --- /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 00000000..ccdd21c0 --- /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 00000000..341b00fe --- /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 00000000..42ce04bd --- /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 00000000..45190224 --- /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 00000000..7235f9e2 --- /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 00000000..05e0e8f3 --- /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 00000000..86235c44 --- /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 00000000..a72d12b0 --- /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 00000000..02652caf --- /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 00000000..cac5fb6a --- /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 00000000..00750edc --- /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 00000000..98d9bcb7 --- /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 00000000..811f4e3a --- /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 00000000..7c08ebae --- /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 00000000..1f853909 --- /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 GIT binary patch literal 6308 zcmV;V7+dFwP)FBa0e37VcyhIDVmU z@{ls-C8mlZam5cr4-}LM9~I+5QpH5B!st{k3!T70hd^+W0NtImr#tP}?9T4a!E3dj1z_;Mr#v4xEk87nE(}rB1UTm zKa|L!Z^8i&PqZ)yF-hzFM_NzLlL93gC7ET zJdxAJ{EsJc$dZZ?qg9C?H%=Uhp!gvq7>XFJZv2qJLp}|JA4)he6fs&g_@M!h`?nMP zFcdLboA{vt4?(r_Roi-xqGx{o#=A#n-1*mS9)0ddf6I7fwa{w^kL-K>P;dG%5-xZs zQRJxBWOpk;5K!*IW}S{3Ju`jj)R{TY{OdN4Fs58ZGa@umc6HJZt5OQL&~}BD_X#6j7>kzV+ag=2Su& z*^ps;xmpNk#CEA4JC#2;tfJUh!dn3pYI(23qBlJfZQ?4fYlU?p*Kk`A1ALJEPpm~v8j|n_ll(i4PgaZ13 zG^>0oNB>dv^v7BKk`xsxS_E!aRn@A>o_1@ALEROB#w}+2tSUIKBs+tQMKi_kkd+_mRx#&-V{N+jAABQf&vNoMc;Ws2q%1) z{8=;hPnY^J(l&BDqp(fNRmFH*7d}&;)-=P+(QOaIiC{Y1G@BPrGfL<=D*F1BCZ@Sa zOsbV+f#(AG(A<7G%6oCf574a>V~i2Jxw^-Ic-e2_{?*KZz$0X1Bn=ytnM z`EQTTK;;B!PeU*KP?{+TxD9#{j(x8m z+Pi!EU+%cGy-EPX28Yf04zXsO9^m%wZ4-NTOm+g=9<&Ru7e=T~7~R42G>SJ3b?%gF z(|_%DTbpS`MX{J(=f?~61|ORUX+o&!TwbBYL1N+xJzXr<;G`BC0?Vi=JuGCj2^uww;Ps)T>wAnJg8$7-muj&@gu7T&kDXSW29Gh-<7o(O+lU5Y2oyiHd?`LK z6crqRa0!{_f8{Et)vKOTh-~)QFLgMExye)oDIxUQ!6R*Ou)C7uGp8SaWGDTA+M9O6 z1y8ubN3U%-(_Q?~EI?>!ZVGSutf$W^7Em<1y|Ge@Gm(&pp=;M0!%3mUi75b2UP0Mn z(>2%({W0YZ$F-2RC5qk!L>*bzq4I`<(AJ4DP;$tl_%r|UMp&ZHZc+koiP=eQ|4K(&ze{(0QnjmthP*Fcy0LzCrRV>Tg!5Kn#ZbqVj zWTmdvO6l}40OQj|^ij4ImtglX*wcv!x+0DuVzgeV2t4u(SwIxQqqrICP8GQ~4iWGZ z`oL@g1NfD^#HE+*!XOg5Y`43iaUoZisr}=2#5r=3LbXzjBxC$N&6eTuP+nBU7p@8XbZ%e=OWn_*B+SieC!^#3vbo)%>dVe zvKI>PI^L}=j%EV)V~50dZv5C~QCd{Wl{)BS-yD}T&4@f`M(?Z$_AxHqc8!*aqnfIz z#jKRhfC{!yL<{+b*s+Jkt%&zQ$g1Y#MRZBgLw>4!+%t@o(!1)bYU2R*^gn!;zzUuW z2et=+iOn^}k3X`@Q#FUoC%^a5-rd{D+SKLHE=VmL(}x0{5c{!P_#t?%JsGrtrCJ&O z8_n==I3Q&6HfRE`er-rUFXReZG#wX(N*%p($~!d9BV?|5{9#eAH6e0kE=s@*F2BQN zbHG?+u5t)B(CCOQj?y>)U^FFrCfpin@7o1!%CpSYo4OUx(aU9X{`jGcymZH&C4{Oh z*C2hz*CgYz>YOPuez%YFl8DNRs#Y!~lPM_i*&?dcJfMOs2qD{Vv%vWxx==QBv`9>K z8D?z{T8MhN6%42ZH;!Y-$C(5s6zLV4y$_K=>vT-@tKIg>geZJamzO{K+dsa_8*+vA z@M^KHuG^5}Zy$>pAmy9$o{fMSoQN;N5|RqRd+hcChHNC;)w+}*cNfb~q{)FyN@=uY&C4Llo&3rg=+zuLu_ zNufs`p`I_BYtw(=sl2&kpQET&kShbp*w)Qa&SRl=qKLhEC_u4H*=RiuJO>^MT%b2+QUuW8)9tL+pT`g0d8FAtfL8rQK9g z!U^Q3o_!f!uPZ+>BOR>}j zkVOl5baFv6gXP?zaR}idWXdEC{a+T1B+-D#$&o}vE75Pe6H2%{O<{LLrk!?rxw*+i zX%_dZ-K`U21b-b30!@2n-|L6=?40y zE|=ZEGWJ6U0fe4^aesSV(Cy`q!RAlN%3EF$lc{(^vGNF7 zTcOCQD#|U+=ZfV_O1k-K?o<}LMyMG9Egsfv4my!~nm+SvEwP=_h=4v^U_(mF;IsBEG z$OC^IOU1>D#Z*3@Uq3i-?GS(bOkGi(YlJwirL7SRp?fx>q^M8DN@|%CXpJA7DiX+J zV=n&jwgGH&9fe}KL-zwE$2bH_zuL8OUU=p)kRAu#IoA0iD=?@$WlmqSvv8^U!RdmvCy1?p)|xqO#PX;I-&*U1J4VY<;v?G@1O z2U1C1Rq`c$4bQEc1k(ZFFofI|k!1*7okkntdIUGBR_w^>#Q33KR`vXg`*DNco*k3a zO3~>+FaNcJM{tb>a;f#JT{7(m?o!7&4?15S7Z^V@n-8wsybAH61l)S|Vr6bgX%+B- z(8~JN_dcsE7F0n%d}0GCWx;w`ALq7S!<*5iZeIfO+IaEi4SIfAQ6)|xAjf0bT$aiY zOXers6bIBm&j+|rWt`55lXyC4gRJ82SG(a7VG;s2huc&6LypK?uJDq`7c2F*ewW2* zca{f0vqDIlTHJeQbjT$WVx5Z?3MJj*+`t=GS3n41HeS5>O0+JfyA5KtIa5!~%?%_1 z>(J<3xQ{g9gb&%-weO8Xl)UoH&)*;j0XJy-)o$BFn6UD+Ckc}f-B?-Nss3h%Q&rVO z!)N``xl+xpq}eb-HiXVxsGeJ@^Bj`WgArw^Tvd}Ix_?5jAk?bK%MiMD&=fv3kwdLkU391`!WGMpvSxUi9Br&brLGHxB=QFu#0CTTff?ETbR6xi6o@ACoOvQ z;8eIPZQJ+1c`jJUD`FzfW%ISE6U(TvG_4tZW1cqSYbtVBxEBQ4e0F*7L)+cjBh5xRfLKopq+ji}BYE@CarWa40D>dhK8Vj%aW)!D23*?v)(l7D6dDr9(@td!T)M}cNJC72> z2`RFW*QzSAd7>M8S#hYfg~-(d`fo+9Bn5@%dE5qz2=gh`KmWU*bmN6S{e$n|=IqES zpIrb3T|N!`@#Oa&YERV+yWKkB9bvq4(<{&YV~AL4fBm+i ziE*Agw^TXxWzm}E)SA&dj%CuVUxS4kSDV6R>SK9yU2=Vrmt*UBC8tFPN75X!!>1X$ zbBW?Ep`R8@@R-8N!4&4AnH#h`>pK76?GKWS?)3+a)jaZu`aJ zm_CqF2bF{?h^W?Ydy*jN_s%aVEqkUZuyBTuty-rcR8sUgpJ-HwakWBG&X;tLcD@Kl zwE#z{T9oyppdU3jisf3VToaAeKAtiM5qI8M$X*J!gH5%KY(_&F7_GzYKj2_r^P`vT zc4J^7k4k~O7ojg_AmN8Ri&CrVuCp7jPDBNv(fX}*vaifLXy287bOh`dfHWg>DWQqG7KNl+W=pqKuJ6Fw-6t&beN0%{vgFNPQr zX098h+!>>1?S{U*)OS=ey`7YQTIk`V0rWS=y3X}+v|OnrVv(J9Z20AodAmM_TpLG` zeF^uB>pFL-Tn7!#cT4y{3B2N4(4yKTfY z5Zsu1ci%@NF-%B<-Q}yJhQ5~wmH)uuNU*-Wvs_X|DGvPk-@iM5_PpE*5^Zv^g@Q(7 zhEt*8JTRmNBqlb-?;VdrBb8EK;%lBCR-nfT<;NEue&VN{cs8#yK0|Q*=Fv{(J)pC} zEP4068Omu2;1Xad-)&9%+ir&+M6llNJ=-RNhEAK_LfkHJzTTbQ;l~c4tSlrY@qAAC z#XEB?ZyN?ep1!!hnam8t`9eua^QAU~58)Rlg6LPL_J)9u^-zH9G7R1h!3dm`PR2)u z^{J20qlx>~?ph*${2=1je&i~u@zDs+zcaIR{L@^6HLVZ*G?*0&p>N;5Zqs^Esj5OX zCkk93;e*2oLGoON;9<0?i4W>La5%W)BC1r3(9bOcR;a;>4c`!Q$T7=*ke2vOgCeAA zN=1jDK^A_jv^zogmKFmKqkiHC$8c`fuyvXiRi&m5#DxdHG17vN4L1n6M4XX--`CS{ zp?&M=k7v(W>9`an z)MmEfxRm#Ob@pfQebrEy{G3+1W_oBaJ(Nk)l=Lm!9z{I4>D2o}Z?& zG6&-Pg;F&siFe;P=-7aOb0>}el}a_0;3+?#?e;{sjU1qLQrEgg2ruMQoB-|v5S2TjS7v*!p8|L-pyw4Xk>eH-ra06dPu<6~EmpW&6a z4nymNIz68u5s&`U_xIo+1ck}%{_4>0-=6w|b-H)=eK<(Gvj6bZv6J?khj&d*-gaZx z@qkGg9d~Ol2 z>Nyyhg$aMr|4w}X;PFMQ`R4$5;PL+X@Aq_7S%}ae$1}&SK{fX5jqtIE>Rfs1^&Q0~ zBzPQPXtcF9kYm#H%q+ZF8u09U{SYWfka+XZ??I_}c-LLt$eEdi-pVfJfAbP`;F?2^76#m|i4zf`Vl8XdZG>o~UXavtzt7S0+v&;65sL{RpC zkMF-zXX3Yyd_Z_e$1?zU;4yG7$1F_v+YcM^1b}T}8z-rte?ic}D|+I`|4AuM!^Dr{ zE4-ec;B_YmHMlw3H|VAfuQa8T0CeKvK`K4?n$clkEHtZcE<@2IDuawEsB z=6QZZ#DSmAkrULn21xk$^f?e3!1rW}7W4$r8KA?+3Ip^C9B&>v`q$sStHT~L$KdH^ z1Q)^NHIYW(He;|KZWcJ{hsH(FQQ_gCJQyLsZ8-b@6T@E$$b?%gy$kmkQ0A`N#^LRO z$bxr1ed06$KW2r5zX)Chi~{gZ%#I_BQ*L(%h$HCe-sx{{5#$LWU&s;i-Li-fw-%yH z8uTmZs(r8j#ytJuqYn}WX6U5J!ExU@p~FBg@4SbAYk_w`8#HZSg062G9)uP_A2X{m zx#xlVwvk1dSrtGC#tXO$-jXMDUwP{=2Q~04oQ5*UjLk^>_3VsmvcNyA~KMXvK);NCX zq2gJllUY|rjMfN#Ix0000 + + + + 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 00000000..e69de29b 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 00000000..e69de29b 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 00000000..e69de29b diff --git a/docs/docs/chm/README.txt b/docs/docs/chm/README.txt new file mode 100644 index 00000000..ab4a6df1 --- /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 00000000..cfe2b692 --- /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 GIT binary patch literal 837904 zcmeFae_&L_xj%e1yGb_5!X99Qiw0RWYHSdr37D`16JVF1ByL!;OOyoLB3-vy5%(b0 zBqTjq%gK0J@BQkn_S&mlu(h?f+Fy#bKte1D;#EKkvCv9e?(Io8woy_^AmzNDXU^Hp z2Jzm0-+$hJUR$zf=FB|v%rnnC^E}TyGpF{B#|5h(2sZrFbwSvLU;3|#|NWo;P}!+- zelb<}S-mxwH->R>5Y;!#N^=)q=-}mf4^WRnXd@(|0k{AVi zg0Rw(Dg5@0<>i$3r^^K4q>y!0o+Z;ET%IKezrjEJC*F>piFhcXbcv5YXBhpZKGQ$` zpJxhB+3s4YENLO;DOu?xb}DJYa<{CCJ9Y*~ocWm!T& zGVdSx1)e1r0hg>gFLw8q7!r$T0|~;9`g%cmk09JNZ`1nE$38CzFZ~E*sP8Z1_e%Vx z{a1xyo@W#j?)6zfK)j!h-y@$Y*FA63gPXocb*Zn^=WpZpRCXFP&NEf>Hr;*i{V4d< z3cLahgj@03hTpXRssv$4TJryY{Qr;w4QxmraxJBJ=yPh8?S>R(n zhdioFmu`?-&)PTJO1l#dRy!KCIA5wgyXM`KiqD}giWdQW#qSDho+&n=ksV_1ly7CBGip!d zMs10#s3nmRb+6f=ESbt`hn%l=J74OTd*-a`8O%i6!#%&xP;PbgWl+=1H>51F(O3x%xn8!c(2kCVA_db*e0r=h0yo*}a0AiROjyg-b8`ZDc`ZAtdu)v3|E-Q5OEwN+% z2+ESOb~ZnlpQh!xs24O0fs0MNV7CX{yXa|rl9&dlZ2FiE~Nt6sDtRdxg`EcOw>0Q==m!#R3Yv6l)bLGw?5K29i4li zOn<4#&HtEIq%Uz|MaQf7RNP^#T2;>KhK|l0!erq*3P6 zilt%JI$qp55*3Q~7yC{=UA&JCfYil(#lBOA&mn1TI(c~1>N}{K@@L`(GiLjdS) z8g8|+reWqAsqoobttb$+ghRSy4^jj9@1e{(V{~>sp1;7Sop;)VdU>ck$eQe-FspnH z1(dsoqlut?i~)>8){32-tFc(gn$_89v;38kP?5GQQ({2!u1sjf7O6>auDzl{LLa)SEiGVR&F>$;v_aMJ?c z)jAE$=rn0-MWq|Hobi95_Bpc!6rW4ae;H8NfcJygRjO}SAgJe8fq|oU;9(gaf{G6# zg1A1|Py`En~GONkHgPKiT zRZ)2tex)J<4QU2S+avt|r1gAG5O|?*=*PYyoR70X1(R9<)kDkk+C{DhP)o+b}?S zsUf!@$Yb^ZJE+}=)tH3sZOLg7otIcha3m7&^9@*Y_;dlw>;kp`>ZHO4wFcCM{7Ud7 zO{r)xA>wAWBkP*iE6||?0TLIov$`-8?+(YVWvdGv&R1Is9X)>**+v^=mdh(jHt%^z z{BB2LNDtW2sue)jHA5;wM%Bv?+k{{!9J>aSo?$@Pu#~yy6vmBs_5p}t!YLHc^Pj+P z;$Gyk6(XBWxk~MLz5Xse;tWjA!sRz9z?Jw-XzhxRdIGXzp^Z-J(Rb(H<^|qWax~eS$ zdUBghh`EW*n@u`HW+o}^iR)74UV(TjtpMs$34=OKSkOS6jv*1HXdE$&?kLJTBEK?v z&j)ZD4cwQBz7LCRJ`G%0KMEi;YE@pJqwRL8QFzQEXa%zcA)v;G&+9r0Jca`D8xA8K z6#`-H|3L8vAfx`{c&+*z5zqDozCfQ3ss`j)BPg}5nbd&N?uu$#Aa*IO)OtzeBf^N* zb>bevq9fn?Qc!t@vf~zMJMXh}X%PD8j!EYNK z$GV>CDqcswNCk*$NN881zSk$VIJ`dB)@)YmP%MeN5Zz9zO7AT&W2k|DfO#vN9O4_x@Xyr*`$OtV<29yb=lqjqX-vlzwdn%_y!`!7_Zh9L4yHHuXi04--A3dZpet7t{JQ0#1wdFG30 z$rn!J1%_}wElJRgE>I&mPZ7Rqd>rG*QHKHsx!VFX%*+u8g@E>l9L(u>cVp}lGh5@? z2hD8h(&!McXsk6=SZjEaRvQRcV*h`rG26}5m~>%dCz9wtfHZTFG3hMHqaoS16u_nUqgS9fmh6U@(#3G8xmRG-!`<_ZVM)y6EA)h zn~7qN8pRU1k$C6rI{3=l@9ZptPSr66e~RFI)X$$Y&oSpx|pDq0PJE*%W1CIa~x8j$J=C;URkdM~K(Yn0B2DM5kqnYAz?(K)(>fGC{ z_(n(*4=c69dVU1Os88DO02-Q6R1fP9ih6z_DO}J2M|5cz&RVdeq`d||v7~&@|*n(${4^|EU??BSI*XL4v(9>O$(J*izA!fAoZX6hn zx7;_;`nzaP@r}ZKL;JDyRCL@Na?V%4kL0>e772vJMiYJBayD9q&2dwbEcf#M=G#CM zQ#~Dg9t1PRCQ){<8|jW#k?81*{{Vlv&6B?oH96h%{1_gculh!uufoziDdzPgtmqc+ z@2bxxb6OX@=!(x3o5xXHk0!82y0km-060+#x|yOzA}5e2=Af^H8dS!gu>O*i4}|sk z#FKjd79ixXC1x7=5N(s*aGgZtB78`cTkSd+iP{VWwST52n;dMIdImjojoC>(|1FF- z6m1w{q>Phn9tEAtk;};;*&|PZw5UQe88)1J-$;hsoq?%+2xY<;Lj5Qhp83X$eIt<- z!W}|@`9_Pm`DilLA{2yhz)TMV4k`0@Hm@_~5T=q`SweF%BrPvJf;QQkdm0+RRlm2q z``=48C?!=@@>zS!AYl`=;D7cg#LRmD$%dgr&VZmEKq9n*fEX6=c6w|+(7WrqWKOqe^&oO=m_j;?GHgtOmJt;UbKz$FC|Y#{I0NWNK`*xp zA&!fKePm!`HdlH8hU^nPWEZ1~_601&NhKb%zY*rXVe5^mzEKQg#DT>HY_^(M2=9m| zz(G(!dUx%jK|2f6Q68FWx&R)rvyWt5S6YV*i~f_P4jBIP&|Ud%JN}IeVJ(D|;?t@E z+P|MgU0rVkS4z`U-C=KQ1t^lpV11xXAfluZi#;N;rEd987Lr?iY<3OMIWursw|p{7 z?zRWWj*uWj?;@t_>p5w4WTx`gB2SlwRNny6`iEG$RbM|Ik*77I2{d~KnXL9yaqWrX ze%1q5$>Gt5$-tV4cgH{du2ffR2OuXjpjppqPgr}R83CAyhffy!`mMf0R^Nbu&Ke>f z+L<&E0W=>Vb!b?VFz^+v_E-)8X-yzX;|0bU6cvkMSKLBxduixW|B`IxAn%ur{4gW{ zh)F(5XOacrc4%c?1~rdy({0yVG=w*w=R*kgj0$RPKm1eLyVuf)jSH}FOAkam!dpT` ztr!)YPxip8SFcOJ9D)doF?Y0)Iy@W^8FUXKm7bhuq}< z3=`Y1%lSM=ioQ|sRBQ?HuWqgpqa;abjZl3WhCHm@2e!wWg(TJ}6tiRXfkBz+ZF58X zVYv5>gNxhTB&d7Ylp=_!_yK87#S{;oq)Q@?L$}iN7r}KxI*h^##4g)Dm&$cZp6FC~ zHmdM8-o1nJq^W(GR1>s^u9KJ!Du|Q*9fJM6Yk&sh2jfrgrVw~?zB2Z z!pwRVV6NYXKhDm_@wX;6vCI$$tsBzy!4L5QQultjtz3XR0%l_$R(W#ce%ed+PP&)O zNElu+NZgc{Y#U7gc*%_SrkBh}B)w!|T}1CTW5r|}3*a{tBVC?So41%Dom2Gq4UEGqGVNlQ?cFA2}~u%2GIrO zVDHhZ;<4zJtcRUpXIG^|WFKq0v7ZK7TiZQCsUD7C(%GZdFxE{xwPU?3hY*0IQ>;>^ z@`x>QRm9c~|Hk)ETLopQEmJ_EQCaFxmfHK4isYtI9&xF6kFZ{haubG(Xq<)m*hA3s z%Sha8CVyOZNLxVUZ6@~6(rPa~&ir<$vYYZC!XAL?4AibcR+qhMn-hd{?l~Zj z<;Ld8V^dW$X@F^yg}yM=wAw2lO|Zj2@yZM2?~ z+gt*iN`?c870Rb-2CnY+4O9zjYkC zZt-aGKt~^_iDF^+1#8eQ`32k0pna^Sa0g-hO02(Aq!G|B2lOMp;>Kp}uyw!nAk<@T z|ARkJ1XAJe5U>@th>7Cd`QuYT|Ak z1q}xufb8t^yMTf)7{N0pQJ1}a?077vee94k-hiyGD$AnhV~va6i8T!Rs0g*{9oW3Q z{VJjKKzsS6SlMBFFT}_rN8W(J!8G&PE8Ls~uB7sI@B5pb?T>&Bmg-U#HUr+5K0;yg zEkhsYCXL|?re#_6jk7izDICP(VbWzw_<9(-1nMK$QndDwS%qy9d%H(4K^*8MhBwHX zqrD77QS#DMe=^Y@DbMJO9esg1(A{846Bq~ z8$Sol151gX#imAW%Cfg@n#15prFA&2_xWf)MSv}hvJdUYe9T7YuTyMD<%foql{CLd8 ztf&NT{lYNDHK-k=AH1{S-Bft+&j9D3_H)X;{Z3^uXkC%j?EFr5uUtt>k|9H32l;I~ zD7}3({ultKQ60Div>*No>+ojB4tk|+0M^Ve?pQ;GM^c4P{goGXX| zLTp_ai(5fB1nH^kJF0(UYD<(?5av`K_K(hK18bO%-nGmx5iT&V@46YE|Nj4b} zhZ@{c=mOT>F)-2jtHQUP*d~OJgj|XzYw>;bA%t@zpi{3Ew4J)s?mA%2?K-yQHfZUFm$XyQc7* z+1!o)Dp8&#S^OyOX|r{9OMi3j$qH!KKorH{%EbG>c4d76 zo9imU_xm-y@AjCXfm$S+u5E5I#P}?qVKj(>Mwx7$9TwTo;e=spf;A6H$ zIn?0kq*lX$iD5|SK-cA<@U5g6MCXOImx*N$#g9l+K{sQuK5SiGD7K%Q7qjipn71Tt z9WNd;mg@ACIx#&u55w%zz63y^GOgFdSJ15tghOFzhI7xdLNS11qPB(fy2eB)^{p$b zvm2XYyf*>rO)Sd~>LgBgWi3R7*bKb3clj-T(CP!zKwQC7^xTkb00-Z~|2&{sIRBIp+CL^4XJ%*+bz2@MO>cz$;J) zI_pPE4|KiNK6b~0x%$yXwg)F_uavK@k)+iL5RBGd7$ih=MUjdqjUcIkbX_w-{o|O1(79 zQ%(X9bC+W#mRILrtU^ew#oEZ1$9rLcqCqm&%xaQDJ204PP;P~xFicJjhqi4H^9d^< z+dr`s0<4F??)s2}70K>G(R>cpl@1p9=E!o3jl&eRvWvhJg^rd&TZ)B3CJ*fyfbkt6 zmwX7l#2hzyNXqhL(klucvQ4fEeb%h}da7~|mB}4w3{|SKA-yq1*|CI;9cBGmsU0(O!pxC-#@iQPFIiT^547DFwW38NzW;3QJB>R*|RR!Nw@jzhohSItgxfC<` zQ`91_WImPUwoAv*%TVourN=8~uLoB;;|mao5)N?zqQ(Pb;AF|(mr3tP;RtBY!bc2b z@DA>Xy#r`ENdFnTaF8huK#q5-4JV``R=FD0Oud*w543^n4LL^7g_->U``ZXaL1Jpeb;=Hu9&JV5>F;BK>Ft*q$ZX3!N;W zJp=4#Exb@DZTO=F6d5|8dXvZvLaRN$fw?L(qi|YG4EfFmefCX_a7otp%^Vy|K$M ziA;4_3*ut27f0boz`&}7aPveFqYe2{=Hgg^EBhJoWV&=BP*N{I13CQ|l zGrQ~yb0ymn_$aEdc1pv>o1{MK>&jpsLs2W+=F97v!`^{%Ii<^&w{Req)zxUJPW-jp z5_2c@eFNq&DSjv}y#pm*$}jySF)h4GyByAP#tXnOhvFt()xJ>R3idVZEbkKgm@^;S zZ#`__kZ`nLBlwm19MgT=vjZm?hcUPolOF2D#k)5AnO&nd|L?lSVP3pzOCd{GJ{92o%w*=%xB}LVr-uaM&EsEcD5`wVlnS{GiC=rBB3o3;wL3ro}ym{Qi-%NR;F=@ja8Az(-G}CUBY)go=!F{|DqTw)`P0 zFsUK}VomjY8&c7d$VmXkE`;{P1O$p*%eUh-wjK6`$X$O+P3#7Q&&J%c=7>3E%^tfR zf23jrR41;n9!OlN+SECi3{ek-RrZ|BXzo?3=S1y=CmWwWGlqm?#V0*hI1+lIwx^rV zoDZ!*2r#y{ntNBoE|CZEMjo`qtfk$(yGXz9jf!h}qZw-usS!UAW*@gsVLi|%o-Wl+Vr#D4{r8@e zHtW8GCZGL$%T)R7hOIfsP?w3{PyCv!XCv1Dw2XZ>0dsTh6sg#>P=`b84h(D&fMbiU+sMAs{MG~Dvpn_8^ZN*=SG86fRhv3B`f+m^aw+3-035*jgr zW4PE-g9XM63r^C3%*8wcB!X;M+l!XT7uHB<_X2IM)K3m1?}{!QBwNAED-e?MPj*@koLh}dAsB-@FO;(2}$m0xwDt$pTLmwp61|80XrW*a{5K= zoK$K5d7Q@PP*mIn(T=CH3NM~-dxkuQ`SmI^ga~Z%7Ciu`7aMMjf6^GcL9NTsZiH#QElX|7+yy9KjfoC&eZhk(AubH$qv4@QM#4@}S>nNYc)GZd3^IWjWz^ zL5w*ml|_qm2rQnMjeS4|+z&5U5Dae%MY8G5BD|4Dv$?86vEMYf4eZ`Rd;CM5x6$NS z1Tn>~>uM6%d}1v2_n>|h+%+xb0L<=MXITyhp!e^wn-Vj+e1f?)T-~6(OuNLRX|&~3 z_D-F81Z5x?>M0n2?4^jX zke1wG?JDC%Idopc0kVLISa)Tb^VNW;)Z19V<$Sfug{%tbk@a?^+CgrNVXbEXJcPa{ z=!KE>Bg(=)gc&78TlWYA=c+eb%$jY$LTMdUny{>ME!;O=+)FxkabEz#QAql=aij)a z35Cr-SU73k1GDJ)GLHv1H?K_$ck#zdS3 z$cA6`m`RYe(Y0YMm&T8D;@Qy~!rJ(s%@oe*P}xo@3$bw{)PyMFfHq+Q;urRS{w}YT z7l_QFR;v-eU{tB6Ds2A+(-h~iOzSCP!*FU1$5IMdFS!>u?dYUyJ4Lk6L=NCT1f&U( za+F6_z6W%N*v*QOFUYj5GHGD3lSPXU=c~EfPht>4!SgBDcZd!+N(NCRA8M0*+j&QKWJA$O6SSpf7z?KN7@ zq>2_=%4|VF!PH5a499{c->BclzO{qzTN}!4 zb1#J)V_@Q+gq@w=MGIK6Tq!3NTk0xaDw3ai(5pQ-HJTgJ{*Otd%9elAza$6gw5&5sxeaZ^@E3sGx+ahto! zo61{)Jig&zIP$5=m1(c9!fOy2u~B~@2h)YG!9j5Lb2mK67lbc>;C`{Vm!eOlo4^6{ z*kTHMx>l{VM}_)85G;5C<4B@6Yz~q!67p0!3xc%)i+EW5RaovDsO6g544=I_hl zcFDy1*oUwp>`ynH`8&3BuH|BDe^w4wQd6XTYCVO3%dTE7kJ+URY**hRNZ*FSkR8-Y z-o?Z*M}^N>9CpR|juCC~X^QU~;Tp!{h&D?Fu{vOQu7niejiRKv;EIzLTxb^*F`~AP zpcs`{0sD`DIkexw2~J)d6LuM3U$BQ^`mrCx+=J(beEpCyrs0@OL++l%IyPyeA{8pE zm0zT)m{yg7)5s}2C}nojBz7RiWb2UIid*I3xdg&)gBx3Sk;Y z;sl_vn)Kxgu>l+kZz~-TpO?w57-Ur}CgjtBy8%22nPeV?6<}Yr9_OSBmAWE5f0)ZJ5{k67h8=mo z4V27-!A>1(2Uvt5uuAG7@)1Rf@JR$mq&-7z=TSMd7023&;<{A8{2qM)vU4!t6eyd( zdEFL*pvQ6%SYC*IJLKZL?_@Dt$QD;L+k$~GLKJw@i5%k>77_^92?z-n5QHmm3Y>^0 zevsCNV#)g#?}j{|Be&V912jSaMaU=Sq=t!L5W7s_Am}9pYb95O5Ql)BeiuRbbafY1 z$1cO9>aI^$cU-)>gQ^qx(pz`%>L9<|hGSEi8qST85X7ltTBElCLj=eov_QL)OB@~! z6&18vr067&u?xDvEi_Zuh}*Ffiqk^+oNDN%dFq`eL%aXw)}|gP}7S+u#Uj z#yp2OfLqH$UGUKzU4POc+BPAm9;!$b^Mr0MlR%8vHH1)r*mfak-p3(dy%3yMCu2XFsw}5sDa6@1kA+RoELtnOF zZM#~nv#856+3Bu&%eH{tHEo;NRj+RgSO_(_#|EtGq(6cTgcKVHCz?0NTc_GLe?DTz za;^R9An)x>M{YXcX~^5qhciVM-bsXw`!lV|h95Xx32143WPQP9=+KPncu8pM3KXi!vN$yaTHp|r76WVWf>w4)YQ029S zZ*kR_WH75e36tnVNPhrKfw+1c-2~py4@^S+oCtL<5o-M@Oc3d$_9I$6Xica+0ng8u z_ketpcW@1TQZ9E;uxicJgbjalwdY|40JqX^3Z<|^?+(!M2t=tPsT;ap^u0Pfagkmv0}1j|CWB73s(OiI8f_rjTla1FR|PWv27hm4&uQCU(D! zU7~vZ5cGMDN2ESj;@jas;TKxdysB;`$VaSsZ>at`5aEB zQ?6-p)FZ&buI&UO0Co*DxjrAUl2EVWjI>%iS`XR5BOq*iC$YDgv)As%-yghv|Dt#h= zIAAB(1KO9KrBfLc;gZ~I>KJmtgIIbbSdmYJ3PG9wCp6CH6T!S6J3D1c;TnmIbzSbR zg9|U0E`{#gbakte*-w}9S1`hD&WtDpu!nipn|(INcC(Tp3wUZ zBu?*?vQ}wVlZsqPNEub1oTy3;pbPdgK~45%AgIQv6r>zhlG8gQz@{DB)O-L9(}&Jd zjVKM{f#9mhNub4xC=JLOO%{}H!;zrUPcT5Efe@>-qjoS93Ppx#+TfHPg;;&AVm>Dq z?2lG7hzi`}5u$=Re?_Bu3?HSQgXc8v@fCScsECdwimV4M-hUGdTO9i%30APms7to@x~lZZBIC@{nO@MRJvNsn5T*_m z*aEbK0l5@OyY@CI8$8>MY~BTI{>^tG!O!IzYJC`f0>e@ETRssDvta_3J5Bp<;SizU z5v|R9lqB$Jz!E>kVhC>(g;o@SV5D42q7j@qpE4AGS;DF`mtjZQ8jM=j@!<7#pllfT z6tvDycse_m(+p}Zi>BE;f6v1KiWUhTLe4!3#4fgj~5Eenur@e+Tq_4M~?>s zN*nIaDI^t(7}f|Wc6L66A*g6VG&ylCq1s$AyAa@UY#dWomr7NCNdT^lAFRdAA;9@P z;7rZTO*V61M5Jb-Xhx}|nu!8f(DRKh4e%c7^Ql8P!-y2LK!$}8uDvWAOKNsQQO80K zc}!1Yyq6dsv*MYn?2escwn0yjq-W;)Sw#>V6K6Z-|?f;<6-LkZCW(|Z~|9=l$qO! z{;ZPsgMzMMs1zBULtL~;BmJ1%I z380{Z2sjDpFR=D2SxTL4TcZV|ffd?sC*k3Mg^XiVYK^5!07;aoiNBJfW?UMy)W-UY zZ!7TLR*0)U`it|twIXgFsufu&s})t(jow2Kl52CaD^r=lFV-mDj{t8(rXM!MHCH7O zr|(e9>W0GPcrxi?L_1S@zdHV%+#xk&aLKh;gi_qbz z$Xw!xHOB#@RkXn8A~~7g4OEKJ&n)XG9X)WcW;c|y8@z3<*3YrJ0v56rpHpp4?>;4K zlgQc%tz+I}4`!QmDDJWL4n7Can3EW#Y#7x~BL%xC7^K@u-XhLwD_{evPsCyYz5?B0 zH%?F;$EV2b4C3^IwU2m3sdFid!F_Q5@Zp7dVMz|C!M(?Dke>J`=Ad`Up{1QbDTx;y z%yO7G?xF+mCS4Fd^9E4DjS>d4;Pl>6d27*msn7s5F*^V_zaK@DC2{4$37EO*060q> zE!8V3JwQjQohZ7U_?%54aZpiHAZ4*B#I9*eQFBRdT zY=L|74+sl|y@@%+7HykYgo4`CEWEf)WI-E_aiKiB&Bk0ESg#h+5lLyhN{5oM=*Mt- zrfOXf=LVs~eOWjIH+wySTAXD+|!M-s}AVO71aiQbTkEoUvH2nfXWgvV*kCHj0G=a6kgCOS>s%mJ#8%h{ zP{;oa#8Ahfln_F6+Cn6Zu1aCFm<4QHvk9@XF4ffqkPDQX*+RL`b} z#p=e6u{!adBN&!jXy$y-^T!P9;hsNaKs2sWm+i9E2ecjgu~y=oeoLVT9@{E7=TpS2 zH-Q`?FV7Lh<>p(Mg(yk~GfKOo7xP3LRDo~=Rm_tu6EkEE;gqaS=0tr^3s7EaW=zap z-q`0RmA+us8dG+uh&5BWjhyx5ZZ}SoPBi&L2p%w{E2#YmPZu_{r~^(A;>xQ)PTZ>( zn+^}CYckORYoY}nJ(ygTlah(NzVaiBgxCg@l}9aY%`hly>Lbg(Sb`f8NW~7&eDAge zwD*2RcB`|KuW79lw1%q$v{*(c@^g5I*+P6?ruK_>Ni^7L`&Cfruo)9^0PRy1^Dfdi zTL-2{8ET?llB~&^@;;kk%}o+2oS^zrW8VWzZDF}A$J;LvThsLc88y8i4^Gd^52Lel zS+xjW=e?|n+5+%L1ytNNiTLAgZk%6VykFLAJ);>_i9%K{LV9`+wYf28(OGsQMppDL zj^$P%<=xlv7c!Y?01d|8OPkeE8*7I0WD8q+Y3bhu2?moPTYDZHoyfOTlJHSwDhZEu zkCp-binxHwYsgdRDlb@Z(Ugt$1yx&|mK<79+N$7du3&XFrAKfqz1H4#nF1xH$-yr3 z_HK1LJ6}OL+2^n?@g8o`Zr$Qk9ml+umWOYZ2kr4Ats_ujP)RMoSu&4zpe3m8A`HCe zTBoyv#qV_V=uScC8Fcjg-eDbMQvv!q1RB{QRLI&7D+ewbvnM&)@xyRJ(cK9o{p}Vm zPRZX7eHr=_S264Y+E>?jyt7(o6S>908{x8qTCKWDunm8mC9HiD^iJFW0BW_4!Z;r7 zJ%pmI1?)HXKsD3nSO?T)$Lu|Sv<3t9+K>0~%^94&c@`t+J=BtcKpac_$QlU`O1;~3 z)v^X6U@}}&vLpQ2KNp)k*ruo*mRg;!EQCTq;ojkGzC2iec#2xK`DiEXPM8f%Be0Cx zYH<|T`ASnBwpZ9p=bjAsN$k#7YISdqRG1!YbZn#seJqvfuD)TJOu`b`)Ah1z=XSs(a0#^psxVbvLsAv{} z9q?+~<$T4L2Q5_b4PhQA4R*FrY1N#2vc0~c6nZzM#NY}-?kaeunZG2jm)~RouQR+u z0Gv7oHw(e3gzP>-79hQTvE_xq+dzDz`Ds#f=PjM8eA7%GvpqQ1*hG8r2kdNewO5-) z_}omcHioeCjo_SI21Xhdif`l&j30a=-hFK~>|q<0E9PVkBi?D!JVaM?&FXrW`;v~p zm(*xMf_zEU)qX!h3;$4h0KTLH^7}fD-nyV~pmK$8yk$>{#85C2BfuGLL7&E~tQW)H zeOsF`0V%KrE~q@>WzCH^?Zo}0IPd#yVLI@k9QO&V+&D^C*ggD z@DFQ2xG~u6*j0iNqhy$p*o@Jbw7e`dolU9bg=`YYb-Llhu001U2EvY?OXGKbXiGqO zTK7?k`x*I0KuC+yVF|1TA&sv1V51NOSJV1wESc?yT%vWdPGqiKiffyWb#b$(`t?Mv zQK=Z!A*J{tAP>3zrztWjZT{b;h;O8gj;b4Tv}e*02y(@0Ct#Gv&i{+2d3$d#EkH^z;*0UsJ5rO%D=iMjE!)Z7@Jm>WZUZVabT zn>05@X>N>~b7P1M`3vX9rI;JC5BDtX11lvb$M**P=H#ft??omDBsEy5nTwp`O6`dB z$i?W%n#E`a=Jguy0Lhy=j{as$Z9Aw#B4;5E<`d#R-8*`r%o#Cd&brr=GKWOJ?i;k-Q zm^{`a(&cbGf}{=$ZbrnlQx^!E8H8dlB+V#^nI8|*;dLYiZ>QgCXdu>>>*R;$3b9!m zIv$>zV~b5=^<_1{uwJPz*X{x5_wtm6CxOI$Jxy_}fFbWd*s0Q;grI&63^BSPY@D1x zftDp?OofVAONWiwI;>}{`?|!gHy2)FdaDB#B*Ks|RaMKEPx4mBySHXBf1oDuYDIIv z`Pd)PCYl2@Ywy!+5x=%Zbv>>4SF5%TrEMj%E4l0)#g0Hn+#Jcyq3x|-rCAvYu(~4E z^*FOV1y@Rg-I}XFE2?#LO+(9~GzU)eODI`Sm;@|11?zKUR8;|&-=sX}H~@APU@ceL zRx`&g)wWBiTS*cw2Rf1;@X^Xj#nl1)bbp}2A831&T6R69I-a7!p_L2)aI9`6&|9wK zdOv$07}8#c^jYq06D*xIv-U*l4qzRqmT#JvKEH!Ipe$Tubk+4nRnc#UpiQeCf^glskl zd5|#Wg#3UAc_;58?q4d3>Z}x`cJpTDYaB-2BpyXr~WreJC zHHlJ7G4((xgdqO~gn`H+N}U72oR6I~D3x?D4HaOap*RELVdrDGa1+<@&Bb=ae(Gyo z3Cx?kcWMAhsVmpEqb^F~$_%;tJm}~<<^0AAR1P82HPE*0xHK0s0St^=DHzP8B9@~r zg4;|}T^7E&D-A<@Wx}pR4>Axm&X+CUFxD+-C|*vcRn}fko3gZVuu5~t%J*q<>qrJ} z&43Ts-R9tT$=x?@m+u?px`1z-lmXc{YV!iO#~#G&OyttU3u*8MkOS!eO}!D$evRiFzI=jhxBX-Z6afIIrSY2WGfCJgbU6(^Sn*}*anp!hyYK@Si zet&iK1)7?)8C<76fXMXL+riUv4_JJJwwoJFVoXxE%HctlW;G>AZW+uQcPa&xtLdJ!j_%)972EF zuAtat6xXU{V&P%zry|e{#R?1cW5IxN!5~jSm9lw%+j63L9mFe-UWCud#+HziX(>Nqv7-vC z!i7fUKQ@*4pqVTYqc+HingCluroA$y1|qky*{6+l;YCv5Msx9 zL~MXRRH2g|3dW&8*oe@MDVC)j`94D0{1ilM-t2_WTkx=3eygPspouk_uDA2{Y@V*d zfrzg(^sEZh!``H5P5cqyniXnoHjXY2AsK zB*Z8RTTw{y{jAUT!gE_ne0{$DDr^T~`wPAR#rI3qw-c9@cN51Uq8WL8nFNU@hw6JA zv=Px4WP49bvm^b;X#X|Pt z!{7{X-CLdflKBW>VAwXtptt%&9BZgOfq~$$=2)>&&yFvCP<5OzI8}_3$8<8@?g<1V zD`_+98t4$TjeWIHMPWh5*eJwP>oAZdd{3fj9Lt*v$3oG%O#piA>&y{TS zpd&_QN+9tAv^Tk>ilzeN-q_fs(R@(sP}HL|xbRTxvep);%c^ezz=|e&%oCl%Utf`Y zjd!`M7H9El?a=AzQ!1*u9xH@4ox0|S6=r9P_v5}Px_9_GHlN4qOWn#z;A-$-QcB5q=}1>S>F=4*5fVW2(;rb1k(!B4({sHNC<2n_IEvF|N#A`WQL z=)Q*mFc8?*G_K_U2P3rWIqmQ7L5V2Va=uG&wWx(Sq`3BE;W_LJoq_-@?#G3w^=JU2 z#lb`~ImAvtBz0`^cO=}TIe@~U8UzFV7jUg{c0P|EI>Op4Yk9G<>pwy=1{Vw6m<;Af zEW&Q&WfCGS@jqlB0AVNR7J47Cpo@u1({92(1Ut!ag@xXoiF5TZre zjc6UCW%R3OP^>RJhg+guykiKcqEk3T8%W87Hw^-OK5aI0QxvWg+z$i1Y$ynUgJ51t z(F6}^|FIKufUM~zBbpO^zy9mgL$9oT6<23b-*9zSs&8vi3xhS$MUa5N&8I15TpW#W zYuMHhIN$>xkZ}}Za<(bgFG+f^mL$d<3-B1puDDt7HBJy<&t=_7v$Iw5XSz8P_qsry=bVMus{ z-cPX6ltIBHv3#{{oP*GBMs+O{zSl4!#qKMEBJ3TJ>HhaxG2WdU@*0+U;Pl3sq6haVOZ?m#TT zDP{UGKUq*Sqi_Pe9qqTYi9d5b z?RB;6bu=<1pgls3Ttiykc+|cI2BfRF&pN7xY&GPtovzHp>M0G&g|EYo>Z_gvvSWyn z>7=4VgY5l_Q)=Qs;ivaPSSej=XAp_X8API|G$Q3KhxRDz_SW3QyJ3V>T#FGiS5&N^ zH{ui%`yIc$ZYE9)BK+D3))XgbjOx9-`kci3c;iyb_Gni=luo^k+letjI@;jErVKvZ z5eloeZOjgQ@=A}CPjf!8kG)ABn`uN2ZD*A-kS{1?E1 zW{$S=m$l{B;GpbdnDlh~gacG}(>qKG zxb8~3gWTZ9B_@=K=^M~q!~;h7DzK-jQZ9^~dR(ppgV4Zm92hQ@&*ijiR_CCI;I57>ceU>v4 zLL!LZ-=pTJONMyia|V_k8Z~aAiSjK%l^?5J5eTx6wBOwW&22ZaKgen74>%6V#+)ie z#8k98TBld|M5BnbYA^ph(QWPCwQ4X!n%Vw{WvwK(FI*eTL$u&Bj1fDO7%n~|pSQNn zz|xM4RS2j(L?x`N5+m&6;?wG~#hDd8N2}+8X3d@8ddJ2654)mkcrA}CxZfE`G{4kF=ap0yjMc^x9sQ>^bVCv>7zB$9W z!w53K$=WVE{E;3yelE6;&5LEzy)9XZEL^CFwF5j#-A()ki?4a;kPrD9XepzxIVd|J^99f%|wUV+nM3$vxl~GnOGB+)&fU>G0u4Gp1 zhKM8ej0=@h&tha81IhcrSBm+2hmcNW?mdB@^mzeB{|xFFwlaCQDH;GPPQdwUbq1@? zQf<|$tKPfs!CP>~!PYTWl>-fLUdLE<9)7Rr7%QEEUsuQ2QtXf;vd^yCY7&R#?t;WL zx!av^$laGFvgPiXeBX|5;&%*{ga3oZT}>mn2SAMvVC4A#(-hDi#fkwgnbW?T@`V_# z{G$iVFMdn{$5)i5Q68#I0*cM2t4Sgym1I61jTF)^u4_0N$K48&BO)TrXAbrSk0Z*_ zmP!MTv-3GXfRc-2Nc_qg5^m89M1+oJIOCmo7hOiS@$P=0#E6_;d_e$JFV_^)3&P5b^3Wwglsvu)~9WdcVB~S`{r!tt8sdgNA1%34GMqmiCv}I_}Gg5^?GAXLYDW3=mrRL}l5DXo!0vwQ+@&nov z0GPP9az2ok7Rt}_Ha7I}7Db^iUWBq%wA9CI38VD140$IJPS+Q&!P6YPO%zua6961m zGHWLC;@xfeChGF@1V%8SWAXM4heE)BXn;@qN!_qhAgsOnrE7xPCQz;&)&^1R8Bh#o z*~s36qXvruybRA#zi;!f83;(^?`T-3kDNI{i1ci+(l}wkJBQY zlukQQ%1}Rca_)lPSdFg*hCz6a_$||5Gvzy{2y=eP9~-8i?n|NYAuHlWC9+LB!L9hA zyXHD})0BHV<5Ta|i#Z_j&EaX^mI z!8fdE6G|hkjo5aB-xS~Sh%B!HXf=vyB( zcBKxU@qVH|z9(hVzIT8>${RfJri$9NfP}zaetE^8Y0iHAX;`+nhnBt_L5k!@IMV}q zAm=9JI6KF{TS$~sB2F#{a`YX-i8AT>XhfTh8Bew_l>esjm>A88)L@?B7~{ewOaa7I z5TEX#;(MoJ4CsSU##ipx6v~7rhfZi{hnm5_{*9U39b-o*`~}tu{4+TL`jW_RafTiR zgZf4{|9oNOCP3vtw}C_G&FesP>t4*f_MqG?;wZ>sRIC0buZH+lx!Z-jTab4>@}f9L z6xo;rk>*UmqhoBfec5=2#)h z(?qOC#CN6%u@}DaX~dpD9yTze8&EMS4EE9FZWawxz<9fWK?)IPCzpBY$ozr>sqbK7Ch1!ge_t;vMTkh5uAp*43xLyf|8(?_#XQEC5kQP4pL|h7kI(& zA**^UMh?0np_2F%hQ!zYf}T`z7JZaI8Vou>#9A&!?+f70a<|E9#@G0c2bmU(bYfH+ z^rP@qgHL1CZ2895>4~);LQT}c?em2N@ufB>l%?8p-^biGcY{!g#3SDf!ZV^XWUn9{ zmMgcQx?n(}N7nw{MIeR#cStE->|0*=G62E+#&@tL@g(gqHa3#i=YDjt!R+4bQ{V{l ziSd0j>Nxf}*+U!gN!vcUxn0@AG1@~t#3i*t*!Xf1fq%DBfc^TQvyw#MCVS4KR3?#? z^C;C=?u8SeE6U5+~(P!W}cTh9t>Y z^gav)J~?sff^jf5{P1EJ3(D4wkR3ivX&O?V<#;~J@tlt($^66|PG_BpUF#nduXVhtzoHB^HOX1+!& z5U;m6BNNL|riZ9yG#SCKLd*YPvj>92vaC;5MS*#KfO^`8=Y+6;oTmztoD z81jl}WnV|@35s5n3L}>Hap>#A?{ZX(0uWRS;gsbcoJ5U8F%<>?6c(s(_XUOV6|_`g zAZoPxue^}CCCWSS)78Lda3RLLo~9%ljBbMUWehT$SOXQUHbV=psN{2t&%fAG=3BOx zr;~F{#9R~O%Wa5ax>+kTn^_9{pmggGVXoC1&vKs~A3~81(|H#@AYKARPwWL^fcX6e zh>xD9z6+7h2JveyrRxl^iP^??Iw7~|P#zi$2O@Nt9-b6m6}Mh6-+CkXRx-X0WOk6w zG3FP5?|XN3UxHy-{?DZIdhCYItNskCn&!np6D*TWc3KoKfo7r_`TtzO)nVh>9<0y! zyjRo{)L!`)UFVmfM>nYIYN%AkM#g(u&bLT?Adr1=%GavF&hay0F6KTaLa}6(64kRMm zKx|d*gi?c&nOZchBxM%yk|TIBuu;{TQH%)6W@+BQUUmJhBhUa(kGF7}*5r=RJP?h*b{&yTD zafdeYX`Dpu&reXAcnd5W(2nyY@eohG#goJp!KNkhVuKAt4H^W*}aB;xYqwLD2gIYZZ7jiq7tE;N{OanwUEp-a4InX)_M^wnBz<-eo$#4ue00h~6tm+)kYE9^X( zVy7_xNaMpl^JI#LkMm@T^WWl0A`iyFuI=VYA|8_2+K+gWNQ-0^u5%~Isp(1knQ8Ny zK2n<|4L0#)N``!qCzHZQTTRK@e%jqU_0J#%U0h+vuqV(PY*9~Ir)axjf@r|SX?o81 z`G0%Tk-=|);#AW{CQk>lD^xW_v7wh6vgi2$rQz4g`jXs65h^}DfwB&lPQYb$df6GT}erUVn6w(Nfi46Xo>CTL5lW- z(aZez8sDqK>Wrh2<}dM@YdUE7cJV24eu9r$Rsm zZfiv(8zR({wj!l%k96LfNyE=g@Fz55oYVz*Rf;deG_pk5Z?xDcV+`?9q6!A^!Ib`r9^F z+4BNVj`P2yvM76K-$7|B$C>9oe+i!Xl~m@2D)uIJEt&i6BA=1*_c(RrQKG7mF=S+%Ol2H5 zGH48p5^owAG&DxWYeoi*n33^vDg6*f{HBelXvksAk4yhh4yq^{?w0Fs`2^M(hu(QyaBC$#mbEqDe?O#|25xZQJ1 z$6Eq>2THV^V4F8Ku&nE;cpyURn^7oogN?K`ZW1Ht6N(va<3}?ZxJ{22ldPw~ZxV8C zKn~6tvZ6U!r23&E*-&UDlbYaQ!)l!!QE0!t19h@8U%uu%JdZOTTH<`A{d?ao@#%%} zuj3~gOWaiPl>%&XNVxsM9sLq+io7o|Cp~Lp18unz^j^H&1k-6lGAF5F!l0`Mum=32 z->=}`67zX6emCJCFt=o6WLRyPnc3!lS>&IsECJbL*K$KRc6B8Uf;20d2_=|&HArcl zL<6!Nt2Z(s)uADDDE_a!Lk;+$4n-r0dC`rD&!H#RaJ?llCwhP4vWNmC60Qh+HZUYc?x zUCYY0=j56Hz)6KLL+{(j;yY0cm*hEX!ZlG#P|D-)6FE34Z`3u5 z`h-f7Z?UPBtLZ1Zl6Xc6My@rWnO=wJ|HIq+fJa$ei~pN!{w%Pts|E}T7%^%zsL`Mj z6EGMy1U0xAlRy!qw@BAjdr@}5)+7Ws!E9ca+G~4j@3mGc-dgLewkpP=5)2X)tKeT$ zY_X!9xTy`I7!}#?=ghpjBmr%2f6w#NC+s`_XU?2CbLPyMb27oI7MkKHHYt@zQ-R~Y zF5hFD=|D{~ovd0BM&2n}Xa0!=<1v`J*L zjT*ZF9Z4f2O(Xie5MLs>1k!d*rQM#ElfctM9f&rfoS$P|&jG=#v*Dgw)5yUhd-Lbu z|cM}y1jmice zwE(KgYn`DHG9^`%y!DCKAfmd#`q&!jK(um-`dO`j$jBZAHspfk=2l`s^tUqhctJ8% zMrcyq-K!-@@H3tjy<5J?FFS(B{18H2A74_Uqj{{gS`U>f4=JCdThG$Qu%LUcVNtB} zVykWBT5&Fjb@n~~EMkdhU(@erdk%tEBPe*_7v}GDzBBl9@Hd7(3CrJj{*LCaqegg= zlW!3T!CX)XF0f{UAWB_f7Yco|h^j)P?^6aRziZ5I>yISs4PF>x;TY8yzZfW877*3J z37QosmnSA)W+lQ@zq*OCCZfA_JH_3(E{8hl9)0_HoSqo&KLoL2F-5YdCkalJh>!WP zltt>M3L0TIdh}EA?}O+mG_2=B9;XRO!WJkH-#TyJ!Rhu4nKv!ZL(F7X38~U_7wZ>D zKn(dxXtE?Y(DN$>Ykgz&r%Lrd_~)vRUt-N0*i~(r4Ff5H^Fo9Jr$}XIBrAi2i6k!7 z*Lu^{I=ysj2KH6JP4}U(gHJrrXGrU-q~`tJ z%E~(R)enSU+-|+d5$cQR9a4jwj(%gkD5@b3SYM@%oky}^fJBZ0sE(a+x2TTs0D+s= zpy1f1m51Hph@?Api<4~vhJ@_{^m2={CwYrgAE8%+ZgCvbU|6=QPzB2`d5a_2hg^uT zZZDx`M7d~aX%=dv)VC_6plNctLW^IA%Gxvf*{PJeWxS+Vc z5OR?5cvh3vRtuewx-XN}wajbCneYa)$O_ISAeLu%$nR+xK@8*(E(^uy5uVml30oCQ ztz{XRa;&np`2$Cj5trcVsigprq-~kIWf}v=5U=h}Mefm&M@i%zL`IioSj(1LtECp$ zmLXbs!Y$PYj$xefiROrR#5~8;2Xe^67}PD?1NKDeCU3lww}CPQa7^~f=xRknmOhUU zSm!9=B03wSRLT&vs+jfgZc3p1HH@8Y6mF#f%yTGXd^ge|RXM^7Ha#bo7w~TO^!QQ5&z0yH`n_t?Pe?+)L59kvBNLtrNV+S;;FBX>Z_Q7V z?;HSz1m2oDj&zZ>zoBQ5C>@AT8j@9PaK3Jhm)ubMS9E5yjT3P zjC)q`ew;R5-kvd`?8LC^+LsF>&y0vqD?8KvcE`^tyUP9^89$}0$o?K4Kd$UsE8XPx zJlz?)B7J*&cty_5{4Ju_f1WcdD0c_?VKr*HJ2* zZH_cozN5n zT$AK8hbmI8hr{C8d#sr?P~7>z3Q)edxLm$QsZ?(U$C=!&J>8yB!` zhbINgx>t7+m&u>9Zqyuy@ox2nD4g|0|5KN^`$^JE?iRUS_|)KBHAk2jcJk6LM1E(kT(0Fe~e1OgW4x z((7eEIGb^5rIQ;QlB~+=TPR9Ei!zolw~@{=fACuM9wzDtv26roJGPp8$)~kmujy2% zV{wO!(Qtq8CJ5B!*9#k9fXLrgnVh!6pyyi;DO6y|!@89FXNg`5FKXLFRp<=W(A` zo(pZ-?H#d6ZfdViC7BmLm{^rlczs}mOioj(uAPw3ar$iTx#eX5nIfLs3E0F_KWI0z zmhTUYqXP91sA5lKfj=->qVAHYsluvi>7OvkLK`cWMz2HnqfM4X=^vxm_G-GsY7>mN z?w7@4&B`FsYvCSPelk{xkuC<%Y|4xL#N6mp8KTQ^k!Rh~P9vNg zik9}#TF%xfRSu}XbQEc6<59FVlbNbl6Iz(te~(X`h8rb6BYYy{i-Kqgy{iN8U#FFG8ycQU8Mpi>r zRZR7pSoMR?#9fhIQPD~*-|u;o8cKS-1-SrX=48Y*(JSR?y;wy?Qk5EZt(p#D>XGBA z8MdrU$f&YbYn-|AdNW)Kc@ss34_Gg~R}GKR8I6RcsxjZ7USSswFHFHp5iMr4nWyw` zhxPC+z5C&DEl1|z5~CLu)sb{;G4HQ2KoMUA{0dfXYfLa#4yw$Rm z!-N8OBU{`hSdeUZDYcx*MbX^St&OPl#j{~PdHOwTj>cEgizVZ5;^U>#2b_Jqr9-zl@L-YJ(Aq6-(#@2*?~QegkU8LeC- zT*Dy0_G~TM58U4R4K65Ltm)GF8ui-0aRFcHw_fxIK7~N3XLa}r2@fZedW^7mbMmyF zN!9xO;$e(x2!EDdFmePdEEt=!Fcsm4w=Xon= z4x0<*@iS1*w|*hGPPb~*J^xFGD!f&ZrbS3t%R{3Q%NOhQP@``6J+xuD-+D=14j>ZC zufRr9?`_XMH} zb7{3&tYz7(%Du!gwn%5bA0MZ~q@&;SZa5LZ)YQUTN1SRq;7rWs%nMf?uEtPu>Ys~>5fjvv8Sm;~0FF04~ z36*xpPf1lqXap9KD#fVi$MI7VlRuScR2wf%H6kpXeFaOCLJT8iIu~ypFlA8#(O)DR zI5f~|maBU@%X4&pU?Srilqfg)$;6WmC8qFV@C8NB^<>xBWy5U;6cHZLz^xu11-WVr zdZN-W1Uyfw7O{!T7Ms||+UGnia*^5YK%g-efd&re;B_(uDB91PpT5U~9LD6N%dMN{ zK4h0NFo5ac5@M1piSQX(%~Kw;awZO(0GiaR<$@-n>;*e)*kx+zxt$0BfrxL(Ec&_V zg|CuEHwajyIad9h0=MN$>G(0R)dD)o$gxoODLe8%66M$+pc+s>a;MYS7<6;j^ZoJtvSz(iMjF!bh^!Yc)Mi!hrCAI`RE3M5!%1zl zdY8OVndy$LaF=f4op&_6M-x@Ayjy<8oSip?j@Oh$>_? z^Ej~Ew-aDHqElk6_rve-)@1ig!ri{@ygKKt$_qRsv6IxP&AcBhqYYacCk4JizGjLc zW#bW2>Rn=Zwu!bMuIZPF$@;rjQh&ieUB8y!!Db_K(_L2++BH8o%JOwu)tjx_tybd; zaku5$X*IrT)o#b5k;Sv3rXok^G@jY-xqOa4Afri~ALy^(NBCC=JI1NZN*%}{S;8|oG<*(Za>HLz;3AB#)tVQQ6xeT`0C`ab98N6 zDQs2d(bL1&iSR_Mq)Q!27eB0MOxj()74(rz_efVU{xYQgfYiVG1u_Y38NW&^?Q8vR z_bRQ%FG^RT0EwYInOUT%iS@6NJ+Xc}{|0WST7%>9@g^aeNhh}?lf5Qdk2&MW{e5Qy zZ)iC9MH+WIJT2cMgd3}#zsS}_{~M@jAhZq}$=y<5{Z8qWjI}2*+!PG`qk>mU!R2M& z0Hg|XSZjKz8jkE#qYov#*8nmBN?u6f@b1-;ZS$~XfmrRMYAFjf=6h6+{W^McglTwJ zI&19N>m4Lz&p=*RUq&JZtpbZ>SOxa5uKY*CT0_Q&R*7?jt0GtTas=*$s{zZ>)nBE? zFs~T)1a=;IGW_H)lhLciLcJ<-mC!1!{bf+`Ct`B}Ssl0uCVmtAoYLn3qdQd6({dxA zVsJhEP-f|m{~wKOJq7G>d0Hn+VBpxCYQ#SrTZlr*v3Xkdx-=}}4bpnmKWcr-z}DAO zbWrOVDn|M@Lv}xf4z<3_w60EG2y}a{mI|NV3vm=imjX47-#bLPrOI>cA zlp8YFnd(c^!Z*zIVsa#VBoB0Z)lV1bxz?<^&Cv{;>jJ4PmyR6)laHk`t5UQ0M<|&u zCEZ6xxpz>Vw9migoHY8=!l#RkO-x2mMtmv=6+C;0%KkMx3rk6@ubbLc z4-ur$$%*w|_*jkMN5<20DIaOlwoE|G-N5bZ5OaiX>0xlv`oCfH%P@gfQgiq)YU?sd z@m#}~t~pDPcxSh7m+;@mEd7 z;FF?FN5^)9hg<&{Jp8>bcO-f@Oo=4_oAD6Y)DS%U)m#C@>fQ7sg%bm|;BawpT4Mb! zQkA78(&32#xdxA|(QyrzASKd;O@v<^O$(-g;L*UD&>XE{?fwR5lhF5d0pSXIX4{<3 zlY&v-MC~6XGhsIi&}$!e7^GD$nIwKf2f=A=K)sG%Yvuob1d4}EUGF|f;DP!`cWK%y8yHG~AAR7lFzFqNb5LirC zSZn&Eb&+m$PD$g@xwX~K=(7G(lH!?vF!@CGa^!q#Bq^Txgyh2}#pQDX4+B(Co+E{C z4=aJsubY-SS^cZ!q?~kzl2|V%+r)Y~4f_M@bWOsguNF;yDmxOSN`sSP)!WsINpkhD z9oe@qUT*a{)f(V$*C5)iCe;D_#CoYpB;-Z2Wd8aDZ49dj-^>#txtg|7M~D3?n~dK; z|MVtHEl1c!xQ?WWJyfTHeDWK(lQF5ss)VkMbA(4q)aDYRekoC@i@{a3np}J`;EJ{D z`e%xK|FyBmH;%u_PZjwjd}3#jZ^9P734gVr$T#EZBHvNZ7UB9A3)<6K6JZY`6L+FW zy?Q!ml!Yz^!5U7nR&G*v?MvJI4O$bi8N<=ZI8QCp#A^GzltCo1V1l)^XGf399 z%goE4ZS(bERNJe=8W!jM$b))54?jeOPBcVx7G1&9j`xsFsynV=w9#oO`bF*+Fp(Hh zSc$0$4X+BH7I=Z9Dhk1yPVTEt1;yhk4V#8*VJ*4w*?aWMIf;fniJ{G zjaJ9f`KAC&?ih9y1Hx)a!r3O_ly0Xe^b1q3Uga7=dh|XVYiUH6`s&Chhb!Pvv|CeY z^CWGiq{&f9(ymRV&5^W1Ns}#1(k@G-)k&I%G%o!60w*H6R9Al&F7*Ihqd9|e?8wvE zJuUm`pk7kZM`RI5O_`>qvW>FRG@5IbD(iE;osE41v3-F1-+k*M_ufwpj-ETEN?EK@ zSw~Dmuxz75{2wao)|5bIBz}n|08-htrm_n*3Pt!oS0)QQwn0cl&la|BbE*OqqfM=O z(!&3qtm#TcfpNI|#bsc2^yY#dF<@*CQxw>9n;w%c&|nwHHwB(E1@e1-C8o?bQDvXisbT&AtUL7q=lU`xxQ!g~* zA-Q+g)Tq_;&7VMWWW= zX}wJ<-mq2Ls1r7dQ)U^=9Z>!qy$4<=HRs7#O7b;zjqE0;A+V9z0`^BFBDO*JzMj## z0*q{(uPfanacRVrJR--=@M)+;MLPLnzz!9vrZ@(OJ=o&1P>YJ*A(^6&JjuV7`B!I- zS)IgS`ThiS8}No;Yc=R9)xTdZeTYcOdBIZY^_Se`$oW%+vZdpEL^cQy?+6#5GWB=a zu@N=4c0xam%GA$M85OCG5Y%WyvSRlcjey?m8?$s^L7r=^lv?yi_b zOOBokG!}qbXY&!;u#-5MnEn$7_Mp=Apl2j`szT*e;W47Nbr0Hr(MYe<@(FeEB&W*L zD(|zUg2$zTeygI~EaD7Z!_DPA&)exgwbRQ?`kqT`abt z(Z~T(r2l^5nV?{y@3Z3fUMUbtQm;&%QD2Ecy-t;kt*}OZbQC{C&m|g>BSCz6NqA4V ztS*qpeip6XqkarP;**R(9y;Z}RnuggNcSm)jW(IiJTqPAN*ALy=V^Y2BZ_+KTYBej z9nV|);I!iXut(8l-srL%^?)pT>7}zd&k<014|Ayp$X~i8x-2(TCCpnZnXLYKr3dGQ z#?Gu)`7)UP<_jl=(`LfLoiAOk@U~}j2bs+sq;qC`U%g7q$I9E3lkp^6k;`b{jqJK- z>$*+FlLlA3jWPo&{?j#5an6v6|7U2$ui6!VI!^}4)751~sQZbmu}>AwVt6ItUL$!N zFQLI|K4_@b@8Ip`tLE=Dz9szLOGUn`UoP^c^Y;V3kLPy{zgqoYCQd7}h#_Frq?--R z6+m4%hXz`0F83=2+U^pC@=O%Un}l3A%j17zk~0~Y-#BDP%P?>$3@7)ca={nb>^1R` zEi?Re>UWTgh0kG-pu=@MOzE##rmK3Td40`DS?R!6s8SZcUE1Yo`Kh2D-FVGUH%hw< zv%Q>dpjF;HWg<$p{_t?zEU1YS!LMTVyYcKN*qYbCa;bweDHaX8P>;_G9aAQY?#gKkWe588@)ctdA=fv_obKp|Hl4^%Qoe`ZP zBYJ~1I7gmd>*tW@2C4V_;6S5Ggi766i)bO*v^26&=&HDa?}NY4`nop?+kuPkYOF!a z>I`M8yw!%jMr|E1G;a=>C}*C(MjP|W{9IANTJ@#ef_rZH6%84M%y&Fm+i=yFq8;LC zmG^9^3wxuHIsQWWYLqmS8kxhBQJJz;h(bjFG%{)Bhm?*cSJmTCHdyE#s3VB3(bB}j zGEjBef1!g~YgGSq)})^0U=4a(%aWlDQlIP}$7)NdPku-!SkC)Jy>;y(RQgVMbn)Lx ze!GsQk~$=3qXT}1?jPKbTCYfieD0mNe_T9rfr9{URna^w} zj~L9-=i&-4Hh(dUiMgsh+*>O-8b~O7KwW>4If@8xS`ywJI%lIu$>G0tsWUlFK*lCp zmn^k@CgAYbs9(21o$Ewd*{f5-@iZA)6}d&v!Kh#o!2CU?LrTKC1hIFi z7iWNj3`k{zA%hXTtD|1P(GTNm^xoW}_qI&kaXw2#k$t#Cpqkd5bvtMt8m|wn z6OPlAJZTl-T4@5K7*|n!WXTMyMA+I3nkqnqVwL6oKr!Q0x0i_$*$mMwnk?aWz&kV{ z#ML@#q2*@JJ6`I8f3Bq;sCR~>lQncQ(tD*QDH?RKY6WXnBbuD*KcqiCg}0(D%-bLp zl+qVHEq?)ez%y2Tr(X>N3;2*BsaUz0-}^|%Djj;4R)>akv~iF652%Bm2bR6+E!4CH zoD-ANzf+wB&&TwSL+H0h{f;Fq8SCPIMW|M<))G!l^O0wGcWQ508lop~Omu>`wC7`;DB?9gd$69^s!g)_?DZ`N-V2z z)+g0PhpNZUkQe%LAC4N4){m`Kx%E)4@7C99t)Dz>O9^6&NN90>zQejx09T`~i~_Y9 z^()bsMma`fG@0^v8e}&`>fe82zpm9dt5ZwRZwVRgnDKf9L$qMJI{rt-P+gg%#O*XE zlz84H3_eMTJBCu?DHw0klvwFabr2=~&*uNXDe)a8^mQ;LZcav}DDn3s=Kn^C#lF+O zPKm#VOzRLOUPR~+CBB@{zf6h$imINm9B?E`+#&PX$V&ejO5Cgd&J^2}_&vym2!$RY z3QEkx4jaPU-$&P zpmqPJ)&8wKR3wXzKgtXlmsEnp#r&4Kx+Ww@p)5v-pP4)VJBVQ#5tKs=+k1 zn(+UPrnc*|`_RquAJEjbQ*E01R*}rEO;at29XeC4aX|2?>Hpto>gG8EXzB~c9GRxN zAf`~wnw8%~Q~&$+Z=$KsmB|Q(($pI3O5Bwgo>G*JXK&QX#(!R3ZP>~1RH&6a$O=r9 zz53P3z{HR*wsTR5RGWxO>5d-heT{yLY04z4i5*_e4~Q!Lb9k(NN?EdM9SEP~`3^mw z(bd~p!14P`-|K@TYt$FB>DTtwmqYon9~kGM!I1-`p#&xNTqcnlC`el#at>%= zt36&x-(%AEsIyJ_o|3Rv(!FZ4PFE&fsiRD~DhcOEdX8GB(|b*NuiATouAiqkxv}bp zgL!r8or^$QqDv2k`hkNL5Ex0^xMLF z$8fc3xSYI)ny&l31d|5FRc>r9V`Tf*D0>G4b`9;SDr%RVjxz zj)i&ht|x8f8Diec@fIRXG4I8FY05IIJ}RZ`d!>`5>1|G9JP*n`Lkgs{%Q^7b2EJY! zXxs}%PV77lKG?<28fe%{cW9<`C}r4dpiQq~9=ZBkP~16Rp4%A#1vT1_PGSDTH{oH? zn=+$?PW1pY67&^2c0lnk4bV{b(_$wNwbP9sj`8^Epm$k{3PWS?!fy1l1k;| z6^lt4s$;Iw-mE^39nyn!bP<|s55k>Y%oIPY@Rgpte&d#(L& z?b`DN1$@{DoQuWE%0&$o_=;~%atd24Pw2!)gpKp~=R!2GLi$^#`&*807wNBxG+jwI zufkSMsMeb8wdxkdrYB0DS(#zI6i+XFzH}?^nOBxtbs5&exrLj`V`c4Zs&X{)J$hJo zA5EOkuJfNFBE|7qcSfSRH~ea9%qz}g%(5yur=7Bb(G0THGQe$-_z$z*lwrta7S02LWzfdQ-iL>cw$8g+D|FcP7o=)=65=tIR~B;m7}MU#!_lJ8^Ds^Us;PJ3n& z3Bz=6Rp@l>A9fc0eXR>>Vv|={JGFaRd9nclXnDa$8JC1VoWJlYiges2VEmND2petW^)cUFb$;~|#0PciVbFmvLa$cBGBbuS-K8dy0t}Kt!jh}YtdTx zL^<~)ojuvMYZ~45ZrAg;fXep?UZYU3>*r7058)GCJwSq0>u#Rt*zfbEg^K0L3U2Aj zY|VqD+a*`ZZ4(&|xn0s~1r$u@i5eb<2N(Q$zciG{kP`j>bP0J6g&P}2Z99%Np0BLh z9K1XEa*Ow)7|~qnus%l?7@Z=k?;QE@MvFoL$U$vRyL*D?=}i%JX2@3+IxB+b#@vXS z7&>`QVsrs-2$+(R%1TU8_~Rc@+N$l(&ON1j~VrZ1^E_fyfiEAj|r5{M(jIX8`tin&8I1TLBAb1vIeXr`3 z`&j%i@5ckRuLY9gSB_t&JCI%Y`moyMTi3HCU3R%hOG#jaXP^b8l8z{v=&g- zuat{9Y}^y`?POA0>izH^Jmy#u4e#XdEw$>ibS(6_5h*OOt{R0GS!<@t^Z2%CrCV)f z+g*a|9pF{z4P`Cqo;eB^jQk&~zF++uu}1OR!Z9o(As#OmK~{JdMkLhk zhv-$UyY!W&LR{m-ssOB%YoB+pZEjloyhK}W``EU*2`L}hk1H)Ef%@%E)DX2;?CH@D!(7oYP`4)-*4Q#aCMj!F0u5s>_vg%esu!Zpe(&h@hxIFgZtHg0hmbR z9<8vnN8K!y1zkPwG9{kJ>ql9$UCIL|Z(%0Z*BkU&-9fLozQa@E+00g8f*8W;u99sj zcB$|nFHUCqe0_A!8M)~Su1`N;e39AZuC=$rbYW=1=Q?qLyEV~tjpy-<1#QH69`d=I z89$fgm|Oppb~lWPpe=1p7iZ-a1hZo^aX--bk@XTVFWfo{&#k@A*;R9bY3i5<(jAwc& zXN8Z^;bVm(xX6c^#WXU@2)6ytpb;AT1RVkGiy_pJoL=*tAI^!OGL$y_*9Pvu)IYaiqP-Rsp zlVCVdAGilJNsR8JM7`BlAK1k8I|waXAGFGY|1Zzuj!o}+M{J!_9}pD^64#L^Ptqn0 zEDcfgJdTfs$A@kDi+9A1%Y$jUE}O;El6^?@;jlTk57?yJu$gOMBR_}1Mj~z4=+7i< zOkfCXgxWS9I{+|}%K!#*sl0hfjoRc1Jj2lJzAm7j9ovNj4?jmpu-siDOBV9tD&$h? z6~a}XmO}Xn(}p{`z^ih=8wjPn5yW4u3VoZ~=>z1EquhQDIhO2aJP~h1+01J6vLy}D z+VlF=%1L061qqbt1kUFE%w1Clf^)$NV)d)SGbB%U&wbQfGX6S76<#K8hyr6B>5iJf zcE%MTsTmK+&?IgTYhyldH#;hkaJqeP6J~D@^a}_;o6#9$6Bei&0({-SJHF_>s&z_vKpH4OF3ZBVIo2#s;#}RCt(rkG$R58!=II8y&MXEp zX37f(CiZ~(;{@vDZcqRi7%$ZMG>(37b=wLx#*{H2p&?m`(OVe`o1E+-Zgoqckc7jW z<*)?gQLpasl)%F>T@KFab$Au#)_L@kR8hL+UY+cU>TYu1QCAnlRLAH}67Q9fEbP+o z5U=*ME~Eqa1I|fcIC-WD6mOg)J2g-|`zy^HkJm-Wi+L#WhHxgrQO^x(dC4Gb2f++A zLiQ^H+Ek)j^`0i^wjFVho1^qzOAAPn<`A#4o=KIv<8-^6Fg56(MhGYQ8C~%&r6$vg ziwKw6aV8P-AY~j#=tw=3F7s)vs(esSpd8NUsB7&G9EyYK)Jm*Yx2?WvYp;s<2&P=u zeJ-Vy)}jo#L3(pp=Gs?5 zuZ_Y~S?5jx;2a7;%zD{04BSsQSKOF8IhLY^=xZP!1$cj5KtslFe00PECMOEX)DU%E zWpxSbn(Vk6h|xW_ViV&z+D5za>|BRWxi`#bpa^95tBC@i*3Nn1bHLuDl^5+W@f|voYQfX;BEd+t z8(B_2>vLd5pP)bPS8vK*C>4bwjqZfGtqhO!;|Gm@lG?kMh*N&k)YyiEE75M=yH!)&;tX#p|p7hg%$j)o?C zWJ-6aD%qj$n$Af6z%0`lxwgs$W*O3qnIvjG5XDJhJQTYrtzLb2%0JtIDpO^=3}ES} z;?n=$NO2U8Ut;;}unyY2ud};NWjUt!HZCfidd%PVz zMMqDuqeB^6%F~v`o|463uV9GrpncA{<8t-0lc^<|#Uz;SiEzc<>8{e3z7hwW<@=PQ)R6XiXkA7&CfEi?FLQ=ck76Kbq4 zRg3H%!V0*YpQ%>vwpjw$M40Gld4tZE<#}3OlHXyTmTrDqxbE7>uWrp%Hp$cSJ3?*Q zGvVJ$4~9z%_Z5D*YD+V5t#8+bv(*@e7|*Uzv!%n_Rvd_?u}$VWzl4|!t5Mm~xM)4b zCOg&6e9hs{XRWoDiCtOW;9)whc4 zRD33T*8b2a>k!$WCC^%>Cqe2?3bKqBFG2j|)UB`E~!|ga5qYCmZ$2z~-fqnpWm?*#M#nh$w#vZ7e=uU?G zY9B5pMbe-hAjPV8imahEhdl&YgVj2YkE-s9=UZ48w>ED-TWv?9Z*bVn;(OS&u27c$Mns_&_iCW;f0-QIfasnjot zR*X{HE`x48CH+W~({}jO;!f>&ukjc}32ieFAGlYwO+T$|`swBI4-(5Ws79T@QNA8m zp!M3uS0a3m5ftDVRgcp1kRBJ1NP)yMRssA7S!zTYfNVHB>f5fqD3?X9=q>MwJP&Qf zF2im$=`#)G47Kn?xKEJ{z@4i5Aw_Z=u5<^zMtTs71z10_u_eNU&_J)EKT166a|EZ08VB{9Hgh*UrH$GtcWPT-N-ID0<_&{WWv&PdV6Mi_%VR~+kW90>K&D9^4{Obq<0VN1tDN`}5(P4g|5%O&?=%0& zVXhel?)hHeIdgeVq~E=Agr`Mhn=tP2vm*TkD~Ct=Pi<_9^pB6{Mf#ziF`ZZxx;D~Z z9GVsBKd*@#rA;Fu{S~25N5{b;{L8JCe~-{~a4ZVehxaJxir03$_H|{l<5N05{<_4h z`0*W{#MiWT{7`?K$a&I)lj2aIL16^!91nqji?>sYhWOl%W zY*v^71QtE0NtHHYJ|13T0d+-3F6CI%g&cIMe57H@wX5S|A$T((#`wHuV};%wf!J-s zy_hC1IKkSRSLVgE@JF+sRzpS>Pf33TE}}gFrSvCE131TJO+-i3HGX zUrnGrhG;O+{JArHT=P>W@#zX3b#N0FYDjam>BM-JXZw>Sd#5@0)@|%LonyQvRe};=wnkxWQi9|PA>xB6s`RDW2$J}6C92t z6On`U=Y7A~=*Sc4Y;QfwC{68<48Gpz)SCbp(#U&5@;iWTMsK!>rmVUpp7pIV9)3+H zAKD}|Qzn5uf&{&`)e3+JdwD(vix5Ys1-dANXmLMD-DhA(2>~ z;9n#r1eu>)`Qf?klE}@Ya_N#YJQ9GQJei2iDEG#XZGKAnmk~ZO8Jp3{xf+>=E~%aX z?DsY>L|oIKEWZvUpg}M1+LH3uFOMg;k-yF?7QzFdaMsjI(>h#+innr&SIs zCGx!7-Ow<278BBb-;ipkZZtz*V2hY z13vY*K?Ba!!NUj45$+0^IlU*WV^4@_wS?d(Cd4Jz;G@EMcn=pvrT{Yw&$THw{Wjk?W>#?fZ#JF)!U=K7s8nu zBaaCF?=i(lY3h<_eTrveOdze>vi8o2! z)f`v~bVFeZ)gOy=XU5Zc%M8&H%Ct zG&g$O;T(OVCBBO!YN}jsg|cBSo&z$1SUKA4J?Nwq^VRbZ(d~1mH-DMdwqQg!bIM$2 zXdLx8d4aHC#07*#5lRoAXhPw!&EHLTG=CQ}0H->dFUv|aUzW*VMj{?0nr`-n%-8QuK!Jwe~;z5y(-)jKW~Y3(I`!dMm-@1{->MSeD~cK zpCCjkoEvHMI)mPMPnYZ1uxqV+L@&ap(Oi8U={0x8Uc~s#S0^0Yqq;fhJm*>S2gby< z8?FAtv+w)rMWSY7IwG$Mzm#BO1b#Op7p+j^-|%BrJI(eTU(c4 z$*{T~#e&djp2xS6Z+iPqYe)N+)h4JR_!P4?z4*%ZPh2VyU%H>KDOOm{BUzy z^@#SZ?b|0-AA9=N{di-TSUV!}Zu9BeS8ZwrqWj-E{^iJDIwQ}N4}YFaV@}_0V)`P_ zcy&ze3CXD4k!SLTKX26@*sj{#$4ch*ttM?^^$8c5$|LU{oIZW{j`pn+t4Abb4sZ!* zqU;_--tEV8_V67@0=6qxj%Q{hk>R@2cM|PYqrUaZ zUt&uOVi|R@OaGI7I2}!{Ok{q5`-`|}))Aq(V?(j|sdtQF^gw~aa96T64&T#0x`pkggXE`$jkLeND(7fQ| zbSl=d)q_34BoW*$LH6D>^)nr{-KySc^_Omw?U<)*(Z+|_DKqIk_d~Dp3rUC;VNe43 z-gpYg!Oph_T#?M0%6M1ByYptLdNyD&0e*usit5Ys(Q*#Nar$bB= zOD80jaxb`5PLunQO_Xj4&qx6yUpkfo#uyW_A3M0drqjX9o-1iKm==r8rAf7%6SsBl z4C)WgO*|%1%uWV-!nZiJ>M-|GTmo@y#J))HFnNEQ;YutWlNfz~-GC&{?sf|MFZ{Aj zKF%ZuuVYN6nrMYvEOomhmtdnB*E4qIqi?5ak?}-}!)2OD*{qMjc2AtjPX|*YKIf=` zBhELWojpNj-Hb<2OO2;U@!PTLmYN#%AgfhtiR2_0d*T3dQ<15>Q3 zG0{t0R@HIQOWa&o=P7RyW97^Py6>?rLE-iV-iBHkQ#_CR^VENwWmKaL&_LJjiae&) zp1vB)((SPs(D?QV+f_>wk|``($u95!u${DV#C499`mjL7t`G*K~aB;sOgD z-9~r0HF=s9T76#hY^ZCg?}Y{h|9`XQ|1VEY_&vZuFv=-)UI?~W)muFeUE;QuW;y$; zO|lQ(XPH|`$$_jaqbSmOG{QV)M?_gfW)xZF!?j5@|0uu`t(YOJ=q8NspKZ+=9;M1X zR?gYh#lx)|M_HSk9}lcFa&@1Usx*zYd=K-^7c*39{fL2-;jf}n@T8E2Csn7^KLEEj z0U&FcpKWRZxEpxI8mia3Z1C)Q|%zogMdj`Ji>Nu!M%1tw%8$8i!m0&>9p-&j&@SMcdb z$<&ynavzvrlFGfIgNIYOpfi4^5gp}aTi^Q>9$ z1!#s10lgocrq9csmQo@k{RcfQ=kUSAL^FOU^H|Hrk7Uv@Dv{Bqca0Fw1P|>Px#pDM zr4^`qiLb9=U5_}2mu;iZb6Y2$kbEoS)M|9 z4JbD}`m$ASUT`{s2buIGTziDa!OT0iaK(`s8d;VV8dl~)LuG3selhb{DY{FMZRnzP zvXeJWjx}Y#{8?L^*<9WkZ3(|RnRQ#*wakUhVYpR%oNug5=TZRfxWwmbc!>dMF?){i zxpUy-MAXeu;i&rNFI-_)@SM3lo2jAs3)*k~A}i#g@t)rk6WNsha9WG_+c|s3M=b4l zw&!uarcc*#NA38~j^k_k^!BkWJ43^lSS3q#{C)cLc=q-<0+TOIv}=hqY{`zEc$SXb zR?6!3dBYi{+e62eejFAlZMW~hVpvOBpd2Pa@t#sC9JF%(bc0NK7dP-~sos(g~HDN)yNX@WyaHyuaLR7&%@%s-L`T}Y`MEr05y<{HmNKzCV& zb89enPU3acCW)Du9?a$DKI+>e$@-f-SujtgUBAv_7m>dFP5Q#7wg)j+;7(|jEfr-3 zBb&!r<$i=-7=_f=&1d{ssG<`5G9{sjO09;=;k>{*p~%%rYXV27`y<^ReD1u7jbsi~ z$jm&qJ;D$UR~qp$s(8F(yG-bEh)<+9m!Y#4TSZ#t_m~@O@vDP>lI8BQrpgi5TCfL+ z1Fty!Vid}Uz=O?A=acJ6!&JxIItF=Ez_YO;9ficI(mw9P)3wl~bw3Z;u6!h;uq(Qt z&)OLuY0Y>fg9uhvU*S%?&+JmS(PB`)`PJZ|5h~x6svqKcQlxR0W;J)Ir7lf`lbVs= zmSFJU+&DHiP-TUi0t~PeyHv3(JBpcS{JYfog9{c&P?*Porqwt^u&^V&ml_mD(YHOT zeRf)9oA1%evdp&X$2_;(3aeC>h*k!dxq@(e*8OQAxQ479suDi7GCmBA(H%-Y zJsY!vfaLjk&b@p(_eOm$?$08#MPBGjWJ^YTxGqS*xpzR)`hiL72PHi{FzIRMUTaje z`VZFZjM&nPqSepTsm3fB+D`3%bcgk&eJ~DsIhV%5kM4T_b8h?YTXG+iv%6x{MM5Hc z&m_W6JGVp^ptfCckzf5cypq*;fHhW+E+)d2PFREq;ZZeeuhfm~BEpLGtgn77(&Gpf z%nIeq3Qtai*ZVEsADn%4iW^}^9MdqVi21U>kG87+K%8?g#G-^2s6O(YEJyQqxRAOz zy{CXY0sxN%$OJlnVx05iBLRFDsB%d1tAmnXtuz&n+R+oOe%`Lw1O~PF;=ndvOeRg+@%L!s2X>MPB$Mkwz zhsmTdJ3froCa2j1l1aMMkZIm$O^96mI#+UUIjAnW;1AutEpjX7d1%ucJC@}n@{hOLY7a$x#Y~y)+ z(`i1WMmVfAQk>4^i-^&-Nu{itCZfN^f$w=Q1Zp1#D|dr`8${%EahIkKp| zlxg2ti6rVpWKcVdEXrPQv`uMtynPSQqg20s_&s(3L?Cpx(09Ooa3HJ%Icm;%8(}Od zb*0bOM{6Ot?q#(tZ-+-BqC41CT796ccEqw7?X@FX-fBN8R5ZP<_Gqh5#CNqa??+o- ztoloWBl@Ply9+;#bUSCG_UvgN)8;L&ye#}#JcEzv+ux&_8-G*ib8FBY(xp8ac?M5L zrn$m7k)|vM3M!Qov`(Npm=4m^sn6smrQ{}>HEX@^VmFXW!g^2ZEkHY_pVK5?nHaYT z^6&W)KyRSigpgLw<;{qn{{p+s_IVe3 zlw87pw)0-;42&V_Ia)!-9sEupfX1C#cQ9S_bj<(Culxkx{VM`R^44 zYhGu`jyHZB|Keus^n3j}@=5L*@4b@GSgYJl`@8kekEsX+Ewb)!T|{(xC@VU39JwM- zT|qG8MuLk7TIY%eEyDSYqFU>(=RPy@O(Ms;9RhWzkYu`2kj#$ z=YEC{ipD*9GPDX(=t2|Jf%X|A-;0GtzK7i+H+G9$xIm4lqWIDL`qj6&DR0Y~r{n7H zPYY*7$M2@^TG26b@(X-&{gum9XyA8e$`lAYs;)c0Ta2!rC;7%x&jNria&80+$L!!f z!bLXg+#kacGGZrO)mlYN@_W~S@0~j5r9g?)VZwinm#DS5CXb1cz*l*jznCA=0on0m}&h_+7scOsoCV13XWJ@mxS?Lg*=nExobCy~FPLzRM+@yrfy zT1K-dwD(JgN~A*^{y2%MpOUVb)XIF|e7h{5>QB0}{NVUNqb!J7-4iG(v_xym*;%IE zMhRVhVMdH9x}ACzydk3yS3nx)n8EmD(YekC$3 z-BRJ~Km)MGeIUMGNxI5<*7#D_YF!QaIkBtqxslOj&uAb6{$lEQ?0O!Nk{@<5r!^58 zhb6D+Ea-amUFgWXxI1z%Em`$z@A zO!m?~OiK01$eFAY!~uC^i3@w9bQv)S#&4RXrqMDeF8#ED9Wu%z4NH_BlT$hjUMWpH z{uThCA(P1r#kh&j+Dc8*fIUCmSr6;US=hzVd{c%{&yzNZC<#;9GbJrk`l+RYHmOBZJ2ZRh=sMN>EN0 z>L?SS>|<%!SY$>kz|a8bu9V#cS}4;Zn7~^7*%z$7fv+9KezEvua`A$4_9V2w@`%Ze zRu-v`At;e01ppMFp29n#e90TF#CFqWsc^|;;&P=cUKG?ht)35LkLK!pmsV?~v%DMU zGqECHr9-vQ+!Kv&B;q4;n4a*3iOR`V<>b=JqADnhG4)v}D*;(>T;aOOY>gr#}`| z4Qspzmrraw5QGi7hphp*-Cca4%K@s3ys7iA zFC3~FKaYjJ?Qngs780FU?&keA&Av+Uz&`dazUA$6q$$sla_`B7Y*U`+@!5I21riUR zX&Pd<^yHmS2H$f2dj)ME%4#Rom6N#QMPAc1so@ye*ENWBCae3h_y@sEc~>{OMS47# zKoocKqTMA%R#D<%o?jUBpOt0}FWl61d-6Ydm|&BIJZ>3rq?YS>sN4B$sX{?AcSWPM z35Z!ccYGPDjl7#?b>UWRT-X__NbrUL*Jz%H`kbFyuP3g^&xd0=4NX5h#1(!45!PA{>fcfNTZSVYVG)S#O|}cq6w*Ua6$}SSnJEeorhve-`Tfr z#Sa%=wP60L&9a7py!0A)xOjiSB8c>-3!pu>j3kx*=M&fZwx{KwU{_UwX2ucYd1#yS zkFgo~1+gFJ-$M#!2J-lE$Y_|6anURCbFq@}a^bU|?JJM;yF9mUBh}i3Q(qKXm){%< zjd$Q;&s*BJ;soAid-b>rq^ZuP4DBC}Y|ee9eaqjKZN%Efu%FE525|5Iu@FU)ZQ9s| z#pPC+QrBOND?^|c-?g?nW zIy5Onf68NP$s}W5;jt0H2FPClNKWCGrC%+VgqOe&lh7D1Js54s&$qVSSYzM=@iMhy ztINEdScjLmoWo%xof9~v3fQ+1f-ltAa|7dLWS`2&fDt{*AJkodPV(R(=#fe0{y|w~ zj%4NZS#K16TDW6&>BkM_u`9+qO1CdNnRyt;JmeyJ%944Bo?ae#CIcQprbBRuk&i2V z$rG8$A;s#U9&gWm$QMgrT6U6@iw-Ah97UofbUSY*yCncIB}s@~N;6wMkztgk3BYS@ z?YWxr8sD{J&0OvX>pTy=Bi{6KoPREU8QO6r(C+^1({ihC$48!rK6QSEC5`3NrKKbZ z@wCW$v_^O7pTZf1@5D!0e~J%B0YAg}6^D6L9zgt|6|C5(D|o}uAiN1&kzWwKKvR%h zM`Hn_&xyIuaz0zw?XRDso`jVl$7BxO9UzM%l~d=Nd=|N48UN0y{|?D`>41!9+f@=- zfE|nI*~0(i4j@gMNKs8jT`MoW5NGzo7~tsSdBmBbjUziSv!VF_L~WSuWKP*#O$vIU zBH?_|uX5=Y+R`nT@IK*#B0?Rb)9}X^UG;(#!9h#JC2^~^Cxc>{GP+7C6jtDJ9$iwyT)7Go zmZ(jNMJ=hvYLhZiOUheqQXpzcVe6*6)Dh1ZSun!Dh8wlR;%n7g?;q6GN&-2w*PS&NSgDU-)rQz0_3-c%Hnx*pI$Bvi zYg`u6z+ywJ7=K?@w( zUte-_Mq-)Q)AAdJV;GT=ss5=( zT80+S8n#;cRZ$A*Y1pn6lNQXM$77EB1@hN^DkwZx7S!j#>#=Z&fy+I1KQyq4->#{# zdx9DW9?HwHIpb4!I*S?_i?ach^q9i1{k9!pF1O1%DHy_q13PvTAqX>3+OSS!m1?^3%#g@m5Jf?WnwD zZ20ezu4iQ76Y^6!CnGf6PTLp1n4ROV&cx%AqJG26Nq@?I9;1>cdxsu3C^OVUItE)#q0d7YPiyC<_ne7Gqe-0H2}dx29L8?tnN?g$urr4918JDy zS9zu@CIc({0x`jP3xy~VFOYHkFx zLRRoPwfkL}uZKH8Tl*j@ma`s=Lk~11d04srqM?%{BVt0R=MzfJnG^Yb22PN9IV8+; zOQ%fk_sgwoywIJ=asiVF6FKR_3DJ#WGEt&*;QX51DHGfjQ=j1zu5+fEx(^ zSsyxPn`rjD9ECEhBYsq}VxXTGJ&x`iT2%V}C|6d~UMY-;sel-%(k6{@KHi6Pf&A9a z$d^1`?W8tqc{vL6OCtDh@vISq`8)BHS(iP0$ zZcdzr9k3eibaND)Zn(O zed_l0Ne|I;R$q_~NV;1kzWm!@*JC1f4SqisyOJ0Yj;Pnk)7>gTug)OXx`9?Ih{Z(s zN}hD}d!0vuyETe#w#~|Ijp}C-yhEc<)OS}*HzbNWPNgWLz07%Hx_0{OSFaEmYn6(0 zaI*v%$Gh@-s5#eS(Sc6&@bmB3M&9)B)Q1Gkve>G=PeF)AYFTvI2Dr5+du;&6YFcWI z*XQ3e^a*+;4jD%VSBg2p*AgoxiPyrFc<>z=Y_g+@bX2}0G+RU5jzu8H$yyY(Rz|uD zw8XhSunH(4hZy|8a|Yvuj7*`Hq%o;#vV$@vfE2dcYSkB$x+NhC@Vs}j1xfi;*a21G%2gA5BaPcmTJjOs5ID+qOPI= z!8NyGV;WAhmgmjXY~WGJUdv+ED~vQN7IojEj@?VIzy3#_VRox*rdL_ zOOxNFg8xR2DCGAHrZq`^qvRNfXGrrp&XVeWKy|Bng*0N1ytXcKGq(OcEl0B@!DCow zXvEV7!+CxMc1&WMyq_iHS2uhiyD_mLY$c5fR8oURiDh2A(rc7>&8l29sK_+C$Rbl@ z<`Ii59#mw6U1YH-Qgy^4fk8!fer`GzFhv9d5AWD@gNoc|7rD+9x%dc0c$Wu`!+Ke1kLtyt2)TT{$8x{s#RW7myQ` zpIo`d7J$V0)jLl@?ezL}Mb_mPkj0_RYEOO(`XCL--)qSKa~#?#c8<#atFZC6<%`LD zvj9>z1zjCu^FXAtFCpK`rq61zqjjuWs{FSeW(6c^ss~Se%3oTIxX;^AUT4YCRcZ5j$C<1o2sH% zzH0JDn{ts2Mw>2;HWfsh#zmVZN1Lv|C}Ol}O0=mAW5m&>8Q76R1k9UYt)KbY1`cC* zTa?yHyXE=y2_G=dV0rXz(}8=We(l0J`t<#Ls}oq~`Z&{D`Vu`l3YQAw=3(=Rwn0uhzHi}|Onv^o zw7OaV0p8Nhn@ohj$3%SBL`bhqM4gEcXqpJ0i4Y*0h{+~GU~eK$G7&N*CgNxl(VU7% z(-D;oCVAf;=~d-TCiK1ug-qxT6IyCQ&zX=cIy%3>gk;qc`d<^0Wl!iACbY;mboy|KQ+-3VXc-qGttc^S|Y5~GPfrB8WSxMDP*R}%T2T( zg|%96#pEtE(GtO(q4kS<_<+vL$6Zx9i&#vf{6F5_1-{85`x{SbfB=OQELs({2r3F9 zET}ClSS)FaSPWKDP^dT5SY1U)kX!L-iqNQA;aA2J zt92#isAL}oJ}U{-*_qI?~mBVkA`6Lk1S2~RMJINpzYSNPQEJ+o9k zl7J}{nlmEwC8tbJV$4_-6-M& z?ktN(J#S_)r})8ULCj+mkppy=WuEewSxg>*?Fid4&nV&q?<~u8YP^}nWC6={mg|fn za-GhyEKq&SEGA#NMrT=IEUDsP=p@(R=$njEAHOa{kXed!;6GmT*%3LUu-} zhs^9|I%IGDf(=|n0A$S0@}i4ptC>1up~)U!l3eApjU}A#o#g_;j8cQm8qIX5@eW-h z0mc%OxgSR*WM`E6`#RlTGaa&DptB1@Sz<00on>c~dd|#lrbG7D&!xS>c$S!pPiNT~ zrEW2^w=Yt!>g>XxmY9oKXW1F0hM3vSbg2Dqon08&k~K&J(xn;8`Q=n^l)^X1lC^Ot zznp6FhtOen=c3#V8x|;`;hK~up+yMdm5G9fTVqY?!en5_|MBq48>oeW5+?1rqzYjwM_R4#=B@&5!aU zI(iRG@#Sxtf+7>)bagxa8im1YKd8pJF3J^$@idUazsh83rr3%!k2Eac%PI(H<8Gq}3l4#C? z@E;)73DoXihEJ!u0x`ZD7vM3v1&m5W!tTG7AYLvxdJI=#Muew#OyU^~>xxi~O!gOF zMU`>I{o#GAaa{OpX7Mq>qRsrJezG56;a4e$%*lh~(%W9w&8fB`1Dx$l?|{PBHc$w+ zS|*|NU_oB^6NHU9+3{@mb)N0dX0{B;mK}bA*%BLPV$O-FzFV7!`B)S4+mU6_W+sT_ zbe5GYL9I*5+QrN|QnCuqNM(ZuA}nvACYO`NhTY8)&{Nl8Zembv_^b5Pb>VL*=@N?f zk?`qM&mzWm<8|n%4;huznE#XEGQUszaQXJn8VPer9ix$$6?O{}fZF{t1&J&{Viu4n zISz?iHBSH4m_5|H9SOIIgt#WKJIuW4Rm3eubt}mNaMTF4NIfF|Mvu`NWf+P zE1DqYQhu(+#S<>$s4W20?!O$LPGuJiJRnFOqyDdZ9S&}JcT&+u*7p}$ux={eA-Cv1Mr^=U-=Aoot zGb*VhJ=eL%Qt$o=)x_s|FDY(Zcnq`nm|)Rny%n?j&ju{~9)wGd^_!qL@~Lh#*~kwT z3=8)_B;h4V@XN#BTQ&T`B)BuY7jW{Up74Sgs9$iBudRpqFyzA2iXPK~1zF)Yki>Um zrX~C*vyAU8iFFPMKWM`DCcy`XD^2*uB=~^vO(y)sBzRhw+6dzQ`y{wEe4z>dO%gmk ze3}WrJ_$ZLOfx8!GZFAn+u$6@{@_MjtqgyQr2!hIIHP;+lTP{LR<0n(K6DNFV}AGz zX6vNes@ZMbkf^=eu0n}q(U0*E*~bKnHuIOGVF_SP^(&iU$0XjgiY^=0LAx-0 z>4{4>jXBAC3S55oTk1+dpbVDVso$p_@z;C*hI=zzPp$Vgp^IP;RZz?wO!#!-XfqRZ&csFT`tGH~tYgir zw@X$Ly@ZL+Kp65bVud6n9g(s7#{iV$TaC)(^0LJosiN!@4n9{>n<3u|6rx#wWp_Kqy(xK+M2wmoFgx0po-=Ov^Gf9;tJpvl6|TjYapGKd z{)FS~+O>_2jAgy1K>qoqWZ^nAk@H~Ci<}1&!ml7qR`JD;6kRgHs~Aq27pF1#!57f= zSbfc1-uRC=Z06h^xm$y7bE@G0`EI-&OH4U4JPlE(orPT$nV4KCd8B&6EOdrm(pw-> zqtF=*1=Bz$OXNhOfHA$C>O;i%Zk&Nb`WyLt$+U1kTppb}ex&2sf{~8%CX96ajPLV` zMmp}p_vx38bld|$u>yae!oO{ojda{?#`VMBrTDiI|1QP9L5MqVqRw{>$~po6ekvU4 zScQKs{A)t~H&AB1W2ED1q(7;6q~m?S|Av3LfHfgph5UCQyccEt5#h!7J{k27$G@KV zuDy96WZP@NBBo$aoB-2;^YqNS&U@BYhwYpQZj#%^MeyK&4W`~Uq`c|CF?b=f z`)RRIl?4@I3m%?@p}n`fVg{awlvwP0yuB(eC{y<%$W2h84YK}#{E7?UH(XM9QZ*PQ zA`N!QaCs0{{qbQaftY{-G3?~m)fh2%Tjq)kZXf$bE&j=2y&csyC%w%)1*PxUPw0Ro$C1#@i=UnB}a-&BALN(PJhxB91*PgB&$nSHi(512Se6#06akaKd@!I0Zm^+hl($*R zIi34LJk}u&d1H1!FEC0!0s%$mqYRbPvdPzyF1Ah3sLyQ8$+i2ppzXM-mov`pe+!>E z3o&HY5;kdo??@NBe>J|B7Gz=N>M^D;%N|(CxYA7DkrXQ9r^26%&3h@{Dmw=R!EtYH zJB*Qb84wabi4qd;ndfm^KC&|mhzgyWYOChch8&RCD!scCbqRX0S%zzW9&VmW5s zFvY!F?TH({uI&C=_8IPrjluUCeqTC(G7BA+8I#$~@C#)3-;dzZ$yxqw=;_PQ(=-w> zCTAGG&CJ~e&r0YX`+av1R+0ugTVt;`&-iV6Vk^1dmP>!I084J8;XMk)Fju&}$elVf zEt0mQur*WkNhE4JSmf^26gDy+A1y|1Hd5{wa}vodKd!c1@Q6z`7wEk94Gb{xVBnmsJ8)# zdI7cQ*z;qY!X2j7rt zFF>++NQQFY0&omPm&&~Eh^zJb+w5II7Q-N@uryCA2>5qdWv z?W_3ih)|ko=YRC3iyTe(*NA_(fMV@J+cr=C&^<@pKm5-q2VUp0mZ>E;LUKiHh)=@> z6@=d>L&gO!9+dx;?V7T){kTr`_zJk;QpC|EeQm>sI?O0 zDvV&NdI~`*AM2U`3D(hvXs~V_*Q>gBv&EQtZS2Bn?S7c zdr%-P@~hWufNI-nX4lQ=vxDVEeWoqd*HeRqZk0Cb; z{B8{=z9#%-fnP1~#r1@XmS=Ax3s}r%2tfPYGwO(yne#5mnWal4&L(`iz-=1N7Mbwz z0&kUq>)2isey+fqG@R5h;e7>Oui>PX2|t1!C{r(JxUC)jrNCEcI4N(Y-zM;R8czC~ z@K*(Xorbe_O!y-LFV=AOoe5tg@DYTEmdD4#ZGa|>mKhR^k0tDHqQ+tlFiqCqH6S;q z2L#O8FJ&Yp_VDxU;g`0Pwfo=3W*l}Z^$-upGaEh?gAfO{dQYNmUp-{8035MaWuNICiw7B` zk-B+$ZK*g@H`83Tbc=K&RoY$_<~gq_%Mv-ue19h~Z&FSX9CUVSvZd+jWAG{s(-e2A zg?o-gE2fP)bZvMDn!%Qj+LmpDq6979#uw!K0_;>fVNMBwYH3Oy1i@n5bg$+>37sJ<#>e0A9l9`O7Uqf<#tF>A)DB&>6xLM=dnlJ7Zy|Bo@|73TuQavz=y4X!!UWE=6IOgvNIF^Y$)y=m-_SI4FDx!1O2O zzX%_=V$rJpftem2f{@9FGBBAT_6GV(N)VG%xoQ(=(h1Z0<^wVDYai@BS-WzwS2$kDA)%;BPlMYQeLaksHhOE5c;b-DNuo%Ry zJlSOEYe7C-vlfJ&Bi&3x4bWX5VXoY0Y=m2ilxcwc$`GUbVu-Zo7>gT`I6B*^Tz>%X zYSZ=|NQC2&CpWUs>v*(+d#1H@XM&?QLA}gt7CsRawC?R;Ss!`pTeNSuh^q>rU}X=G zI>E(UqYVdlN?joWd%M3yM?$zT)M!YQJl&!$2gyOOm=Gt=y8fM2-h?V+*9!OIaVcnv z%HV5k=Kc-`@L*NbT%izO08?GNrC409=$zYin5)cdA9Lk`3kjfPrn(O=d4&t8NH^91 z#gKkIOfAP{*MwBJB9$JDWak-7UYtG=ciT&v?EbC@;;q?=l&f>!r(2Av@Nx7N)+$(X zZXnAKI+`OkW9EJd;AR1C(?mxvQsDp^S7+v-AL>TcLdy40N*b4F{` zIPlklTtm9J2iy#&7Ao8fnRW}PY4`639Pi~0f_{Xf^DhW4?M6mSBRw!;zZZYq&37@| zF=z;w2V}5RjJX!sc1i_-Lw5fiNQPH9%J3SR40PN&YAr;HH9FK2pHJZv7sHJ8q?9Xq zPnz0_F(=n0n(=%DOl?$#GzxY(;zq7jUAF;k!rL-RJ%tM~rD_$1ywU1z6?E=2(Rr3l z8$<0BBXN`aG#z?VlJJbnNh}D2nH=d0EGx!1)d}rr0+;kKMxe#LRti4R zEO@!J)1?$^g)YSIuSQi+(=h)>0Ae_H!4pgsa6Yp|2Yd0m7T@`p2sLbI883RR#K^?O z6F3P+mTtzh^hp@n`*1fjz{_xa2_P$f`Xh&rz~7whN=((WvtcI3jH|(ipxD9d0pU-O z(p@hIdZCvP=!9fWKo^%|7KUzCS&@+yn>AldYbVSjIAucGU z#8Ava3!SQHZ5L>E4@@cz*LT{qNwIv}Fu|p1Sx(gtnIygY1!>?)+@xRw-v=LJ18?3P z>w#`)APF9hmz`)O#EF&SRjK=a?EUjdp&!R;=_9EO6dV}oA1 z2=9`?eHo}eT%&e{vkZOlP!6UzRp!TMxwk#b&rvW9bQCZD#71-B{hXrhqxt@KVx##Z zbYQ94y_2nS??#iM!^D*UHkpqXu|aciHYkrNnWOp0?`1T%aWqe4LBUFO1xB+TjSi$X zMCjr{9-*_i5-{mYS+3Lq?geg523ESl>~fAo^5s_b_}ge3FUP3Q&<7P`%hbd0!bhJa z-rJ%29GJyx1SaQD+T)dyy>{6@X zX5LuNK&f*|WMY~7DTpcIMH~r(ECm(0rRo%2OKMdXRNj{Xr84!zXZ*df4JF7X+F6DR zHtJ`{CUUl)OY^_niLpUSPknUs2G=~FMWT^2{=>ShBHNH3Ie4#Q_RmVDDZDf zK2x+~Qn{Z77MM#v9X1(0?#DITm)Bv=B<-Sy!aTlA{q-%h)%P6x4^HmT%R2T*hX_Eoxt_?!Xo`0O$AYz)!aeWo%{cXV9+5gsLn{zEh3l5-h=X?8=xmS}q+tvO<5E++nqR7t5z~ELKK{xHA z4$M0n$?e_>11|xXnp@Az_5kgUQ19_OS^}Nex#>cGT&)JfRbwb1VD(H0Ik2m(Lai8j z5ZS(c6SxLz2!Map@wvFf3o0$gu!LX@^d7MLCj)?M$Ia>wS?CRP7&{KaXKrgXboLHq zU&iaBx&XWeWlq06%VJ%J`KEjCG~$Bk*P_ZX%H!;h|LzvVn|pe8nyD`q#YKEa&j{I_k2(Zhr!Gt73g(O=R%_tl z6eykJ(tYoWvGOzj5g!gQY=;9|6ECzQ+J82*sOY7@Y|LH(P^}uJ!*-SHz~Jz*iuGJ> zu)JQAL}RJFqmqTdBpUxdjsr36qA~3ktznTdq#nV5Gitb{Hb>yGe{lr<>2(=_geQ!^ za|neeQVQYlkcH#6YZG<`ywf+0!|`(Pl-j(Laom13c!9N!+;XS`fsqUM1gqe zZ;+G~Vp)~&cH4rU?lG!9yF0F1a;fAb<{F>W`Hkq-<0cq^aqW?eS@py>9D75c{Lj;Inl^+G>SbbacJaeuxG@8l%7l~Nd3OOj94T8h|~UfBUd2M-bhE4?#8iD zdBj?H&t|spOR@0#Pg~fA#rL=t64;@IKOSHU8R1mVO=k-wCtA1wEn*8L4lT@u+9lS) zq=M9++slZxa6JrP;w^jyfrJ+NbqlY7q9E472RE^WQEC!?X`mk0hfV+Nq=f`_XklN$ zjuB3^Wg1&3InlyLsYpT#B@Qi|p4Q&Nq=M96aG+$Si?wj?4+$;Yfj~kF-_b3^&G~o> zYc{flr?G{to${`ey!4x}31tDRIy1*xao%ZQQcmG2Ws^%MdLq^j4XnoLcEIiaiTNvaFx^+1{>*8G0dgDKt*KqA3!*R zz?+UBT(l-;J;Tg83t3`WvzT?Yne`!^_2Uikto>1I->T4A$N^`6>N9Llf{tqDnQi8| zLFai&@>Gq(>40dUX1dg5Vj!BC2ayJ5Dts!csL)mIh^V`fT;rZ@BH0%;^+pxHWfg&J zRLEL-N-dswXwW6?SjEy#mb7_h+Ru>yQ~GkGJ>mGYXG+?9Gwo|SZ5GmggN@G8^s1jm zEa+GD6LDx%hp@v7%4yG1N2IK}yV{I2Mr*||s@3k1tT5=u+K%imNR-ey6HUm_t+Jve zYo(MCs1dowo4H2mTz7Yx%f|LguF*PIFEiKwfaRmEyiRlFBi97U#e*r-^)ZrhBsAz; z-P&^{bY~aj>cd=)WytchnS~~rsOY12I~xI6$g&UnsGws7vfL?IJU1cv>Q0lB25Thw zN+i$M$uB~3?=L2=l;jU1d0(BpJCYY7dDO=vYomt0A^q*E$2YgYZV}JAyoAjj{H@)( zjln5SHS*68>~1~8(Da}rt{545ryEDh^w8@R>wbK;ihGy%CiXrQF+BfP-u3otpl{Up}wT`}sQiG>Q&V@vm3MsQxEl-Ny&vUd6<~(CW9r7K1z?5YO4B2#rNg3~^KNM)Y%U zgTsd$Rk)yu@ezI+9J?+Z`CKgN7RiSjLRSlsN1GG%2;vOU!Xs_&7^-03nwtmL>CZIP+*dh36Z?7t{)|NmZI zRpnRb!w9b@9YXyXo3se5wp-k<=%Ls%j*J@3-(Q#wGg3UUUR5<1KcdGajLd9(r&A_w*w1>+cR-G`K?- zb>`=sMZ}d7rnSKHf2G7Eg+oeOiE6Q)j)YEvptw$A`Cc5S*07cK0F@xn(t5#0r~m~4 zQX_Y6$kO%W0V%;WK2-h<9h8<9eOk`}5Yodydqc=WrE9+)`b zfV9*rJ1_QLYJ4lRN*)gJgKsKToj#Ls)C+X8%DK`F7pmj##wG9kPjkHi_Ow840Q zwHXo@GMFNF_ucRZiez}kB!%xmM5Qo1>IMZDPKYI&x2rlGYZ^F1jB6#fI^l+=G!Fwl zu4#SyQ_w~b(rphMa(er#pPPY%L8S4Pi;pNp#;C6W6gnJr3T;4;3aitl@ln;d353PM zid7fyjKDjUtuUCPn+lz%nBIzMKp9NIEuOQ5R&aU(Pu);!$)eW-U7i;HJ%|E$TG)pV zxDZN%kwqTpTBh!zL@0NDb#UIR|0;ku_kIR9{uEpG-)_b>3K7Dc`@8X`r;aI|Byn`Biy%?)h672b>;C%U(JqTJ_TmPp_(NXbw#AGOpg=Kp2A6~P(7L)-_0K0k zu!`Z(*0riukU$QUdt;e(zW@#&eiZrL#UPMNWxNm@hr?KCWovxtfFk~Q&9b%}6LuI1 zF&^^cqaUO45H}*29E61=K!06bRQ8{xN6tsxur_%SwX5}?Yae00cbUgxU)B#b>pW^5 zl1IMgme7!`4UEVrhpJz%k!8XEYmV}m5m~GH-K!cb7j1ATK_jyK*N!tHBT|~T9%n?x zC^QFLRW%?Z*mwscvi7`5{6UjInj2>lYQ>%oBv3i8K+riKEf5Kga?X!DNaHC=k^uKv z3_80i%d&y;TRw~s8ce9S80#PoF%(Yh?j53ysGy~VAXf$U6n|cQa z-r-A7O}kjPLbBTZ=K|U;XSGXf>i3BS{0i#@SO1^UE0Q`c*)2#(DO0^@P~2LE8{4W3 z>c2vlDn)L+FSak+icApc?yJM!GIh;+{7%y5H`59AC?g||UY~$(+-5?BsEz?RakR1G!ShQ{+k`kXy`Am6PkcpvEo08RQ4;$ByX; zn#YacKwE&ePKwbMdJvs~wGuK`KKd_4A#{%T$qIgkirW2NxVr z>_i^q${M7Fl!;RegS02P_WlXYYlHdHdeA4lg#4t2ai*xb>3K|FbrVZ$S5$ocNNg&= z9c18HkkH#wnCop0dNHZ;$Yf*!nnld{D<{>NEJBmO_Y9{eYv>PA^eTx?MYQi3G6|$g zvTNMzo_!Mg;S8J@7>^OP>4AOI;l+5nIt$2^szzWF8D*wA0S9b_PTfjd#TeLglqstWAJsc{9ALpo71RPE;ogW?h~f#zEI*vp_Lj6d)snP-T3dj|powC&~|M)q80PFX8q zxPhnXaZT>1w}&>L$1P=?9-&Mwpt$>cAK3TfYP0Bgo^TJNzeVy9wgTY}w!9-Zpk|EoxnHjD!+_yW+ z=v6x!6wPhC#~Rq??Sl7@;msEB1jL@PW63W;%Eb;!orp09V_4jq6mI`)3sxT-{lKyu^+GTNe1ypQ5kFOt>OdrveMc2W@6*x&~~ z{04`quE4yeV7Gh>FamqzBg+Uh$;V(LuwOog7=dQ_7#81JmX1go|1zQy zFxP#LCk79Op523{m^Y$iz~Rc;7LKpE55vORyn@-PdcO~LurIVc18t_;@ozuG;nMQk z5u${qK1VP}Ehuh%Q5v9xr?yF&EC?f)>u1*8R6@%Sycs!4vcXq3d-@T(5}9*mRrfwv=cZD?^C+UpFi+AS$sku$hzhkUP--&*;7M}F(& zcZ>Ws%I`}4*3Fjh{qmcK-)Mg~v=HcNc7Ur=9QK0|`(~knDAA zy$K)q4%Jt~1irYKa9WV*%W+k83IIHgGz)DAEoOjE-+fe7M^ais^2gJy43KjyRduAb zCA64-BpJMl>3aI3{+Dj+g8H|B;=bny=9M#!FAS|->i(-x%VG{Xsa>7VjxiQCLm$Jul#^hCO#bk5{yrlxdY|7kO%;6cWE){{_HQZd5%I%d3OOALFb`WmOqFthiy zckPJ#&~ffGETqBpgsMya002&ZxKOe^*rMb-ipI8KlOkIlV^?r}Gdf;f1u*w0OAv_G zFf&HpN)vcDfIi%&*`R>02iDo&V4AU9JX#OUD4rue6y%;Szh3@JvIEg1^avRL6xMESgI1`vZm1GeT&+?-`b6*}%yphpgM!LLXX6s3dL(A+k(_OzWNY`ItFzTJ+lLPbk_QAy*hN}Aed9rO|Mnr;G{1lZ!v zByfTW+$_LWcNT#cn7~&6bPoXp%=lCjhJLWPo1h86nCx!C76XQ-D0h{+^a=VBs7>Jy z*w`Md*#mTfKCaqooPnGZ_|?cY5xpst;Nt5!851%(XGHYE)k{V?q8C1iU-kGb>}sJb zk!b;4$&<{w2|#0O{k12pxpFbPt@Krkkp_|oj?eAVuM5s}9H z1tvpT3;A6$6tM5)C5%x?>*lxbVgbuk-*R=wbTd~JybTcwF|FHD1)C5|#}{6Mrorr0 zUpD-P5g{))h?MAFE6SYfK_jr>Gb8)I- zV(XOXh*DLCuGGoUx~ee~8{4`>8cR6DT|S?t&(4C5CS{umJa9Fk zU9h@RQezng_W(}zz+PlC3TDLxl?Qo66{M#w@mD%%kmEwBOwQ z$DGE@pM}&3+u)dXAQWImkxC4G>mLdUm_n_G(j10P81tEhXX$Lkzi&D(7?@}I`_NRJ z+%pehB5>__3xQbkc@=@xv-#hh&{^}(FYK)OuV8R=-hAAT>w_j5d(cp*-zL&`S*v~7 zl^CjquaT`UX$?KdIx(StS)-nG7{}B&jO&fogx+P~I9kM*LxNb%Mkld{eYF%!1+0FJ zLnEgqE%dJ%YHY8-PAf(b)hu@$yytc3_;n4~Y3NeS0n*DM6p9q^DHA;PA~QJ@VntIh znb!*!jCy*Txysb5sJw0(_^QjCx-i6am8nMo{w13FXxHl_O>sX79`0N1%aIxqtc*Ph zzIHzpv`9l))+o;KZ9E1STnjHY@@*4wvKE?c4b8I|-SEy+Ka1x?!@ktnf6SErcc(2a zKB?-NY@Qb5bdN3^gz_zspo4#2gta>7>*yd zm!JcT8X_1QbURfO)?Rep&gdJ}Xq@`}mmGt3|BoCfTTzEub}eIL8ki32fD8z|m3as{ z;<$?pc7VBbq$FjT2Ba#WLk#+|fD1aDDY5g3VYOWy!19He+_CR#ah90e_x1wa_y0k! zuLo|O^!jRmea{dPO9ba1q)v1#TN~pv1*p`h;o1?a`h4=0_a4RwhTc#=3yHU=Wfj0- z1rmbYcE|OTi6}biYlgIL7=tl55~ky2G95EHV*dSf)C?z?|HkLwzvDx+AcS4}%@mq5L2 za=FfEdkjpalTrR5jp(m)JTTOIbaqa({R^wzN5O zGI1&gO`X;>I9kJR6U%~GKqOfJruT`*5a(9-QG*t1Nmd-Pbn*1Yd9AWzn}l=SNGfit z;eB;5WQ;p=Jv?4mh5|0doV;4R1?!8?%m#qT}FsQ1iyASdaV*B$1bL=c;sO;e?RX>k~bU)pF5xLZ+mGKdXPI>uO?3|1z zkykC9fzR#g>Fco}SlA?(O(A&L2#5S*B z0Z;jejMh}+*RVOGQ($58Fup}Y!!SDi@#OG&*=0qIUD!Yw+ycS+o4c$ky-{+hhFs)N zh_8J(7V{^@zzdFcr+%Dj&NI;6h?P_AoW=JgN+c6zlmLH4xNXImQCZY|gyAClfTEEF2bzO&O zLna3v|LFtI24p~pe}tmvE>ret;(3c&tGucQDw)gc(#W4I#q+nSMF-zs){ ztgb++LzD;m0Qcn_W~ukL58oI==#Ir%>%5GeW$NuEs6vK}#dAfHOvKHf7CS^07N3QL z>shGkmT_t4cmr?wGfL81Myj=LK**3P%?GZ`W`VR6 zfYEYqEbr|TSa0BlI+{j(Xuem?$EwTSIcO^$tUiQ0_mHrV3ZY&CMrqEio;+g}$F zZlGwL0J{`0q@!H>kq__L(qd%4dLB0brq_1Ow^W5GID=X#;)rx2NV7U+1qOvXmuTk`?F%V_VITjAMxPJ!ISz0eZ^~le&$8US4L!S-A40`Z z2S{;9)1a|$%Hk*xd-|=MKFXxI~d9o zbuaKCj+kFauV(9DQ?!QJ)%7~4qBYE^u4K@i$9BwHj!(3}w`B+kr;SYH5=2)X4&>{t zBU~<49rgtdzm8UolRkVL5G8>Os zfRFnUWEncMDTKi{ss!u$IE3L}083b^IuiiH!Eb9|-vT)LWqXaykBr(hbQA8evK|@> z<+Ik8L$St4t#o37Yu?hDi&1Tkx0xfLSv@-!BOnLsviOkr14He@qng2vs=Uo$4rSOH z=$(B5>M>e72;O%8OE~j&g;(L1Dly-B%JLTPWw-=HMf9a*38(N=Lj_jsYyS${Wn*^& z9Lj*hMi?G}8#LGW%S=o&?pIhAZ|+#-g7KcZJt zN7n;P0e0G0TUQr*?$K>`4Za~9ZK!|fY^y6eLY)m^N3(6Uc?L#8x_dT?f=0GCB7AM>_P}XKJ?c>IF*%`( z{*IdVr@bV3%~}-Y8JAPTb>DN57Qx_j3LzN$z|TI`*!V|_kyQGcr~-AqXdhF`J0p{Z6(*tjw>NptYj z3zVq^tgbqZY?|M6gmB)6_zV4k#DQ?(-LjnYHzDr#dhs+OJQ^s#q)+U<;HC$-K~m`s z`-TeiUbKcNhH7|1s@6?Jf$@hxx_Hn$!4*_BD$;j2NS!j@UbRI zhJHG9ck267po|}nQRM<@4BrG~J$HQ*a#4+m^EK1aW4jved32L+{RpJ9c>B5Q1mSET zJbik28KR;!EJ6*?c=_5-ZEv1K+#VQB+}0C3^Z^!PtY>;5^QBxhCc<5saU}Osx`+1D zq~0FFISd!PVJvbNt_}^|m1+>f+{T4tcrRurI#l&xY>92?uFwPXltrLqNUbIx5{@=z9R$7>NTG4w__;oz+pSMp6US$ByJfpSYf3l z6)EZ?Y~_6GGk+m=Kc{oU;ilx1Y;cj<#bgi)v(ndcT`BzTmBBp8e_TSA%v@(cM;v9>OiOG@dxAp{JmC$aU0=-^e6wk!?(( zE$W_ydXn<&9Y>y~Eozs0IX&#lzD3?Lb6WgSijG}~j9_yO-yvziaccFWVD>>@8j;g_ zWFwv5Fhzr$rxzzo(2@fwHC$vui#N{1W{zC&Fud(zRBe<9Y?IP zg;TaNb|HLbuf+0Ms*YU*5|yl!CHJ<=uyIAw%$ypseot3lW0Vf;GpQ?n54=hz?4q_| zkl>Am9$b`t#2Qzf_^Y`c%2hvs;eiCbqq3EES7U<~naWPj(Jr_SsFUv`GZDj5oIlZE zbmsyZjNV1KuQE-9wlwv_9SBn4l4O#xDT8fr2W8(^c>$`Hf-n(cLZfimzv8ETx34VDf9Z>TvG>N0? zTdt*!(ysSZml{>T&1tj2OrSv(Zlz#v+8j*vU1IT`YKF#Eu9vn zC24gfIm{rqcq?@~DuA6j)ZQ_-O;=$~S6J09EUBaRO~(Tn)?lX5-ThK9}t6o%bsda16y44P!|T!mF@4|oIC z`pg&_Ai)NbKz%%n-I?yYm!0q?rV!c_!~Q&Azag!&Mr-qaJX_fLbzAj47iAo4oAMB> z5L=?JHe>oib9D1>@F#9kVb+Cp_4DF#K$*Umm)onQ!iIV z7yQpPD<9huu2i@n=&*S%HBQa_9E_kt>p~9Ya!%os0nz^Zab_zYz!Mg=OhX^z^?{tzjvl($;VQ%K*?YR%l8=?|ZYaERH&1`24H4Mx z^|5rX(r>qQWm5M7kO{S_F(88BP0uOM@Sa3&wCPq38gH*?Zzc=F8V>Y&oC8~M^Z-ZM zg*AKAb&}d{EE#VRtKP*aU39qJ-;>h~hd|<%+ez<}Qvkuz6=((OF);GI zii+bwyv>B*A*nds1H?F*uwJIIhNCDs{3sh>L}&LiU3apkyAsC{iWPGYB(mn z9t+3>F>XKZDA@xF18Ncc_@YBSk3}zJm#~vw1tLaCMm{{rTmuGBlHs0*?o>BOAVzDq zo3O7?0{LZa)x{WHXSR2R`zl6nk?2}KBE4N}odBUUr^+;oy_{)!Ay8(F;1!mounU6}my(NY9*^2RvQbj!*Sa=m|6{QmQkF^08YuEaF3{Ip#MGS3tb! z;lJQu)f`S#i$u<#B0=8g&`^+E=&EkN1vPct8*fV2cam)wSu_sAx@h-5h?Z3hXVrzj z)v}Tg5aUAf;(Tz)BdF53HPD7XxzL}CbppOVqX7030z=Py3PY=^>|9UxtpN_XTx9wm znFybR1b~U&hPhkyPS>9q?dhq(%&E&j24-}s+wT!8_^uEixG@xaY@&&GaEw)ytbET= z&f#0$vwd~knp!*~jKzL@73UCJIu*#^#jc!HdB_}E%wKzed!`22c`M%N zFzTprHQ(zUa2I#gm!l-S0Zq73w*#3FORHc5)`j3;j5X@mj?gRoMXa5TaHh+zEjSZ+ z&0};Of3Y&!L{)AJo?$FrAaMRB!Rx9Be}%uD6(_dICXNFq5sMdY5*$etO|MWLsg_u1 zw%BtUW3@eU%+UDLY%%a|H&Fg`(N-ELXP@rr>WY3^efqWKGq2gqZUp7DF;(tnZy&gQ zmE!IGbsTYZ>ole$i|1}4bP^FV>T28JGXx%;CGdCJ;S&V@jfU5^!-olcmxga?hi3@< zO$~2shaZ*BdV=uaD&iAd#oB|bSXXcrONN=h{4y8D#OB(1t}?}#*^63u8(xg8^btCj z#NZ`tfBP_@aoAkH6z{KbYIa_y8A<(yOO_i+wn5uHzvY zaJ@A3!3LDTpiMM*p9P^R-D<5!cPR%C$12lfhf7-K3O%?7bE(71PEdRaj#-}E@dv6* z80Az0(}0S6Q)P0v9witVKn(9;K7r~>T7%=QAxD!_ACJLxZN&iR%?*x!K$rIxuCCz8 zL<;FPbr5c*crOhzIML;Pnr1vEeT)Y(QFP!#yWa+amAOos9Kd$HBU!!&S-uaBz%xm3 zN#0c?U{eW)C!*NkDOaj-yzr8&o8yyH4jXR%95&kY2JZcebRhtiB17zf(FUhVWmZz~ zsK~i73ewD4Q!qj0lw^A?WvO8gk%EkHsxNwyf|3&ye0>8c$Y$a_^gohk1KtV#| z6vTm=x(7D{%dZ8=;Ics|H3d@L%rxv;Mq#s(=2D-Nn+F|fv`$R}>rTTpU#ObmIQur< z3y-fQX;Zx2)zjBu=Z3w|UpaZEV^4rR9GSg0OIuwYx(JxH#`X>qaJV-;I4a!0Vd}6g zwa{z*s|e&}d4G-TQA0tQHtRhDjnqYsv?{mK?R;=f--6x;L_F zY^Zb-H^9+t1RI~joTq4F7+V9R0s>WV1Yxck+WQ7pI=P{khEuz}cE5)^sr6at0C4SF z5U5CVuYh){Ouc!REPjD20Tg5WGWGdv4Z4JxXy$Sd9j)6`(WS!#V-)p~p#Z;rT zW5b~B?n3Vp78_%5dx51?7t={0dX~y1J)7FFlH-f%d1>#c`m=;tTE%dTtGh9HTj>Id zh74{xlX0odTuOMq|4#SA=nR*7Ee0reFUup~sTg3KdxfM}5d)m>ZjluC#sCA{)so_l z7@!xPa|_jA?`4S$XmGUQFO;Gg4E9D4lNrG+_{D|46mPevk7pW~U$Pa2W35lhv7Vj- zH?EpYY!n^=QQsgVWUn5kwPa)x;^U1*d_#LYYm5w~_^FEs)nuUxoS6OtybuF3U4vP$ zOZ^J78y%N}f#j#7C12&yF5Ve7Gr zMW_~&Jt;-4^ThwU80yPgoY?UAcXrpk2ReE3O`*Izd-hKf%;_A6i-*E@t^ zKETUe7q`oD<}yI}6Vkw5+#F6b+ePuxoLU`ih#4iSeyk3w)f%A`VO*#lfw>y@Nb}IU zrYvb*(`<`+25Jb?{Y$6wJLBoXdH8IvpYrD~)Gwkbx=tUk0fln~1p&8LcDt5gSy{DI z=CPYnEjDH9OqdamissB8;OP^Sb(aTV;e1k=4$4eWpWVk%phe*;Mxupy=n@|0a7GVi z_vkg`)Tf7e(}RSEYh}y@3J4QWQtTM`!T+QoLdY9e#401s&Nt;yWK;}ieb*I49HAjh zvsTh1wd=A~m|=npboZ9@AL*w0Ie&5#ZQSlXRP=Z)>; zh|}2~cp3fHt8qg%xE*b6+uN&)(~!i;OIw=c2bDW2DaZadeqI5HpsEdc|c@aN<``t9o zi*X`w>K7+Jp+Np7xDUiA$WWE^&$JuE1-nSK`&QXu7DX5H^xarojo;8Tyl~?gjS_O< zAhC79dA^2j)E3t*;8bg{RzRWH61`Zhl)T>4`TRhG6`T8oe?M-A4e6|IH?nCzEZra^ zL2ip(oa3t)>mF*q*brRIq?p3dH~68B;-CbIhow_eLgQ2D>8UGxKH;ue;}n&Deurio zWhlA~rz^LhGN2xw0~sjx*z}dgw48abd>OMVao$HU}jW+>bqR2N)36+Knr@A;#;zoFqVbV&q&5m0*rGwZ-?G5;VCegyj57x9hOmkw z)#VvgBtbYYGc3_gJz>H%0OIL)dmkSZ}rzSWd#Yk%bMZko>h zCRJ*Bzq#H5PRqxY#MYqWy|_?l2imS|H)1?vJK!#ciI)khxEUzmyrVK#Olypd=-^YH zS| zhii0`1BWpB;h?oE)3i1?4xqgjqX;gd4!oT?2Q$)YGk!|kzD}HSCG})GdD^)p?Qqkn z_4z?ZGtRZnwnT=%Jp@^>l*Ddjn2De2ka%GO9v#D+7{ik8zJ>E0RY2k9!1+#tqg7lT zAnMz5F{N-6+Kh*SaGI8)3X!%d3zLbCdd5P+fL9YZMn%$LQi>-vKhjm~e_;NAB&Q$= zPss2HI_`3JFH?t0F((b_3i>lebA4OW_(WU|-L6`>Ns;&OZkA^_thxtohLfY4Z>vx9 zskEDej(_6B6Q1ocsc|AIbhf|g_$Oq<{c0M3sjUoR^O)P}F%;J)u7Y?Cy^B27kRvYPJQ*$=+rOU8*ozRWycF1l;34SPqdt|T+|g*BjNveH4_3@8QDpm>nA-y01@jY} zot^~-gmb%#;zQ2vufe!AnU~%F90GZR?EY2w8)sqg($iYY8Jk;Q}!2V9%2;N~z=ioIgwFd?|R}K_-bFkzGmbm~0z@$hQNyE3> z07z|Pft>7ZxTS|7ZWN3dwJqp)+$cy3I-bPU*`Q-J3>t03XDzNJ$;UdQ;Hsdb)+m@3 zbiAX@<#RWB>^a72Fy98p3n&NPA%Z0@Xy^+9T@!<@0a9?8Y3wATRttWA7;I6W-H?D@ z$nm&SZ3iR?KfLb-jN{fv3jFQ4xZ>p@rs;FUd)p~tW)4Vsp9Q_w+xXM`1 zsCW(O$Jg*QN^9@g8YWlElWXwwrlR;8=nunt@Dq2%(2QWE<3xBmUrQ@(rPSk|j4VfL#{Ny8?G!(^l4R-p+k3+kEDG-UyaqEEy)oX9F z#(}6Yat@{o;ycOcnQGK9iX`Y7bH;Q$YOi0LjM}pZC!prB)8O0gKZ=PO{sz5>>jf}L z=&U}N)EB3CN`3POTRbH|m=$-I>1eg6QZKbFN3hR>a1@)cDw~zZcu2_6jN_~1>g|DT zXu>aagH)(bVtn&)>3t%*1(o)SRru}%J&+4LjYMPfwc%k-;~p@ z?ZH4TVCp?QZ4?Z=BhmFbZM_7xNZLmH!saEgg=rr_TB*GW&|sjEus{s9Utl{3yGzR4 z&0=8W!vU_3eM6xGfI&r9V#D=vxr2VAk#EJCn71|*SV_HGnL0Tm#xuZ`qcv41R&|ZT zoMyVXE!7EHd_ML)Duc%fhs_#H(Y3~|u>Vm9Wef!N0|6M~;x`y*#xIFY7;c>x`=Y6y zS=uV$T_+`LTzb&%KhOq?=ah~YO`Pf+7pN0ApK;r?s8GX$Jhf;#8@}KKAdK?e+^BKo z?J@&wDvGHFBUf`I?&3)7EhEvAuD-m6Wg5FoZpX|{wFAHeZs+OG!EhFiJaKkeI~8YI z;eHI%yZ}VW-033?R$=r?BDW*Xfk`k;qBmKMF|vBdX%=?L*iS}bga~_DSjBk%MojuJ zCq3{!GIUdg^@FycqY()q7GS&Z15k$NQKDD^bNd4!MM4!9K zzWn?+xCcGz;E97s*WlFsumu{QhO|A5+3Aym-rWT5Hhu_M$KiDDgXY{Hz`PcoXiOZ! zJN12i8*Oa3)#?2a@QuxQ>!8VjPRFGMDrV4XyfV3$WW>7_rW2n5+}SD5Kv;iPWIZzd z@DYBblviXK?|<~QgiF+*(TjlRA)KSx8oG1bKuK?A&-%}^AO8H*L%y%Oz=}@i^`ahQ zJLU@hhjUnE{|*Bf`&x;`*%e~*ZN3H^ZXiKJcM!5z!c4EjiIgG&hp&k5fo>XG!+J+GMMoFQJo+( z`g?Q^e5Q262(-Y86iAlrz)qXpr8lnE6AkZvVggfcd0-hc;SZZI6L@h1wmPjOG^@6S z@*0go5ZW`$q;i8pk&K$yr1VWnNIiLgF;xx9SQMOU^7T>m*!IS$J|?Fy>whmJD_(}N zN$>f(1iQoaE9!=0d9Y?s!l9x#Vcf1B!%T$1ZZg?P^L+F)DK33OI^D&T(o9W!V<(a+ zTYGy0CxakS$9`}=$Np0> z&6Te8n%wORF2&HO7-Nin7+eqUUrm*x!_(V=mU05eqmhAq^QLJ8~PPxonq7*HBbQu?-Tp|Ky;t!m1VoS0>zc8AI8IT*h?Hn zZ?fGO!rN(oY<;f{Lpr7_8Gtp38-F|nJN_h$>bdF0%w{_FH;-I%TcNyJFhaKx)*j?v zR>N9taGeSEavHmEJ5Qba50se7dwPymT-aK;8%09l0?!cGoV|4wmpVN6%g$a0Ln@al z18UQAD_fwds%#eX@MiTtHy(xz^1NRukC4Gibs&(?+v3J~*5+ zGu`gz6(-RlXUGRG0QAB~9p{}(1&UEFnxw}4$pBkd-;eIt)T8e zNoA@pX(Oh;+tmy}N>%g{KtQR;*=9nABvb^O2}eo7PY5|~(ufrxjY!1)ZzZW!i@~1b zO{?r>%*1i8!hDaMvZykRw*UaC1ndA|IMHv$U&Cj`c*ZzA$0&wC=E-uW55_|zwkgrs z=^;m&Q|+9&-r^R400DBm~VhVDlN_GM=w$eOylCp6({^ZsTn2w%!@S9byaC<9Yc zJJc}7%GFIM%(0wd2jYH*774I9G@UV}yV`GYibsvZZe(?&josb7i)F!pv25AG?qi>{ zBh+Us8??|dmX5M3$Ds(_j2=ADu#Va$uam=Z@L;EVovsB_zr*E0spA3E5ptx1FQuvG ztAG^_Q4V7FEZ15^p3`T^*o})vsm?9IbpvDNKV~B``%r$V8in$q?w`52b|D9U1oLQ7 z3-vtcG2u3F3(ytXUiB z5EtpHHeQa>IloM zcdnz=dlI;UcK}w2QtS&PJxLVVfu!mZEPzC)1+&%zuAi>%yNpaJU5yyaMwA?c`Zm#K zES)zEj~Ey8zJ^hl2?M9@p6|KrVdlBi&w0oc`SRNG&2k+C0uK+#y@cuo6QNsl$fo0_ z>kwC2#7&aWMJOD$QsWrFy^*I$?MlqIMJS9Y$Fx8V@)hA4yRc7jt2;`xV%?ahe>DrDBx??W&%oS7QtQfPNO0HkogR zTw@QAk5>#(JGl;Gr3lpX-V-F~M)eWOpaka|M~|&3UTd%${J)i?1;=Nizc$Q(K0aaK zg&t(VNeArE>52k8G&^N!H!Ll^a2nX%75xbNrSC%T5*>o|;*vMh?tdMqIIFuy`wzi5 z0L{8BEljB{N;C6ye!Yaf17D(w+MaJ9*05IxUu#C zwUC05MB}*9^L;yJo^$egdj{q8^qlc;D~Nn#T)39j#^*r$Mbz9RjWhZQjDs!*1no5K zk$r8m%<#hg?u}p*Je>O*l;oK7VLouBw%b8N%$xXG^NC~FFXO_zO=gyUUA%M{ZAx{NY zg<0K-<8%GoC)S?AG(8I(I#*f*p7n%SYvZ}jjMepCdoFX9*>x`PdKv5L3WtpIKo&Fx z?T;UXv(c2;JgJ_5JL)iSycYAk+;q3SjYrBGq0zPli><+8{H6tq(}Tqs!Q#x#JCgrP z^#9IdXt4>$fDaaqMld5-m;t3YKRE%LfF@GlJ#m z!Sb|Vxi#pr1Zac46`Vu1EOqoEgQ@ODPO`K+r@3($SI?2!oPULp)~a!1 zyr&wIMu&=0a$C^>IJ6#xZGtCPS-*h#B&X_<3%qCI{e=s>1KPWyoNfC5XgeSHsETXx zZ;}NTSl9)EM2(v2s!>oQK_w(&Amk4aaFdV?C<1LMZ@Z6L3cE;a2uU}=Y%Yt~qEB0& zPg~pPt3IXGD*h?|N$@|SRV-GqrFGK9HVTCx$o{@(?%mBMfVKVno*&uVJ9p;HnVB=^ zoH=vmjF>2H2Uh2|`4I@o!fN;1pitW-ysCtcNk%f2HT);M>3wcdTHh@^Idsz{cbA(NRnlS)vQHF$;>m zT5m7L9M)QyZzj); zvE6=$uDQ~x+12v4u>F#8M&o<%5Z2!nk&+6THIDf73S1guhh&na&EI5`avddO#7Y;r zJxl$Hy#?*5;%Xj97yFCpf3G?$LX;M{TK18T4dBS_V<7gyUe$IrbMNbU%%PHT;T4r^ zvVEUoG9?bGdiu${(fd}?m<0YtJ&g{kL6b#5$#8^$7oCY*iqAyR>PERbjB?e5G4Wtq z8v5J-^f|o64za$wc~WCRPVlqFf(t|5Nr4NiRJI-m@v13qA21QQYe@_=czySbK6f#? zw99h6fGJksgb4vnAD4lpL8WO%-T4+MP`*>PrTn{Cafz=@da}j8B02U|p``AAXC&_$ zlCudx5XO#kMKo6J(K#4(Xhq7=I^$u`ElwurW<0zpQ}5m zORY+L%cpXm%F-2cA*4AZUrl@+nK~TDuSyIDrz3A4!*D!3kO2evE4HQ!29<7&Q6syBl}^{(pG;xAFvBW5OD6$p0j7Lq(b6~wm^*_WJTd!^bVES5~F z+A2?{o#Z|Z(baMh1ED9`IXs+cl3iwHKEjB~BzsHO{E-%?G8w#}BlJYOg%im=lS`>t zde|A9)2G=ixHv=e_6>cSjhk{x51W~OX=Y0Huv4WUkscPJ73G8aUXcd(`v;YM^UG8= z<&?_qmVNITU5sdSoFhp)_p-mKTjpy18jq)KUH8N<(YiOyOxB=EP!JClQd{RB;QDvy zPX4~gHqCMFW>!cimyGKuk%L;c#)%W7Gt(li?cRnUBW<(Z~6svs_zHG{u!TEyTICuJh<$pnAx>rP^5aKrybfCT^HEH%X zUY<@%h_7BRUFB-|5iQb$c$c*E3=-!-ojLR!B#!?nUF+8pwSHY{-5}I(RQCFGt=r`3 zw6)fmfO4sE`9)`{ZLFCI`L?&N^QZKv{}Em1U&kiKL_EHw-Up@LRZ<%-_wr(Nt0la0 z%!#Nkh4KWC&*!fegLUdr3k1hGLe9=|fxV7mb?OI+59Men1vk5$YXRK|UY@OK7xHq53ObTmOffIJTb>`ExH~;q$El=XHQOr}*ZC{KL%oOumPWZ+ zSf+z%7utsUgh=Y0q8A9A6iYU?Y2c=2C~iH2`V&_X$a#@5eu z2bbiTW|N`0(!F{F}lFCMD@-8D~Y)}@tS1fy^@%%6LXS@Ld|}+P8^&}6qU{I z(1}MlKckz}JVz33I`P9~;uJ~j)_wa*GVv-B19pFxPX2Jb=5@{QL!f~|X~|b7mKYy(~{nV3)*P>x~ddPBjWh#bsV!=XT*qDZtjt1p=~@ zBV6`D`M504e*k=Z>f$7tqQX6QU~=D@d}>d*uE+BIJ{Vg1T=!{mJ=Qx{Y=Zwi-QXQp zm^~IMOvR|@N`v4<8WU;IeUg>lB|wMPub|kGY>Xr6<+!Z5;0vHc$$~F>33)Lg%rjUv zTIMSbn>Z3N{?rp%@v0w8=(CmmjVY_ObA*oXXUm1?F2hb_UN0ihmJtU*EIwWAW?_rE zaHxXnOy*qTI-9k*j40&&522&ZkUpV7T;P zdS@7rcz(-?tO0!P{1g$dA>PM_$g)Z~k&+|FSBA*(l|ey{uM7;~v;Pt3HIBb3RMu9J zRxDYLN|sM0%g1ueMFsln)vlL(s)ijElgvkbr6ki_PF+DSi2`;on86j-pxB8?H12O3 zVM?aQ4?15 zH*^LTk{XAYAW}!0b8M|M4yg-{aRVVPKfs!C$loeG5<1c9P~p)?jBf7TRYZBrid<*K zQd58HCjWrQZFaus4QV;aK%JZz%E4keg!6lYI59*Aa$*Q=tu2j1f)<7WSWFVD!Y{%q zLM=vDB=nw%7beY&R?J8Tzj&zF3V4nNd{KWf)E9;>D3-2sG`|=u;5CRvQxnHum`2nQ z`%~kwOGB3@^Ni#*h|OB(X;0>1>u;RoiCqbt%iFdVO$>VIf*iUan=Z&I8W_y93f*NE zl0)*Ly~gduM#*>_Q0f=~pZYGUR`~0=Eak_?hLWlsY<=o$B%i5Q_1Tdb2hA<0=P@9| zVKgNuR2|`+;)+Xn_1c4t6F@33v0D9f95cT?G@McNKW8aM-=vBdN3bT65u}n!adq?! zWBk<7Z@8Ww;59xq-FvYPjc`3(j&(?T`(h!I8<&S^`&FH~L&TaWNB!8PiVXsr#uf1k zLuoVhYE!9q56WucplAf)l?QCx0|cppO6OsdAY@dpalP9VRg-d?tq(C*A2AuEMb79Z^t|m$P|n2Q82eMaP2a`~ZW!VhkXyf*A z#vP)uiGik13{L{>NL`t$EC7#e?qFea=MF=`E-`t1^(bzqw zWzU>oO~JB?;LOP>;&}8i>3^*--d@qm>ReKR#sejf-e%fY%rTn5ju&I3Zn}U*cHY2S z`0Lqt(H+P?5*sVDk)#ZFTX`B3F|ep$RlmqGXN+h`TBa@$;U{E)wwx)I7oK!AKhA*E zseS;BeXH@2RIgMf!ENq|SYJO36*S4g~Z2OMMTK8P7 z3HoFIEHWoadhQ40+u@8=HXfT88s=9SCZjDS8Af|;U?L~KDM$#blQI_$`d_f-!YvSF z>?{mksfj2qVrCL@9zT)$0V#bmrNKhj?G@lu9KPLc_lP%C;t5bm`E&b3%yU^c=i8(&yfynJwYQLe4smLq#x%732r(I`T>NDAny z+G^6s8=aokyeH&px82ZQoOXi@SlRfPtL+v?YgVf_jrU0;L|m~P^0v)zv^oSJx3HVF z4CpA!Wv19lA{U4c1Dg?ghkm>2`LMu4Bu5GhV)Jx_pgN+< z;^LMaZKyEz#&6rAev(bsaQgN~{N>o~^f{qU!`imLLq1Ul1vywsOs7nh^(iCKV8?4G z?p`@c!aS*dBt@odasW6ocXdU)Oiog6(_y8)W6$5$a-@#hzUz>@R1>}km=Jq#SP8Wi zzF+?lM^&YO-Nt^;k&UxO1-c35QB~FWjYDku>#Y^yHOSUVYWTYFv9ZhZ+e*eZetoR1 zrnU5tTKNeM1neLgM7ow~@#48M<_j5f!fA_#!OLhBv2$wFtUehZl#FBu2oF&YLL3H` zmEgtE@0oVjzz}oQS>0+0`?XtfC#&>0Zi=+7z{s8d;!kZyuPcqTJ_eOUTHj)JMp~cJ z&l~jbI{mv||JG9=(%PthWeF8&y)$mxJ*a;l)V~j# zIpueq_UK=CuTI&e^S`2h#oifdZPn>Z_%*4R;8l{utVf0oJV)BUT1uG--Dm3rLBve> z$V?EN%!Iei1VPM9*l8vRj%LDBI$@JE4<<5#fS$nth>iQ$c&bwabd8&&)u|ur^~b-M zproNDsBfB}?w5o(;p57kW_p#Rb1Q=W{PZL8Sv$cLNCN&evb`?DW!Q{?OjcZOXKz1u zi|1tV_L^E_vB$}5t_wIKkIV2WkEkvAZ0#3z+#DPc86R0;k6dq;;XQA`hXm3SpJPX4 zwX{cdGiwSv=A0p0;ol;wrDeh4aE6OalluT3|IXP#;)msLktwLduQ3Wj3bbaB>GsWJ z7#Q9pgkcNK4X>7m9OD7`6V)%#$AuuGMK^E#D4oTWO>Kg4L`peB{sQT)C$`UtJ}yHr z2X7^Au@SBkeLzMH9~|!P%U5e9DUvbASStnC#XV-c;d)||V3Dy&N{SqQ)Obne+%Jr^ zl5X510NBcOPK_3|J^JXQItH2!N@O{5>6p!iAyY!F4k31;Er&7Zd)2i>-%31Z%83R; z1N@j@1ZGG&;<_@UY4 z9}3768sk*V!;Y??@-^sx_ z=?UFLL!)m*9z#EhvR7OAeZ1wR?dFGgqkJ$6h-+fhSsaj{l_xYA)qPU|LE4UrL;5BBqJj!tPh{37g5M_i~2Twt{4 z@0ow}=+?hx1k$6vw0V)cgr^i2z8z^27PEYav3u(u(#_P^;P7WeM~eJXvS80z?&9Qp zF2oyY+DHYlK^^+<7*dQT$y3;l=-x6k(j;9ipXINc&-2B?08L@A;C^9ZE6il`-JBD! z+-_d(J9=z3KKlE^n*>n0Nx-*_bUiV{Y1|`&wP@g!VMC*p!-mF&OJc@aNgO!kS<;>z z3e6%Y!_VrnKB9o>nvIC$aXm4`<7AYF3a?mX3|utO5zEitQ*f7V?`3ciC-*5hTuSD?VZFy0bQOoUISbqCyCk9|0|o&_?M<;m4BW;s z45RuRl2ptoto6cDw2naB+5W-(#+C-0@h1gxBrGxm|3>!Sh)7)Uq%dDs^B8`yFTCZ_ zeld7;iw|ACp|MwsphqiExi@=S+uU9excJu{XOZqGK_FO~=xSjtzPo6!X) zdy4}xgu0W;t!nSPgvYSRRaTRc(0&3#s6%)m$i_*Cn<+*yLQhKm&L@TN+r#@^!HWa# zIiq(4+!>$n#{^o{8)}I_eO`)1Sdu>};Eg+_nOpzN6&O#7a8?(PhaMdoBj!CPZuUy$ zp|_GJ1_jk<=&eJKMt`HR{u%$7AiX9iHB2heP&Y}RnTX&v)PAuBoT-toQ$OD$l!aT! z0<+p$C~8noF@@AmEB?t+;wcO5p(~51qoF;DsM+PETZ0*0l~SyhRyk8jvWW_495>Z;4+?q0Ry zR#~eYU|m_K{pa z6)oe0&%xv%OFyaCJm9AB3_v`sI&CFsgv5i)S8*R2WSJ3JLSsbe8Z){Bc8TM!i_{sq zvvHCx?NXTnX@-RF3E1m0x|ChsS02bPZ)X#Ym_u=0vLgG-MRJ-aOiW?Xb`Ps_-AJBr zX}8lN^{sy;M&Svw38g0@x)p_b09#?Rd!LlaO_xFunvTky)~stgPDBfIOF3R>mZ`e8a}3eY1=KJto`t)eU{DNC{!tr$bv7u4TK13FfV_RikCP5pQX zDxOx(jn%>|=WtXZkbblAUAy=}&L_q7^o=76W@kp$$_k`@LLIv1n>-2UE9SFtk8sB5 zTKSDIPc)RtkzriiTKKM<({dO^_m&jC+t5zrTFKwR2{o^}h_SU+O)f#`Q6r!oEgV6cE@KNjueEp zaWdrlnbm#?Mv@XLgE3Vuh&9w5()ghigO9V4u@{DA-Y%cdE!2YA z%(&}`t!9RBr8~19w+%+8xHHut={B9Um@Ao==b5}Dyn^To9-lu-hj`V;FTn;m}qb3sHN`M58=QIKoH~=}YX$+zbObqZuIgMX>h)8}zBpB_e}DnLhvBJrM3OA(+{? z>bFAJ;LB>ffD)zW0$xUQPCmeDParYMY;CuIB&XLt_D|;#!?U7;-`#D1*e@c2N<~+u}jOvtBolp~RwN9E*+a zy&x*HhwE7lL6cG-G(`t=oyhiiupq@9sY+e!&=BBstUXLg5~s_hTGtcA(h34Z$DWf# z=8ajPXiSm=47UrY<>-wEa7gm1alfPwv{olEOeBq7jz6=50aqJ~bi@Fi@88L1em8I| zpR|ZlhNxX^Rk0CAA7&aeS=WkEAnR~vTVzHzkxOTE9$~FaZ@zJ;(I_5? zphNF9=!4VtR?a_KLBB}P7c{R-)N!!Cu47oAIuaGY=Iq3LK2ko)9U3VTyI2e`gGF32 z%>PYHhQ?KAF)~U<<_4`VrN##KKj=q0>g`A(L2)fdl1W+G`aG&}0j}V(1vaGd*o2_o z0nMn0eazmeEqJpfsM)%^b%XScSh6C`hWKt61jRLHmJya@bLtq)`UXelmj^QIH5=nP z8>}g_1v1Dq(7jeVVpkh|Ci5swqP-`wP$<)oT`Ee^AL&63R`eom*4mk3GT>}Q*L-eh z5(E=4GQu(k5chC0D@bxIG{7MFp**!+F@?DyOh$%@>&i(Z5xr-eR6-M>$(Cbytn{!}_Q zJ%1k&v|Uf!CHyesF6p#_`_@a7mfAzZjdMDhrv7d2HWOfeO?7xJwhr7o{My<>WjExpG-8_0PL7l_@ zE%~*Ho=d%8U7vxC(O!6$VCh;jAO4n54YU|TC@ z>zQrFJ<|7qv2=3AHly}1)1Jd36^`%%r?~NRf87fsb196vX}r-(QmyPdQj(54Mzo|q zQl2XqWTu$Q=ohiNvfd3%Nh7jGJgt6Iv_)VT?-+6%Tp9I!yl1?!y z?2DRKAVH%~Me_h0=^q+}QFO#2W9jgMX#@&cGJM&n@U+Zg!UG;lTkf1%_-_3GWBG~j zqRh?4?u^nCC50ck4WP{R?l1wfad=|jrlWDHi8+dT7{e{%? ztk`*?W%20xUrR<-e|kysjczD(`O-k{Y>L{kIxIb56lG)(MN;d>11F-f{Zh-bXH9d| zvMkF`6|J8*^tMsPv=b7Eeg^7u(TxKq4qQnbPsP?eVCo0#&FIoeaipKFpRs~kmafOi zmk`}H{81*KXsj5S7XFJ|O6zL*rVQ8i4Bc9EYt)>UAtc>AZ~lwhQBlofs^`?iuQld5 z)ZfyOfeV)zxxm;L{Dx2cT3+fs*>fz1!pI17SErZU&^tj7>18%Le?I{fDY2uQ zyVLXwdaR!GvmN2DW9`Gy2t}36UhW*(E;cveM{^)jvz;iP+{M8ChSw%z{&0VqBleNe zjtk7|O2#m0mptf{vD7N3>zNX&VR|-P%KR;HiaC_tNB(j@z)SgC4*fj1n7NWxD<+G= z(!=!!78%p+i?->Hp`QsT*E3ruEs9Jx9WN>ltQ;l37E_-Ch#gxz6jC6t1fr z`3MI|^;y&*MRP;_8yn&iLK$VTkK4}Y>>dW1_{alfXg$BIc^}57YYy`wR}6QXa5!^n zbXfD7PP3~a+3eh5EY(4I?L}9KYt5l5KCuBSx9Tt=c8sB9v9tQxI(}HNU-5W%=y-9# zERQ4TW@Y5$B*|R3D?nm@A#2YW$<+O}jf-WE@@Y2B%>c-ssIj6AZDA*UJ=&>HeZCnE z(H*@Sxy81P@Vt|4e?|8_2Gy}56pGRa`2{Cnj?l{W2d6NU_ zt~J?G;%TYYxJTczlM!EP*LUQgb=8NWs~h>`_2=l~0emTwCI0|)Lw_~~W8!kdfWVYO z#TGo?pI#w=OE}(5jM)aOm9e8aQe8U7I5)cXe!f&$Uv|isjGDMNC#vr+dVcpcI3f7A@Eb@A*lMJ;^<$%} z#h|drf-6enHLS|4#iM0r}tGu;fv@EX|8$I5bYdjwUe`S zDR&L^{$O4<^nmn)=oP7V7ioa&`OwrZzmywk0VJsJppMmhNo4R~JYCw>)}@|+!}r-) z7E=$}P-Mmladk*C&gi&-KDFVvWZ!MP#>U*c=7G;g38_*I-wUt?cd#Y5@$pU2;D!A9j z)PIcG-n7y^5bQ%2@O_x|jg52v3xJBri8=ox@^l5Cxr{&;mBa_7rj}RWH5ecyyalG8 znB4y5zxUKH_-7vsWWtj$_Yf_CFx#|%2X5o>uP1vFgfrT*Lr%97i(;-c@)r1+B-B9d zYs`!bB>kESerx=#B>5ZVX9Yj;w`=?hT90Wu-C;QDRBen{9{az$aS0rc=A2S)zvJq zISqYJH2Wf^t6I`&o0NeC%e=1UgUm_u9$Q!Qe*L^b7nU`0>aOh6=#+sNJ}>WCo(p z)T1vI?~eg2q&Ca)qK*WQ@nhk$+%oQe50cW%(r)yp|HqU=nL0;*aY?94f)G@00>6Tl zYL1xmm8ukM3s^ny)}tT^D~- zYu{Y;((vz+TeALLM%;StOnLr&%JUm3&pT6|MdO#~`nHrB#Gob{BC<*pU9Y?T?i9pC zUiK}K#Hl2K$5&J8Ah=Z$zp1AwjmWvYr>@`h1x`1~osEgrsr8Eex{GN}yoWki9h1_3 z*z9PNVZ)XkNDCwpO*8#3rjn2NI2ca_eU^8r8*VbMhwFSM=$mWluE`>jJm*SD3&i=JL;FWRx(S@aTrUt4Z3dJ<>&vb3UUy#CvAN71cI z9Yx=}&3)A9-U)%wTPE%Ag!Zx2OHJ4 zIUS|Dn0hwunII(4jQ3_^zKqV;(NX%!)LAtp)`ogV>0W%7*!10x9?YKul{d{U;Y|Y-_Yu9rW7i8u$Q+B^vkxo^=~`nCR*TCR-%-DcbOsEl2+Bm0b{`dw%&A z_=lsk{QqbKW@Q_fg2{z2etD+LBsP;nw7NvMMeml+fwXEp)Oj+*vS^jd!uyaHpSH6? zW}Ovrup6#}&$L!JQ*#e9h89k;_o7K|c}O8rhe?&(!C|V8#O63a?CwVkhikPQMoqAV=&u!g-DC|IQuJDW zWtS!ui$z46M@p8_Se_)NN$YH^;QK|rA?gFOw>DU2c%kGc83X>CIr=a4{VKyyb zIz1G8B2g#O*61I-TfQ0&VvG&1mYFDV#T+ZoF!1{j*W@dInmRT zs(qhRlxHUJF{uM^I57Z3AeYm1i2+cqmY_8NBhN_;K=&C3pywzjez)cT9PBdylBL%G zyk`!8r1u(t!<_d_4uE9(!U2#By$4{ckVeV?bjtu>+32E^Yfn`BZ7dC?BZo0u{fz#M z5KaWWMy9)GWE7l)8$y#qe>h-05eB~Wfa%GM6RGY{ zqdx{kb7q@-5ch$USv`Od6;<*cjq2GwyoyV4WpRFSa<=%KDN-~M?#Ch*QJA%d9O3g! zM*j(YR#$EGH@mIa?v)U@j`*;AqOovt4$0eJhd5EGwd@ml<6t-3_~g6l|@5FsDF5dGe?f=I6Wtw!-;?(Z04#_ z2`Y!pGz$r#uT-RS&+PZC9lI~VW;8cR68T*B8QBaTGAvUp{z68T&J#;LyM?7BS5^7F*RvTpmE=^9_c@9fTiuuADE#vO9 z9$C=9l|wR%Fw6~zd-LG_nH=|Y!;n|lfgtxy6BZ2vDbCg}_Kv{D>7MM%t}R{o5Tj`G zE{t3(f0<8)pHgD4@~UDvd(-Fk-&vk9fF9H9{$DLABVmEWhTB48jVF(4BgT43nDW+Q11C!{ zl(mz%*fZ-{Os4oPMC(0yv}^96NBy$?Y;V?$Nh8Nx{6c1pB~9gZrg2;=yu<#iykdm< zEZ{u!Xk?bh%h?ka={xKZJTwY-QdnA=PLEFyiq)F1j^k*asH5aq0MH!%x%oGSf4Th2 zvdZ+MIl1{C(@D*GF_zdoh_1(oZ{9;T`dF=L^*7dg##4=@D(GfM*LX6?#$CzZI-gCV zW?e{n8V@cA0!?TkVaT$jQe)ODi;eWcon~hcnTjT{m+We8;=!vnZlbrl8RbkILP@dk z>+e+$$d@iQE<8S~mjq@n+m~7x6>YM)^h6l^BhXL;uL5(&>yWhP-E# z?ybVl6Ri%q>eNrn#F$+$6ilORTzHMjR~D;xV8DetL;0F!jvW>Hay2iI{V)bNWdPZU zl>v4{45_Pg0}`4X?rOCjIx|$u$F62BBIKM42RmKOckx)n5#-;X$8Yu{9+N5w+cZAE zq|~Zbs9BDvU(_yjW-=!;b_Oo=s`TTU$}jJY=#?NU`K}RvS85JiSgrO_Hwxw3#a=Z; zKf0Q~>eTc<%jl}|MrV1lXz5}i->tiZQX0!*GDtTd4l6z5eE7JiKLQfaEpr81+cJ%< z$it~setGk$@53-~ZZXf(i>J^GHjHNJHW^1HCwq1f#<4M{n?~#idpxI`M*F2B6=b%# zdueJ9Rr%%Jr<{FiH81(2S7!Mad=KNCYSP0MTqMZQCD|52(VNU$y=#>JpFxQ3$YToS zRRywZ+NXG`)A;fBQ|DjKWlxjAk{V`JtK-iLiP9vPYjB`fmH*kCok33)lR1|eV(ZM5 z++kq~(yPxpXyL{_EtGekx_m(IeswjkAv13G1m?aPKrc(toKwh0Qfk#yTAv^voFQg; zax!*K_QEne$|e(1bqcV}xu+DDlv*|DG{vWx#kcZ_;xnXp-YLZ;rB=Osq^EXQ^DVR+ z;^kCiDOEEk$3b@s=^=Olv#rwOt}-g$TCBeLi6+?L^q*UD3+Eu$o|rxVqu5tkk>)IfEX%$3Y4 zYqC6P6?8R^5F{Syg#-=p%+}$-s#Ks~@9_(s)5b9L;u@{9Jf)o(Ah=m#jah7f=Fig8 z%ZxvEQ6Dg_<`!1ckkf2UPAhoXd~Z)_N(vK^lv-8tcgAY((S7IcyXbw1>pqVnfS)at z_c;{E`3d283yjq!J)$I-<_QLAKt`<74{-9&rTuyEiAQqutHdZ7xhP!knQRLVk%@r` zk9pxE_}OJRuBfYo=`rJ&31*}sefJ2S&(+Xhw(83La*O~FnWk{*nS0ghu}eRS}2VRw>K8ZX^QKd|q#pI^$37q_N-s%AD{ zu@OYO0cOqS@BYD@&B(^YZ0^wI1Oh-O0Ce;CUPDpkm-kvVkG;}V9_ebi1zYXriawd; zy;fa)O6EMtJiAY3d9PLWQ!-~r=00=dSe@UT8&@AXq@{HEJET@=as#v z{M8HT6qz1{y{E^{kIm^Z3d)dj8GrZEy_r5JWHC(s9;=wE`G|DJ#vYXE##E}Fk>0yQ zfYvm+_05oq2 zUfDk`Dhh2r<9r$MX$s$JSx)wZeAW`LM>_unR+V6{uI7Ko{%A_)g;dMj8PglRbq6&g zGZ`B)e4@@3{2h#KOKbp)?OW6KJ;)~rN@InL@*Zh2*uV)PnGI-5rUCW zRHA{;@~S^P)mt!LNgOXxTT=xiwa4>6?mVAA8LCraJZx_4p&!i=<-Jx7JEf&^pvNMa z;AfCbmypbnVE*RTJ^$z-2b4_sG5d7js~8p-GOWx?}eR zCi+x^7F4blgKC)sBFgG}mwP~$L;0{oS*0o3_Au5>3se zqFS{`*G|5c;dsyXu4Ii_NhbZ|4ir_Z30B_V-dMli$c?#DY~NvmX)Og>!J{IOT+QqF zrIsvoeAKD#_cYZ=rz^i7}Fh5e?0mf zJLmk3{zM9&mew|VBxg7Jo!r*y9obef(s-lk4{<;&3a=P$!`bYD3DZX|b+%QEYW(nI z<0omY6{C=%;ST$Z&}NX&HaLs{;9*9U!>IiJiMC0jJSWGcwN4r(y#c+^8-LlCXb;u{ zNq9GzkmwB(caTUK=?wykcVR?u7*$T>sHFEN)vF#d%lVWe*&(w`h<79*ruGolhGDvQ zK7u+0HkO3Hnf;@!%t;I@lEp0yud@;=JqZj4RjCU}?2Vz@n9Lm?gCu<@7*?q`A?F9 zC%G8a*h}H#bMV%96z-WBIlml>%SiK5|jMO-B4PjGV zACh1XD8AgO^1&G2y)p7JG#<<` zE-U9-&jh#R644Fo zl;uN(xtg>#H>>>e?o(q=$vjUoZ%I^OL6&!)>UT=!$3>kU-v_e1`_$fJebH!=%)5I* zHqezM1=tXe7V;gUFFPcw--K(SAaAUHPl5V-(a9g_1+~gA?><#~O6IRg=GlGlm3N=Y zJtgxslDVrFWWiTbfDMaH;2SJ6mPyQ?LFT;tU(OR7+yz?fj;D) zV@uOt%ucG|oAJ4(eC!-T7^uP85p%bdENN_A92Ne6C%N8(7w&NA;Z!(-1-0TnsL4Ag zu1s;f-J`qX_>UDAl<8l$Lj&x}Z<#U`0v;%y#`qZ@Q%FtaFj@ zW66pykn;Qcl$Up(x~6aWQ(L;>Y^|o7H1|cswJTZSbeaYa)#V>amR~95^ZJyRcdm{;UHR8oz(v9jCd*$h$OtMV(OL*KRlAF7Ud0xAa=c!(?0)M(S&BEww8rs4h z*-|A5B@0qyOM}~zD{C?>xnj(8Pc1x#$&9>I93*w#dH2?{N;!)ci><0YLC zbuVjC2mW~?lhe#$KTq~h@WBdA)c^$+AggNBn^49-5AHSgCXAVRT=F}?7QBEp6N_9_ z<}rlOI8043HYow`tx=VjB_!iKk1@8~H`{rQ-ZVLVH_Nbi)s(;W9+u$O1wXx6JIL^j@l~s_(pM%v z8aG;EggnMcYXBY^p?fS56W-D_PC<)6QzlA35p6y9^e9QPSN-y@y-{*C%TcVpX#H6F z{8mp=FB*Ud-wYKR&)>^03zKg&5?gFRU_z~$xnB$nA=wkc0+DI;oj!Rg@76{lDxWAt zNrFfSa7sa+uiludIYon>Om8oOBeN?pktMlGm7P-N zsA%}fwL|ZTEXmbs_$g&>lQJ86ghc9OmSnGb|6pI-N~Fw|o-(PpNph9?#VKW6Ql>J| zp5C}ga*0M|!#)pE1 zzXwJt=8{~cx?;Us8@yrjiry{t%X_Wr=#$aaycFPqvOS5ir1Y#AdN(?c>Z(=KDNz1X zWm4AImSnKGaZ=VXK_AJik8#>MwCu^q}yNSmtGAp}9%#F_2`h z+VGd&{pV^vO@o|fgKB_Qi#5q?P&?z>r$JwTx+_4cg>Ve;$v72_VfbHy zt%=>drx6@c#tkrW$rA>Dx!;c+S^N^_zGWId=U>z=!5(!7g%7&LZjHBC9eF*AjE3P6 z4BxKJAE4{wUY1P^YJ_ao)(^$UZ!Q=u;%Xxm9BVAkGPV=Q!PsSdPIw^{O|v&%@&YHz zR8iTW@vh^Pb~?K^xV(9t1m9yfAV2Qf zytifFqR6D-k#A--j2Fy|;vjLo?hF4RBV*gv?)30Zr%_7?V}e8uVKo!V!g*p+;ja2a z;hpaC!sGRS5P*$SN4crh!`XtNk(u_$Oh;s<)A(Lc!q2L7R<_3L^zSF^NqmMbA^1OP zye6psf*LXY-(omAiXjf0?dC|8lP!QmubH$Zzg8&TI%~m4V2C3^0+z~+IKcYQ`GD*<;x&zHQvCVDUyrPdCOy05oe%On%XNOAs=7)keED&Rjj9Q~|yIpO4 zMQRBR&=|W3bi-Yiz^GC~6Im0V0vGyJmBuM_F);~(Z)&8Qba_|v4B>f%T%d(xOvFEA z3-_ygFeOcas`y7OJ%~fgIdVS9rO%+Mb2poMRe$4JpYguRW_1o}Ys$Qpe5d zPjAvtJ))7O#aur1C$X!{^5n9?9!Upmj**w~KGvJTKJ}xW8X>XWM~nJ{OSVR$<#rU* zSWh$9#%|BBsR=YwR9-=i5xl~{4khRo4_adh#lp9wlxtTEZFt+wyLy5W>m|mRU(oUB!+xqof^G^k?6v+MaKJR(S^ZfjC7WCXN@(|XY1N<;2s?-<+|L` z!jns{H!?b?`Ug1eRi6${6Zl#_e9DT8f6QNhJ|A4oELG{!%UBg%E{xJ+c^?^Cb719;Q3$<^FQwrFj7 zwR#@c;5wQ7{L57T%bT$m=kUy^ee~##c2TFWXojw$nM0CjIJ7|Bx|4!N| z$r+I{ztP~YsZ-CS%c2m#V?u*@{p6%(Gh;waxGMKJEvWOVACO6CaFyRETY?C>xcI*O zZKJn^_g^4?LT4Fe!KkwZbZy1luMjBi0(U`f!P?PfaL}o4tf1YE! z+AuU)8sDn=;l19OQxW>iSiMHtYG3!9bn}~k80en9VqmRIjk_MDL-e9oTp5NwuSe0M zClWrV0K+O=WxlbqX9GXHBMS|OIZjr4P5!=GU*UF%Q{8Xteg`KTY+ZMzd80G!>J8kf znLRe!vzV<=UZV{QI{N!@6pqZB8+rTyX@t|%zw7kxdi^VUQ{(~JF^W7On+uT#p3=Xv zYZZCm1^v5A|L)emZ|UE?`u9EkyPw}fj|RLQs~dTey4Ba7O|wOA4GNL2ZYCizk3I|7 z)ilzLnL(plM~TuA4Lev)lc9dJ9RdDQc)Og&qa0%VaVZ%-?(LW|x?A$pZvuh?2z>64 z1Y4wR1xbHLzLG?2$V6&=z#e(vG0E_NZ16-L*r9*7@Y}Ka5q@FUJUz%$CjZovCIo!) zH_6xq>?Ts`$7Z?(cD3#{qLk}d&4@57RTlY=Oz}9<#QWe;6FCDFO$LmaJmB)a=RLv) zb-1o$%rb37pR8`~Q?d6G`*NtSd7G8|UyV}vzJ_y*XY^nR%GkFO2s);R{$|`MU#ipvBpP+~3=|Sip37J8 z%q?W{e5Z6fuT`p><&yCq($hL;C$Bt6|A-L?lWV`|jl!y5R1xv<#xFC~&m&X&c_hT5 zW}QYS_hZAWjFv`#GT)aOp`h`3g+-MLOxL_ywgzuBXWm+flilc+!EaS$MhOCO<=#A z&|8gft+4b~t)tQHw56P(q0uZi9bDd2Rb8a4OJL6pHh9fBWAaSOo~ z$t3d*6PL*h8RVqA%w?7({CUh3Q8p_@pSqFwQ~IDyjwzWSqa5Ja)L0C5TyKL1<-Sm6 zU_za`lejVl%a))U#jPaPpWpEIbiSTvlrCV4<(3mjdDQISz&ce6UUV8q;8z(l{78jj z`M71(0H`xi7n@&Uyh?$eQ$sf~Bk)qGU0_VM8{;+_+uPi2FHJZrluf9~%rc&Py{x}B%U1#wm@9HZqYO>+R;!u9D0b^_+Nvw+Igr0#(Qf=slP2hh zEKm)ff*QWUxKRowY1$>3kDRiRBUqA_Ud55`Ann4v_GCOb%ea0CFGren9(ORi@deK~ za$gzrMA?4iiFOO@YHw@^kaP-u^|;4`IH18tflV+W;!TB~C8p2{0lmf}Qk7L^Xb3&J za9YbASMynRy7zw13UKK0{Lek~XzN_h^(Fqx(WD~xd+PbBevQ5fc3drblHH`8<{o7& zgO#JcCmgZ2DU}{_LlEv>&dp}8u*QZ#<#MW_R!tCWt!`3jjLLeABP%1DZCc^m#Dr+} zY~Z}q&hdRRRyFmNtq!pYG(+f*VZy4GAl-slUO zQ1l1_tb(Le%Z$bK65}SHtJK-A(Jr$gv!&rh>!R6mueRtoy+9llHbM>z{x4aUo0rH@ zN$2*0=y#J+ZAMsXL<0L4^AjK0c(tbW)!$~&+M0DSIm@OTdvtYeTY6aITCnQpR}pUdl+Q_h0dstxirF@L=_5U_!N;y