Commit 0886042c authored by lishen's avatar lishen
Browse files

dlib from github, version=19.24

parent 5b127120
Pipeline #262 failed with stages
in 0 seconds
**/.idea
*~
*.swp
*.o
*.so
*.pyc
build
build2
dist
*.egg-info/
docs/release/
docs/docs/web/
docs/docs/chm/
docs/docs/cache/
docs/docs/git-logs.xml
docs/docs/python/classes.txt
docs/docs/python/functions.txt
docs/docs/python/constants.txt
**/.vscode
cmake_minimum_required(VERSION 3.8.0)
project(dlib_project)
#############################################################################
# #
# READ examples/CMakeLists.txt TO SEE HOW TO USE DLIB FROM C++ WITH CMAKE #
# #
#############################################################################
get_directory_property(has_parent PARENT_DIRECTORY)
if(NOT has_parent)
# When you call add_subdirectory(dlib) from a parent CMake project dlib's
# CMake scripts will assume you want to statically compile dlib into
# whatever you are building rather than create a standalone copy of dlib.
# This means CMake will build dlib as a static library, disable dlib's
# install targets so they don't clutter your project, and adjust a few other
# minor things that are convenient when statically building dlib as part of
# your own projects.
#
# On the other hand, if there is no parent CMake project or if
# DLIB_IN_PROJECT_BUILD is set to false, CMake will compile dlib as a normal
# standalone library (either shared or static, based on the state of CMake's
# BUILD_SHARED_LIBS flag), and include the usual install targets so you can
# install dlib on your computer via `make install`. Since the only reason
# to build this CMakeLists.txt (the one you are reading right now) by itself
# is if you want to install dlib, we indicate as such by setting
# DLIB_IN_PROJECT_BUILD to false.
set(DLIB_IN_PROJECT_BUILD false)
endif()
add_subdirectory(dlib)
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
#
# MANIFEST.in
#
# Manifest template for creating the dlib source distribution.
include MANIFEST.in
include setup.py
include README.md
# sources
recursive-include dlib **
recursive-include python_examples *.txt *.py
recursive-include tools/python **
prune tools/python/build*
prune dlib/cmake_utils/*/build*
prune dlib/test
global-exclude *.pyc
# dlib C++ library [![GitHub Actions C++ Status](https://github.com/davisking/dlib/actions/workflows/build_cpp.yml/badge.svg)](https://github.com/davisking/dlib/actions/workflows/build_cpp.yml) [![GitHub Actions Python Status](https://github.com/davisking/dlib/actions/workflows/build_python.yml/badge.svg)](https://github.com/davisking/dlib/actions/workflows/build_python.yml)
Dlib is a modern C++ toolkit containing machine learning algorithms and tools for creating complex software in C++ to solve real world problems. See [http://dlib.net](http://dlib.net) for the main project documentation and API reference.
## Compiling dlib C++ example programs
Go into the examples folder and type:
```bash
mkdir build; cd build; cmake .. ; cmake --build .
```
That will build all the examples.
If you have a CPU that supports AVX instructions then turn them on like this:
```bash
mkdir build; cd build; cmake .. -DUSE_AVX_INSTRUCTIONS=1; cmake --build .
```
Doing so will make some things run faster.
Finally, Visual Studio users should usually do everything in 64bit mode. By default Visual Studio is 32bit, both in its outputs and its own execution, so you have to explicitly tell it to use 64bits. Since it's not the 1990s anymore you probably want to use 64bits. Do that with a cmake invocation like this:
```bash
cmake .. -G "Visual Studio 14 2015 Win64" -T host=x64
```
## Compiling your own C++ programs that use dlib
The examples folder has a [CMake tutorial](https://github.com/davisking/dlib/blob/master/examples/CMakeLists.txt) that tells you what to do. There are also additional instructions on the [dlib web site](http://dlib.net/compile.html).
Alternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install dlib with CMake integration in a single command:
```bash
vcpkg install dlib
```
## Compiling dlib Python API
Before you can run the Python example programs you must compile dlib. Type:
```bash
python setup.py install
```
## Running the unit test suite
Type the following to compile and run the dlib unit test suite:
```bash
cd dlib/test
mkdir build
cd build
cmake ..
cmake --build . --config Release
./dtest --runall
```
Note that on windows your compiler might put the test executable in a subfolder called `Release`. If that's the case then you have to go to that folder before running the test.
This library is licensed under the Boost Software License, which can be found in [dlib/LICENSE.txt](https://github.com/davisking/dlib/blob/master/dlib/LICENSE.txt). The long and short of the license is that you can use dlib however you like, even in closed source commercial software.
## dlib sponsors
This research is based in part upon work supported by the Office of the Director of National Intelligence (ODNI), Intelligence Advanced Research Projects Activity (IARPA) under contract number 2014-14071600010. The views and conclusions contained herein are those of the authors and should not be interpreted as necessarily representing the official policies or endorsements, either expressed or implied, of ODNI, IARPA, or the U.S. Government.
#
# This is a CMake makefile. You can find the cmake utility and
# information about it at http://www.cmake.org
#
cmake_minimum_required(VERSION 3.8.0)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif ()
project(dlib)
set(CPACK_PACKAGE_NAME "dlib")
set(CPACK_PACKAGE_VERSION_MAJOR "19")
set(CPACK_PACKAGE_VERSION_MINOR "24")
set(CPACK_PACKAGE_VERSION_PATCH "99")
set(VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
# Only print these messages once, even if dlib is added multiple times via add_subdirectory()
if (NOT TARGET dlib)
message(STATUS "Using CMake version: ${CMAKE_VERSION}")
message(STATUS "Compiling dlib version: ${VERSION}")
endif ()
include(cmake_utils/set_compiler_specific_options.cmake)
# Adhere to GNU filesystem layout conventions
include(GNUInstallDirs)
if (POLICY CMP0075)
cmake_policy(SET CMP0075 NEW)
endif ()
# default to a Release build (except if CMAKE_BUILD_TYPE is set)
include(cmake_utils/release_build_by_default)
# Set DLIB_VERSION in the including CMake file so they can use it to do whatever they want.
get_directory_property(has_parent PARENT_DIRECTORY)
if (has_parent)
set(DLIB_VERSION ${VERSION} PARENT_SCOPE)
if (NOT DEFINED DLIB_IN_PROJECT_BUILD)
set(DLIB_IN_PROJECT_BUILD true)
endif ()
endif ()
if (COMMAND pybind11_add_module AND MSVC)
# True when building a python extension module using Visual Studio. We care
# about this because a huge number of windows users have broken systems, and
# in particular, they have broken or incompatibly installed copies of things
# like libjpeg or libpng. So if we detect we are in this mode we will never
# ever link to those libraries. Instead, we link to the copy included with
# dlib.
set(BUILDING_PYTHON_IN_MSVC true)
else ()
set(BUILDING_PYTHON_IN_MSVC false)
endif ()
if (DLIB_IN_PROJECT_BUILD)
# Check if we are being built as part of a pybind11 module.
if (COMMAND pybind11_add_module)
set(CMAKE_POSITION_INDEPENDENT_CODE True)
if (CMAKE_COMPILER_IS_GNUCXX)
# Just setting CMAKE_POSITION_INDEPENDENT_CODE should be enough to set
# -fPIC for GCC but sometimes it still doesn't get set, so make sure it
# does.
add_definitions("-fPIC")
endif ()
# Make DLIB_ASSERT statements not abort the python interpreter, but just return an error.
list(APPEND active_preprocessor_switches "-DDLIB_NO_ABORT_ON_2ND_FATAL_ERROR")
endif ()
# DLIB_IN_PROJECT_BUILD==true means you are using dlib by invoking
# add_subdirectory(dlib) in the parent project. In this case, we always want
# to build dlib as a static library so the parent project doesn't need to
# deal with some random dlib shared library file. It is much better to
# statically compile dlib into the parent project. So the following bit of
# CMake ensures that happens. However, we have to take care to compile dlib
# with position independent code if appropriate (i.e. if the parent project
# is a shared library).
if (BUILD_SHARED_LIBS)
if (CMAKE_COMPILER_IS_GNUCXX)
# Just setting CMAKE_POSITION_INDEPENDENT_CODE should be enough to set
# -fPIC for GCC but sometimes it still doesn't get set, so make sure it
# does.
add_definitions("-fPIC")
endif ()
set(CMAKE_POSITION_INDEPENDENT_CODE true)
endif ()
# Tell cmake to build dlib as a static library
set(BUILD_SHARED_LIBS false)
elseif (BUILD_SHARED_LIBS)
if (MSVC)
message(FATAL_ERROR "Building dlib as a standalone dll is not supported when using Visual Studio. You are highly encouraged to use static linking instead. See https://github.com/davisking/dlib/issues/1483 for a discussion.")
endif ()
endif ()
if (CMAKE_VERSION VERSION_LESS "3.9.0")
# Set only because there are old target_link_libraries() statements in the
# FindCUDA.cmake file that comes with CMake that error out if the new behavior
# is used. In newer versions of CMake we can instead set CUDA_LINK_LIBRARIES_KEYWORD which fixes this issue.
cmake_policy(SET CMP0023 OLD)
else ()
set(CUDA_LINK_LIBRARIES_KEYWORD PUBLIC)
endif ()
macro(enable_preprocessor_switch option_name)
list(APPEND active_preprocessor_switches "-D${option_name}")
endmacro()
macro(disable_preprocessor_switch option_name)
if (active_preprocessor_switches)
list(REMOVE_ITEM active_preprocessor_switches "-D${option_name}")
endif ()
endmacro()
macro(toggle_preprocessor_switch option_name)
if (${option_name})
enable_preprocessor_switch(${option_name})
else ()
disable_preprocessor_switch(${option_name})
endif ()
endmacro()
# Suppress superfluous randlib warnings about libdlib.a having no symbols on MacOSX.
if (APPLE)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
endif ()
# Don't try to call add_library(dlib) and setup dlib's stuff if it has already
# been done by some other part of the current cmake project. We do this
# because it avoids getting warnings/errors about cmake policy CMP0002. This
# happens when a project tries to call add_subdirectory() on dlib more than
# once. This most often happens when the top level of a project depends on two
# or more other things which both depend on dlib.
if (NOT TARGET dlib)
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")
set(DLIB_ENABLE_STACK_TRACE_STR
"Enable this if you want to turn on the DLIB_STACK_TRACE macros")
set(DLIB_USE_BLAS_STR
"Disable this if you don't want to use a BLAS library")
set(DLIB_USE_LAPACK_STR
"Disable this if you don't want to use a LAPACK library")
set(DLIB_USE_CUDA_STR
"Disable this if you don't want to use NVIDIA CUDA")
set(DLIB_USE_CUDA_COMPUTE_CAPABILITIES_STR
"Set this to a comma-separated list of CUDA compute capabilities")
set(DLIB_USE_MKL_SEQUENTIAL_STR
"Enable this if you have MKL installed and want to use the sequential version instead of the multi-core version.")
set(DLIB_USE_MKL_WITH_TBB_STR
"Enable this if you have MKL installed and want to use the tbb version instead of the openmp version.")
set(DLIB_PNG_SUPPORT_STR
"Disable this if you don't want to link against libpng")
set(DLIB_GIF_SUPPORT_STR
"Disable this if you don't want to link against libgif")
set(DLIB_JPEG_SUPPORT_STR
"Disable this if you don't want to link against libjpeg")
set(DLIB_WEBP_SUPPORT_STR
"Disable this if you don't want to link against libwebp")
set(DLIB_LINK_WITH_SQLITE3_STR
"Disable this if you don't want to link against sqlite3")
#set (DLIB_USE_FFTW_STR "Disable this if you don't want to link against fftw" )
set(DLIB_USE_MKL_FFT_STR
"Disable this is you don't want to use the MKL DFTI FFT implementation")
set(DLIB_ENABLE_ASSERTS_STR
"Enable this if you want to turn on the DLIB_ASSERT macro")
set(DLIB_USE_FFMPEG_STR
"Disable this if you don't want to use the FFMPEG library")
option(DLIB_ENABLE_ASSERTS ${DLIB_ENABLE_ASSERTS_STR} OFF)
option(DLIB_ISO_CPP_ONLY ${DLIB_ISO_CPP_ONLY_STR} OFF)
toggle_preprocessor_switch(DLIB_ISO_CPP_ONLY)
option(DLIB_NO_GUI_SUPPORT ${DLIB_NO_GUI_SUPPORT_STR} OFF)
toggle_preprocessor_switch(DLIB_NO_GUI_SUPPORT)
option(DLIB_ENABLE_STACK_TRACE ${DLIB_ENABLE_STACK_TRACE_STR} OFF)
toggle_preprocessor_switch(DLIB_ENABLE_STACK_TRACE)
option(DLIB_USE_MKL_SEQUENTIAL ${DLIB_USE_MKL_SEQUENTIAL_STR} OFF)
option(DLIB_USE_MKL_WITH_TBB ${DLIB_USE_MKL_WITH_TBB_STR} OFF)
if (DLIB_ENABLE_ASSERTS)
# Set these variables so they are set in the config.h.in file when dlib
# is installed.
set(DLIB_DISABLE_ASSERTS false)
set(ENABLE_ASSERTS true)
enable_preprocessor_switch(ENABLE_ASSERTS)
disable_preprocessor_switch(DLIB_DISABLE_ASSERTS)
else ()
# Set these variables so they are set in the config.h.in file when dlib
# is installed.
set(DLIB_DISABLE_ASSERTS true)
set(ENABLE_ASSERTS false)
disable_preprocessor_switch(ENABLE_ASSERTS)
# Never force the asserts off when doing an in project build. The only
# time this matters is when using visual studio. The visual studio IDE
# has a drop down that lets the user select either release or debug
# builds. The DLIB_ASSERT macro is setup to enable/disable automatically
# based on this drop down (via preprocessor magic). However, if
# DLIB_DISABLE_ASSERTS is defined it permanently disables asserts no
# matter what, which would defeat the visual studio drop down. So here
# we make a point to not do that kind of severe disabling when in a
# project build. It should also be pointed out that DLIB_DISABLE_ASSERTS
# is only needed when building and installing dlib as a separately
# installed library. It doesn't matter when doing an in project build.
if (NOT DLIB_IN_PROJECT_BUILD)
enable_preprocessor_switch(DLIB_DISABLE_ASSERTS)
endif ()
endif ()
if (DLIB_ISO_CPP_ONLY)
option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} OFF)
option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} OFF)
option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} OFF)
option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} OFF)
option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} OFF)
option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} OFF)
option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} OFF)
option(DLIB_WEBP_SUPPORT ${DLIB_WEBP_SUPPORT_STR} OFF)
#option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} OFF)
option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} OFF)
option(DLIB_USE_FFMPEG ${DLIB_USE_FFMPEG_STR} OFF)
else ()
option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} ON)
option(DLIB_WEBP_SUPPORT ${DLIB_WEBP_SUPPORT_STR} ON)
option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} ON)
option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} ON)
option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} ON)
option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} ON)
set(DLIB_USE_CUDA_COMPUTE_CAPABILITIES 50 CACHE STRING ${DLIB_USE_CUDA_COMPUTE_CAPABILITIES_STR})
option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} ON)
option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} ON)
#option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} ON)
option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} ON)
option(DLIB_USE_FFMPEG ${DLIB_USE_FFMPEG_STR} ON)
endif ()
toggle_preprocessor_switch(DLIB_JPEG_SUPPORT)
toggle_preprocessor_switch(DLIB_WEBP_SUPPORT)
toggle_preprocessor_switch(DLIB_USE_BLAS)
toggle_preprocessor_switch(DLIB_USE_LAPACK)
toggle_preprocessor_switch(DLIB_USE_CUDA)
toggle_preprocessor_switch(DLIB_PNG_SUPPORT)
toggle_preprocessor_switch(DLIB_GIF_SUPPORT)
#toggle_preprocessor_switch(DLIB_USE_FFTW)
toggle_preprocessor_switch(DLIB_USE_MKL_FFT)
toggle_preprocessor_switch(DLIB_USE_FFMPEG)
set(source_files
base64/base64_kernel_1.cpp
bigint/bigint_kernel_1.cpp
bigint/bigint_kernel_2.cpp
bit_stream/bit_stream_kernel_1.cpp
entropy_decoder/entropy_decoder_kernel_1.cpp
entropy_decoder/entropy_decoder_kernel_2.cpp
entropy_encoder/entropy_encoder_kernel_1.cpp
entropy_encoder/entropy_encoder_kernel_2.cpp
md5/md5_kernel_1.cpp
tokenizer/tokenizer_kernel_1.cpp
unicode/unicode.cpp
test_for_odr_violations.cpp
)
set(dlib_needed_public_libraries)
set(dlib_needed_public_includes)
set(dlib_needed_public_cflags)
set(dlib_needed_public_ldflags)
set(dlib_needed_private_libraries)
set(dlib_needed_private_includes)
if (DLIB_ISO_CPP_ONLY)
add_library(dlib ${source_files})
else ()
set(source_files ${source_files}
sockets/sockets_kernel_1.cpp
bsp/bsp.cpp
dir_nav/dir_nav_kernel_1.cpp
dir_nav/dir_nav_kernel_2.cpp
dir_nav/dir_nav_extensions.cpp
gui_widgets/fonts.cpp
linker/linker_kernel_1.cpp
logger/extra_logger_headers.cpp
logger/logger_kernel_1.cpp
logger/logger_config_file.cpp
misc_api/misc_api_kernel_1.cpp
misc_api/misc_api_kernel_2.cpp
sockets/sockets_extensions.cpp
sockets/sockets_kernel_2.cpp
sockstreambuf/sockstreambuf.cpp
sockstreambuf/sockstreambuf_unbuffered.cpp
server/server_kernel.cpp
server/server_iostream.cpp
server/server_http.cpp
threads/multithreaded_object_extension.cpp
threads/threaded_object_extension.cpp
threads/threads_kernel_1.cpp
threads/threads_kernel_2.cpp
threads/threads_kernel_shared.cpp
threads/thread_pool_extension.cpp
threads/async.cpp
timer/timer.cpp
stack_trace.cpp
cuda/cpu_dlib.cpp
cuda/tensor_tools.cpp
data_io/image_dataset_metadata.cpp
data_io/mnist.cpp
data_io/cifar.cpp
global_optimization/global_function_search.cpp
filtering/kalman_filter.cpp
svm/auto.cpp
)
if (UNIX)
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads REQUIRED)
list(APPEND dlib_needed_private_libraries ${CMAKE_THREAD_LIBS_INIT})
endif ()
# we want to link to the right stuff depending on our platform.
if (WIN32 AND NOT CYGWIN) ###############################################################################
if (DLIB_NO_GUI_SUPPORT)
list(APPEND dlib_needed_private_libraries ws2_32 winmm)
else ()
list(APPEND dlib_needed_private_libraries ws2_32 winmm comctl32 gdi32 imm32)
endif ()
elseif (APPLE) ############################################################################
set(CMAKE_MACOSX_RPATH 1)
if (NOT DLIB_NO_GUI_SUPPORT)
find_package(X11 QUIET)
if (X11_FOUND)
# If both X11 and anaconda are installed, it's possible for the
# anaconda path to appear before /opt/X11, so we remove anaconda.
foreach (ITR ${X11_INCLUDE_DIR})
if ("${ITR}" MATCHES "(.*)(Ana|ana|mini)conda(.*)")
list(REMOVE_ITEM X11_INCLUDE_DIR ${ITR})
endif ()
endforeach (ITR)
list(APPEND dlib_needed_public_includes ${X11_INCLUDE_DIR})
list(APPEND dlib_needed_public_libraries ${X11_LIBRARIES})
else ()
find_library(xlib X11)
# Make sure X11 is in the include path. Note that we look for
# Xlocale.h rather than Xlib.h because it avoids finding a partial
# copy of the X11 headers on systems with anaconda installed.
find_path(xlib_path Xlocale.h
PATHS
/Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include
/opt/local/include
PATH_SUFFIXES X11
)
if (xlib AND xlib_path)
get_filename_component(x11_path ${xlib_path} PATH CACHE)
list(APPEND dlib_needed_public_includes ${x11_path})
list(APPEND dlib_needed_public_libraries ${xlib})
set(X11_FOUND 1)
endif ()
endif ()
if (NOT X11_FOUND)
message(" *****************************************************************************")
message(" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***")
message(" *** Make sure XQuartz is installed if you want GUI support. ***")
message(" *** You can download XQuartz from: https://www.xquartz.org/ ***")
message(" *****************************************************************************")
set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE)
enable_preprocessor_switch(DLIB_NO_GUI_SUPPORT)
endif ()
endif ()
mark_as_advanced(xlib xlib_path x11_path)
else () ##################################################################################
# link to the socket library if it exists. this is something you need on solaris
find_library(socketlib socket)
if (socketlib)
list(APPEND dlib_needed_private_libraries ${socketlib})
endif ()
if (NOT DLIB_NO_GUI_SUPPORT)
include(FindX11)
if (X11_FOUND)
list(APPEND dlib_needed_private_includes ${X11_INCLUDE_DIR})
list(APPEND dlib_needed_private_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(" *** On Ubuntu run: sudo apt-get install libx11-dev ***")
message(" *****************************************************************************")
set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE)
enable_preprocessor_switch(DLIB_NO_GUI_SUPPORT)
endif ()
endif ()
mark_as_advanced(nsllib socketlib)
endif () ##################################################################################
if (NOT DLIB_NO_GUI_SUPPORT)
set(source_files ${source_files}
gui_widgets/widgets.cpp
gui_widgets/drawable.cpp
gui_widgets/canvas_drawing.cpp
gui_widgets/style.cpp
gui_widgets/base_widgets.cpp
gui_core/gui_core_kernel_1.cpp
gui_core/gui_core_kernel_2.cpp
)
endif ()
INCLUDE(CheckFunctionExists)
if (DLIB_GIF_SUPPORT)
find_package(GIF QUIET)
if (GIF_FOUND)
list(APPEND dlib_needed_public_includes ${GIF_INCLUDE_DIR})
list(APPEND dlib_needed_public_libraries ${GIF_LIBRARY})
else ()
set(DLIB_GIF_SUPPORT OFF CACHE STRING ${DLIB_GIF_SUPPORT_STR} FORCE)
toggle_preprocessor_switch(DLIB_GIF_SUPPORT)
endif ()
endif ()
if (DLIB_PNG_SUPPORT)
include(cmake_utils/find_libpng.cmake)
if (PNG_FOUND)
list(APPEND dlib_needed_private_includes ${PNG_INCLUDE_DIR})
list(APPEND dlib_needed_private_libraries ${PNG_LIBRARIES})
else ()
# If we can't find libpng then statically compile it in.
include_directories(external/libpng external/zlib)
set(source_files ${source_files}
external/libpng/arm/arm_init.c
external/libpng/arm/filter_neon_intrinsics.c
external/libpng/arm/palette_neon_intrinsics.c
external/libpng/png.c
external/libpng/pngerror.c
external/libpng/pngget.c
external/libpng/pngmem.c
external/libpng/pngpread.c
external/libpng/pngread.c
external/libpng/pngrio.c
external/libpng/pngrtran.c
external/libpng/pngrutil.c
external/libpng/pngset.c
external/libpng/pngtrans.c
external/libpng/pngwio.c
external/libpng/pngwrite.c
external/libpng/pngwtran.c
external/libpng/pngwutil.c
external/zlib/adler32.c
external/zlib/compress.c
external/zlib/crc32.c
external/zlib/deflate.c
external/zlib/gzclose.c
external/zlib/gzlib.c
external/zlib/gzread.c
external/zlib/gzwrite.c
external/zlib/infback.c
external/zlib/inffast.c
external/zlib/inflate.c
external/zlib/inftrees.c
external/zlib/trees.c
external/zlib/uncompr.c
external/zlib/zutil.c
)
include(cmake_utils/check_if_neon_available.cmake)
if (ARM_NEON_IS_AVAILABLE)
message(STATUS "NEON instructions will be used for libpng.")
enable_language(ASM)
set(source_files ${source_files}
external/libpng/arm/arm_init.c
external/libpng/arm/filter_neon_intrinsics.c
external/libpng/arm/filter_neon.S
)
set_source_files_properties(external/libpng/arm/filter_neon.S PROPERTIES COMPILE_FLAGS "${CMAKE_ASM_FLAGS} ${CMAKE_CXX_FLAGS} -x assembler-with-cpp")
endif ()
endif ()
set(source_files ${source_files}
image_loader/png_loader.cpp
image_saver/save_png.cpp
)
endif ()
if (DLIB_JPEG_SUPPORT)
include(cmake_utils/find_libjpeg.cmake)
if (JPEG_FOUND)
list(APPEND dlib_needed_private_includes ${JPEG_INCLUDE_DIR})
list(APPEND dlib_needed_private_libraries ${JPEG_LIBRARY})
else ()
# If we can't find libjpeg then statically compile it in.
add_definitions(-DDLIB_JPEG_STATIC)
set(source_files ${source_files}
external/libjpeg/jaricom.c
external/libjpeg/jcapimin.c
external/libjpeg/jcapistd.c
external/libjpeg/jcarith.c
external/libjpeg/jccoefct.c
external/libjpeg/jccolor.c
external/libjpeg/jcdctmgr.c
external/libjpeg/jchuff.c
external/libjpeg/jcinit.c
external/libjpeg/jcmainct.c
external/libjpeg/jcmarker.c
external/libjpeg/jcmaster.c
external/libjpeg/jcomapi.c
external/libjpeg/jcparam.c
external/libjpeg/jcprepct.c
external/libjpeg/jcsample.c
external/libjpeg/jdapimin.c
external/libjpeg/jdapistd.c
external/libjpeg/jdarith.c
external/libjpeg/jdatadst.c
external/libjpeg/jdatasrc.c
external/libjpeg/jdcoefct.c
external/libjpeg/jdcolor.c
external/libjpeg/jddctmgr.c
external/libjpeg/jdhuff.c
external/libjpeg/jdinput.c
external/libjpeg/jdmainct.c
external/libjpeg/jdmarker.c
external/libjpeg/jdmaster.c
external/libjpeg/jdmerge.c
external/libjpeg/jdpostct.c
external/libjpeg/jdsample.c
external/libjpeg/jerror.c
external/libjpeg/jfdctflt.c
external/libjpeg/jfdctfst.c
external/libjpeg/jfdctint.c
external/libjpeg/jidctflt.c
external/libjpeg/jidctfst.c
external/libjpeg/jidctint.c
external/libjpeg/jmemmgr.c
external/libjpeg/jmemnobs.c
external/libjpeg/jquant1.c
external/libjpeg/jquant2.c
external/libjpeg/jutils.c
)
endif ()
set(source_files ${source_files}
image_loader/jpeg_loader.cpp
image_saver/save_jpeg.cpp
)
endif ()
if (DLIB_WEBP_SUPPORT)
include(cmake_utils/find_libwebp.cmake)
if (WEBP_FOUND)
list(APPEND dlib_needed_private_includes ${WEBP_INCLUDE_DIR})
list(APPEND dlib_needed_private_libraries ${WEBP_LIBRARY})
set(source_files ${source_files}
image_loader/webp_loader.cpp
image_saver/save_webp.cpp
)
else ()
set(DLIB_WEBP_SUPPORT OFF CACHE BOOL ${DLIB_WEBP_SUPPORT_STR} FORCE)
toggle_preprocessor_switch(DLIB_WEBP_SUPPORT)
endif ()
endif ()
if (DLIB_USE_BLAS OR DLIB_USE_LAPACK OR DLIB_USE_MKL_FFT)
if (DLIB_USE_MKL_WITH_TBB AND DLIB_USE_MKL_SEQUENTIAL)
set(DLIB_USE_MKL_SEQUENTIAL OFF CACHE STRING ${DLIB_USE_MKL_SEQUENTIAL_STR} FORCE)
toggle_preprocessor_switch(DLIB_USE_MKL_SEQUENTIAL)
message(STATUS "Disabling DLIB_USE_MKL_SEQUENTIAL. It cannot be used simultaneously with DLIB_USE_MKL_WITH_TBB.")
endif ()
# Try to find BLAS, LAPACK and MKL
include(cmake_utils/find_blas.cmake)
if (DLIB_USE_BLAS)
if (blas_found)
list(APPEND dlib_needed_private_libraries ${blas_libraries})
else ()
set(DLIB_USE_BLAS OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE)
toggle_preprocessor_switch(DLIB_USE_BLAS)
endif ()
endif ()
if (DLIB_USE_LAPACK)
if (lapack_found)
list(APPEND dlib_needed_private_libraries ${lapack_libraries})
if (lapack_with_underscore)
set(LAPACK_FORCE_UNDERSCORE 1)
enable_preprocessor_switch(LAPACK_FORCE_UNDERSCORE)
elseif (lapack_without_underscore)
set(LAPACK_FORCE_NOUNDERSCORE 1)
enable_preprocessor_switch(LAPACK_FORCE_NOUNDERSCORE)
endif ()
else ()
set(DLIB_USE_LAPACK OFF CACHE STRING ${DLIB_USE_LAPACK_STR} FORCE)
toggle_preprocessor_switch(DLIB_USE_LAPACK)
endif ()
endif ()
if (DLIB_USE_MKL_FFT)
if (found_intel_mkl AND found_intel_mkl_headers)
list(APPEND dlib_needed_public_includes ${mkl_include_dir})
list(APPEND dlib_needed_public_libraries ${mkl_libraries})
else ()
set(DLIB_USE_MKL_FFT OFF CACHE STRING ${DLIB_USE_MKL_FFT_STR} FORCE)
toggle_preprocessor_switch(DLIB_USE_MKL_FFT)
endif ()
endif ()
endif ()
if (DLIB_USE_CUDA)
find_package(CUDA 7.5)
if (CUDA_VERSION VERSION_GREATER 9.1 AND CMAKE_VERSION VERSION_LESS 3.12.2)
# This bit of weirdness is to work around a bug in cmake
list(REMOVE_ITEM CUDA_CUBLAS_LIBRARIES "CUDA_cublas_device_LIBRARY-NOTFOUND")
endif ()
message("CUDA_VERSION: " ${CUDA_VERSION})
if (CUDA_FOUND AND MSVC AND NOT CUDA_CUBLAS_LIBRARIES AND "${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
message(WARNING "You have CUDA installed, but we can't use it unless you put visual studio in 64bit mode.")
set(CUDA_FOUND 0)
endif ()
message("11 CUDA_FOUND: " ${CUDA_VERSION})
if (NOT CUDA_CUBLAS_LIBRARIES)
message(STATUS "Found CUDA, but CMake was unable to find the cuBLAS libraries that should be part of every basic CUDA "
"install. Your CUDA install is somehow broken or incomplete. Since cuBLAS is required for dlib to use CUDA we won't use CUDA.")
set(CUDA_FOUND 0)
endif ()
message("22 CUDA_FOUND: " ${CUDA_VERSION})
if (CUDA_FOUND)
# There is some bug in cmake that causes it to mess up the
# -std=c++11 option if you let it propagate it to nvcc in some
# cases. So instead we disable this and manually include
# things from CMAKE_CXX_FLAGS in the CUDA_NVCC_FLAGS list below.
if (APPLE)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
# Grab all the -D flags from CMAKE_CXX_FLAGS so we can pass them
# to nvcc.
string(REGEX MATCHALL "-D[^ ]*" FLAGS_FOR_NVCC "${CMAKE_CXX_FLAGS}")
# Check if we are being built as part of a pybind11 module.
if (COMMAND pybind11_add_module)
# Don't export unnecessary symbols.
list(APPEND FLAGS_FOR_NVCC "-Xcompiler=-fvisibility=hidden")
endif ()
endif ()
set(CUDA_HOST_COMPILATION_CPP ON)
string(REPLACE "," ";" DLIB_CUDA_COMPUTE_CAPABILITIES ${DLIB_USE_CUDA_COMPUTE_CAPABILITIES})
message("DLIB_CUDA_COMPUTE_CAPABILITIES: " ${DLIB_CUDA_COMPUTE_CAPABILITIES})
foreach (CAP ${DLIB_CUDA_COMPUTE_CAPABILITIES})
list(APPEND CUDA_NVCC_FLAGS "-gencode arch=compute_${CAP},code=[sm_${CAP},compute_${CAP}]")
endforeach ()
# Note that we add __STRICT_ANSI__ to avoid freaking out nvcc with gcc specific
# magic in the standard C++ header files (since nvcc uses gcc headers on linux).
list(APPEND CUDA_NVCC_FLAGS "-D__STRICT_ANSI__;-D_MWAITXINTRIN_H_INCLUDED;-D_FORCE_INLINES;${FLAGS_FOR_NVCC}")
list(APPEND CUDA_NVCC_FLAGS ${active_preprocessor_switches})
if (NOT DLIB_IN_PROJECT_BUILD)
LIST(APPEND CUDA_NVCC_FLAGS -DDLIB__CMAKE_GENERATED_A_CONFIG_H_FILE)
endif ()
if (NOT MSVC)
list(APPEND CUDA_NVCC_FLAGS "-std=c++14")
endif ()
if (CMAKE_POSITION_INDEPENDENT_CODE)
# sometimes this setting isn't propagated to NVCC, which then causes the
# compile to fail. So make sure it's propagated.
if (NOT MSVC) # Visual studio doesn't have -fPIC so don't do it in that case.
list(APPEND CUDA_NVCC_FLAGS "-Xcompiler -fPIC")
endif ()
endif ()
message("CUDA_NVCC_FLAGS: " ${CUDA_NVCC_FLAGS})
include(cmake_utils/test_for_cudnn/find_cudnn.txt)
if (cudnn AND cudnn_include AND NOT DEFINED cuda_test_compile_worked AND NOT DEFINED cudnn_test_compile_worked)
# make sure cuda is really working by doing a test compile
message(STATUS "Building a CUDA test project to see if your compiler is compatible with CUDA...")
set(CUDA_TEST_CMAKE_FLAGS
"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"
"-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}"
"-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}")
if (NOT MSVC) # see https://github.com/davisking/dlib/issues/363
list(APPEND CUDA_TEST_CMAKE_FLAGS "-DCUDA_HOST_COMPILER=${CUDA_HOST_COMPILER}")
endif ()
try_compile(cuda_test_compile_worked
${PROJECT_BINARY_DIR}/cuda_test_build
${PROJECT_SOURCE_DIR}/cmake_utils/test_for_cuda cuda_test
CMAKE_FLAGS ${CUDA_TEST_CMAKE_FLAGS}
OUTPUT_VARIABLE try_compile_output_message
)
if (NOT cuda_test_compile_worked)
string(REPLACE "\n" "\n *** " try_compile_output_message "${try_compile_output_message}")
message(STATUS "*****************************************************************************************************************")
message(STATUS "*** CUDA was found but your compiler failed to compile a simple CUDA program so dlib isn't going to use CUDA. ")
message(STATUS "*** The output of the failed CUDA test compile is shown below: ")
message(STATUS "*** ")
message(STATUS "*** ${try_compile_output_message}")
message(STATUS "*****************************************************************************************************************")
else ()
message(STATUS "Building a cuDNN test project to check if you have the right version of cuDNN installed...")
try_compile(cudnn_test_compile_worked
${PROJECT_BINARY_DIR}/cudnn_test_build
${PROJECT_SOURCE_DIR}/cmake_utils/test_for_cudnn cudnn_test
CMAKE_FLAGS ${CUDA_TEST_CMAKE_FLAGS}
OUTPUT_VARIABLE try_compile_output_message
)
if (NOT cudnn_test_compile_worked)
string(REPLACE "\n" "\n *** " try_compile_output_message "${try_compile_output_message}")
message(STATUS "*****************************************************************************************************")
message(STATUS "*** Found cuDNN, but we failed to compile the dlib/cmake_utils/test_for_cudnn project. ")
message(STATUS "*** You either have an unsupported version of cuDNN or something is wrong with your cudDNN install.")
message(STATUS "*** Since a functional cuDNN is not found DLIB WILL NOT USE CUDA. ")
message(STATUS "*** The output of the failed test_for_cudnn build is: ")
message(STATUS "*** ")
message(STATUS "*** ${try_compile_output_message}")
message(STATUS "*****************************************************************************************************")
endif ()
endif ()
endif ()
message("CUDA_cusolver_LIBRARY=" ${CUDA_cusolver_LIBRARY})
# Find where cuSOLVER is since the FindCUDA cmake package doesn't
# bother to look for it in older versions of cmake.
if (NOT CUDA_cusolver_LIBRARY)
get_filename_component(cuda_blas_path "${CUDA_CUBLAS_LIBRARIES}" DIRECTORY)
find_library(CUDA_cusolver_LIBRARY cusolver HINTS ${cuda_blas_path})
# CUDA 10.1 doesn't install symbolic links to libcusolver.so in
# the usual place. This is probably a bug in the cuda
# installer. In any case, If we haven't found cusolver yet go
# look in the cuda install folder for it. New versions of cmake
# do this correctly, but older versions need help.
if (NOT CUDA_cusolver_LIBRARY)
find_library(CUDA_cusolver_LIBRARY cusolver HINTS
/usr/local/cuda/lib64/
)
endif ()
mark_as_advanced(CUDA_cusolver_LIBRARY)
endif ()
# Also find OpenMP since cuSOLVER needs it. Importantly, we only
# look for one to link to if our use of BLAS, specifically the
# Intel MKL, hasn't already decided what to use. This is because
# it makes the MKL bug out if you link to another openmp lib other
# than Intel's when you use the MKL. I'm also not really sure when
# explicit linking to openmp became unnecessary, but for
# sufficiently older versions of cuda it was needed. Then in
# versions of cmake newer than 3.11 linking to openmp started to
# mess up the switches passed to nvcc, so you can't just leave
# these "try to link to openmp" statements here going forward. Fun
# times.
if (CUDA_VERSION VERSION_LESS "9.1" AND NOT openmp_libraries AND NOT MSVC AND NOT XCODE AND NOT APPLE)
find_package(OpenMP)
if (OPENMP_FOUND)
set(openmp_libraries ${OpenMP_CXX_FLAGS})
else ()
message(STATUS "*** Didn't find OpenMP, which is required to use CUDA. ***")
set(CUDA_FOUND 0)
endif ()
endif ()
endif ()
if (CUDA_FOUND AND cudnn AND cuda_test_compile_worked AND cudnn_test_compile_worked AND cudnn_include)
set(source_files ${source_files}
cuda/cuda_dlib.cu
cuda/cudnn_dlibapi.cpp
cuda/cublas_dlibapi.cpp
cuda/cusolver_dlibapi.cu
cuda/curand_dlibapi.cpp
cuda/cuda_data_ptr.cpp
cuda/gpu_data.cpp
)
list(APPEND dlib_needed_private_libraries ${CUDA_CUBLAS_LIBRARIES})
list(APPEND dlib_needed_private_libraries ${cudnn})
list(APPEND dlib_needed_private_libraries ${CUDA_curand_LIBRARY})
list(APPEND dlib_needed_private_libraries ${CUDA_cusolver_LIBRARY})
list(APPEND dlib_needed_private_libraries ${CUDA_CUDART_LIBRARY})
if (openmp_libraries)
list(APPEND dlib_needed_private_libraries ${openmp_libraries})
endif ()
include_directories(${cudnn_include})
message(STATUS "Enabling CUDA support for dlib. DLIB WILL USE CUDA, compute capabilities: ${DLIB_CUDA_COMPUTE_CAPABILITIES}")
else ()
set(DLIB_USE_CUDA OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE)
toggle_preprocessor_switch(DLIB_USE_CUDA)
if (NOT CUDA_FOUND)
message(STATUS "DID NOT FIND CUDA")
endif ()
message(STATUS "Disabling CUDA support for dlib. DLIB WILL NOT USE CUDA")
endif ()
endif ()
if (DLIB_LINK_WITH_SQLITE3)
find_library(sqlite sqlite3)
# make sure sqlite3.h is in the include path
find_path(sqlite_path sqlite3.h)
if (sqlite AND sqlite_path)
list(APPEND dlib_needed_public_includes ${sqlite_path})
list(APPEND dlib_needed_public_libraries ${sqlite})
else ()
set(DLIB_LINK_WITH_SQLITE3 OFF CACHE STRING ${DLIB_LINK_WITH_SQLITE3_STR} FORCE)
endif ()
mark_as_advanced(sqlite sqlite_path)
endif ()
if (DLIB_USE_FFTW)
find_library(fftw fftw3)
# make sure fftw3.h is in the include path
find_path(fftw_path fftw3.h)
if (fftw AND fftw_path)
list(APPEND dlib_needed_private_includes ${fftw_path})
list(APPEND dlib_needed_private_libraries ${fftw})
else ()
set(DLIB_USE_FFTW OFF CACHE STRING ${DLIB_USE_FFTW_STR} FORCE)
toggle_preprocessor_switch(DLIB_USE_FFTW)
endif ()
mark_as_advanced(fftw fftw_path)
endif ()
if (DLIB_USE_FFMPEG)
include(cmake_utils/find_ffmpeg.cmake)
if (FFMPEG_FOUND)
list(APPEND dlib_needed_public_includes ${FFMPEG_INCLUDE_DIRS})
list(APPEND dlib_needed_public_libraries ${FFMPEG_LINK_LIBRARIES})
list(APPEND dlib_needed_public_cflags ${FFMPEG_CFLAGS})
list(APPEND dlib_needed_public_ldflags ${FFMPEG_LDFLAGS})
enable_preprocessor_switch(DLIB_USE_FFMPEG)
else ()
set(DLIB_USE_FFMPEG OFF CACHE BOOL ${DLIB_USE_FFMPEG_STR} FORCE)
disable_preprocessor_switch(DLIB_USE_FFMPEG)
endif ()
endif ()
# Tell CMake to build dlib via add_library()/cuda_add_library()
message("source_files: ${source_files}")
if (DLIB_USE_CUDA)
message("dlib_needed_public_includes: " ${dlib_needed_public_includes})
# The old cuda_add_library() command doesn't support CMake's newer dependency
# stuff, so we have to set the include path manually still, which we do here.
include_directories(${dlib_needed_public_includes})
cuda_add_library(dlib ${source_files})
else ()
add_library(dlib ${source_files})
endif ()
endif () ##### end of if NOT DLIB_ISO_CPP_ONLY ##########################################################
target_include_directories(dlib
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
INTERFACE $<INSTALL_INTERFACE:include>
PUBLIC ${dlib_needed_public_includes}
PRIVATE ${dlib_needed_private_includes}
)
target_link_libraries(dlib PUBLIC ${dlib_needed_public_libraries} ${dlib_needed_public_ldflags})
target_link_libraries(dlib PRIVATE ${dlib_needed_private_libraries})
target_compile_options(dlib PUBLIC ${dlib_needed_public_cflags})
if (DLIB_IN_PROJECT_BUILD)
target_compile_options(dlib PUBLIC ${active_preprocessor_switches})
else ()
# These are private in this case because they will be controlled by the
# contents of dlib/config.h once it's installed. But for in project
# builds, there is no real config.h so they are public in the above case.
target_compile_options(dlib PRIVATE ${active_preprocessor_switches})
# Do this so that dlib/config.h won't set DLIB_NOT_CONFIGURED. This will then allow
# the code in dlib/threads_kernel_shared.cpp to emit a linker error for users who
# don't use the configured config.h file generated by cmake.
target_compile_options(dlib PRIVATE -DDLIB__CMAKE_GENERATED_A_CONFIG_H_FILE)
# Do this so that dlib/config.h can record the version of dlib it's configured with
# and ultimately issue a linker error to people who try to use a binary dlib that is
# the wrong version.
set(DLIB_CHECK_FOR_VERSION_MISMATCH
DLIB_VERSION_MISMATCH_CHECK__EXPECTED_VERSION_${CPACK_PACKAGE_VERSION_MAJOR}_${CPACK_PACKAGE_VERSION_MINOR}_${CPACK_PACKAGE_VERSION_PATCH})
target_compile_options(dlib PRIVATE "-DDLIB_CHECK_FOR_VERSION_MISMATCH=${DLIB_CHECK_FOR_VERSION_MISMATCH}")
endif ()
# Allow the unit tests to ask us to compile the all/source.cpp file just to make sure it compiles.
if (DLIB_TEST_COMPILE_ALL_SOURCE_CPP)
add_library(dlib_all_source_cpp STATIC all/source.cpp)
target_link_libraries(dlib_all_source_cpp dlib)
target_compile_options(dlib_all_source_cpp PUBLIC ${active_preprocessor_switches})
target_compile_features(dlib_all_source_cpp PUBLIC cxx_std_14)
endif ()
target_compile_features(dlib PUBLIC cxx_std_14)
if ((MSVC AND CMAKE_VERSION VERSION_LESS 3.11))
target_compile_options(dlib PUBLIC ${active_compile_opts})
target_compile_options(dlib PRIVATE ${active_compile_opts_private})
else ()
target_compile_options(dlib PUBLIC $<$<COMPILE_LANGUAGE:CXX>:${active_compile_opts}>)
target_compile_options(dlib PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${active_compile_opts_private}>)
endif ()
# Install the library
if (NOT DLIB_IN_PROJECT_BUILD)
string(REPLACE ";" " " pkg_config_dlib_needed_libraries "${dlib_needed_public_libraries}")
# Make the -I include options for pkg-config
foreach (ITR ${dlib_needed_public_includes})
set(pkg_config_dlib_needed_includes "${pkg_config_dlib_needed_includes} -I${ITR}")
endforeach ()
set_target_properties(dlib PROPERTIES
VERSION ${VERSION})
install(TARGETS dlib
EXPORT dlib
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # Windows considers .dll to be runtime artifacts
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dlib
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.cmake"
PATTERN "*_tutorial.txt"
PATTERN "cassert"
PATTERN "cstring"
PATTERN "fstream"
PATTERN "iomanip"
PATTERN "iosfwd"
PATTERN "iostream"
PATTERN "istream"
PATTERN "locale"
PATTERN "ostream"
PATTERN "sstream"
REGEX "${CMAKE_CURRENT_BINARY_DIR}" EXCLUDE)
configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# overwrite config.h with the configured one
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dlib)
configure_file(${PROJECT_SOURCE_DIR}/revision.h.in ${CMAKE_CURRENT_BINARY_DIR}/revision.h)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/revision.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dlib)
## Config.cmake generation and installation
set(ConfigPackageLocation "${CMAKE_INSTALL_LIBDIR}/cmake/dlib")
install(EXPORT dlib
NAMESPACE dlib::
DESTINATION ${ConfigPackageLocation})
configure_file(cmake_utils/dlibConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfig.cmake" @ONLY)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfigVersion.cmake"
VERSION ${VERSION}
COMPATIBILITY AnyNewerVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfigVersion.cmake"
DESTINATION ${ConfigPackageLocation})
## dlib-1.pc generation and installation
configure_file("cmake_utils/dlib.pc.in" "dlib-1.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/dlib-1.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# Add a cpack "package" target. This will create an archive containing
# the built library file, the header files, and cmake and pkgconfig
# configuration files.
include(CPack)
endif ()
endif ()
if (MSVC)
# Give the output library files names that are unique functions of the
# visual studio mode that compiled them. We do this so that people who
# compile dlib and then copy the .lib files around (which they shouldn't be
# doing in the first place!) will hopefully be slightly less confused by
# what happens since, at the very least, the filenames will indicate what
# visual studio runtime they go with.
math(EXPR numbits ${CMAKE_SIZEOF_VOID_P}*8)
set_target_properties(dlib PROPERTIES DEBUG_POSTFIX "${VERSION}_debug_${numbits}bit_msvc${MSVC_VERSION}")
set_target_properties(dlib PROPERTIES RELEASE_POSTFIX "${VERSION}_release_${numbits}bit_msvc${MSVC_VERSION}")
set_target_properties(dlib PROPERTIES MINSIZEREL_POSTFIX "${VERSION}_minsizerel_${numbits}bit_msvc${MSVC_VERSION}")
set_target_properties(dlib PROPERTIES RELWITHDEBINFO_POSTFIX "${VERSION}_relwithdebinfo_${numbits}bit_msvc${MSVC_VERSION}")
endif ()
# Check if we are being built as part of a pybind11 module.
if (COMMAND pybind11_add_module)
# Don't export unnecessary symbols.
set_target_properties(dlib PROPERTIES CXX_VISIBILITY_PRESET "hidden")
set_target_properties(dlib PROPERTIES CUDA_VISIBILITY_PRESET "hidden")
endif ()
if (WIN32 AND mkl_iomp_dll)
# If we are using the Intel MKL on windows then try and copy the iomp dll
# file to the output folder. We do this since a very large number of
# windows users don't understand that they need to add the Intel MKL's
# folders to their PATH to use the Intel MKL. They then complain on the
# dlib forums. Copying the Intel MKL dlls to the output directory removes
# the need to add the Intel MKL to the PATH.
if (CMAKE_LIBRARY_OUTPUT_DIRECTORY)
add_custom_command(TARGET dlib POST_BUILD
# In some newer versions of windows/visual studio the output Config folder doesn't
# exist at first, so you can't copy to it unless you make it yourself. So make
# sure the target folder exists first.
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/"
COMMAND ${CMAKE_COMMAND} -E copy "${mkl_iomp_dll}" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/"
)
else ()
add_custom_command(TARGET dlib POST_BUILD
# In some newer versions of windows/visual studio the output Config folder doesn't
# exist at first, so you can't copy to it unless you make it yourself. So make
# sure the target folder exists first.
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/$<CONFIG>/"
COMMAND ${CMAKE_COMMAND} -E copy "${mkl_iomp_dll}" "${CMAKE_BINARY_DIR}/$<CONFIG>/"
)
endif ()
endif ()
add_library(dlib::dlib ALIAS dlib)
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
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifdef DLIB_ALL_SOURCE_END
#include "dlib_basic_cpp_build_tutorial.txt"
#endif
#ifndef DLIB_ALGs_
#define DLIB_ALGs_
// this file contains miscellaneous stuff
// Give people who forget the -std=c++14 option a reminder
#if (defined(__GNUC__) && ((__GNUC__ >= 5 && __GNUC_MINOR__ >= 0) || (__GNUC__ > 5))) || \
(defined(__clang__) && ((__clang_major__ >= 3 && __clang_minor__ >= 4) || (__clang_major__ >= 3)))
#if __cplusplus < 201402L
#error "Dlib requires C++14 support. Give your compiler the -std=c++14 option to enable it."
#endif
#endif
#if defined __NVCC__
// Disable the "statement is unreachable" message since it will go off on code that is
// actually reachable but just happens to not be reachable sometimes during certain
// template instantiations.
#ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
#pragma nv_diag_suppress code_is_unreachable
#else
#pragma diag_suppress code_is_unreachable
#endif
#endif
#ifdef _MSC_VER
#if _MSC_VER < 1900
#error "dlib versions newer than v19.1 use C++11 and therefore require Visual Studio 2015 or newer."
#endif
// 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)
// Disable warnings about conversion from size_t to unsigned long and long.
#pragma warning(disable : 4267)
// Disable warnings about conversion from double to float
#pragma warning(disable : 4244)
#pragma warning(disable : 4305)
// Disable "warning C4180: qualifier applied to function type has no meaning; ignored".
// This warning happens often in generic code that works with functions and isn't useful.
#pragma warning(disable : 4180)
// Disable "warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)"
#pragma warning(disable : 4290)
// DNN module uses template-based network declaration that leads to very long
// type names. Visual Studio will produce Warning C4503 in such cases. https://msdn.microsoft.com/en-us/library/074af4b6.aspx says
// that correct binaries are still produced even when this warning happens, but linker errors from visual studio, if they occur could be confusing.
#pragma warning( disable: 4503 )
#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
#include <string> // for the exceptions
#ifdef __CYGWIN__
namespace std
{
typedef std::basic_string<wchar_t> wstring;
}
#endif
#include "platform.h"
#include "windows_magic.h"
#include <algorithm> // for std::swap
#include <new> // for std::bad_alloc
#include <cstdlib>
#include <stddef.h>
#include <limits>
#include <cmath> // for std::isfinite for is_finite()
#include "assert.h"
#include "error.h"
#include "noncopyable.h"
#include "enable_if.h"
#include "uintn.h"
#include "numeric_constants.h"
#include "memory_manager_stateless/memory_manager_stateless_kernel_1.h" // for the default memory manager
#include "type_traits.h"
// ----------------------------------------------------------------------------------------
/*!A _dT !*/
template <typename charT>
inline charT _dTcast (const char a, const wchar_t b);
template <>
inline char _dTcast<char> (const char a, const wchar_t ) { return a; }
template <>
inline wchar_t _dTcast<wchar_t> (const char , const wchar_t b) { return b; }
template <typename charT>
inline const charT* _dTcast ( const char* a, const wchar_t* b);
template <>
inline const char* _dTcast<char> ( const char* a, const wchar_t* ) { return a; }
template <>
inline const wchar_t* _dTcast<wchar_t> ( const char* , const wchar_t* b) { return b; }
#define _dT(charT,str) _dTcast<charT>(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 default_memory_manager
This memory manager just calls new and delete directly.
!*/
typedef memory_manager_stateless_kernel_1<char> default_memory_manager;
// ----------------------------------------------------------------------------------------
/*!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
>
constexpr bool operator> (
const A& a,
const B& b
) { return b < a; }
// ---------------------------------
template <
typename A,
typename B
>
constexpr bool operator!= (
const A& a,
const B& b
) { return !(a == b); }
// ---------------------------------
template <
typename A,
typename B
>
constexpr bool operator<= (
const A& a,
const B& b
) { return !(b < a); }
// ---------------------------------
template <
typename A,
typename B
>
constexpr 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 can get
rid of this in a few years. So this function is already 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);
}
// ----------------------------------------------------------------------------------------
struct general_ {};
struct special_ : general_ {};
template<typename> struct int_ { typedef int type; };
// ----------------------------------------------------------------------------------------
/*!A is_same_object
This is a templated function which checks if both of its arguments are actually
references to the same object. It returns true if they are and false otherwise.
!*/
// handle the case where T and U are unrelated types.
template < typename T, typename U >
std::enable_if_t<!std::is_convertible<T*, U*>::value && !std::is_convertible<U*,T*>::value, bool>
is_same_object (
const T& a,
const U& b
)
{
return ((void*)&a == (void*)&b);
}
// handle the case where T and U are related types because their pointers can be
// implicitly converted into one or the other. E.g. a derived class and its base class.
// Or where both T and U are just the same type. This way we make sure that if there is a
// valid way to convert between these two pointer types then we will take that route rather
// than the void* approach used otherwise.
template < typename T, typename U >
std::enable_if_t<std::is_convertible<T*, U*>::value || std::is_convertible<U*,T*>::value, bool>
is_same_object (
const T& a,
const U& b
)
{
return (&a == &b);
}
// ----------------------------------------------------------------------------------------
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; };
// ----------------------------------------------------------------------------------------
template <typename T>
std::enable_if_t<std::is_floating_point<T>::value, bool> is_finite(T value)
/*!
requires
- value must be some kind of scalar type such as int or double
ensures
- returns true if value is a finite value (e.g. not infinity or NaN) and false
otherwise.
!*/
{
return std::isfinite(value);
}
template <typename T>
std::enable_if_t<std::is_integral<T>::value, bool> is_finite(T value)
{
return std::isfinite((double)value);
}
// ----------------------------------------------------------------------------------------
/*!A promote
This is a template that takes one of the built in scalar types and gives you another
scalar type that should be big enough to hold sums of values from the original scalar
type. The new scalar type will also always be signed.
For example, promote<uint16>::type == int32
!*/
template <typename T, size_t s = sizeof(T)> struct promote;
template <typename T> struct promote<T,1> { typedef int32 type; };
template <typename T> struct promote<T,2> { typedef int32 type; };
template <typename T> struct promote<T,4> { typedef int64 type; };
template <typename T> struct promote<T,8> { typedef int64 type; };
template <> struct promote<float,sizeof(float)> { typedef double type; };
template <> struct promote<double,sizeof(double)> { typedef double type; };
template <> struct promote<long double,sizeof(long double)> { typedef long double type; };
// ----------------------------------------------------------------------------------------
/*!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 <typename T> inline typename disable_if<is_built_in_scalar_type<T>,void>::type assign_zero_if_built_in_scalar_type (T&){}
template <typename T> inline typename enable_if<is_built_in_scalar_type<T>,void>::type assign_zero_if_built_in_scalar_type (T& a){a=0;}
// ----------------------------------------------------------------------------------------
template <typename T>
T put_in_range (
const T& a,
const T& b,
const T& val
)
/*!
requires
- T is a type that looks like double, float, int, or so forth
ensures
- if (val is within the range [a,b]) then
- returns val
- else
- returns the end of the range [a,b] that is closest to val
!*/
{
if (a < b)
{
if (val < a)
return a;
else if (val > b)
return b;
}
else
{
if (val < b)
return b;
else if (val > a)
return a;
}
return val;
}
// overload for double
inline double put_in_range(const double& a, const double& b, const double& val)
{ return put_in_range<double>(a,b,val); }
// ----------------------------------------------------------------------------------------
/*!A tabs
This is a template to compute the absolute value a number at compile time.
For example,
abs<-4>::value == 4
abs<4>::value == 4
!*/
template <long x, typename enabled=void>
struct tabs { const static long value = x; };
template <long x>
struct tabs<x,typename enable_if_c<(x < 0)>::type> { const static long value = -x; };
// ----------------------------------------------------------------------------------------
/*!A tmax
This is a template to compute the max of two values at compile time
For example,
abs<4,7>::value == 7
!*/
template <long x, long y, typename enabled=void>
struct tmax { const static long value = x; };
template <long x, long y>
struct tmax<x,y,typename enable_if_c<(y > x)>::type> { const static long value = y; };
// ----------------------------------------------------------------------------------------
/*!A tmin
This is a template to compute the min of two values at compile time
For example,
abs<4,7>::value == 4
!*/
template <long x, long y, typename enabled=void>
struct tmin { const static long value = x; };
template <long x, long y>
struct tmin<x,y,typename enable_if_c<(y < x)>::type> { const static long value = y; };
// ----------------------------------------------------------------------------------------
#define DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(testname, returnT, funct_name, args) \
struct _two_bytes_##testname { char a[2]; }; \
template < typename T, returnT (T::*funct)args > \
struct _helper_##testname { typedef char type; }; \
template <typename T> \
static char _has_##testname##_helper( typename _helper_##testname<T,&T::funct_name >::type ) { return 0;} \
template <typename T> \
static _two_bytes_##testname _has_##testname##_helper(int) { return _two_bytes_##testname();} \
template <typename T> struct _##testname##workaroundbug { \
const static unsigned long U = sizeof(_has_##testname##_helper<T>('a')); }; \
template <typename T, unsigned long U = _##testname##workaroundbug<T>::U > \
struct testname { static const bool value = false; }; \
template <typename T> \
struct testname<T,1> { static const bool value = true; };
/*!A DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST
The DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST() macro is used to define traits templates
that tell you if a class has a certain member function. For example, to make a
test to see if a class has a public method with the signature void print(int) you
would say:
DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, (int))
Then you can check if a class, T, has this method by looking at the boolean value:
has_print<T>::value
which will be true if the member function is in the T class.
Note that you can test for member functions taking no arguments by simply passing
in empty () like so:
DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ())
This would test for a member of the form:
void print().
To test for const member functions you would use a statement such as this:
DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ()const)
This would test for a member of the form:
void print() const.
To test for const templated member functions you would use a statement such as this:
DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, template print<int>, ())
This would test for a member of the form:
template <typename T> void print().
!*/
// ----------------------------------------------------------------------------------------
template <typename T> class funct_wrap0
{
public:
funct_wrap0(T (&f_)()):f(f_){}
T operator()() const { return f(); }
private:
T (&f)();
};
template <typename T, typename A0> class funct_wrap1
{
public:
funct_wrap1(T (&f_)(A0)):f(f_){}
T operator()(A0 a0) const { return f(a0); }
private:
T (&f)(A0);
};
template <typename T, typename A0, typename A1> class funct_wrap2
{
public:
funct_wrap2(T (&f_)(A0,A1)):f(f_){}
T operator()(A0 a0, A1 a1) const { return f(a0,a1); }
private:
T (&f)(A0,A1);
};
template <typename T, typename A0, typename A1, typename A2> class funct_wrap3
{
public:
funct_wrap3(T (&f_)(A0,A1,A2)):f(f_){}
T operator()(A0 a0, A1 a1, A2 a2) const { return f(a0,a1,a2); }
private:
T (&f)(A0,A1,A2);
};
template <typename T, typename A0, typename A1, typename A2, typename A3> class funct_wrap4
{
public:
funct_wrap4(T (&f_)(A0,A1,A2,A3)):f(f_){}
T operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { return f(a0,a1,a2,a3); }
private:
T (&f)(A0,A1,A2,A3);
};
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4> class funct_wrap5
{
public:
funct_wrap5(T (&f_)(A0,A1,A2,A3,A4)):f(f_){}
T operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { return f(a0,a1,a2,a3,a4); }
private:
T (&f)(A0,A1,A2,A3,A4);
};
/*!A wrap_function
This is a template that allows you to turn a global function into a
function object. The reason for this template's existence is so you can
do stuff like this:
template <typename T>
void call_funct(const T& funct)
{ cout << funct(); }
std::string test() { return "asdfasf"; }
int main()
{
call_funct(wrap_function(test));
}
The above code doesn't work right on some compilers if you don't
use wrap_function.
!*/
template <typename T>
funct_wrap0<T> wrap_function(T (&f)()) { return funct_wrap0<T>(f); }
template <typename T, typename A0>
funct_wrap1<T,A0> wrap_function(T (&f)(A0)) { return funct_wrap1<T,A0>(f); }
template <typename T, typename A0, typename A1>
funct_wrap2<T,A0,A1> wrap_function(T (&f)(A0, A1)) { return funct_wrap2<T,A0,A1>(f); }
template <typename T, typename A0, typename A1, typename A2>
funct_wrap3<T,A0,A1,A2> wrap_function(T (&f)(A0, A1, A2)) { return funct_wrap3<T,A0,A1,A2>(f); }
template <typename T, typename A0, typename A1, typename A2, typename A3>
funct_wrap4<T,A0,A1,A2,A3> wrap_function(T (&f)(A0, A1, A2, A3)) { return funct_wrap4<T,A0,A1,A2,A3>(f); }
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>
funct_wrap5<T,A0,A1,A2,A3,A4> wrap_function(T (&f)(A0, A1, A2, A3, A4)) { return funct_wrap5<T,A0,A1,A2,A3,A4>(f); }
// ----------------------------------------------------------------------------------------
template <unsigned long bSIZE>
class stack_based_memory_block : noncopyable
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a simple container for a block of memory
of bSIZE bytes. This memory block is located on the stack
and properly aligned to hold any kind of object.
!*/
public:
static const unsigned long size = bSIZE;
stack_based_memory_block(): data(mem.data) {}
void* get () { return data; }
/*!
ensures
- returns a pointer to the block of memory contained in this object
!*/
const void* get () const { return data; }
/*!
ensures
- returns a pointer to the block of memory contained in this object
!*/
private:
// You obviously can't have a block of memory that has zero bytes in it.
COMPILE_TIME_ASSERT(bSIZE > 0);
union mem_block
{
// All of this garbage is to make sure this union is properly aligned
// (a union is always aligned such that everything in it would be properly
// aligned. So the assumption here is that one of these objects has
// a large enough alignment requirement to satisfy any object this
// block of memory might be cast into).
void* void_ptr;
int integer;
struct {
void (stack_based_memory_block::*callback)();
stack_based_memory_block* o;
} stuff;
long double more_stuff;
uint64 var1;
uint32 var2;
double var3;
char data[size];
} mem;
// The reason for having this variable is that doing it this way avoids
// warnings from gcc about violations of strict-aliasing rules.
void* const data;
};
// ----------------------------------------------------------------------------------------
template <
typename T,
typename F
>
auto max_scoring_element(
const T& container,
F score_func
) -> decltype(std::make_pair(*container.begin(), 0.0))
/*!
requires
- container has .begin() and .end(), allowing it to be enumerated.
- score_func() is a function that takes an element of the container and returns a double.
ensures
- This function finds the element of container that has the largest score,
according to score_func(), and returns a std::pair containing that maximal
element along with the score.
- If the container is empty then make_pair(a default initialized object, -infinity) is returned.
!*/
{
double best_score = -std::numeric_limits<double>::infinity();
auto best_i = container.begin();
for (auto i = container.begin(); i != container.end(); ++i)
{
auto score = score_func(*i);
if (score > best_score)
{
best_score = score;
best_i = i;
}
}
using item_type = typename std::remove_reference<decltype(*best_i)>::type;
if (best_i == container.end())
return std::make_pair(item_type(), best_score);
else
return std::make_pair(*best_i, best_score);
}
// ----------------------------------------------------------------------------------------
template <
typename T,
typename F
>
auto min_scoring_element(
const T& container,
F score_func
) -> decltype(std::make_pair(*container.begin(), 0.0))
/*!
requires
- container has .begin() and .end(), allowing it to be enumerated.
- score_func() is a function that takes an element of the container and returns a double.
ensures
- This function finds the element of container that has the smallest score,
according to score_func(), and returns a std::pair containing that minimal
element along with the score.
- If the container is empty then make_pair(a default initialized object, infinity) is returned.
!*/
{
double best_score = std::numeric_limits<double>::infinity();
auto best_i = container.begin();
for (auto i = container.begin(); i != container.end(); ++i)
{
auto score = score_func(*i);
if (score < best_score)
{
best_score = score;
best_i = i;
}
}
using item_type = typename std::remove_reference<decltype(*best_i)>::type;
if (best_i == container.end())
return std::make_pair(item_type(), best_score);
else
return std::make_pair(*best_i, best_score);
}
// ----------------------------------------------------------------------------------------
namespace detail
{
template <class Tuple, class F, std::size_t... I>
constexpr void for_each_impl(Tuple&& t, F&& f, std::index_sequence<I...>)
{
#ifdef __cpp_fold_expressions
(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))),...);
#else
(void)std::initializer_list<int>{(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))),0)...};
#endif
}
}
template <class Tuple, class F>
constexpr void for_each_in_tuple(Tuple&& t, F&& f)
{
detail::for_each_impl(std::forward<Tuple>(t), std::forward<F>(f),
std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_ALGs_
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_ALL_SOURCe_
#define DLIB_ALL_SOURCe_
#if defined(DLIB_ALGs_) || defined(DLIB_PLATFORm_)
#include "../dlib_basic_cpp_build_tutorial.txt"
#endif
// 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 "../tokenizer/tokenizer_kernel_1.cpp"
#include "../unicode/unicode.cpp"
#include "../test_for_odr_violations.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 "../bsp/bsp.cpp"
#include "../dir_nav/dir_nav_kernel_1.cpp"
#include "../dir_nav/dir_nav_kernel_2.cpp"
#include "../dir_nav/dir_nav_extensions.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.cpp"
#include "../sockstreambuf/sockstreambuf_unbuffered.cpp"
#include "../server/server_kernel.cpp"
#include "../server/server_iostream.cpp"
#include "../server/server_http.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 "../threads/thread_pool_extension.cpp"
#include "../threads/async.cpp"
#include "../timer/timer.cpp"
#include "../stack_trace.cpp"
#ifdef DLIB_PNG_SUPPORT
#include "../image_loader/png_loader.cpp"
#include "../image_saver/save_png.cpp"
#endif
#ifdef DLIB_JPEG_SUPPORT
#include "../image_loader/jpeg_loader.cpp"
#include "../image_saver/save_jpeg.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
#include "../cuda/cpu_dlib.cpp"
#include "../cuda/tensor_tools.cpp"
#include "../data_io/image_dataset_metadata.cpp"
#include "../data_io/mnist.cpp"
#include "../data_io/cifar.cpp"
#include "../svm/auto.cpp"
#include "../global_optimization/global_function_search.cpp"
#include "../filtering/kalman_filter.cpp"
#endif // DLIB_ISO_CPP_ONLY
#define DLIB_ALL_SOURCE_END
#endif // DLIB_ALL_SOURCe_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_
#define DLIB_AnY_
#include "any/any.h"
#include "any/any_trainer.h"
#include "any/any_decision_function.h"
#include "any/any_function.h"
#endif // DLIB_AnY_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_H_
#define DLIB_AnY_H_
#include "any_abstract.h"
#include <memory>
#include "storage.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
class any
{
public:
any() = default;
any(const any& other) = default;
any& operator=(const any& other) = default;
any(any&& other) = default;
any& operator=(any&& other) = default;
template<
typename T,
std::enable_if_t<!std::is_same<std::decay_t<T>, any>::value, bool> = true
>
any(T&& item)
: storage{std::forward<T>(item)}
{
}
template<
typename T,
typename T_ = std::decay_t<T>,
std::enable_if_t<!std::is_same<T_, any>::value, bool> = true
>
any& operator=(T&& item)
{
if (contains<T_>())
storage.unsafe_get<T_>() = std::forward<T>(item);
else
*this = std::move(any{std::forward<T>(item)});
return *this;
}
bool is_empty() const { return storage.is_empty(); }
void clear() { storage.clear(); }
void swap (any& item) { std::swap(*this, item); }
template<typename T> bool contains() const { return storage.contains<T>();}
template <typename T> T& cast_to() { return storage.cast_to<T>(); }
template <typename T> const T& cast_to() const { return storage.cast_to<T>(); }
template <typename T> T& get() { return storage.get<T>(); }
private:
te::storage_heap storage;
};
// ----------------------------------------------------------------------------------------
template <typename T> T& any_cast(any& a) { return a.cast_to<T>(); }
template <typename T> const T& any_cast(const any& a) { return a.cast_to<T>(); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_H_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_ABSTRACT_H_
#ifdef DLIB_AnY_ABSTRACT_H_
#include <typeinfo>
namespace dlib
{
// ----------------------------------------------------------------------------------------
class bad_any_cast : public std::bad_cast
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is the exception class used by the any object.
It is used to indicate when someone attempts to cast an any
object into a type which isn't contained in the any object.
!*/
public:
virtual const char* what() const throw() { return "bad_any_cast"; }
};
// ----------------------------------------------------------------------------------------
class any
{
/*!
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is basically a type-safe version of a void*. In particular,
it is a container which can contain only one object but the object may
be of any type.
It is somewhat like the type_safe_union except you don't have to declare
the set of possible content types beforehand. So in some sense this is
like a less type-strict version of the type_safe_union.
!*/
public:
any(
);
/*!
ensures
- this object is properly initialized
!*/
any (
const any& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
any_function (
any_function&& item
);
/*!
ensures
- #item.is_empty() == true
- moves item into *this.
!*/
template < typename T >
any (
const T& item
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. a copy of item will be stored in *this)
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any& operator= (
const any& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
void swap (
any& item
);
/*!
ensures
- swaps *this and item
- does not invalidate pointers or references to the object contained
inside *this or item. Moreover, a pointer or reference to the object in
*this will now refer to the contents of #item and vice versa.
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename T
>
T& any_cast(
any& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T
>
const T& any_cast(
const any& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_ABSTRACT_H_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_DECISION_FUNCTION_Hh_
#define DLIB_AnY_DECISION_FUNCTION_Hh_
#include "any_decision_function_abstract.h"
#include "any_function.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <class sample_type, class result_type = double>
using any_decision_function = any_function<result_type(const sample_type&)>;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_DECISION_FUNCTION_Hh_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_
#ifdef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_
#include "any_function_abstract.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <class sample_type, class result_type = double>
using any_decision_function = any_function<result_type(const sample_type&)>;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_FUNCTION_Hh_
#define DLIB_AnY_FUNCTION_Hh_
#include "../assert.h"
#include "../functional.h"
#include "any.h"
#include "any_function_abstract.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
class Storage,
class F
>
class any_function_basic;
template <
class Storage,
class R,
class... Args
>
class any_function_basic<Storage, R(Args...)>
{
private:
template<class F>
using is_valid = std::enable_if_t<!std::is_same<std::decay_t<F>, any_function_basic>::value &&
dlib::is_invocable_r<R, F, Args...>::value,
bool>;
template<typename Func>
static auto make_invoker()
{
return [](void* self, Args... args) -> R {
return dlib::invoke(*reinterpret_cast<std::add_pointer_t<Func>>(self),
std::forward<Args>(args)...);
};
}
Storage str;
R (*func)(void*, Args...) = nullptr;
public:
using result_type = R;
constexpr any_function_basic(std::nullptr_t) noexcept {}
constexpr any_function_basic() = default;
constexpr any_function_basic(const any_function_basic& other) = default;
constexpr any_function_basic& operator=(const any_function_basic& other) = default;
constexpr any_function_basic(any_function_basic&& other)
: str{std::move(other.str)},
func{std::exchange(other.func, nullptr)}
{
}
constexpr any_function_basic& operator=(any_function_basic&& other)
{
if (this != &other)
{
str = std::move(other.str);
func = std::exchange(other.func, nullptr);
}
return *this;
}
template<class F, is_valid<F> = true>
any_function_basic(
F&& f
) : str{std::forward<F>(f)},
func{make_invoker<F&&>()}
{
}
template<class F, is_valid<F> = true>
any_function_basic(
F* f
) : str{f},
func{make_invoker<F*>()}
{
}
R operator()(Args... args) const {
return func(const_cast<void*>(str.get_ptr()), std::forward<Args>(args)...);
}
void clear() { str.clear(); }
void swap (any_function_basic& item) { std::swap(*this, item); }
bool is_empty() const noexcept { return str.is_empty() || func == nullptr; }
bool is_set() const noexcept { return !is_empty(); }
explicit operator bool() const noexcept { return is_set(); }
template <typename T> bool contains() const { return str.template contains<T>();}
template <typename T> T& cast_to() { return str.template cast_to<T>(); }
template <typename T> const T& cast_to() const { return str.template cast_to<T>(); }
template <typename T> T& get() { return str.template get<T>(); }
};
// ----------------------------------------------------------------------------------------
template <class T, class Storage, class F>
T& any_cast(any_function_basic<Storage, F>& a) { return a.template cast_to<T>(); }
template <class T, class Storage, class F>
const T& any_cast(const any_function_basic<Storage, F>& a) { return a.template cast_to<T>(); }
// ----------------------------------------------------------------------------------------
template <class F>
using any_function = any_function_basic<te::storage_sbo<16>, F>;
template <class F>
using any_function_view = any_function_basic<te::storage_view, F>;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_FUNCTION_Hh_
// Copyright (C) 2011 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_FUNCTION_ABSTRACT_H_
#ifdef DLIB_AnY_FUNCTION_ABSTRACT_H_
#include "any_abstract.h"
#include "../algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
class Storage,
typename function_type
>
class any_function_basic
{
/*!
REQUIREMENTS ON Storage
This must be one of the storage types from dlib/any/storage.hh
E.g. storage_heap, storage_stack, etc.
It determines the method by which any_function_basic holds onto the function it uses.
REQUIREMENTS ON function_type
This type should be a function signature. Some examples are:
void (int,int) // a function returning nothing and taking two ints
void () // a function returning nothing and taking no arguments
char (double&) // a function returning a char and taking a reference to a double
The number of arguments in the function must be no greater than 10.
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is a version of dlib::any that is restricted to containing
elements which are some kind of function object with an operator() which
matches the function signature defined by function_type.
Here is an example:
#include <iostream>
#include <string>
#include "dlib/any.h"
using namespace std;
void print_message(string str) { cout << str << endl; }
int main()
{
dlib::any_function<void(string)> f;
f = print_message;
f("hello world"); // calls print_message("hello world")
}
Note that any_function_basic objects can be used to store general function
objects (i.e. defined by a class with an overloaded operator()) in
addition to regular global functions.
!*/
public:
// This is the type of object returned by function_type functions.
typedef result_type_for_function_type result_type;
any_function_basic(
);
/*!
ensures
- this object is properly initialized
!*/
any_function_basic (
const any_function_basic& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
any_function_basic (
any_function_basic&& item
);
/*!
ensures
- moves item into *this.
- The exact move semantics are determined by which Storage type is used. E.g.
storage_heap will result in #item.is_empty()==true but storage_view would result
in #item.is_empty() == false
!*/
template < typename Funct >
any_function_basic (
Funct&& funct
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. calling operator() will invoke funct())
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
bool is_set (
) const;
/*!
ensures
- returns !is_empty()
!*/
explicit operator bool(
) const;
/*!
ensures
- returns is_set()
!*/
result_type operator(Args... args) (
) const;
/*!
requires
- is_empty() == false
- the signature defined by function_type takes no arguments
ensures
- Let F denote the function object contained within *this. Then
this function performs:
return F(std::forward<Args>(args)...)
!*/
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any_function_basic object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any_function_basic& operator= (
const any_function_basic& item
);
/*!
ensures
- copies the state of item into *this.
- Note that the type of copy is determined by the Storage template argument. E.g.
storage_sbo will result in a deep copy, while storage_view would result in *this
and item referring to the same underlying function.
!*/
void swap (
any_function_basic& item
);
/*!
ensures
- swaps *this and item
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename T,
typename function_type
>
T& any_cast(
any_function_basic<function_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename function_type
>
const T& any_cast(
const any_function_basic<function_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
/*!A any_function
A version of any_function_basic (defined above) that owns the function it contains. Uses
the small buffer optimization to make working with small lambdas faster.
!*/
template <class F>
using any_function = any_function_basic<te::storage_sbo<16>, F>;
/*!A any_function_view
A version of any_function_basic (defined above) that *DOES NOT* own the function it
contains. It merely holds a pointer to the function given to its constructor.
!*/
template <class F>
using any_function_view = any_function_basic<te::storage_view, F>;
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_FUNCTION_ABSTRACT_H_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_AnY_TRAINER_H_
#define DLIB_AnY_TRAINER_H_
#include "any.h"
#include "any_decision_function.h"
#include "any_trainer_abstract.h"
#include <vector>
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename sample_type_,
typename scalar_type_ = double
>
class any_trainer
{
public:
using sample_type = sample_type_;
using scalar_type = scalar_type_;
using mem_manager_type = default_memory_manager;
using trained_function_type = any_decision_function<sample_type, scalar_type>;
any_trainer() = default;
any_trainer(const any_trainer& other) = default;
any_trainer& operator=(const any_trainer& other) = default;
any_trainer(any_trainer&& other) = default;
any_trainer& operator=(any_trainer&& other) = default;
template <
class T,
class T_ = std::decay_t<T>,
std::enable_if_t<!std::is_same<T_,any_trainer>::value, bool> = true
>
any_trainer (
T&& item
) : storage{std::forward<T>(item)},
train_func{[](
const void* ptr,
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) -> trained_function_type {
const T_& f = *reinterpret_cast<const T_*>(ptr);
return f.train(samples, labels);
}}
{
}
template <
class T,
class T_ = std::decay_t<T>,
std::enable_if_t<!std::is_same<T_,any_trainer>::value, bool> = true
>
any_trainer& operator= (
T&& item
)
{
if (contains<T_>())
storage.unsafe_get<T_>() = std::forward<T>(item);
else
*this = std::move(any_trainer{std::forward<T>(item)});
return *this;
}
trained_function_type train (
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
{
// make sure requires clause is not broken
DLIB_ASSERT(is_empty() == false,
"\t trained_function_type any_trainer::train()"
<< "\n\t You can't call train() on an empty any_trainer"
<< "\n\t this: " << this
);
return train_func(storage.get_ptr(), samples, labels);
}
bool is_empty() const { return storage.is_empty(); }
void clear() { storage.clear(); }
void swap (any_trainer& item) { std::swap(*this, item); }
template <typename T> bool contains() const { return storage.contains<T>();}
template <typename T> T& cast_to() { return storage.cast_to<T>(); }
template <typename T> const T& cast_to() const { return storage.cast_to<T>(); }
template <typename T> T& get() { return storage.get<T>(); }
private:
te::storage_heap storage;
trained_function_type (*train_func) (
const void* self,
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) = nullptr;
};
// ----------------------------------------------------------------------------------------
template <typename T, typename U, typename V>
T& any_cast(any_trainer<U,V>& a) { return a.template cast_to<T>(); }
template <typename T, typename U, typename V>
const T& any_cast(const any_trainer<U,V>& a) { return a.template cast_to<T>(); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_TRAINER_H_
// Copyright (C) 2010 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_AnY_TRAINER_ABSTRACT_H_
#ifdef DLIB_AnY_TRAINER_ABSTRACT_H_
#include "any_abstract.h"
#include "../algs.h"
#include "any_decision_function_abstract.h"
#include <vector>
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename sample_type_,
typename scalar_type_ = double
>
class any_trainer
{
/*!
INITIAL VALUE
- is_empty() == true
- for all T: contains<T>() == false
WHAT THIS OBJECT REPRESENTS
This object is a version of dlib::any that is restricted to containing
elements which are some kind of object with a .train() method compatible
with the following signature:
decision_function train(
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
Where decision_function is a type capable of being stored in an
any_decision_function<sample_type,scalar_type> object.
any_trainer is intended to be used to contain objects such as the svm_nu_trainer
and other similar types which represent supervised machine learning algorithms.
It allows you to write code which contains and processes these trainer objects
without needing to know the specific types of trainer objects used.
!*/
public:
typedef sample_type_ sample_type;
typedef scalar_type_ scalar_type;
typedef default_memory_manager mem_manager_type;
typedef any_decision_function<sample_type, scalar_type> trained_function_type;
any_trainer(
);
/*!
ensures
- this object is properly initialized
!*/
any_trainer (
const any_trainer& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
any_trainer (
any_trainer&& item
);
/*!
ensures
- #item.is_empty() == true
- moves item into *this.
!*/
template < typename T >
any_trainer (
const T& item
);
/*!
ensures
- #contains<T>() == true
- #cast_to<T>() == item
(i.e. a copy of item will be stored in *this)
!*/
void clear (
);
/*!
ensures
- #*this will have its default value. I.e. #is_empty() == true
!*/
template <typename T>
bool contains (
) const;
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
bool is_empty(
) const;
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
trained_function_type train (
const std::vector<sample_type>& samples,
const std::vector<scalar_type>& labels
) const
/*!
requires
- is_empty() == false
ensures
- Let TRAINER denote the object contained within *this. Then
this function performs:
return TRAINER.train(samples, labels)
!*/
template <typename T>
T& cast_to(
);
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
const T& cast_to(
) const;
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
template <typename T>
T& get(
);
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any_trainer object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
any_trainer& operator= (
const any_trainer& item
);
/*!
ensures
- copies the state of item into *this.
- Note that *this and item will contain independent copies of the
contents of item. That is, this function performs a deep
copy and therefore does not result in *this containing
any kind of reference to item.
!*/
void swap (
any_trainer& item
);
/*!
ensures
- swaps *this and item
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename sample_type,
typename scalar_type
>
inline void swap (
any_trainer<sample_type,scalar_type>& a,
any_trainer<sample_type,scalar_type>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename sample_type,
typename scalar_type
>
T& any_cast(
any_trainer<sample_type,scalar_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
template <
typename T,
typename sample_type,
typename scalar_type
>
const T& any_cast(
const any_trainer<sample_type,scalar_type>& a
) { return a.cast_to<T>(); }
/*!
ensures
- returns a.cast_to<T>()
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_AnY_TRAINER_ABSTRACT_H_
// Copyright (C) 2022 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_TYPE_ERASURE_H_
#define DLIB_TYPE_ERASURE_H_
#include <type_traits>
#include <utility>
#include <typeindex>
#include <new>
#include <memory>
namespace dlib
{
// -----------------------------------------------------------------------------------------------------
class bad_any_cast : public std::bad_cast
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is the exception class used by the storage objects.
It is used to indicate when someone attempts to cast a storage
object into a type which isn't contained in the object.
!*/
public:
virtual const char * what() const throw()
{
return "bad_any_cast";
}
};
// -----------------------------------------------------------------------------------------------------
namespace te
{
/*!
This is used as a SFINAE tool to prevent a function taking a universal reference from
binding to some undesired type. For example:
template <
typename T,
T_is_not_this_type<SomeExcludedType, T> = true
>
void foo(T&&);
prevents foo() from binding to an object of type SomeExcludedType.
!*/
template<class Storage, class T>
using T_is_not_this_type = std::enable_if_t<!std::is_same<std::decay_t<T>, Storage>::value, bool>;
// -----------------------------------------------------------------------------------------------------
template<class Storage>
class storage_base
{
/*!
WHAT THIS OBJECT REPRESENTS
This class defines functionality common to all type erasure storage objects
(defined below in this file). These objects are essentially type-safe versions of
a void*. In particular, they are containers which can contain only one object
but the object may be of any type.
Each storage object implements a different way of storing the underlying object.
E.g. on the heap or stack or some other more specialized method.
!*/
public:
bool is_empty() const
/*!
ensures
- if (this object contains any kind of object) then
- returns false
- else
- returns true
!*/
{
const Storage& me = *static_cast<const Storage*>(this);
return me.get_ptr() == nullptr;
}
template<typename T>
bool contains() const
/*!
ensures
- if (this object currently contains an object of type T) then
- returns true
- else
- returns false
!*/
{
const Storage& me = *static_cast<const Storage*>(this);
return !is_empty() && me.type_id() == std::type_index{typeid(T)};
}
template<typename T>
T& unsafe_get()
/*!
requires
- contains<T>() == true
ensures
- returns a reference to the object contained within *this.
!*/
{
Storage& me = *static_cast<Storage*>(this);
return *reinterpret_cast<T*>(me.get_ptr());
}
template<typename T>
const T& unsafe_get() const
/*!
requires
- contains<T>() == true
ensures
- returns a const reference to the object contained within *this.
!*/
{
const Storage& me = *static_cast<const Storage*>(this);
return *reinterpret_cast<const T*>(me.get_ptr());
}
template <typename T>
T& get(
)
/*!
ensures
- #is_empty() == false
- #contains<T>() == true
- if (contains<T>() == true)
- returns a non-const reference to the object contained in *this.
- else
- Constructs an object of type T inside *this
- Any previous object stored in this any object is destructed and its
state is lost.
- returns a non-const reference to the newly created T object.
!*/
{
Storage& me = *static_cast<Storage*>(this);
if (!contains<T>())
me = T{};
return unsafe_get<T>();
}
template <typename T>
T& cast_to(
)
/*!
ensures
- if (contains<T>() == true) then
- returns a non-const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
{
if (!contains<T>())
throw bad_any_cast{};
return unsafe_get<T>();
}
template <typename T>
const T& cast_to(
) const
/*!
ensures
- if (contains<T>() == true) then
- returns a const reference to the object contained within *this
- else
- throws bad_any_cast
!*/
{
if (!contains<T>())
throw bad_any_cast{};
return unsafe_get<T>();
}
};
// -----------------------------------------------------------------------------------------------------
class storage_heap : public storage_base<storage_heap>
{
public:
/*!
WHAT THIS OBJECT REPRESENTS
This object is a storage type that uses type erasure to erase any type.
This particular storage type uses heap allocation only.
!*/
storage_heap() = default;
/*!
ensures
- #is_empty() == true
- for all T: #contains<T>() == false
!*/
template <
class T,
class T_ = std::decay_t<T>,
T_is_not_this_type<storage_heap, T> = true
>
storage_heap(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)
/*!
ensures
- copies or moves the incoming object (depending on the forwarding reference)
- #is_empty() == false
- #contains<std::decay_t<T>>() == true
- #unsafe_get<T>() will yield the provided t.
!*/
: ptr{new T_{std::forward<T>(t)}},
del{[](void *self) {
delete reinterpret_cast<T_*>(self);
}},
copy{[](const void *self) -> void * {
return new T_{*reinterpret_cast<const T_*>(self)};
}},
type_id_{[] {
return std::type_index{typeid(T_)};
}}
{
}
storage_heap(const storage_heap& other)
/*!
ensures
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is copied using erased type's copy constructor.
!*/
: ptr{other.ptr ? other.copy(other.ptr) : nullptr},
del{other.del},
copy{other.copy},
type_id_{other.type_id_}
{
}
storage_heap& operator=(const storage_heap& other)
/*!
ensures
- if is_empty() == false then
- destructs the object contained in this class.
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is copied using erased type's copy constructor.
!*/
{
if (this != &other)
*this = std::move(storage_heap{other});
return *this;
}
storage_heap(storage_heap&& other) noexcept
/*!
ensures
- The state of other is moved into *this.
- #other.is_empty() == true
!*/
: ptr{std::exchange(other.ptr, nullptr)},
del{std::exchange(other.del, nullptr)},
copy{std::exchange(other.copy, nullptr)},
type_id_{std::exchange(other.type_id_, nullptr)}
{
}
storage_heap& operator=(storage_heap&& other) noexcept
/*!
ensures
- The state of other is moved into *this.
- #other.is_empty() == true
- returns *this
!*/
{
if (this != &other)
{
clear();
ptr = std::exchange(other.ptr, nullptr);
del = std::exchange(other.del, nullptr);
copy = std::exchange(other.copy, nullptr);
type_id_ = std::exchange(other.type_id_, nullptr);
}
return *this;
}
~storage_heap()
/*!
ensures
- destructs the object contained in *this if one exists.
!*/
{
if (ptr)
del(ptr);
}
void clear()
/*!
ensures
- #is_empty() == true
!*/
{
storage_heap{std::move(*this)};
}
void* get_ptr()
/*!
ensures
- returns a pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr;
}
const void* get_ptr() const
/*!
ensures
- returns a const pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr;
}
std::type_index type_id() const
/*!
requires
- is_empty() == false
ensures
- returns the std::type_index of the type contained within this object.
I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.
!*/
{
return type_id_();
}
private:
void* ptr = nullptr;
void (*del)(void*) = nullptr;
void* (*copy)(const void*) = nullptr;
std::type_index (*type_id_)() = nullptr;
};
// -----------------------------------------------------------------------------------------------------
template <std::size_t Size, std::size_t Alignment = 8>
class storage_stack : public storage_base<storage_stack<Size, Alignment>>
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a storage type that uses type erasure to erase any type.
This particular storage type uses stack allocation using a template size and alignment.
Therefore, only objects whose size and alignment fits the template parameters can be
erased and absorbed into this object. Attempting to store a type not
representable on the stack with those settings will result in a build error.
!*/
public:
storage_stack() = default;
/*!
ensures
- #is_empty() == true
- for all T: #contains<T>() == false
!*/
template <
class T,
class T_ = std::decay_t<T>,
T_is_not_this_type<storage_stack, T> = true
>
storage_stack(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)
/*!
ensures
- copies or moves the incoming object (depending on the forwarding reference)
- #is_empty() == false
- #contains<std::decay_t<T>>() == true
!*/
: del{[](storage_stack& self) {
reinterpret_cast<T_*>(&self.data)->~T_();
self.del = nullptr;
self.copy = nullptr;
self.move = nullptr;
self.type_id_ = nullptr;
}},
copy{[](const storage_stack& src, storage_stack& dst) {
new (&dst.data) T_{*reinterpret_cast<const T_*>(&src.data)};
dst.del = src.del;
dst.copy = src.copy;
dst.move = src.move;
dst.type_id_ = src.type_id_;
}},
move{[](storage_stack& src, storage_stack& dst) {
new (&dst.data) T_{std::move(*reinterpret_cast<T_*>(&src.data))};
dst.del = src.del;
dst.copy = src.copy;
dst.move = src.move;
dst.type_id_ = src.type_id_;
}},
type_id_{[] {
return std::type_index{typeid(T_)};
}}
{
static_assert(sizeof(T_) <= Size, "insufficient size");
static_assert(Alignment % alignof(T_) == 0, "bad alignment");
new (&data) T_{std::forward<T>(t)};
}
storage_stack(const storage_stack& other)
/*!
ensures
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is copied using erased type's copy constructor.
!*/
{
if (other.copy)
other.copy(other, *this);
}
storage_stack& operator=(const storage_stack& other)
/*!
ensures
- #is_empty() == other.is_empty()
- if is_empty() == false then
- destructs the object contained in this class.
- if other.is_empty() == false then
- underlying object of other is copied using erased type's copy constructor
!*/
{
if (this != &other)
{
clear();
if (other.copy)
other.copy(other, *this);
}
return *this;
}
storage_stack(storage_stack&& other)
/*!
ensures
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is moved using erased type's moved constructor
!*/
{
if (other.move)
other.move(other, *this);
}
storage_stack& operator=(storage_stack&& other)
/*!
ensures
- if is_empty() == false then
- destructs the object contained in this class.
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is moved using erased type's moved constructor.
This does not make other empty. It will still contain a moved from object
of the underlying type in whatever that object's moved from state is.
- #other.is_empty() == false
!*/
{
if (this != &other)
{
clear();
if (other.move)
other.move(other, *this);
}
return *this;
}
~storage_stack()
/*!
ensures
- destructs the object contained in *this if one exists.
!*/
{
clear();
}
void clear()
/*!
ensures
- #is_empty() == true
!*/
{
if (del)
del(*this);
}
void* get_ptr()
/*!
ensures
- returns a pointer to the underlying object or nullptr if is_empty()
!*/
{
return del ? (void*)&data : nullptr;
}
const void* get_ptr() const
/*!
ensures
- returns a const pointer to the underlying object or nullptr if is_empty()
!*/
{
return del ? (const void*)&data : nullptr;
}
std::type_index type_id() const
/*!
requires
- is_empty() == false
ensures
- returns the std::type_index of the type contained within this object.
I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.
!*/
{
return type_id_();
}
private:
std::aligned_storage_t<Size, Alignment> data;
void (*del)(storage_stack&) = nullptr;
void (*copy)(const storage_stack&, storage_stack&) = nullptr;
void (*move)(storage_stack&, storage_stack&) = nullptr;
std::type_index (*type_id_)() = nullptr;
};
// -----------------------------------------------------------------------------------------------------
template <std::size_t Size, std::size_t Alignment = 8>
class storage_sbo : public storage_base<storage_sbo<Size, Alignment>>
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a storage type that uses type erasure to erase any type.
This particular storage type uses small buffer optimization (SBO), i.e. optional
stack allocation if the erased type has sizeof <= Size and alignment
requirements no greater than the given Alignment template value. If not it
allocates the object on the heap.
!*/
public:
// type_fits<T>::value tells us if our SBO can hold T.
template<typename T>
struct type_fits : std::integral_constant<bool, sizeof(T) <= Size && Alignment % alignof(T) == 0>{};
storage_sbo() = default;
/*!
ensures
- #is_empty() == true
- for all T: #contains<T>() == false
!*/
template <
class T,
class T_ = std::decay_t<T>,
T_is_not_this_type<storage_sbo, T> = true,
std::enable_if_t<type_fits<T_>::value, bool> = true
>
storage_sbo(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)
/*!
ensures
- copies or moves the incoming object (depending on the forwarding reference)
- #is_empty() == false
- #contains<std::decay_t<T>>() == true
- stack allocation is used
!*/
: ptr{new (&data) T_{std::forward<T>(t)}},
del{[](storage_sbo& self) {
reinterpret_cast<T_*>(&self.data)->~T_();
self.ptr = nullptr;
self.del = nullptr;
self.copy = nullptr;
self.move = nullptr;
self.type_id_ = nullptr;
}},
copy{[](const storage_sbo& src, storage_sbo& dst) {
dst.ptr = new (&dst.data) T_{*reinterpret_cast<const T_*>(src.ptr)};
dst.del = src.del;
dst.copy = src.copy;
dst.move = src.move;
dst.type_id_ = src.type_id_;
}},
move{[](storage_sbo& src, storage_sbo& dst) {
dst.ptr = new (&dst.data) T_{std::move(*reinterpret_cast<T_*>(src.ptr))};
dst.del = src.del;
dst.copy = src.copy;
dst.move = src.move;
dst.type_id_ = src.type_id_;
}},
type_id_{[] {
return std::type_index{typeid(T_)};
}}
{
}
template <
class T,
class T_ = std::decay_t<T>,
T_is_not_this_type<storage_sbo, T> = true,
std::enable_if_t<!type_fits<T_>::value, bool> = true
>
storage_sbo(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)
/*!
ensures
- copies or moves the incoming object (depending on the forwarding reference)
- #is_empty() == false
- #contains<std::decay_t<T>>() == true
- heap allocation is used
!*/
: ptr{new T_{std::forward<T>(t)}},
del{[](storage_sbo& self) {
delete reinterpret_cast<T_*>(self.ptr);
self.ptr = nullptr;
self.del = nullptr;
self.copy = nullptr;
self.move = nullptr;
self.type_id_ = nullptr;
}},
copy{[](const storage_sbo& src, storage_sbo& dst) {
dst.ptr = new T_{*reinterpret_cast<const T_*>(src.ptr)};
dst.del = src.del;
dst.copy = src.copy;
dst.move = src.move;
dst.type_id_ = src.type_id_;
}},
move{[](storage_sbo& src, storage_sbo& dst) {
dst.ptr = std::exchange(src.ptr, nullptr);
dst.del = std::exchange(src.del, nullptr);
dst.copy = std::exchange(src.copy, nullptr);
dst.move = std::exchange(src.move, nullptr);
dst.type_id_ = std::exchange(src.type_id_, nullptr);
}},
type_id_{[] {
return std::type_index{typeid(T_)};
}}
{
}
storage_sbo(const storage_sbo& other)
/*!
ensures
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is copied using erased type's copy constructor
!*/
{
if (other.copy)
other.copy(other, *this);
}
storage_sbo& operator=(const storage_sbo& other)
/*!
ensures
- if is_empty() == false then
- destructs the object contained in this class.
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- underlying object of other is copied using erased type's copy constructor
!*/
{
if (this != &other)
{
clear();
if (other.copy)
other.copy(other, *this);
}
return *this;
}
storage_sbo(storage_sbo&& other)
/*!
ensures
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- if underlying object of other is allocated on stack then
- underlying object of other is moved using erased type's moved constructor.
This does not make other empty. It will still contain a moved from
object of the underlying type in whatever that object's moved from
state is.
- #other.is_empty() == false
- else
- storage heap pointer is moved.
- #other.is_empty() == true
!*/
{
if (other.move)
other.move(other, *this);
}
storage_sbo& operator=(storage_sbo&& other)
/*!
ensures
- underlying object is destructed if is_empty() == false
- #is_empty() == other.is_empty()
- if other.is_empty() == false then
- if underlying object of other is allocated on stack then
- underlying object of other is moved using erased type's moved constructor.
This does not make other empty. It will still contain a moved from
object of the underlying type in whatever that object's moved from
state is.
- #other.is_empty() == false
- else
- storage heap pointer is moved.
- #other.is_empty() == true
!*/
{
if (this != &other)
{
clear();
if (other.move)
other.move(other, *this);
}
return *this;
}
~storage_sbo()
/*!
ensures
- destructs the object contained in *this if one exists.
!*/
{
clear();
}
void clear()
/*!
ensures
- #is_empty() == true
!*/
{
if (ptr)
del(*this);
}
void* get_ptr()
/*!
ensures
- returns a pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr;
}
const void* get_ptr() const
/*!
ensures
- returns a const pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr;
}
std::type_index type_id() const
/*!
requires
- is_empty() == false
ensures
- returns the std::type_index of the type contained within this object.
I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.
!*/
{
return type_id_();
}
private:
std::aligned_storage_t<Size, Alignment> data;
void* ptr = nullptr;
void (*del)(storage_sbo&) = nullptr;
void (*copy)(const storage_sbo&, storage_sbo&) = nullptr;
void (*move)(storage_sbo&, storage_sbo&) = nullptr;
std::type_index (*type_id_)() = nullptr;
};
// -----------------------------------------------------------------------------------------------------
class storage_shared : public storage_base<storage_shared>
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a storage type that uses type erasure to erase any type.
This particular storage type uses std::shared_ptr<void> to store and erase
incoming objects. Therefore, it uses heap allocation and reference counting.
Moreover, it has the same copying and move semantics as std::shared_ptr. I.e.
it results in the underlying object being held by reference rather than by
value.
!*/
public:
storage_shared() = default;
/*!
ensures
- #is_empty() == true
- for all T: #contains<T>() == false
!*/
template <
class T,
class T_ = std::decay_t<T>,
T_is_not_this_type<storage_shared, T> = true
>
storage_shared(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)
/*!
ensures
- copies or moves the incoming object (depending on the forwarding reference)
- #is_empty() == true
- #contains<std::decay_t<T>>() == true
!*/
: ptr{std::make_shared<T_>(std::forward<T>(t))},
type_id_{[] {
return std::type_index{typeid(T_)};
}}
{
}
// This object has the same copy/move semantics as a std::shared_ptr<void>
storage_shared(const storage_shared& other) = default;
storage_shared& operator=(const storage_shared& other) = default;
storage_shared(storage_shared&& other) noexcept = default;
storage_shared& operator=(storage_shared&& other) noexcept = default;
void clear()
/*!
ensures
- #is_empty() == true
!*/
{
ptr = nullptr;
type_id_ = nullptr;
}
void* get_ptr()
/*!
ensures
- returns a pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr.get();
}
const void* get_ptr() const
/*!
ensures
- returns a const pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr.get();
}
std::type_index type_id() const
/*!
requires
- is_empty() == false
ensures
- returns the std::type_index of the type contained within this object.
I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.
!*/
{
return type_id_();
}
private:
std::shared_ptr<void> ptr = nullptr;
std::type_index (*type_id_)() = nullptr;
};
// -----------------------------------------------------------------------------------------------------
class storage_view : public storage_base<storage_view>
{
/*!
WHAT THIS OBJECT REPRESENTS
This object is a storage type that uses type erasure to erase any type.
This particular storage type is a view type, similar to std::string_view or
std::span. So underlying objects are only ever referenced, not copied, moved or
destructed. That is, instances of this object take no ownership of the objects
they contain. So they are only valid as long as the contained object exists.
So storage_view merely holds a pointer to the underlying object.
!*/
public:
storage_view() = default;
/*!
ensures
- #is_empty() == true
- for all T: #contains<T>() == false
!*/
template <
class T,
class T_ = std::decay_t<T>,
T_is_not_this_type<storage_view, T> = true
>
storage_view(T &&t) noexcept
/*!
ensures
- #get_ptr() == &t
- #is_empty() == false
- #contains<std::decay_t<T>>() == true
!*/
: ptr{&t},
type_id_{[] {
return std::type_index{typeid(T_)};
}}
{
}
// This object has the same copy/move semantics as a void*.
storage_view(const storage_view& other) = default;
storage_view& operator=(const storage_view& other) = default;
storage_view(storage_view&& other) noexcept = default;
storage_view& operator=(storage_view&& other) noexcept = default;
void clear()
/*!
ensures
- #is_empty() == true
!*/
{
ptr = nullptr;
type_id_ = nullptr;
}
void* get_ptr()
/*!
ensures
- returns a pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr;
}
const void* get_ptr() const
/*!
ensures
- returns a const pointer to the underlying object or nullptr if is_empty()
!*/
{
return ptr;
}
std::type_index type_id() const
/*!
requires
- is_empty() == false
ensures
- returns the std::type_index of the type contained within this object.
I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.
!*/
{
return type_id_();
}
private:
void* ptr = nullptr;
std::type_index (*type_id_)() = nullptr;
};
// -----------------------------------------------------------------------------------------------------
}
}
#endif //DLIB_TYPE_ERASURE_H_
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment