diff --git a/.ci/ci.yaml b/.ci/ci.yaml index 26efee03ae..d3304b61c1 100644 --- a/.ci/ci.yaml +++ b/.ci/ci.yaml @@ -11,7 +11,7 @@ jobs: - job: Linux timeoutInMinutes: 360 pool: - vmImage: ubuntu-16.04 + vmImage: ubuntu-latest strategy: matrix: Plain: @@ -22,7 +22,7 @@ jobs: CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=ON -DPYTHON_EXECUTABLE=/usr/bin/python3 -DBUILD_GO_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF' Julia: julia.version: '1.3.0' - CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_GO_BINDINGS=OFF -DJULIA_EXECUTABLE=/opt/julia-1.3.0/bin/julia -DBUILD_R_BINDINGS=OFF' + CMakeArgs: '-DDEBUG=OFF -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_GO_BINDINGS=OFF -DJULIA_EXECUTABLE=/opt/julia-1.6.3/bin/julia -DBUILD_R_BINDINGS=OFF' Go: binding: 'go' go.version: '1.11.0' @@ -48,7 +48,7 @@ jobs: CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=ON -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF' Julia: python.version: '2.7' - julia.version: '1.3.0' + julia.version: '1.6.3' CMakeArgs: '-DDEBUG=ON -DPROFILE=OFF -DBUILD_JULIA_BINDINGS=ON -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF' Go: binding: 'go' diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml index 33339f6e08..5e87b118a5 100644 --- a/.ci/linux-steps.yaml +++ b/.ci/linux-steps.yaml @@ -11,6 +11,15 @@ steps: # Install build dependencies. - script: | + # Workaround to avoid a build failure, because we run out of memory. + free -h + df -h + sudo dd if=/dev/zero of=/usr/swapfile.img bs=1024 count=12M + sudo mkswap /usr/swapfile.img + sudo swapon /usr/swapfile.img + free -h + df -h + git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf sudo add-apt-repository ppa:mhier/libboost-latest @@ -30,12 +39,12 @@ steps: fi if [ "a$(julia.version)" != "a" ]; then - wget https://julialang-s3.julialang.org/bin/linux/x64/1.3/julia-1.3.0-linux-x86_64.tar.gz - sudo tar -C /opt/ -xvpf julia-1.3.0-linux-x86_64.tar.gz + wget https://julialang-s3.julialang.org/bin/linux/x64/1.6/julia-1.6.3-linux-x86_64.tar.gz + sudo tar -C /opt/ -xvpf julia-1.6.3-linux-x86_64.tar.gz fi # Install armadillo. - curl -L https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz | tar -xvJ && \ + curl -k -L https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz | tar -xvJ && \ cd armadillo* && \ cmake . && \ make && \ @@ -45,7 +54,7 @@ steps: # Install ensmallen. wget https://ensmallen.org/files/ensmallen-latest.tar.gz tar -xvzpf ensmallen-latest.tar.gz # Unpack into ensmallen-*/. - cd ensmallen-* && \ + cd ensmallen-*/ && \ sudo cp -vr include/* /usr/include/ && \ cd .. @@ -77,13 +86,7 @@ steps: displayName: 'CMake' # Build mlpack -- script: cd build && make && make mlpack_test - condition: eq(variables['CMakeArgs'], '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF') - displayName: 'Build' - -# Build mlpack -- script: cd build && make -j2 && make -j2 mlpack_test - condition: ne(variables['CMakeArgs'], '-DDEBUG=ON -DPROFILE=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=OFF') +- script: cd build && make -j2 && make mlpack_test -j2 displayName: 'Build' # Run tests via ctest. diff --git a/.ci/windows-steps.yaml b/.ci/windows-steps.yaml index cbeb666b48..361b6861e5 100644 --- a/.ci/windows-steps.yaml +++ b/.ci/windows-steps.yaml @@ -9,9 +9,7 @@ steps: # Fetch build dependencies - powershell: | nuget install OpenBLAS -o $(Agent.ToolsDirectory) - nuget install boost -o $(Agent.ToolsDirectory) -Version 1.60.0 - nuget install boost_random-vc140 -o $(Agent.ToolsDirectory) -Version 1.60.0 - nuget install boost_math_c99-vc140 -o $(Agent.ToolsDirectory) -Version 1.60.0 + nuget install boost -o $(Agent.ToolsDirectory) -Version 1.66.0 nuget install unofficial-flayan-cereal -o $(Agent.ToolsDirectory) nuget install ensmallen -o $(Agent.ToolsDirectory) -Version 2.17.0 ## Delete all ensmallen dependencies including armadillo headers, we do not need them here @@ -19,8 +17,7 @@ steps: Remove-Item $(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include\armadillo_bits -Force -Recurse Remove-Item $(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include\armadillo -Force mkdir -p $(Agent.ToolsDirectory)/boost_libs - cp $(Agent.ToolsDirectory)/boost_math_c99-vc140.1.60.0.0/lib/native/address-model-64/lib/*.* $(Agent.ToolsDirectory)/boost_libs - cp $(Agent.ToolsDirectory)/boost_random-vc140.1.60.0.0/lib/native/address-model-64/lib/*.* $(Agent.ToolsDirectory)/boost_libs + displayName: 'Fetch build dependencies' # Configure armadillo @@ -62,7 +59,7 @@ steps: -DLAPACK_LIBRARIES:FILEPATH=$(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\libopenblas.dll.a ` -DARMADILLO_INCLUDE_DIR="..\armadillo-9.800.6\tmp\include" ` -DARMADILLO_LIBRARY="..\armadillo-9.800.6\Release\armadillo.lib" ` - -DBOOST_INCLUDEDIR=$(Agent.ToolsDirectory)\boost.1.60.0.0\lib\native\include ` + -DBOOST_INCLUDEDIR=$(Agent.ToolsDirectory)\boost.1.66.0.0\lib\native\include ` -DBOOST_LIBRARYDIR=$(Agent.ToolsDirectory)\boost_libs ` -DCEREAL_INCLUDE_DIR=$(Agent.ToolsDirectory)\unofficial-flayan-cereal.1.2.2\build\native\include ` -DENSMALLEN_INCLUDE_DIR=$(Agent.ToolsDirectory)\ensmallen.2.17.0\installed\x64-linux\include ` @@ -84,15 +81,13 @@ steps: # Configure mlpack - powershell: | - cp $(Agent.ToolsDirectory)\boost_libs\*.* build\Release\ cp $(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\lib\x64\*.* build\Release\ - cp $(Agent.ToolsDirectory)\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.* build\Release\ displayName: 'Configure mlpack' # Run tests via ctest. - bash: | cd build - cmake --build . --target mlpack_test -C Release + cmake --build . --target mlpack_test CTEST_OUTPUT_ON_FAILURE=1 ctest -T Test -C Release . -j1 displayName: 'Run tests via ctest' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3e7c358def..193f957a23 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,9 +51,7 @@ jobs: - name: Install Build Dependencies run: | sudo apt-get update - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost-all-dev libcereal-dev - curl -L https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz | tar -xvJ && cd armadillo* - cmake . && make && sudo make install && cd .. + sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost-all-dev libcereal-dev libensmallen-dev libhdf5-dev libarmadillo-dev libcurl4-openssl-dev - name: Install R-bindings dependencies run: | @@ -64,7 +62,7 @@ jobs: - name: CMake run: | mkdir build - cd build && cmake -DDEBUG=OFF -DPROFILE=OFF -DBUILD_CLI_EXECUTABLES=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=ON .. + cd build && cmake -DDEBUG=OFF -DPROFILE=OFF -DBUILD_CLI_EXECUTABLES=OFF -DBUILD_PYTHON_BINDINGS=OFF -DBUILD_JULIA_BINDINGS=OFF -DBUILD_GO_BINDINGS=OFF -DBUILD_R_BINDINGS=ON -DDOWNLOAD_DEPENDENCIES=ON .. - name: Build run: | @@ -127,6 +125,12 @@ jobs: key: ${{ runner.os }}-r-${{ matrix.config.r }}-${{ hashFiles('depends.Rds') }} restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}- + - name: Install check dependencies + if: runner.os != 'Windows' && runner.os != 'macOS' + run: | + sudo apt-get update + sudo apt-get install -y --allow-unauthenticated libcurl4-openssl-dev + - name: Install dependencies run: | install.packages('remotes') diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d9ebbea04..5a94f1576f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,11 @@ else() "Compile shared libraries (if OFF, static libraries and binaries are compiled)." ON) endif() +# Enable auto-download if we are cross compiling. +if (CMAKE_CROSSCOMPILING) + set(DOWNLOAD_DEPENDENCIES ON) +endif() + # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES. if (NOT BUILD_SHARED_LIBS) if(WIN32) @@ -156,7 +161,8 @@ set(COMPILER_SUPPORT_LIBRARIES "") # If we are using MSVC, we need /bigobj. if (MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /Zm400") + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /Zm200 /Zc:__cplusplus") endif () # If we are using MINGW, we need sections and big-obj, otherwise we create too @@ -282,7 +288,7 @@ if (CMAKE_CROSSCOMPILING) search_openblas(0.3.13) endif() -if (DOWNLOAD_DEPENDENCIES) +if (NOT DOWNLOAD_DEPENDENCIES) find_package(Armadillo "${ARMADILLO_VERSION}" REQUIRED) else() find_package(Armadillo "${ARMADILLO_VERSION}") @@ -304,7 +310,7 @@ set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${ARMADILLO_INCLUDE_DIRS}) set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${ARMADILLO_LIBRARIES}) # Find stb_image.h and stb_image_write.h. -if (DOWNLOAD_DEPENDENCIES) +if (NOT DOWNLOAD_DEPENDENCIES) find_package(StbImage) else() find_package(StbImage) @@ -322,7 +328,7 @@ if (STB_IMAGE_FOUND) endif() # Find ensmallen. -if (DOWNLOAD_DEPENDENCIES) +if (NOT DOWNLOAD_DEPENDENCIES) find_package(Ensmallen "${ENSMALLEN_VERSION}" REQUIRED) else() find_package(Ensmallen "${ENSMALLEN_VERSION}") @@ -335,7 +341,7 @@ endif() set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} "${ENSMALLEN_INCLUDE_DIR}") # Find cereal. -if (DOWNLOAD_DEPENDENCIES) +if (NOT DOWNLOAD_DEPENDENCIES) find_package(cereal "${CEREAL_VERSION}" REQUIRED) else() find_package(cereal "${CEREAL_VERSION}") @@ -376,7 +382,7 @@ set(Boost_ADDITIONAL_VERSIONS # TODO for the brave: transition all mlpack's CMake to 'target-based modern # CMake'. Good luck! You'll need it. set(Boost_NO_BOOST_CMAKE 1) -if (DOWNLOAD_DEPENDENCIES) +if (NOT DOWNLOAD_DEPENDENCIES) find_package(Boost "${BOOST_VERSION}" REQUIRED) else() find_package(Boost "${BOOST_VERSION}") diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index a578b4747e..4ab00dfb7a 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -145,6 +145,7 @@ Copyright: Copyright 2021, Mark Fischinger Copyright 2021, Muhammad Fawwaz Mayda Copyright 2021, Roshan Nrusing Swain + Copyright 2021, Suvarsha Chennareddy License: BSD-3-clause All rights reserved. diff --git a/HISTORY.md b/HISTORY.md index c292c7ca90..8ee8e3cedc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -76,6 +76,9 @@ * Fix double-free of model pointers in R bindings (#3034). + * Fix Julia, Python, R, and Go handling of categorical data for + `decision_tree()` and `hoeffding_tree()` (#2971). + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. diff --git a/LICENSE.txt b/LICENSE.txt index 46dd15e860..1586fb69c1 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -12,6 +12,11 @@ licensed under the Boost Software License, version 1.0. This code is found in src/mlpack/core/boost_backport/ and more details on the licensing are available there. +mlpack contain some usage of the source code of MNMLSTC Core library, which is +a backport of C++17 features to C++11. MNMLSTC is licensed under the Apache 2.0 +License. This code can be found in src/mlpack/core/std_backport/ and more +details about licensing can be found there. + mlpack may contain some usage of the source code of stb, which is licensed under the MIT License and the Public Domain (www.unlicense.org). This code is used in src/mlpack/core/data/load_image.hpp. diff --git a/src/mlpack/bindings/R/R_option.hpp b/src/mlpack/bindings/R/R_option.hpp index bf343ee65c..5982494c50 100644 --- a/src/mlpack/bindings/R/R_option.hpp +++ b/src/mlpack/bindings/R/R_option.hpp @@ -73,7 +73,7 @@ class ROption data.cppType = cppName; // Every parameter we'll get from R will have the correct type. - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); // Set the function pointers that we'll need. All of these function // pointers will be used by both the program that generates the R, and diff --git a/src/mlpack/bindings/R/default_param_impl.hpp b/src/mlpack/bindings/R/default_param_impl.hpp index 5447d8738a..64eea0d1e2 100644 --- a/src/mlpack/bindings/R/default_param_impl.hpp +++ b/src/mlpack/bindings/R/default_param_impl.hpp @@ -36,7 +36,7 @@ std::string DefaultParamImpl( if (std::is_same::value) oss << "FALSE"; else - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -51,7 +51,7 @@ std::string DefaultParamImpl( { // Print each element in an array delimited by square brackets. std::ostringstream oss; - const T& vector = boost::any_cast(data.value); + const T& vector = ANY_CAST(data.value); oss << "c("; if (std::is_same>::value) { @@ -92,7 +92,7 @@ std::string DefaultParamImpl( util::ParamData& data, const typename std::enable_if::value>::type*) { - const std::string& s = *boost::any_cast(&data.value); + const std::string& s = *ANY_CAST(&data.value); return "\"" + s + "\""; } diff --git a/src/mlpack/bindings/R/get_param.hpp b/src/mlpack/bindings/R/get_param.hpp index d9481d4156..b725698c9e 100644 --- a/src/mlpack/bindings/R/get_param.hpp +++ b/src/mlpack/bindings/R/get_param.hpp @@ -27,7 +27,7 @@ void GetParam(util::ParamData& d, const void* /* input */, void* output) { - *((T**) output) = const_cast(boost::any_cast(&d.value)); + *((T**) output) = const_cast(ANY_CAST(&d.value)); } } // namespace r diff --git a/src/mlpack/bindings/R/get_printable_param.hpp b/src/mlpack/bindings/R/get_printable_param.hpp index 261d363642..8f8fefaaaf 100644 --- a/src/mlpack/bindings/R/get_printable_param.hpp +++ b/src/mlpack/bindings/R/get_printable_param.hpp @@ -32,7 +32,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -44,7 +44,7 @@ std::string GetPrintableParam( util::ParamData& data, const typename std::enable_if::value>::type* = 0) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) @@ -61,7 +61,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { // Get the matrix. - const T& matrix = boost::any_cast(data.value); + const T& matrix = ANY_CAST(data.value); std::ostringstream oss; oss << matrix.n_rows << "x" << matrix.n_cols << " matrix"; @@ -78,7 +78,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { std::ostringstream oss; - oss << data.cppType << " model at " << boost::any_cast(data.value); + oss << data.cppType << " model at " << ANY_CAST(data.value); return oss.str(); } @@ -92,7 +92,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { // Get the matrix. - const T& tuple = boost::any_cast(data.value); + const T& tuple = ANY_CAST(data.value); const arma::mat& matrix = std::get<1>(tuple); std::ostringstream oss; diff --git a/src/mlpack/bindings/R/mlpack/src/r_util.cpp b/src/mlpack/bindings/R/mlpack/src/r_util.cpp index a42eee50a3..b8be116ae8 100644 --- a/src/mlpack/bindings/R/mlpack/src/r_util.cpp +++ b/src/mlpack/bindings/R/mlpack/src/r_util.cpp @@ -35,7 +35,6 @@ bool inline inplace_transpose(arma::Mat& X) SEXP CreateParams(const std::string& bindingName) { util::Params* p = new util::Params(IO::Parameters(bindingName)); - std::cout << "create params " << p << "\n"; return std::move(Rcpp::XPtr(p)); } @@ -44,7 +43,6 @@ SEXP CreateParams(const std::string& bindingName) SEXP CreateTimers() { util::Timers* t = new util::Timers(); - std::cout << "create timers " << t << "\n"; return std::move(Rcpp::XPtr(t)); } @@ -91,8 +89,8 @@ void SetParamBool(SEXP params, const std::string& paramName, bool paramValue) // Call params.Get>() to set the value of a parameter. // [[Rcpp::export]] void SetParamVecString(SEXP params, - const std::string& paramName, - const std::vector& str) + const std::string& paramName, + const std::vector& str) { util::Params& p = *Rcpp::as>(params); p.Get>(paramName) = std::move(str); @@ -102,8 +100,8 @@ void SetParamVecString(SEXP params, // Call params.Get>() to set the value of a parameter. // [[Rcpp::export]] void SetParamVecInt(SEXP params, - const std::string& paramName, - const std::vector& ints) + const std::string& paramName, + const std::vector& ints) { util::Params& p = *Rcpp::as>(params); p.Get>(paramName) = std::move(ints); @@ -113,8 +111,8 @@ void SetParamVecInt(SEXP params, // Call params.Get() to set the value of a parameter. // [[Rcpp::export]] void SetParamMat(SEXP params, - const std::string& paramName, - const arma::mat& paramValue) + const std::string& paramName, + const arma::mat& paramValue) { util::Params& p = *Rcpp::as>(params); p.Get(paramName) = paramValue.t(); @@ -124,8 +122,8 @@ void SetParamMat(SEXP params, // Call params.Get>() to set the value of a parameter. // [[Rcpp::export]] void SetParamUMat(SEXP params, - const std::string& paramName, - const arma::Mat& paramValue) + const std::string& paramName, + const arma::Mat& paramValue) { util::Params& p = *Rcpp::as>(params); p.Get>(paramName) = paramValue.t(); @@ -135,8 +133,8 @@ void SetParamUMat(SEXP params, // Call params.Get() to set the value of a parameter. // [[Rcpp::export]] void SetParamRow(SEXP params, - const std::string& paramName, - const arma::rowvec& paramValue) + const std::string& paramName, + const arma::rowvec& paramValue) { util::Params& p = *Rcpp::as>(params); p.Get(paramName) = std::move(paramValue); @@ -146,10 +144,19 @@ void SetParamRow(SEXP params, // Call params.Get>() to set the value of a parameter. // [[Rcpp::export]] void SetParamURow(SEXP params, - const std::string& paramName, - const arma::Row& paramValue) + const std::string& paramName, + const arma::Row& paramValue) { util::Params& p = *Rcpp::as>(params); + + // Check for zeros in the input---if we received these, the user is mistaken, + // because in R labels should start from 1. + if (arma::any(paramValue == 0)) + { + Log::Fatal << "When passing labels from R to mlpack, labels should be in " + << "the range from 1 to the number of classes!" << std::endl; + } + p.Get>(paramName) = paramValue - 1; p.SetPassed(paramName); } @@ -157,8 +164,8 @@ void SetParamURow(SEXP params, // Call params.Get() to set the value of a parameter. // [[Rcpp::export]] void SetParamCol(SEXP params, - const std::string& paramName, - const arma::vec& paramValue) + const std::string& paramName, + const arma::vec& paramValue) { util::Params& p = *Rcpp::as>(params); p.Get(paramName) = std::move(paramValue); @@ -168,10 +175,19 @@ void SetParamCol(SEXP params, // Call params.Get>() to set the value of a parameter. // [[Rcpp::export]] void SetParamUCol(SEXP params, - const std::string& paramName, - const arma::Col& paramValue) + const std::string& paramName, + const arma::Col& paramValue) { util::Params& p = *Rcpp::as>(params); + + // Check for zeros in the input---if we received these, the user is mistaken, + // because in R labels should start from 1. + if (arma::any(paramValue == 0)) + { + Log::Fatal << "When passing labels from R to mlpack, labels should be in " + << "the range from 1 to the number of classes!" << std::endl; + } + p.Get>(paramName) = paramValue - 1; p.SetPassed(paramName); } @@ -180,21 +196,47 @@ void SetParamUCol(SEXP params, // of a parameter. // [[Rcpp::export]] void SetParamMatWithInfo(SEXP params, - const std::string& paramName, - const LogicalVector& dimensions, - const arma::mat& paramValue) + const std::string& paramName, + const LogicalVector& dimensions, + const arma::mat& paramValue) { util::Params& p = *Rcpp::as>(params); data::DatasetInfo d(paramValue.n_cols); + bool hasCategoricals = false; for (size_t i = 0; i < d.Dimensionality(); ++i) { d.Type(i) = (dimensions[i]) ? data::Datatype::categorical : data::Datatype::numeric; + if (dimensions[i]) + hasCategoricals = true; } + + arma::mat m = paramValue.t(); + + // Do we need to find how many categories we have? + if (hasCategoricals) + { + arma::vec maxs = arma::max(paramValue, 1) + 1; + + for (size_t i = 0; i < d.Dimensionality(); ++i) + { + if (dimensions[i]) + { + // Map the right number of objects. + for (size_t j = 0; j < (size_t) maxs[i]; ++j) + { + std::ostringstream oss; + oss << j; + d.MapString(oss.str(), i); + } + } + } + } + std::get<0>(p.Get>( paramName)) = std::move(d); std::get<1>(p.Get>( - paramName)) = paramValue.t(); + paramName)) = std::move(m); p.SetPassed(paramName); } diff --git a/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R b/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R index ee77ad3c33..789f3056be 100644 --- a/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R +++ b/src/mlpack/bindings/R/mlpack/tests/testthat/test-R_binding.R @@ -126,7 +126,7 @@ test_that("TestCol", { # Test an unsigned column vector input parameter. test_that("TestUCol", { - x <- matrix(as.integer(rexp(100, rate = .1)), nrow = 1) + x <- matrix(as.integer(rexp(100, rate = .1)), nrow = 1) + 1 output <- test_r_binding(4.0, 12, "hello", ucol_in=x) @@ -148,7 +148,7 @@ test_that("TestRow", { # Test an unsigned row vector input parameter. test_that("TestURow", { - x <- matrix(as.integer(rexp(100, rate = .1)), ncol = 1) + x <- matrix(as.integer(rexp(100, rate = .1)), ncol = 1) + 1 output <- test_r_binding(4.0, 12, "hello", urow_in=x) @@ -269,6 +269,15 @@ test_that("TestNotMatrix", { matrix_and_info_in=1e6)) }) +# If we pass labels that start from 0, we should get an error. +test_that("TestZeroLabels", { + x <- vector(mode="integer", 10) + expect_error(test_r_binding(4.0, 12, "hello", urow_in=x)) + + y <- matrix(0, 10, 1) + expect_error(test_r_binding(4.0, 12, "hello", ucol_in=y)) +}) + # First create a GaussianKernel object, then send it back and make sure we get # the right double value. test_that("TestModel", { diff --git a/src/mlpack/bindings/R/print_doc.hpp b/src/mlpack/bindings/R/print_doc.hpp index 19c4d74f8c..2fa9a216bb 100644 --- a/src/mlpack/bindings/R/print_doc.hpp +++ b/src/mlpack/bindings/R/print_doc.hpp @@ -55,19 +55,19 @@ void PrintDoc(util::ParamData& d, oss << ". Default value \""; if (d.cppType == "std::string") { - oss << boost::any_cast(d.value); + oss << ANY_CAST(d.value); } else if (d.cppType == "double") { - oss << boost::any_cast(d.value); + oss << ANY_CAST(d.value); } else if (d.cppType == "int") { - oss << boost::any_cast(d.value); + oss << ANY_CAST(d.value); } else if (d.cppType == "bool") { - oss << (boost::any_cast(d.value) ? "TRUE" : "FALSE"); + oss << (ANY_CAST(d.value) ? "TRUE" : "FALSE"); } oss << "\""; } diff --git a/src/mlpack/bindings/R/tests/test_r_binding_main.cpp b/src/mlpack/bindings/R/tests/test_r_binding_main.cpp index 7e90328e95..4bf0643da6 100644 --- a/src/mlpack/bindings/R/tests/test_r_binding_main.cpp +++ b/src/mlpack/bindings/R/tests/test_r_binding_main.cpp @@ -182,7 +182,22 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timers */) for (size_t i = 0; i < m.n_rows; ++i) { if (di.Type(i) == data::Datatype::numeric) + { m.row(i) *= 2.0; + } + else + { + // Make sure input data is valid. + for (size_t c = 0; c < m.n_cols; ++c) + { + if (ceil(m(i, c)) != m(i, c)) + throw std::invalid_argument("non-integer value in categorical!"); + else if (m(i, c) < 0) + throw std::invalid_argument("negative value in categorical!"); + else if (size_t(m(i, c)) >= di.NumMappings(i)) + throw std::invalid_argument("value outside number of categories!"); + } + } } params.Get("matrix_and_info_out") = move(m); diff --git a/src/mlpack/bindings/cli/add_to_cli11.hpp b/src/mlpack/bindings/cli/add_to_cli11.hpp index 40dc436ae8..1e4e89f366 100644 --- a/src/mlpack/bindings/cli/add_to_cli11.hpp +++ b/src/mlpack/bindings/cli/add_to_cli11.hpp @@ -47,8 +47,8 @@ void AddToCLI11(const std::string& cliName, [¶m](const std::string& value) { using TupleType = std::tuple::type>; - TupleType& tuple = *boost::any_cast(¶m.value); - std::get<0>(std::get<1>(tuple)) = boost::any_cast(value); + TupleType& tuple = *ANY_CAST(¶m.value); + std::get<0>(std::get<1>(tuple)) = ANY_CAST(value); param.wasPassed = true; }, param.desc.c_str()); @@ -79,8 +79,8 @@ void AddToCLI11(const std::string& cliName, [¶m](const std::string& value) { using TupleType = std::tuple::type>; - TupleType& tuple = *boost::any_cast(¶m.value); - std::get<1>(tuple) = boost::any_cast(value); + TupleType& tuple = *ANY_CAST(¶m.value); + std::get<1>(tuple) = ANY_CAST(value); param.wasPassed = true; }, param.desc.c_str()); @@ -109,8 +109,8 @@ void AddToCLI11(const std::string& cliName, [¶m](const std::string& value) { using TupleType = std::tuple::type>; - TupleType& tuple = *boost::any_cast(¶m.value); - std::get<0>(std::get<1>(tuple)) = boost::any_cast(value); + TupleType& tuple = *ANY_CAST(¶m.value); + std::get<0>(std::get<1>(tuple)) = ANY_CAST(value); param.wasPassed = true; }, param.desc.c_str()); diff --git a/src/mlpack/bindings/cli/cli_option.hpp b/src/mlpack/bindings/cli/cli_option.hpp index 065ca635be..d8ea8e6182 100644 --- a/src/mlpack/bindings/cli/cli_option.hpp +++ b/src/mlpack/bindings/cli/cli_option.hpp @@ -95,12 +95,12 @@ class CLIOption typename ParameterType::type>::type>::value) { - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); } else { typename ParameterType::type>::type tmp; - data.value = boost::any(std::tuple(defaultValue, tmp)); + data.value = ANY(std::tuple(defaultValue, tmp)); } const std::string tname = data.tname; diff --git a/src/mlpack/bindings/cli/default_param_impl.hpp b/src/mlpack/bindings/cli/default_param_impl.hpp index b9defc6374..ea0ec7cd7c 100644 --- a/src/mlpack/bindings/cli/default_param_impl.hpp +++ b/src/mlpack/bindings/cli/default_param_impl.hpp @@ -34,7 +34,7 @@ std::string DefaultParamImpl( { std::ostringstream oss; if (!std::is_same::value) - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -49,7 +49,7 @@ std::string DefaultParamImpl( { // Print each element in an array delimited by square brackets. std::ostringstream oss; - const T& vector = boost::any_cast(data.value); + const T& vector = ANY_CAST(data.value); oss << "["; if (std::is_same>::value) { @@ -91,7 +91,7 @@ std::string DefaultParamImpl( util::ParamData& data, const typename std::enable_if::value>::type*) { - const std::string& s = *boost::any_cast(&data.value); + const std::string& s = *ANY_CAST(&data.value); return "'" + s + "'"; } diff --git a/src/mlpack/bindings/cli/delete_allocated_memory.hpp b/src/mlpack/bindings/cli/delete_allocated_memory.hpp index f3123c52e8..2ba1681301 100644 --- a/src/mlpack/bindings/cli/delete_allocated_memory.hpp +++ b/src/mlpack/bindings/cli/delete_allocated_memory.hpp @@ -43,7 +43,7 @@ void DeleteAllocatedMemoryImpl( { // Delete the allocated memory (hopefully we actually own it). typedef std::tuple TupleType; - delete std::get<0>(*boost::any_cast(&d.value)); + delete std::get<0>(*ANY_CAST(&d.value)); } template diff --git a/src/mlpack/bindings/cli/get_allocated_memory.hpp b/src/mlpack/bindings/cli/get_allocated_memory.hpp index 08e97e1e39..82e4bf3b76 100644 --- a/src/mlpack/bindings/cli/get_allocated_memory.hpp +++ b/src/mlpack/bindings/cli/get_allocated_memory.hpp @@ -45,7 +45,7 @@ void* GetAllocatedMemory( // Here we have a model, which is a tuple, and we need the address of the // memory. typedef std::tuple TupleType; - return std::get<0>(*boost::any_cast(&d.value)); + return std::get<0>(*ANY_CAST(&d.value)); } template diff --git a/src/mlpack/bindings/cli/get_param.hpp b/src/mlpack/bindings/cli/get_param.hpp index 34463e939c..a2fd746187 100644 --- a/src/mlpack/bindings/cli/get_param.hpp +++ b/src/mlpack/bindings/cli/get_param.hpp @@ -34,7 +34,7 @@ T& GetParam( std::tuple>::value>::type* = 0) { // No mapping is needed, so just cast it directly. - return *boost::any_cast(&d.value); + return *ANY_CAST(&d.value); } /** @@ -52,7 +52,7 @@ T& GetParam( // times, but I am not bothered by that---it shouldn't be something that // happens. typedef std::tuple::type> TupleType; - TupleType& tuple = *boost::any_cast(&d.value); + TupleType& tuple = *ANY_CAST(&d.value); const std::string& value = std::get<0>(std::get<1>(tuple)); T& matrix = std::get<0>(tuple); size_t& n_rows = std::get<1>(std::get<1>(tuple)); @@ -86,7 +86,7 @@ T& GetParam( // If this is an input parameter, we need to load both the matrix and the // dataset info. typedef std::tuple> TupleType; - TupleType* tuple = boost::any_cast(&d.value); + TupleType* tuple = ANY_CAST(&d.value); const std::string& value = std::get<0>(std::get<1>(*tuple)); T& t = std::get<0>(*tuple); size_t& n_rows = std::get<1>(std::get<1>(*tuple)); @@ -116,7 +116,7 @@ T*& GetParam( // If the model is an input model, we have to load it from file. 'value' // contains the filename. typedef std::tuple TupleType; - TupleType* tuple = boost::any_cast(&d.value); + TupleType* tuple = ANY_CAST(&d.value); const std::string& value = std::get<1>(*tuple); if (d.input && !d.loaded) { diff --git a/src/mlpack/bindings/cli/get_printable_param_impl.hpp b/src/mlpack/bindings/cli/get_printable_param_impl.hpp index 89f3c066f0..f6f303fce8 100644 --- a/src/mlpack/bindings/cli/get_printable_param_impl.hpp +++ b/src/mlpack/bindings/cli/get_printable_param_impl.hpp @@ -30,7 +30,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* /* junk */) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -41,7 +41,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* /* junk */) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) @@ -80,7 +80,7 @@ std::string GetPrintableParam( { // Extract the string from the tuple that's being held. typedef std::tuple::type> TupleType; - const TupleType* tuple = boost::any_cast(&data.value); + const TupleType* tuple = ANY_CAST(&data.value); std::ostringstream oss; oss << "'" << std::get<0>(std::get<1>(*tuple)) << "'"; @@ -108,7 +108,7 @@ std::string GetPrintableParam( { // Extract the string from the tuple that's being held. typedef std::tuple::type> TupleType; - const TupleType* tuple = boost::any_cast(&data.value); + const TupleType* tuple = ANY_CAST(&data.value); std::ostringstream oss; oss << std::get<1>(*tuple); diff --git a/src/mlpack/bindings/cli/get_raw_param.hpp b/src/mlpack/bindings/cli/get_raw_param.hpp index 38b340387e..b9aacd7f16 100644 --- a/src/mlpack/bindings/cli/get_raw_param.hpp +++ b/src/mlpack/bindings/cli/get_raw_param.hpp @@ -33,7 +33,7 @@ T& GetRawParam( std::tuple>::value>::type* = 0) { // No mapping is needed, so just cast it directly. - return *boost::any_cast(&d.value); + return *ANY_CAST(&d.value); } /** @@ -49,7 +49,7 @@ T& GetRawParam( { // Don't load the matrix. typedef std::tuple> TupleType; - T& value = std::get<0>(*boost::any_cast(&d.value)); + T& value = std::get<0>(*ANY_CAST(&d.value)); return value; } @@ -64,7 +64,7 @@ T*& GetRawParam( { // Don't load the model. typedef std::tuple TupleType; - T*& value = std::get<0>(*boost::any_cast(&d.value)); + T*& value = std::get<0>(*ANY_CAST(&d.value)); return value; } diff --git a/src/mlpack/bindings/cli/in_place_copy.hpp b/src/mlpack/bindings/cli/in_place_copy.hpp index f266267bb6..a787045eca 100644 --- a/src/mlpack/bindings/cli/in_place_copy.hpp +++ b/src/mlpack/bindings/cli/in_place_copy.hpp @@ -58,10 +58,10 @@ void InPlaceCopyInternal( { // Make the output filename the same as the input filename. typedef std::tuple::type> TupleType; - TupleType& tuple = *boost::any_cast(&d.value); + TupleType& tuple = *ANY_CAST(&d.value); std::string& value = std::get<0>(std::get<1>(tuple)); - const TupleType& inputTuple = *boost::any_cast(&input.value); + const TupleType& inputTuple = *ANY_CAST(&input.value); value = std::get<0>(std::get<1>(inputTuple)); } @@ -81,10 +81,10 @@ void InPlaceCopyInternal( { // Make the output filename the same as the input filename. typedef std::tuple::type> TupleType; - TupleType& tuple = *boost::any_cast(&d.value); + TupleType& tuple = *ANY_CAST(&d.value); std::string& value = std::get<1>(tuple); - const TupleType& inputTuple = *boost::any_cast(&input.value); + const TupleType& inputTuple = *ANY_CAST(&input.value); value = std::get<1>(inputTuple); } diff --git a/src/mlpack/bindings/cli/output_param_impl.hpp b/src/mlpack/bindings/cli/output_param_impl.hpp index d34b55fd74..e1cd1f411a 100644 --- a/src/mlpack/bindings/cli/output_param_impl.hpp +++ b/src/mlpack/bindings/cli/output_param_impl.hpp @@ -30,7 +30,7 @@ void OutputParamImpl( const typename std::enable_if>::value>::type* /* junk */) { - std::cout << data.name << ": " << *boost::any_cast(&data.value) + std::cout << data.name << ": " << *ANY_CAST(&data.value) << std::endl; } @@ -41,7 +41,7 @@ void OutputParamImpl( const typename std::enable_if::value>::type* /* junk */) { std::cout << data.name << ": "; - const T& t = *boost::any_cast(&data.value); + const T& t = *ANY_CAST(&data.value); for (size_t i = 0; i < t.size(); ++i) std::cout << t[i] << " "; std::cout << std::endl; @@ -54,9 +54,9 @@ void OutputParamImpl( const typename std::enable_if::value>::type* /* junk */) { typedef std::tuple> TupleType; - const T& output = std::get<0>(*boost::any_cast(&data.value)); + const T& output = std::get<0>(*ANY_CAST(&data.value)); const std::string& filename = - std::get<0>(std::get<1>(*boost::any_cast(&data.value))); + std::get<0>(std::get<1>(*ANY_CAST(&data.value))); if (output.n_elem > 0 && filename != "") { @@ -78,10 +78,10 @@ void OutputParamImpl( // const. In this case we can assume it though, since we will be saving and // not loading. typedef std::tuple TupleType; - T*& output = const_cast(std::get<0>(*boost::any_cast( + T*& output = const_cast(std::get<0>(*ANY_CAST( &data.value))); const std::string& filename = - std::get<1>(*boost::any_cast(&data.value)); + std::get<1>(*ANY_CAST(&data.value)); if (filename != "") data::Save(filename, "model", *output); @@ -96,9 +96,9 @@ void OutputParamImpl( { // Output the matrix with the mappings. typedef std::tuple> TupleType; - const T& tuple = std::get<0>(*boost::any_cast(&data.value)); + const T& tuple = std::get<0>(*ANY_CAST(&data.value)); const std::string& filename = - std::get<0>(std::get<1>(*boost::any_cast(&data.value))); + std::get<0>(std::get<1>(*ANY_CAST(&data.value))); const arma::mat& matrix = std::get<1>(tuple); // The mapping isn't taken into account. We should write a data::Save() diff --git a/src/mlpack/bindings/cli/set_param.hpp b/src/mlpack/bindings/cli/set_param.hpp index 8fab3e0fb0..cab459dd7c 100644 --- a/src/mlpack/bindings/cli/set_param.hpp +++ b/src/mlpack/bindings/cli/set_param.hpp @@ -26,7 +26,7 @@ namespace cli { template void SetParam( util::ParamData& d, - const boost::any& value, + const ANY& value, const typename std::enable_if::value>::type* = 0, const typename std::enable_if::value>::type* = 0, const typename std::enable_if void SetParam( util::ParamData& d, - const boost::any& /* value */, + const ANY& /* value */, const typename std::enable_if::value>::type* = 0) { // Force set to the value of whether or not this was passed. @@ -57,15 +57,15 @@ void SetParam( template void SetParam( util::ParamData& d, - const boost::any& value, + const ANY& value, const typename std::enable_if::value || std::is_same>::value>::type* = 0) { // We're setting the string filename. typedef std::tuple::type> TupleType; - TupleType& tuple = *boost::any_cast(&d.value); - std::get<0>(std::get<1>(tuple)) = boost::any_cast(value); + TupleType& tuple = *ANY_CAST(&d.value); + std::get<0>(std::get<1>(tuple)) = ANY_CAST(value); } /** @@ -75,14 +75,14 @@ void SetParam( template void SetParam( util::ParamData& d, - const boost::any& value, + const ANY& value, const typename std::enable_if::value>::type* = 0, const typename std::enable_if::value>::type* = 0) { // We're setting the string filename. typedef std::tuple::type> TupleType; - TupleType& tuple = *boost::any_cast(&d.value); - std::get<1>(tuple) = boost::any_cast(value); + TupleType& tuple = *ANY_CAST(&d.value); + std::get<1>(tuple) = ANY_CAST(value); } /** @@ -97,7 +97,7 @@ template void SetParam(util::ParamData& d, const void* input, void* /* output */) { SetParam::type>( - const_cast(d), *((boost::any*) input)); + const_cast(d), *((ANY*) input)); } } // namespace cli diff --git a/src/mlpack/bindings/cli/third_party/CLI/CLI11.hpp b/src/mlpack/bindings/cli/third_party/CLI/CLI11.hpp index 40b76588ca..dcb57c6c6c 100644 --- a/src/mlpack/bindings/cli/third_party/CLI/CLI11.hpp +++ b/src/mlpack/bindings/cli/third_party/CLI/CLI11.hpp @@ -1,11 +1,11 @@ -// CLI11: Version 2.1.1 +// CLI11: Version 2.1.2 // Originally designed by Henry Schreiner // https://github.com/CLIUtils/CLI11 // // This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts -// from: v2.1.1 +// from: v2.1.2 // -// CLI11 2.1.1 Copyright (c) 2017-2021 University of Cincinnati, developed by Henry +// CLI11 2.1.2 Copyright (c) 2017-2021 University of Cincinnati, developed by Henry // Schreiner under NSF AWARD 1414736. All rights reserved. // // Redistribution and use in source and binary forms of CLI11, with or without @@ -34,34 +34,34 @@ #pragma once // Standard combined includes: -#include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include #define CLI11_VERSION_MAJOR 2 #define CLI11_VERSION_MINOR 1 -#define CLI11_VERSION_PATCH 1 -#define CLI11_VERSION "2.1.1" +#define CLI11_VERSION_PATCH 2 +#define CLI11_VERSION "2.1.2" @@ -891,7 +891,7 @@ constexpr enabler dummy = {}; /// A copy of enable_if_t from C++14, compatible with C++11. /// /// We could check to see if C++14 is being used, but it does not hurt to redefine this -/// (even Google does this: https://github.com/google/skia/blob/master/include/private/SkTLogic.h) +/// (even Google does this: https://github.com/google/skia/blob/main/include/private/SkTLogic.h) /// It is not in the std namespace anyway, so no harm done. template using enable_if_t = typename std::enable_if::type; @@ -6956,10 +6956,10 @@ class App { /// Get a pointer to the version option. (const) const Option *get_version_ptr() const { return version_ptr_; } - /// Get the parent of this subcommand (or nullptr if master app) + /// Get the parent of this subcommand (or nullptr if main app) App *get_parent() { return parent_; } - /// Get the parent of this subcommand (or nullptr if master app) (const version) + /// Get the parent of this subcommand (or nullptr if main app) (const version) const App *get_parent() const { return parent_; } /// Get the name of the current app @@ -7673,7 +7673,7 @@ class App { } /// Parse "one" argument (some may eat more than one), delegate to parent if fails, add to missing if missing - /// from master return false if the parse has failed and needs to return to parent + /// from main return false if the parse has failed and needs to return to parent bool _parse_single(std::vector &args, bool &positional_only) { bool retval = true; detail::Classifier classifier = positional_only ? detail::Classifier::NONE : _recognize(args.back()); @@ -7948,7 +7948,7 @@ class App { } } } - // If a subcommand, try the master command + // If a subcommand, try the main command if(parent_ != nullptr && fallthrough_) return _get_fallthrough_parent()->_parse_arg(args, current_type); // don't capture missing if this is a nameless subcommand diff --git a/src/mlpack/bindings/go/default_param_impl.hpp b/src/mlpack/bindings/go/default_param_impl.hpp index 2458012966..0bae6ce306 100644 --- a/src/mlpack/bindings/go/default_param_impl.hpp +++ b/src/mlpack/bindings/go/default_param_impl.hpp @@ -36,7 +36,7 @@ std::string DefaultParamImpl( if (std::is_same::value) oss << "false"; else - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -51,7 +51,7 @@ std::string DefaultParamImpl( { // Print each element in an array delimited by square brackets. std::ostringstream oss; - const T& vector = boost::any_cast(data.value); + const T& vector = ANY_CAST(data.value); if (std::is_same>::value) { oss << "[]string{"; @@ -93,7 +93,7 @@ std::string DefaultParamImpl( util::ParamData& data, const typename std::enable_if::value>::type*) { - const std::string& s = *boost::any_cast(&data.value); + const std::string& s = *ANY_CAST(&data.value); return "\"" + s + "\""; } diff --git a/src/mlpack/bindings/go/get_param.hpp b/src/mlpack/bindings/go/get_param.hpp index dc46e4a6b7..8ef97d31e1 100644 --- a/src/mlpack/bindings/go/get_param.hpp +++ b/src/mlpack/bindings/go/get_param.hpp @@ -27,7 +27,7 @@ void GetParam(util::ParamData& d, const void* /* input */, void* output) { - *((T**) output) = const_cast(boost::any_cast(&d.value)); + *((T**) output) = const_cast(ANY_CAST(&d.value)); } } // namespace go diff --git a/src/mlpack/bindings/go/get_printable_param.hpp b/src/mlpack/bindings/go/get_printable_param.hpp index 091bfcba80..fb46da993d 100644 --- a/src/mlpack/bindings/go/get_printable_param.hpp +++ b/src/mlpack/bindings/go/get_printable_param.hpp @@ -32,7 +32,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -44,7 +44,7 @@ std::string GetPrintableParam( util::ParamData& data, const typename std::enable_if::value>::type* = 0) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) @@ -61,7 +61,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { // Get the matrix. - const T& matrix = boost::any_cast(data.value); + const T& matrix = ANY_CAST(data.value); std::ostringstream oss; oss << matrix.n_rows << "x" << matrix.n_cols << " matrix"; @@ -78,7 +78,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { std::ostringstream oss; - oss << data.cppType << " model at " << boost::any_cast(data.value); + oss << data.cppType << " model at " << ANY_CAST(data.value); return oss.str(); } @@ -92,7 +92,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { // Get the matrix. - const T& tuple = boost::any_cast(data.value); + const T& tuple = ANY_CAST(data.value); const arma::mat& matrix = std::get<1>(tuple); std::ostringstream oss; diff --git a/src/mlpack/bindings/go/go_option.hpp b/src/mlpack/bindings/go/go_option.hpp index e8160b8344..2554bc403e 100644 --- a/src/mlpack/bindings/go/go_option.hpp +++ b/src/mlpack/bindings/go/go_option.hpp @@ -78,7 +78,7 @@ class GoOption data.loaded = false; data.cppType = cppName; - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); // Set the function pointers that we'll need. All of these function // pointers will be used by both the program that generates the .cpp, diff --git a/src/mlpack/bindings/go/mlpack/capi/arma_util.cpp b/src/mlpack/bindings/go/mlpack/capi/arma_util.cpp index e205deab4f..5610273071 100644 --- a/src/mlpack/bindings/go/mlpack/capi/arma_util.cpp +++ b/src/mlpack/bindings/go/mlpack/capi/arma_util.cpp @@ -328,16 +328,40 @@ void mlpackToArmaMatWithInfo(void* params, { util::Params& p = *((util::Params*) params); data::DatasetInfo d(rows); + bool hasCategoricals = false; for (size_t i = 0; i < d.Dimensionality(); ++i) { d.Type(i) = (dimensions[i]) ? data::Datatype::categorical : data::Datatype::numeric; + if (dimensions[i]) + hasCategoricals = true; } arma::mat m(memptr, rows, cols, false, true); - std::get<0>(p.Get>( identifier)) = + + // Do we need to find how many categories we have? + if (hasCategoricals) + { + arma::vec maxs = arma::max(m, 1) + 1; + + for (size_t i = 0; i < d.Dimensionality(); ++i) + { + if (dimensions[i]) + { + // Map the right number of objects. + for (size_t j = 0; j < (size_t) maxs[i]; ++j) + { + std::ostringstream oss; + oss << j; + d.MapString(oss.str(), i); + } + } + } + } + + std::get<0>(p.Get>(identifier)) = std::move(d); - std::get<1>(p.Get>( identifier)) = + std::get<1>(p.Get>(identifier)) = std::move(m); p.SetPassed(identifier); } diff --git a/src/mlpack/bindings/go/mlpack/capi/io_util.cpp b/src/mlpack/bindings/go/mlpack/capi/io_util.cpp index af086cd73a..86dfed3e8c 100644 --- a/src/mlpack/bindings/go/mlpack/capi/io_util.cpp +++ b/src/mlpack/bindings/go/mlpack/capi/io_util.cpp @@ -152,7 +152,7 @@ void mlpackSetParamVectorStr(void* params, */ void mlpackSetParamPtr(void* params, const char* identifier, - const double* ptr) + double* ptr) { util::Params& p = *((util::Params*) params); util::SetParamPtr(p, identifier, ptr); diff --git a/src/mlpack/bindings/go/mlpack/capi/io_util.h b/src/mlpack/bindings/go/mlpack/capi/io_util.h index 3fcaf41dd2..40b5de5b28 100644 --- a/src/mlpack/bindings/go/mlpack/capi/io_util.h +++ b/src/mlpack/bindings/go/mlpack/capi/io_util.h @@ -71,7 +71,7 @@ void mlpackSetParamString(void* params, /** * Set the parameter to the given value, given that the type is a pointer. */ -void mlpackSetParamPtr(void* params, const char* identifier, const double* ptr); +void mlpackSetParamPtr(void* params, const char* identifier, double* ptr); /** * Set the int vector parameter to the given value. diff --git a/src/mlpack/bindings/go/print_doc.hpp b/src/mlpack/bindings/go/print_doc.hpp index 21bb15cf54..d312f602f1 100644 --- a/src/mlpack/bindings/go/print_doc.hpp +++ b/src/mlpack/bindings/go/print_doc.hpp @@ -53,16 +53,16 @@ void PrintDoc(util::ParamData& d, { if (d.cppType == "std::string") { - oss << " Default value '" << boost::any_cast(d.value) + oss << " Default value '" << ANY_CAST(d.value) << "'."; } else if (d.cppType == "double") { - oss << " Default value " << boost::any_cast(d.value) << "."; + oss << " Default value " << ANY_CAST(d.value) << "."; } else if (d.cppType == "int") { - oss << " Default value " << boost::any_cast(d.value) << "."; + oss << " Default value " << ANY_CAST(d.value) << "."; } } diff --git a/src/mlpack/bindings/go/print_input_processing.hpp b/src/mlpack/bindings/go/print_input_processing.hpp index 8486236557..880770c3b6 100644 --- a/src/mlpack/bindings/go/print_input_processing.hpp +++ b/src/mlpack/bindings/go/print_input_processing.hpp @@ -67,22 +67,22 @@ void PrintInputProcessing( // Print out default value. if (d.cppType == "std::string") { - std::string value = boost::any_cast(d.value); + std::string value = ANY_CAST(d.value); std::cout << "\"" << value << "\""; } else if (d.cppType == "double") { - double value = boost::any_cast(d.value); + double value = ANY_CAST(d.value); std::cout << value; } else if (d.cppType == "int") { - int value = boost::any_cast(d.value); + int value = ANY_CAST(d.value); std::cout << value; } else if (d.cppType == "bool") { - bool value = boost::any_cast(d.value); + bool value = ANY_CAST(d.value); if (value == 0) std::cout << "false"; else diff --git a/src/mlpack/bindings/go/print_method_init.hpp b/src/mlpack/bindings/go/print_method_init.hpp index 1a9a363c48..0e2c055d5b 100644 --- a/src/mlpack/bindings/go/print_method_init.hpp +++ b/src/mlpack/bindings/go/print_method_init.hpp @@ -54,23 +54,23 @@ void PrintMethodInit( { if (d.cppType == "std::string") { - std::string value = boost::any_cast(d.value); + std::string value = ANY_CAST(d.value); std::cout << prefix << goParamName << ": \"" << value << "\"," << std::endl; } else if (d.cppType == "double") { - double value = boost::any_cast(d.value); + double value = ANY_CAST(d.value); std::cout << prefix << goParamName << ": " << value << "," << std::endl; } else if (d.cppType == "int") { - int value = boost::any_cast(d.value); + int value = ANY_CAST(d.value); std::cout << prefix << goParamName << ": " << value << "," << std::endl; } else if (d.cppType == "bool") { - bool value = boost::any_cast(d.value); + bool value = ANY_CAST(d.value); if (value == 0) std::cout << prefix << goParamName << ": false," << std::endl; else diff --git a/src/mlpack/bindings/go/tests/go_binding_test.go b/src/mlpack/bindings/go/tests/go_binding_test.go index 846e29bede..7b9a66ad98 100644 --- a/src/mlpack/bindings/go/tests/go_binding_test.go +++ b/src/mlpack/bindings/go/tests/go_binding_test.go @@ -574,6 +574,58 @@ func TestGonumMatrixWithInfo(t *testing.T) { } } +func TestGonumMatrixWithInfoCategorical(t *testing.T) { + t.Log("Test that the matrix with info option works when we pass categorical ", + "data.") + + x := mlpack.DataAndInfo() + x.Categoricals = []bool{ + false, false, true, true, false, + } + + x.Data = mat.NewDense(6, 5, []float64{ + 0.1, 0.2, 3, 2, 0.3, + 0.5, -0.3, 1, 1, 0.5, + -3, 0.1, 0, 0, 0.6, + 0.7, 0.0, 2, 4, 0.4, + 0.8, 0.1, 2, 3, 0.1, + 0.3, 0.0, 1, 1, 0.6, + }) + + param := mlpack.TestGoBindingOptions() + param.MatrixAndInfoIn = x + d := 4.0 + i := 12 + s := "hello" + _, _, _, MatrixAndInfoOut, _, _, _, _, _, _, _, _, _, _ := + mlpack.TestGoBinding(d, i, s, param) + + rows, cols := MatrixAndInfoOut.Dims() + + if rows != 6 || cols != 5 { + t.Errorf("Error. Wrong shape. %v, %v", rows, cols) + } + for i := 0; i < rows; i++ { + for j := 0; j < cols; j++ { + if j == 0 || j == 1 || j == 4 { + if x.Data.At(i, j) * 2 != MatrixAndInfoOut.At(i, j) { + val := MatrixAndInfoOut.At(i, j) + expected := x.Data.At(i, j)*2 + t.Errorf("Error. Value at [%v,%v] : %v. Expected value : %v", + i, j, val, expected) + } + } else { + if x.Data.At(i, j) != MatrixAndInfoOut.At(i, j) { + val := MatrixAndInfoOut.At(i, j) + expected := x.Data.At(i, j) + t.Errorf("Error. Value at [%v,%v] : %v. Expected value: %v", + i, j, val, expected) + } + } + } + } +} + func TestModel(t *testing.T) { t.Log("First create a GaussianKernel object, then send it back and", "make sure we get the right double value.") diff --git a/src/mlpack/bindings/go/tests/test_go_binding_main.cpp b/src/mlpack/bindings/go/tests/test_go_binding_main.cpp index d608ccafc2..270a863d5f 100644 --- a/src/mlpack/bindings/go/tests/test_go_binding_main.cpp +++ b/src/mlpack/bindings/go/tests/test_go_binding_main.cpp @@ -182,7 +182,22 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timer */) for (size_t i = 0; i < m.n_rows; ++i) { if (di.Type(i) == data::Datatype::numeric) + { m.row(i) *= 2.0; + } + else + { + // Make sure input data is valid. + for (size_t c = 0; c < m.n_cols; ++c) + { + if (ceil(m(i, c)) != m(i, c)) + throw std::invalid_argument("non-integer value in categorical!"); + else if (m(i, c) < 0) + throw std::invalid_argument("negative value in categorical!"); + else if (size_t(m(i, c)) >= di.NumMappings(i)) + throw std::invalid_argument("value outside number of categories!"); + } + } } params.Get("matrix_and_info_out") = move(m); diff --git a/src/mlpack/bindings/julia/default_param_impl.hpp b/src/mlpack/bindings/julia/default_param_impl.hpp index 667ecae5f4..d36b146608 100644 --- a/src/mlpack/bindings/julia/default_param_impl.hpp +++ b/src/mlpack/bindings/julia/default_param_impl.hpp @@ -36,7 +36,7 @@ std::string DefaultParamImpl( if (std::is_same::value) oss << "false"; else - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -51,7 +51,7 @@ std::string DefaultParamImpl( { // Print each element in an array delimited by square brackets. std::ostringstream oss; - const T& vector = boost::any_cast(data.value); + const T& vector = ANY_CAST(data.value); oss << "["; if (std::is_same>::value) { @@ -92,7 +92,7 @@ std::string DefaultParamImpl( util::ParamData& data, const typename std::enable_if::value>::type*) { - const std::string& s = *boost::any_cast(&data.value); + const std::string& s = *ANY_CAST(&data.value); return "\"" + s + "\""; } diff --git a/src/mlpack/bindings/julia/get_param.hpp b/src/mlpack/bindings/julia/get_param.hpp index b8c177262f..53983b88b8 100644 --- a/src/mlpack/bindings/julia/get_param.hpp +++ b/src/mlpack/bindings/julia/get_param.hpp @@ -27,7 +27,7 @@ void GetParam(util::ParamData& d, const void* /* input */, void* output) { - *((T**) output) = const_cast(boost::any_cast(&d.value)); + *((T**) output) = const_cast(ANY_CAST(&d.value)); } } // namespace julia diff --git a/src/mlpack/bindings/julia/get_printable_param.hpp b/src/mlpack/bindings/julia/get_printable_param.hpp index f6e7e442bc..0f204f02ea 100644 --- a/src/mlpack/bindings/julia/get_printable_param.hpp +++ b/src/mlpack/bindings/julia/get_printable_param.hpp @@ -32,7 +32,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -44,7 +44,7 @@ std::string GetPrintableParam( util::ParamData& data, const typename std::enable_if::value>::type* = 0) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) @@ -61,7 +61,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { // Get the matrix. - const T& matrix = boost::any_cast(data.value); + const T& matrix = ANY_CAST(data.value); std::ostringstream oss; oss << matrix.n_rows << "x" << matrix.n_cols << " matrix"; @@ -78,7 +78,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { std::ostringstream oss; - oss << data.cppType << " model at " << boost::any_cast(data.value); + oss << data.cppType << " model at " << ANY_CAST(data.value); return oss.str(); } @@ -92,7 +92,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { // Get the matrix. - const T& tuple = boost::any_cast(data.value); + const T& tuple = ANY_CAST(data.value); const arma::mat& matrix = std::get<1>(tuple); std::ostringstream oss; diff --git a/src/mlpack/bindings/julia/julia_option.hpp b/src/mlpack/bindings/julia/julia_option.hpp index f78427bfdd..1a1bcea4b2 100644 --- a/src/mlpack/bindings/julia/julia_option.hpp +++ b/src/mlpack/bindings/julia/julia_option.hpp @@ -64,7 +64,7 @@ class JuliaOption data.cppType = cppName; // Every parameter we'll get from Julia will have the correct type. - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); // Set the function pointers that we'll need. All of these function // pointers will be used by both the program that generates the pyx, and diff --git a/src/mlpack/bindings/julia/julia_util.cpp b/src/mlpack/bindings/julia/julia_util.cpp index 9a41665525..6c61cf0d6d 100644 --- a/src/mlpack/bindings/julia/julia_util.cpp +++ b/src/mlpack/bindings/julia/julia_util.cpp @@ -251,13 +251,42 @@ void SetParamMatWithInfo(void* params, { util::Params* p = (util::Params*) params; data::DatasetInfo d(pointsAreRows ? cols : rows); + bool hasCategoricals = false; for (size_t i = 0; i < d.Dimensionality(); ++i) { d.Type(i) = (dimensions[i]) ? data::Datatype::categorical : data::Datatype::numeric; + if (dimensions[i]) + hasCategoricals = true; } arma::mat m(memptr, arma::uword(rows), arma::uword(cols), false, true); + + // Do we need to find how many categories we have? + if (hasCategoricals) + { + // Compute the maximum in each dimension. + arma::vec maxs; + if (pointsAreRows) + maxs = arma::max(m, 0).t(); + else + maxs = arma::max(m, 1); + + for (size_t i = 0; i < d.Dimensionality(); ++i) + { + if (dimensions[i]) + { + // Map the right number of objects. + for (size_t j = 1; j <= (size_t) maxs[i]; ++j) + { + std::ostringstream oss; + oss << j; + d.MapString(oss.str(), i); + } + } + } + } + std::get<0>(p->Get>( paramName)) = std::move(d); std::get<1>(p->Get>( diff --git a/src/mlpack/bindings/julia/print_doc.hpp b/src/mlpack/bindings/julia/print_doc.hpp index 911c52194e..30d887137c 100644 --- a/src/mlpack/bindings/julia/print_doc.hpp +++ b/src/mlpack/bindings/julia/print_doc.hpp @@ -39,19 +39,19 @@ void PrintDoc(util::ParamData& d, const void* /* input */, void* output) oss << " Default value `"; if (d.cppType == "std::string") { - oss << boost::any_cast(d.value); + oss << ANY_CAST(d.value); } else if (d.cppType == "double") { - oss << boost::any_cast(d.value); + oss << ANY_CAST(d.value); } else if (d.cppType == "int") { - oss << boost::any_cast(d.value); + oss << ANY_CAST(d.value); } else if (d.cppType == "bool") { - oss << (boost::any_cast(d.value) ? "true" : "false"); + oss << (ANY_CAST(d.value) ? "true" : "false"); } oss << "`." << std::endl; } diff --git a/src/mlpack/bindings/julia/print_type_doc_impl.hpp b/src/mlpack/bindings/julia/print_type_doc_impl.hpp index 6b72612f69..378147f13c 100644 --- a/src/mlpack/bindings/julia/print_type_doc_impl.hpp +++ b/src/mlpack/bindings/julia/print_type_doc_impl.hpp @@ -142,9 +142,10 @@ std::string PrintTypeDoc( "indicating which dimensions are categorical (represented by `true`) and " "which are numeric (represented by `false`). The number of elements in " "the boolean array should be the same as the dimensionality of the data " - "matrix. It is expected that each row of the matrix corresponds to a " - "single data point, unless `points_are_rows` is set to `false` when " - "calling mlpack bindings."; + "matrix. Categorical dimensions should take integer values between 1 " + "and the number of categories. It is expected that each row of the " + "matrix corresponds to a single data point, unless `points_are_rows` is " + "set to `false` when calling mlpack bindings."; } /** diff --git a/src/mlpack/bindings/julia/tests/runtests.jl b/src/mlpack/bindings/julia/tests/runtests.jl index 57a6f548e0..26fbc56283 100644 --- a/src/mlpack/bindings/julia/tests/runtests.jl +++ b/src/mlpack/bindings/julia/tests/runtests.jl @@ -287,6 +287,64 @@ end end end +# Test that we can pass a matrix with categorical features. +@testset "TestMatrixAndInfoCategorical" begin + x = collect(hcat(rand(100), + rand(1:2, 100), + rand(100), + rand(1:4, 100), + rand(1:6, 100), + rand(100))') + dims = [false, true, false, true, true, false] + z = x + + _, _, _, matrix_and_info_out, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + matrix_and_info_in=(dims, z), + points_are_rows=false) + + @test size(matrix_and_info_out, 1) == 6 + @test size(matrix_and_info_out, 2) == 100 + + for i in 1:100 + for j in [1, 3, 6] + @test matrix_and_info_out[j, i] == 2.0 * z[j, i] + end + for j in [2, 4, 5] + @test matrix_and_info_out[j, i] == z[j, i] + end + end +end + +# Test that we can pass a matrix with categorical features. +@testset "TestMatrixAndInfoCategoricalRowMajor" begin + x = hcat(rand(100), + rand(1:2, 100), + rand(100), + rand(1:4, 100), + rand(1:6, 100), + rand(100)) + dims = [false, true, false, true, true, false] + z = x + + _, _, _, matrix_and_info_out, _, _, _, _, _, _, _, _, _, _ = + test_julia_binding(4.0, 12, "hello", + matrix_and_info_in=(dims, z), + points_are_rows=true) + + @test size(matrix_and_info_out, 1) == 100 + @test size(matrix_and_info_out, 2) == 6 + + for i in 1:100 + for j in [1, 3, 6] + @test matrix_and_info_out[i, j] == 2.0 * z[i, j] + end + for j in [2, 4, 5] + @test matrix_and_info_out[i, j] == z[i, j] + end + end +end + # Test that we can pass a vector of ints and get back that same vector but with # the last element removed. @testset "TestIntVector" begin diff --git a/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp b/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp index 85e728f26c..3c674dcd42 100644 --- a/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp +++ b/src/mlpack/bindings/julia/tests/test_julia_binding_main.cpp @@ -184,7 +184,22 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timers */) for (size_t i = 0; i < m.n_rows; ++i) { if (di.Type(i) == data::Datatype::numeric) + { m.row(i) *= 2.0; + } + else + { + // Make sure input data is valid. + for (size_t c = 0; c < m.n_cols; ++c) + { + if (ceil(m(i, c)) != m(i, c)) + throw std::invalid_argument("non-integer value in categorical!"); + else if (m(i, c) <= 0) + throw std::invalid_argument("negative/zero value in categorical!"); + else if (size_t(m(i, c)) > di.NumMappings(i)) + throw std::invalid_argument("value outside number of categories!"); + } + } } params.Get("matrix_and_info_out") = move(m); diff --git a/src/mlpack/bindings/markdown/get_param.hpp b/src/mlpack/bindings/markdown/get_param.hpp index 981c658fc5..748798355c 100644 --- a/src/mlpack/bindings/markdown/get_param.hpp +++ b/src/mlpack/bindings/markdown/get_param.hpp @@ -28,7 +28,7 @@ void GetParam(util::ParamData& d, void* output) { util::ParamData& dmod = const_cast(d); - *((T**) output) = boost::any_cast(&dmod.value); + *((T**) output) = ANY_CAST(&dmod.value); } } // namespace markdown diff --git a/src/mlpack/bindings/markdown/get_printable_param.hpp b/src/mlpack/bindings/markdown/get_printable_param.hpp index e94e9a7ca9..068d4c8ce9 100644 --- a/src/mlpack/bindings/markdown/get_printable_param.hpp +++ b/src/mlpack/bindings/markdown/get_printable_param.hpp @@ -32,7 +32,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -44,7 +44,7 @@ std::string GetPrintableParam( util::ParamData& data, const typename std::enable_if::value>::type* = 0) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) @@ -61,7 +61,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { // Get the matrix. - const T& matrix = boost::any_cast(data.value); + const T& matrix = ANY_CAST(data.value); std::ostringstream oss; oss << matrix.n_rows << "x" << matrix.n_cols << " matrix"; @@ -78,7 +78,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { std::ostringstream oss; - oss << data.cppType << " model at " << boost::any_cast(data.value); + oss << data.cppType << " model at " << ANY_CAST(data.value); return oss.str(); } @@ -92,7 +92,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { // Get the matrix. - const T& tuple = boost::any_cast(data.value); + const T& tuple = ANY_CAST(data.value); const arma::mat& matrix = std::get<1>(tuple); std::ostringstream oss; diff --git a/src/mlpack/bindings/markdown/md_option.hpp b/src/mlpack/bindings/markdown/md_option.hpp index 169ccb8a53..e8d4db8da2 100644 --- a/src/mlpack/bindings/markdown/md_option.hpp +++ b/src/mlpack/bindings/markdown/md_option.hpp @@ -63,7 +63,7 @@ class MDOption data.cppType = cppName; // Every parameter we'll get from Markdown will have the correct type. - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); // Set the function pointers that we'll need. Most of these simply delegate // to the current binding type's implementation. Any new language will need diff --git a/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp b/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp index fca2036f91..e5b6952ac2 100644 --- a/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp +++ b/src/mlpack/bindings/markdown/print_doc_functions_impl.hpp @@ -245,7 +245,7 @@ inline std::string PrintTypeDocs() data.required = false; data.input = true; data.loaded = false; - data.value = boost::any(int(0)); + data.value = ANY(int(0)); std::string type = GetPrintableType(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -253,7 +253,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(double).name()); data.cppType = "double"; - data.value = boost::any(double(0.0)); + data.value = ANY(double(0.0)); type = GetPrintableType(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -262,7 +262,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(bool).name()); data.cppType = "double"; - data.value = boost::any(bool(0.0)); + data.value = ANY(bool(0.0)); type = GetPrintableType(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -270,7 +270,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(std::string).name()); data.cppType = "std::string"; - data.value = boost::any(std::string("")); + data.value = ANY(std::string("")); type = GetPrintableType(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -279,7 +279,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(std::vector).name()); data.cppType = "std::vector"; - data.value = boost::any(std::vector()); + data.value = ANY(std::vector()); type = GetPrintableType>(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -288,7 +288,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(std::vector).name()); data.cppType = "std::vector"; - data.value = boost::any(std::vector()); + data.value = ANY(std::vector()); type = GetPrintableType>(data); oss << " - `" << type << "`{: " << "#doc_" << BindingInfo::Language() << "_" @@ -297,7 +297,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(arma::mat).name()); data.cppType = "arma::mat"; - data.value = boost::any(arma::mat()); + data.value = ANY(arma::mat()); type = GetPrintableType(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -306,7 +306,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(arma::Mat).name()); data.cppType = "arma::Mat"; - data.value = boost::any(arma::Mat()); + data.value = ANY(arma::Mat()); type = GetPrintableType>(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -315,7 +315,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(arma::rowvec).name()); data.cppType = "arma::rowvec"; - data.value = boost::any(arma::rowvec()); + data.value = ANY(arma::rowvec()); const std::string& rowType = GetPrintableType(data); oss << " - `" << rowType << "`{: #doc_" << BindingInfo::Language() << "_" @@ -324,7 +324,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(arma::Row).name()); data.cppType = "arma::Row"; - data.value = boost::any(arma::Row()); + data.value = ANY(arma::Row()); const std::string& urowType = GetPrintableType>(data); oss << " - `" << urowType << "`{: #doc_" << BindingInfo::Language() << "_" @@ -334,7 +334,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(arma::vec).name()); data.cppType = "arma::vec"; - data.value = boost::any(arma::vec()); + data.value = ANY(arma::vec()); const std::string& colType = GetPrintableType(data); // For some languages there is no distinction between column and row vectors. @@ -348,7 +348,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(arma::Col).name()); data.cppType = "arma::Col"; - data.value = boost::any(arma::Col()); + data.value = ANY(arma::Col()); const std::string& ucolType = GetPrintableType>(data); // For some languages there is no distinction between column and row vectors. @@ -363,7 +363,7 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(std::tuple).name()); data.cppType = "std::tuple"; - data.value = boost::any(std::tuple()); + data.value = ANY(std::tuple()); type = GetPrintableType>(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_" @@ -373,14 +373,14 @@ inline std::string PrintTypeDocs() data.tname = std::string(typeid(priv::mlpackModel).name()); data.cppType = "mlpackModel"; - data.value = boost::any(new priv::mlpackModel()); + data.value = ANY(new priv::mlpackModel()); type = GetPrintableType(data); oss << " - `" << type << "`{: #doc_" << BindingInfo::Language() << "_model }: " << PrintTypeDoc(data) << std::endl; // Clean up memory. - delete boost::any_cast(data.value); + delete ANY_CAST(data.value); oss << std::endl << "" << std::endl; diff --git a/src/mlpack/bindings/python/default_param_impl.hpp b/src/mlpack/bindings/python/default_param_impl.hpp index 543253c18b..b370a97fda 100644 --- a/src/mlpack/bindings/python/default_param_impl.hpp +++ b/src/mlpack/bindings/python/default_param_impl.hpp @@ -36,7 +36,7 @@ std::string DefaultParamImpl( if (std::is_same::value) oss << "False"; else - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -51,7 +51,7 @@ std::string DefaultParamImpl( { // Print each element in an array delimited by square brackets. std::ostringstream oss; - const T& vector = boost::any_cast(data.value); + const T& vector = ANY_CAST(data.value); oss << "["; if (std::is_same>::value) { @@ -92,7 +92,7 @@ std::string DefaultParamImpl( util::ParamData& data, const typename std::enable_if::value>::type*) { - const std::string& s = *boost::any_cast(&data.value); + const std::string& s = *ANY_CAST(&data.value); return "'" + s + "'"; } diff --git a/src/mlpack/bindings/python/get_param.hpp b/src/mlpack/bindings/python/get_param.hpp index 671ed78f78..8f9657ea53 100644 --- a/src/mlpack/bindings/python/get_param.hpp +++ b/src/mlpack/bindings/python/get_param.hpp @@ -27,7 +27,7 @@ void GetParam(util::ParamData& d, const void* /* input */, void* output) { - *((T**) output) = const_cast(boost::any_cast(&d.value)); + *((T**) output) = const_cast(ANY_CAST(&d.value)); } } // namespace python diff --git a/src/mlpack/bindings/python/get_printable_param.hpp b/src/mlpack/bindings/python/get_printable_param.hpp index 44ab825687..b9c7993365 100644 --- a/src/mlpack/bindings/python/get_printable_param.hpp +++ b/src/mlpack/bindings/python/get_printable_param.hpp @@ -32,7 +32,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -44,7 +44,7 @@ std::string GetPrintableParam( util::ParamData& data, const typename std::enable_if::value>::type* = 0) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) @@ -61,7 +61,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { // Get the matrix. - const T& matrix = boost::any_cast(data.value); + const T& matrix = ANY_CAST(data.value); std::ostringstream oss; oss << matrix.n_rows << "x" << matrix.n_cols << " matrix"; @@ -78,7 +78,7 @@ std::string GetPrintableParam( const typename std::enable_if::value>::type* = 0) { std::ostringstream oss; - oss << data.cppType << " model at " << boost::any_cast(data.value); + oss << data.cppType << " model at " << ANY_CAST(data.value); return oss.str(); } @@ -92,7 +92,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* = 0) { // Get the matrix. - const T& tuple = boost::any_cast(data.value); + const T& tuple = ANY_CAST(data.value); const arma::mat& matrix = std::get<1>(tuple); std::ostringstream oss; diff --git a/src/mlpack/bindings/python/mlpack/io_util.hpp b/src/mlpack/bindings/python/mlpack/io_util.hpp index 3276eead6e..9966924cd0 100644 --- a/src/mlpack/bindings/python/mlpack/io_util.hpp +++ b/src/mlpack/bindings/python/mlpack/io_util.hpp @@ -87,7 +87,7 @@ inline void SetParamWithInfo(util::Params& params, if (hasCategoricals) { arma::vec maxs = arma::max( - std::get<1>(params.Get(identifier)), 1); + std::get<1>(params.Get(identifier)), 1) + 1; for (size_t i = 0; i < dimensions; ++i) { diff --git a/src/mlpack/bindings/python/py_option.hpp b/src/mlpack/bindings/python/py_option.hpp index 8c6fca7590..f3aa6af21d 100644 --- a/src/mlpack/bindings/python/py_option.hpp +++ b/src/mlpack/bindings/python/py_option.hpp @@ -63,7 +63,7 @@ class PyOption data.cppType = cppName; // Every parameter we'll get from Python will have the correct type. - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); // Set the function pointers that we'll need. All of these function // pointers will be used by both the program that generates the pyx, and diff --git a/src/mlpack/bindings/python/tests/test_python_binding_main.cpp b/src/mlpack/bindings/python/tests/test_python_binding_main.cpp index 0e3bfaee53..ce14d78428 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding_main.cpp +++ b/src/mlpack/bindings/python/tests/test_python_binding_main.cpp @@ -223,7 +223,22 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timer */) for (size_t i = 0; i < m.n_rows; ++i) { if (di.Type(i) == data::Datatype::numeric) + { m.row(i) *= 2.0; + } + else + { + // Make sure input data is valid. + for (size_t c = 0; c < m.n_cols; ++c) + { + if (ceil(m(i, c)) != m(i, c)) + throw std::invalid_argument("non-integer value in categorical!"); + else if (m(i, c) < 0) + throw std::invalid_argument("negative value in categorical!"); + else if (size_t(m(i, c)) >= di.NumMappings(i)) + throw std::invalid_argument("value outside number of categories!"); + } + } } params.Get("matrix_and_info_out") = move(m); diff --git a/src/mlpack/bindings/tests/delete_allocated_memory.hpp b/src/mlpack/bindings/tests/delete_allocated_memory.hpp index 5dd60fa294..99d6ea89c4 100644 --- a/src/mlpack/bindings/tests/delete_allocated_memory.hpp +++ b/src/mlpack/bindings/tests/delete_allocated_memory.hpp @@ -42,7 +42,7 @@ void DeleteAllocatedMemoryImpl( const typename std::enable_if::value>::type* = 0) { // Delete the allocated memory (hopefully we actually own it). - delete *boost::any_cast(&d.value); + delete *ANY_CAST(&d.value); } template diff --git a/src/mlpack/bindings/tests/get_allocated_memory.hpp b/src/mlpack/bindings/tests/get_allocated_memory.hpp index fb4a903b80..4776e9ddb6 100644 --- a/src/mlpack/bindings/tests/get_allocated_memory.hpp +++ b/src/mlpack/bindings/tests/get_allocated_memory.hpp @@ -43,7 +43,7 @@ void* GetAllocatedMemory( const typename std::enable_if::value>::type* = 0) { // Here we have a model; return its memory location. - return *boost::any_cast(&d.value); + return *ANY_CAST(&d.value); } template diff --git a/src/mlpack/bindings/tests/get_param.hpp b/src/mlpack/bindings/tests/get_param.hpp index 399788599f..6838b2bbc2 100644 --- a/src/mlpack/bindings/tests/get_param.hpp +++ b/src/mlpack/bindings/tests/get_param.hpp @@ -26,7 +26,7 @@ template T& GetParam(util::ParamData& d) { // No mapping is needed, so just cast it directly. - return *boost::any_cast(&d.value); + return *ANY_CAST(&d.value); } /** diff --git a/src/mlpack/bindings/tests/get_printable_param_impl.hpp b/src/mlpack/bindings/tests/get_printable_param_impl.hpp index 3a6c604b69..23d1820296 100644 --- a/src/mlpack/bindings/tests/get_printable_param_impl.hpp +++ b/src/mlpack/bindings/tests/get_printable_param_impl.hpp @@ -29,7 +29,7 @@ std::string GetPrintableParam( std::tuple>::value>::type* /* junk */) { std::ostringstream oss; - oss << boost::any_cast(data.value); + oss << ANY_CAST(data.value); return oss.str(); } @@ -39,7 +39,7 @@ std::string GetPrintableParam( util::ParamData& data, const typename std::enable_if::value>::type* /* junk */) { - const T& t = boost::any_cast(data.value); + const T& t = ANY_CAST(data.value); std::ostringstream oss; for (size_t i = 0; i < t.size(); ++i) diff --git a/src/mlpack/bindings/tests/test_option.hpp b/src/mlpack/bindings/tests/test_option.hpp index 307d6c952b..8f4bf87c23 100644 --- a/src/mlpack/bindings/tests/test_option.hpp +++ b/src/mlpack/bindings/tests/test_option.hpp @@ -83,7 +83,7 @@ class TestOption data.input = input; data.loaded = false; data.cppType = cppName; - data.value = boost::any(defaultValue); + data.value = ANY(defaultValue); const std::string tname = data.tname; diff --git a/src/mlpack/core/boost_backport/CMakeLists.txt b/src/mlpack/core/boost_backport/CMakeLists.txt index e7005cc878..8a177fda47 100644 --- a/src/mlpack/core/boost_backport/CMakeLists.txt +++ b/src/mlpack/core/boost_backport/CMakeLists.txt @@ -7,9 +7,6 @@ set(SOURCES detail/unchecked_bernoulli.hpp math_fwd.hpp policy.hpp - string_view.hpp - string_view_fwd.hpp - boost_backport_string_view.hpp ) # add directory name to sources diff --git a/src/mlpack/core/boost_backport/boost_backport_string_view.hpp b/src/mlpack/core/boost_backport/boost_backport_string_view.hpp deleted file mode 100644 index f942fcfeb8..0000000000 --- a/src/mlpack/core/boost_backport/boost_backport_string_view.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @file core/boost_backport/boost_backport_string_view.hpp - * @author Jeffin Sam - * - * Centralized control of what boost files to include. We have backported the - * following boost functionality here: - * - * * string_view support (added in boost 1.61.0) - * * hash function support (added in boost 1.69.0) - * - * If the detected boost version is greater or equal to 1.61.0, we include the - * normal serialization functions (not the backported ones). For all older - * versions we include the backported headers. - */ -#ifndef MLPACK_CORE_BOOST_BACKPORT_STRING_VIEW_HPP -#define MLPACK_CORE_BOOST_BACKPORT_STRING_VIEW_HPP - -#include -#include - -#if BOOST_VERSION < 106100 - // Backported unordered_map. - #include "mlpack/core/boost_backport/string_view.hpp" -#else - // Boost's version. - #include -#endif - -#if BOOST_VERSION < 106900 - namespace boost - { - template<> - struct hash - { - std::size_t operator()(boost::string_view str) const - { - return boost::hash_range(str.begin(), str.end()); - } - }; - } -#endif - -#endif // MLPACK_CORE_BOOST_BACKPORT_STRING_VIEW_HPP diff --git a/src/mlpack/core/boost_backport/string_view.hpp b/src/mlpack/core/boost_backport/string_view.hpp deleted file mode 100644 index ec6238259f..0000000000 --- a/src/mlpack/core/boost_backport/string_view.hpp +++ /dev/null @@ -1,698 +0,0 @@ -/* - Copyright (c) Marshall Clow 2012-2015. - Copyright (c) Beman Dawes 2015 - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - For more information, see http://www.boost.org - - Based on the StringRef implementation in LLVM (http://llvm.org) and - N3422 by Jeffrey Yasskin - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html - Updated July 2015 to reflect the Library Fundamentals TS - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html -*/ - -#ifndef BOOST_STRING_VIEW_HPP -#define BOOST_STRING_VIEW_HPP - -#include -#include -#include -#include - -#if BOOST_VERSION < 106100 - // Backported unordered_map. - #include "mlpack/core/boost_backport/string_view_fwd.hpp" -#else - // Boost's version. - #include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) -// GCC 4.6 cannot handle a defaulted function with noexcept specifier -#define BOOST_STRING_VIEW_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS -#endif - -namespace boost { - - namespace detail { - // A helper functor because sometimes we don't have lambdas - template - class string_view_traits_eq { - public: - string_view_traits_eq ( charT ch ) : ch_(ch) {} - bool operator()( charT val ) const { return traits::eq (ch_, val); } - charT ch_; - }; - } - - template // traits defaulted in string_view_fwd.hpp - class basic_string_view { - public: - // types - typedef traits traits_type; - typedef charT value_type; - typedef charT* pointer; - typedef const charT* const_pointer; - typedef charT& reference; - typedef const charT& const_reference; - typedef const_pointer const_iterator; // impl-defined - typedef const_iterator iterator; - typedef std::reverse_iterator const_reverse_iterator; - typedef const_reverse_iterator reverse_iterator; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - static BOOST_CONSTEXPR_OR_CONST size_type npos = size_type(-1); - - // construct/copy - BOOST_CONSTEXPR basic_string_view() BOOST_NOEXCEPT - : ptr_(NULL), len_(0) {} - - // by defaulting these functions, basic_string_ref becomes - // trivially copy/move constructible. - BOOST_CONSTEXPR basic_string_view(const basic_string_view &rhs) BOOST_NOEXCEPT -#ifndef BOOST_STRING_VIEW_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS - = default; -#else - : ptr_(rhs.ptr_), len_(rhs.len_) {} -#endif - - basic_string_view& operator=(const basic_string_view &rhs) BOOST_NOEXCEPT -#ifndef BOOST_STRING_VIEW_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS - = default; -#else - { - ptr_ = rhs.ptr_; - len_ = rhs.len_; - return *this; - } -#endif - - template - basic_string_view(const std::basic_string& str) BOOST_NOEXCEPT - : ptr_(str.data()), len_(str.length()) {} - -// #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) -// // Constructing a string_view from a temporary string is a bad idea -// template -// basic_string_view( std::basic_string&&) -// = delete; -// #endif - - BOOST_CONSTEXPR basic_string_view(const charT* str) - : ptr_(str), len_(traits::length(str)) {} - - BOOST_CONSTEXPR basic_string_view(const charT* str, size_type len) - : ptr_(str), len_(len) {} - - // iterators - BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT { return ptr_; } - BOOST_CONSTEXPR const_iterator cbegin() const BOOST_NOEXCEPT { return ptr_; } - BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT { return ptr_ + len_; } - BOOST_CONSTEXPR const_iterator cend() const BOOST_NOEXCEPT { return ptr_ + len_; } - const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); } - const_reverse_iterator crbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); } - const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); } - const_reverse_iterator crend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); } - - // capacity - BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT { return len_; } - BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT { return len_; } - BOOST_CONSTEXPR size_type max_size() const BOOST_NOEXCEPT { return len_; } - BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT { return len_ == 0; } - - // element access - BOOST_CONSTEXPR const_reference operator[](size_type pos) const BOOST_NOEXCEPT { return ptr_[pos]; } - - BOOST_CONSTEXPR const_reference at(size_t pos) const { - return pos >= len_ ? BOOST_THROW_EXCEPTION(std::out_of_range("boost::string_view::at")), ptr_[0] : ptr_[pos]; - } - - BOOST_CONSTEXPR const_reference front() const { return ptr_[0]; } - BOOST_CONSTEXPR const_reference back() const { return ptr_[len_-1]; } - BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT { return ptr_; } - - // modifiers - void clear() BOOST_NOEXCEPT { len_ = 0; } // Boost extension - - BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n) { - if ( n > len_ ) - n = len_; - ptr_ += n; - len_ -= n; - } - - BOOST_CXX14_CONSTEXPR void remove_suffix(size_type n) { - if ( n > len_ ) - n = len_; - len_ -= n; - } - - BOOST_CXX14_CONSTEXPR void swap(basic_string_view& s) BOOST_NOEXCEPT { - std::swap(ptr_, s.ptr_); - std::swap(len_, s.len_); - } - - // basic_string_view string operations -#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS - template - explicit operator std::basic_string() const { - return std::basic_string(begin(), end()); - } -#endif - -#ifndef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS - template > - std::basic_string to_string(const Allocator& a = Allocator()) const { - return std::basic_string(begin(), end(), a); - } -#else - std::basic_string to_string() const { - return std::basic_string(begin(), end()); - } - - template - std::basic_string to_string(const Allocator& a) const { - return std::basic_string(begin(), end(), a); - } -#endif - - size_type copy(charT* s, size_type n, size_type pos=0) const { - if (pos > size()) - BOOST_THROW_EXCEPTION(std::out_of_range("string_view::copy" )); - size_type rlen = (std::min)(n, len_ - pos); - traits_type::copy(s, data() + pos, rlen); - return rlen; - } - - BOOST_CXX14_CONSTEXPR basic_string_view substr(size_type pos, size_type n=npos) const { - if ( pos > size()) - BOOST_THROW_EXCEPTION( std::out_of_range ( "string_view::substr" ) ); - return basic_string_view(data() + pos, (std::min)(size() - pos, n)); - } - - BOOST_CXX14_CONSTEXPR int compare(basic_string_view x) const BOOST_NOEXCEPT { - const int cmp = traits::compare(ptr_, x.ptr_, (std::min)(len_, x.len_)); - return cmp != 0 ? cmp : (len_ == x.len_ ? 0 : len_ < x.len_ ? -1 : 1); - } - - BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, basic_string_view x) - const BOOST_NOEXCEPT { - return substr(pos1, n1).compare(x); - } - - BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, - basic_string_view x, size_type pos2, size_type n2) const { - return substr(pos1, n1).compare(x.substr(pos2, n2)); - } - - BOOST_CXX14_CONSTEXPR int compare(const charT* x) const { - return compare(basic_string_view(x)); - } - - BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, const charT* x) const { - return substr(pos1, n1).compare(basic_string_view(x)); - } - - BOOST_CXX14_CONSTEXPR int compare(size_type pos1, size_type n1, - const charT* x, size_type n2) const { - return substr(pos1, n1).compare(basic_string_view(x, n2)); - } - - // Searches - BOOST_CONSTEXPR bool starts_with(charT c) const BOOST_NOEXCEPT { // Boost extension - return !empty() && traits::eq(c, front()); - } - - BOOST_CONSTEXPR bool starts_with(basic_string_view x) const BOOST_NOEXCEPT { // Boost extension - return len_ >= x.len_ && traits::compare(ptr_, x.ptr_, x.len_) == 0; - } - - BOOST_CONSTEXPR bool ends_with(charT c) const BOOST_NOEXCEPT { // Boost extension - return !empty() && traits::eq(c, back()); - } - - BOOST_CONSTEXPR bool ends_with(basic_string_view x) const BOOST_NOEXCEPT { // Boost extension - return len_ >= x.len_ && - traits::compare(ptr_ + len_ - x.len_, x.ptr_, x.len_) == 0; - } - - // find - BOOST_CXX14_CONSTEXPR size_type find(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { - if (pos > size()) - return npos; - if (s.empty()) - return pos; - const_iterator iter = std::search(this->cbegin() + pos, this->cend(), - s.cbegin (), s.cend (), traits::eq); - return iter == this->cend () ? npos : std::distance(this->cbegin (), iter); - } - BOOST_CXX14_CONSTEXPR size_type find(charT c, size_type pos = 0) const BOOST_NOEXCEPT - { return find(basic_string_view(&c, 1), pos); } - BOOST_CXX14_CONSTEXPR size_type find(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT - { return find(basic_string_view(s, n), pos); } - BOOST_CXX14_CONSTEXPR size_type find(const charT* s, size_type pos = 0) const BOOST_NOEXCEPT - { return find(basic_string_view(s), pos); } - - // rfind - BOOST_CXX14_CONSTEXPR size_type rfind(basic_string_view s, size_type pos = npos) const BOOST_NOEXCEPT { - if (len_ < s.len_) - return npos; - if (pos > len_ - s.len_) - pos = len_ - s.len_; - if (s.len_ == 0u) // an empty string is always found - return pos; - for (const charT* cur = ptr_ + pos; ; --cur) { - if (traits::compare(cur, s.ptr_, s.len_) == 0) - return cur - ptr_; - if (cur == ptr_) - return npos; - }; - } - BOOST_CXX14_CONSTEXPR size_type rfind(charT c, size_type pos = npos) const BOOST_NOEXCEPT - { return rfind(basic_string_view(&c, 1), pos); } - BOOST_CXX14_CONSTEXPR size_type rfind(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT - { return rfind(basic_string_view(s, n), pos); } - BOOST_CXX14_CONSTEXPR size_type rfind(const charT* s, size_type pos = npos) const BOOST_NOEXCEPT - { return rfind(basic_string_view(s), pos); } - - // find_first_of - BOOST_CXX14_CONSTEXPR size_type find_first_of(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { - if (pos >= len_ || s.len_ == 0) - return npos; - const_iterator iter = std::find_first_of - (this->cbegin () + pos, this->cend (), s.cbegin (), s.cend (), traits::eq); - return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); - } - BOOST_CXX14_CONSTEXPR size_type find_first_of(charT c, size_type pos = 0) const BOOST_NOEXCEPT - { return find_first_of(basic_string_view(&c, 1), pos); } - BOOST_CXX14_CONSTEXPR size_type find_first_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT - { return find_first_of(basic_string_view(s, n), pos); } - BOOST_CXX14_CONSTEXPR size_type find_first_of(const charT* s, size_type pos = 0) const BOOST_NOEXCEPT - { return find_first_of(basic_string_view(s), pos); } - - // find_last_of - BOOST_CXX14_CONSTEXPR size_type find_last_of(basic_string_view s, size_type pos = npos) const BOOST_NOEXCEPT { - if (s.len_ == 0u) - return npos; - if (pos >= len_) - pos = 0; - else - pos = len_ - (pos+1); - const_reverse_iterator iter = std::find_first_of - ( this->crbegin () + pos, this->crend (), s.cbegin (), s.cend (), traits::eq ); - return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter); - } - BOOST_CXX14_CONSTEXPR size_type find_last_of(charT c, size_type pos = npos) const BOOST_NOEXCEPT - { return find_last_of(basic_string_view(&c, 1), pos); } - BOOST_CXX14_CONSTEXPR size_type find_last_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT - { return find_last_of(basic_string_view(s, n), pos); } - BOOST_CXX14_CONSTEXPR size_type find_last_of(const charT* s, size_type pos = npos) const BOOST_NOEXCEPT - { return find_last_of(basic_string_view(s), pos); } - - // find_first_not_of - BOOST_CXX14_CONSTEXPR size_type find_first_not_of(basic_string_view s, size_type pos = 0) const BOOST_NOEXCEPT { - if (pos >= len_) - return npos; - if (s.len_ == 0) - return pos; - const_iterator iter = find_not_of ( this->cbegin () + pos, this->cend (), s ); - return iter == this->cend () ? npos : std::distance ( this->cbegin (), iter ); - } - BOOST_CXX14_CONSTEXPR size_type find_first_not_of(charT c, size_type pos = 0) const BOOST_NOEXCEPT - { return find_first_not_of(basic_string_view(&c, 1), pos); } - BOOST_CXX14_CONSTEXPR size_type find_first_not_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT - { return find_first_not_of(basic_string_view(s, n), pos); } - BOOST_CXX14_CONSTEXPR size_type find_first_not_of(const charT* s, size_type pos = 0) const BOOST_NOEXCEPT - { return find_first_not_of(basic_string_view(s), pos); } - - // find_last_not_of - BOOST_CXX14_CONSTEXPR size_type find_last_not_of(basic_string_view s, size_type pos = npos) const BOOST_NOEXCEPT { - if (pos >= len_) - pos = len_ - 1; - if (s.len_ == 0u) - return pos; - pos = len_ - (pos+1); - const_reverse_iterator iter = find_not_of ( this->crbegin () + pos, this->crend (), s ); - return iter == this->crend () ? npos : reverse_distance ( this->crbegin (), iter ); - } - BOOST_CXX14_CONSTEXPR size_type find_last_not_of(charT c, size_type pos = npos) const BOOST_NOEXCEPT - { return find_last_not_of(basic_string_view(&c, 1), pos); } - BOOST_CXX14_CONSTEXPR size_type find_last_not_of(const charT* s, size_type pos, size_type n) const BOOST_NOEXCEPT - { return find_last_not_of(basic_string_view(s, n), pos); } - BOOST_CXX14_CONSTEXPR size_type find_last_not_of(const charT* s, size_type pos = npos) const BOOST_NOEXCEPT - { return find_last_not_of(basic_string_view(s), pos); } - - private: - template - size_type reverse_distance(r_iter first, r_iter last) const BOOST_NOEXCEPT { - // Portability note here: std::distance is not NOEXCEPT, but calling it with a string_view::reverse_iterator will not throw. - return len_ - 1 - std::distance ( first, last ); - } - - template - Iterator find_not_of(Iterator first, Iterator last, basic_string_view s) const BOOST_NOEXCEPT { - for (; first != last ; ++first) - if ( 0 == traits::find(s.ptr_, s.len_, *first)) - return first; - return last; - } - - const charT *ptr_; - std::size_t len_; - }; - - -// Comparison operators -// Equality - template - inline bool operator==(basic_string_view x, - basic_string_view y) BOOST_NOEXCEPT { - if (x.size () != y.size ()) return false; - return x.compare(y) == 0; - } - -// Inequality - template - inline bool operator!=(basic_string_view x, - basic_string_view y) BOOST_NOEXCEPT { - if ( x.size () != y.size ()) return true; - return x.compare(y) != 0; - } - -// Less than - template - inline bool operator<(basic_string_view x, - basic_string_view y) BOOST_NOEXCEPT { - return x.compare(y) < 0; - } - -// Greater than - template - inline bool operator>(basic_string_view x, - basic_string_view y) BOOST_NOEXCEPT { - return x.compare(y) > 0; - } - -// Less than or equal to - template - inline bool operator<=(basic_string_view x, - basic_string_view y) BOOST_NOEXCEPT { - return x.compare(y) <= 0; - } - -// Greater than or equal to - template - inline bool operator>=(basic_string_view x, - basic_string_view y) BOOST_NOEXCEPT { - return x.compare(y) >= 0; - } - -// "sufficient additional overloads of comparison functions" - template - inline bool operator==(basic_string_view x, - const std::basic_string & y) BOOST_NOEXCEPT { - return x == basic_string_view(y); - } - - template - inline bool operator==(const std::basic_string & x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) == y; - } - - template - inline bool operator==(basic_string_view x, - const charT * y) BOOST_NOEXCEPT { - return x == basic_string_view(y); - } - - template - inline bool operator==(const charT * x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) == y; - } - - template - inline bool operator!=(basic_string_view x, - const std::basic_string & y) BOOST_NOEXCEPT { - return x != basic_string_view(y); - } - - template - inline bool operator!=(const std::basic_string & x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) != y; - } - - template - inline bool operator!=(basic_string_view x, - const charT * y) BOOST_NOEXCEPT { - return x != basic_string_view(y); - } - - template - inline bool operator!=(const charT * x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) != y; - } - - template - inline bool operator<(basic_string_view x, - const std::basic_string & y) BOOST_NOEXCEPT { - return x < basic_string_view(y); - } - - template - inline bool operator<(const std::basic_string & x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) < y; - } - - template - inline bool operator<(basic_string_view x, - const charT * y) BOOST_NOEXCEPT { - return x < basic_string_view(y); - } - - template - inline bool operator<(const charT * x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) < y; - } - - template - inline bool operator>(basic_string_view x, - const std::basic_string & y) BOOST_NOEXCEPT { - return x > basic_string_view(y); - } - - template - inline bool operator>(const std::basic_string & x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) > y; - } - - template - inline bool operator>(basic_string_view x, - const charT * y) BOOST_NOEXCEPT { - return x > basic_string_view(y); - } - - template - inline bool operator>(const charT * x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) > y; - } - - template - inline bool operator<=(basic_string_view x, - const std::basic_string & y) BOOST_NOEXCEPT { - return x <= basic_string_view(y); - } - - template - inline bool operator<=(const std::basic_string & x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) <= y; - } - - template - inline bool operator<=(basic_string_view x, - const charT * y) BOOST_NOEXCEPT { - return x <= basic_string_view(y); - } - - template - inline bool operator<=(const charT * x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) <= y; - } - - template - inline bool operator>=(basic_string_view x, - const std::basic_string & y) BOOST_NOEXCEPT { - return x >= basic_string_view(y); - } - - template - inline bool operator>=(const std::basic_string & x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) >= y; - } - - template - inline bool operator>=(basic_string_view x, - const charT * y) BOOST_NOEXCEPT { - return x >= basic_string_view(y); - } - - template - inline bool operator>=(const charT * x, - basic_string_view y) BOOST_NOEXCEPT { - return basic_string_view(x) >= y; - } - - namespace detail { - - template - inline void sv_insert_fill_chars(std::basic_ostream& os, std::size_t n) { - enum { chunk_size = 8 }; - charT fill_chars[chunk_size]; - std::fill_n(fill_chars, static_cast< std::size_t >(chunk_size), os.fill()); - for (; n >= chunk_size && os.good(); n -= chunk_size) - os.write(fill_chars, static_cast< std::size_t >(chunk_size)); - if (n > 0 && os.good()) - os.write(fill_chars, n); - } - - template - void sv_insert_aligned(std::basic_ostream& os, const basic_string_view& str) { - const std::size_t size = str.size(); - const std::size_t alignment_size = static_cast< std::size_t >(os.width()) - size; - const bool align_left = (os.flags() & std::basic_ostream::adjustfield) == std::basic_ostream::left; - if (!align_left) { - detail::sv_insert_fill_chars(os, alignment_size); - if (os.good()) - os.write(str.data(), size); - } - else { - os.write(str.data(), size); - if (os.good()) - detail::sv_insert_fill_chars(os, alignment_size); - } - } - - } // namespace detail - - // Inserter - template - inline std::basic_ostream& - operator<<(std::basic_ostream& os, - const basic_string_view& str) { - if (os.good()) { - const std::size_t size = str.size(); - const std::size_t w = static_cast< std::size_t >(os.width()); - if (w <= size) - os.write(str.data(), size); - else - detail::sv_insert_aligned(os, str); - os.width(0); - } - return os; - } - -#if 0 - // numeric conversions - // - // These are short-term implementations. - // In a production environment, I would rather avoid the copying. - // - inline int stoi (string_view str, size_t* idx=0, int base=10) { - return std::stoi ( std::string(str), idx, base ); - } - - inline long stol (string_view str, size_t* idx=0, int base=10) { - return std::stol ( std::string(str), idx, base ); - } - - inline unsigned long stoul (string_view str, size_t* idx=0, int base=10) { - return std::stoul ( std::string(str), idx, base ); - } - - inline long long stoll (string_view str, size_t* idx=0, int base=10) { - return std::stoll ( std::string(str), idx, base ); - } - - inline unsigned long long stoull (string_view str, size_t* idx=0, int base=10) { - return std::stoull ( std::string(str), idx, base ); - } - - inline float stof (string_view str, size_t* idx=0) { - return std::stof ( std::string(str), idx ); - } - - inline double stod (string_view str, size_t* idx=0) { - return std::stod ( std::string(str), idx ); - } - - inline long double stold (string_view str, size_t* idx=0) { - return std::stold ( std::string(str), idx ); - } - - inline int stoi (wstring_view str, size_t* idx=0, int base=10) { - return std::stoi ( std::wstring(str), idx, base ); - } - - inline long stol (wstring_view str, size_t* idx=0, int base=10) { - return std::stol ( std::wstring(str), idx, base ); - } - - inline unsigned long stoul (wstring_view str, size_t* idx=0, int base=10) { - return std::stoul ( std::wstring(str), idx, base ); - } - - inline long long stoll (wstring_view str, size_t* idx=0, int base=10) { - return std::stoll ( std::wstring(str), idx, base ); - } - - inline unsigned long long stoull (wstring_view str, size_t* idx=0, int base=10) { - return std::stoull ( std::wstring(str), idx, base ); - } - - inline float stof (wstring_view str, size_t* idx=0) { - return std::stof ( std::wstring(str), idx ); - } - - inline double stod (wstring_view str, size_t* idx=0) { - return std::stod ( std::wstring(str), idx ); - } - - inline long double stold (wstring_view str, size_t* idx=0) { - return std::stold ( std::wstring(str), idx ); - } -#endif - -} - -#if 0 -namespace std { - // Hashing - template<> struct hash; - template<> struct hash; - template<> struct hash; - template<> struct hash; -} -#endif - -#endif diff --git a/src/mlpack/core/boost_backport/string_view_fwd.hpp b/src/mlpack/core/boost_backport/string_view_fwd.hpp deleted file mode 100644 index 3d2317addc..0000000000 --- a/src/mlpack/core/boost_backport/string_view_fwd.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (c) Marshall Clow 2012-2012. - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - For more information, see http://www.boost.org - - Based on the StringRef implementation in LLVM (http://llvm.org) and - N3422 by Jeffrey Yasskin - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html - Updated July 2015 to reflect the Library Fundamentals TS - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html - -*/ - -#ifndef BOOST_STRING_VIEW_FWD_HPP -#define BOOST_STRING_VIEW_FWD_HPP - -#include -#include - -namespace boost { - - template > class basic_string_view; - typedef basic_string_view > string_view; - typedef basic_string_view > wstring_view; - -#ifndef BOOST_NO_CXX11_CHAR16_T - typedef basic_string_view > u16string_view; -#endif - -#ifndef BOOST_NO_CXX11_CHAR32_T - typedef basic_string_view > u32string_view; -#endif - -} - -#endif \ No newline at end of file diff --git a/src/mlpack/core/data/string_encoding.hpp b/src/mlpack/core/data/string_encoding.hpp index f1fd9c31fb..eba8c87849 100644 --- a/src/mlpack/core/data/string_encoding.hpp +++ b/src/mlpack/core/data/string_encoding.hpp @@ -14,7 +14,6 @@ #define MLPACK_CORE_DATA_STRING_ENCODING_HPP #include -#include #include #include #include @@ -75,7 +74,7 @@ class StringEncoding * @param tokenizer The tokenizer object. * * The tokenization algorithm has to be an object with two public methods: - * 1. operator() which accepts a reference to boost::string_view, extracts + * 1. operator() which accepts a reference to STRING_VIEW, extracts * the next token from the given view, removes the prefix containing * the extracted token and returns the token; * 2. IsTokenEmpty() that accepts a token and returns true if the given @@ -109,7 +108,7 @@ class StringEncoding * @param tokenizer The tokenizer object. * * The tokenization algorithm has to be an object with two public methods: - * 1. operator() which accepts a reference to boost::string_view, extracts + * 1. operator() which accepts a reference to STRING_VIEW, extracts * the next token from the given view, removes the prefix containing * the extracted token and returns the token; * 2. IsTokenEmpty() that accepts a token and returns true if the given @@ -159,7 +158,7 @@ class StringEncoding * @param policy The policy object. * * The tokenization algorithm has to be an object with two public methods: - * 1. operator() which accepts a reference to boost::string_view, extracts + * 1. operator() which accepts a reference to STRING_VIEW, extracts * the next token from the given view, removes the prefix containing * the extracted token and returns the token; * 2. IsTokenEmpty() that accepts a token and returns true if the given @@ -188,7 +187,7 @@ class StringEncoding * @param policy The policy object. * * The tokenization algorithm has to be an object with two public methods: - * 1. operator() which accepts a reference to boost::string_view, extracts + * 1. operator() which accepts a reference to STRING_VIEW, extracts * the next token from the given view, removes the prefix containing * the extracted token and returns the token; * 2. IsTokenEmpty() that accepts a token and returns true if the given diff --git a/src/mlpack/core/data/string_encoding_dictionary.hpp b/src/mlpack/core/data/string_encoding_dictionary.hpp index e40c72b8f6..ea429afc01 100644 --- a/src/mlpack/core/data/string_encoding_dictionary.hpp +++ b/src/mlpack/core/data/string_encoding_dictionary.hpp @@ -14,10 +14,11 @@ #define MLPACK_CORE_DATA_STRING_ENCODING_DICTIONARY_HPP #include -#include -#include -#include + #include +#include +#include +#include namespace mlpack { namespace data { @@ -105,20 +106,20 @@ class StringEncodingDictionary }; /* - * Specialization of the StringEncodingDictionary class for boost::string_view. + * Specialization of the StringEncodingDictionary class for STRING_VIEW. */ template<> -class StringEncodingDictionary +class StringEncodingDictionary { public: //! A convenient alias for the internal type of the map. using MapType = std::unordered_map< - boost::string_view, + STRING_VIEW, size_t, - boost::hash>; + std::hash>; //! The type of the token that the dictionary stores. - using TokenType = boost::string_view; + using TokenType = STRING_VIEW; //! Construct the default class. StringEncodingDictionary() = default; @@ -155,7 +156,7 @@ class StringEncodingDictionary * * @param token The given token. */ - bool HasToken(const boost::string_view token) const + bool HasToken(const STRING_VIEW token) const { return mapping.find(token) != mapping.end(); } @@ -167,7 +168,7 @@ class StringEncodingDictionary * * @param token The given token. */ - size_t AddToken(const boost::string_view token) + size_t AddToken(const STRING_VIEW token) { tokens.emplace_back(token); @@ -184,7 +185,7 @@ class StringEncodingDictionary * * @param token The given token. */ - size_t Value(const boost::string_view token) const + size_t Value(const STRING_VIEW token) const { return mapping.at(token); } diff --git a/src/mlpack/core/data/string_encoding_impl.hpp b/src/mlpack/core/data/string_encoding_impl.hpp index 8823706243..06558960e9 100644 --- a/src/mlpack/core/data/string_encoding_impl.hpp +++ b/src/mlpack/core/data/string_encoding_impl.hpp @@ -66,7 +66,7 @@ void StringEncoding::CreateMap( const std::string& input, const TokenizerType& tokenizer) { - boost::string_view strView(input); + STRING_VIEW strView(input); auto token = tokenizer(strView); static_assert( @@ -112,7 +112,7 @@ EncodeHelper(const std::vector& input, // The first pass adds the extracted tokens to the dictionary. for (size_t i = 0; i < input.size(); ++i) { - boost::string_view strView(input[i]); + STRING_VIEW strView(input[i]); auto token = tokenizer(strView); static_assert( @@ -143,7 +143,7 @@ EncodeHelper(const std::vector& input, // The second pass writes the encoded values to the output. for (size_t i = 0; i < input.size(); ++i) { - boost::string_view strView(input[i]); + STRING_VIEW strView(input[i]); auto token = tokenizer(strView); size_t numTokens = 0; @@ -172,7 +172,7 @@ EncodeHelper(const std::vector& input, // at once. for (size_t i = 0; i < input.size(); ++i) { - boost::string_view strView(input[i]); + STRING_VIEW strView(input[i]); auto token = tokenizer(strView); static_assert( diff --git a/src/mlpack/core/data/tokenizers/char_extract.hpp b/src/mlpack/core/data/tokenizers/char_extract.hpp index e8b5a4553e..084e5e8631 100644 --- a/src/mlpack/core/data/tokenizers/char_extract.hpp +++ b/src/mlpack/core/data/tokenizers/char_extract.hpp @@ -36,7 +36,7 @@ class CharExtract * * @param str String view to retrieve the next token from. */ - int operator()(boost::string_view& str) const + int operator()(STRING_VIEW& str) const { if (str.empty()) return EOF; diff --git a/src/mlpack/core/data/tokenizers/split_by_any_of.hpp b/src/mlpack/core/data/tokenizers/split_by_any_of.hpp index 5173d1fb7d..9097c34f76 100644 --- a/src/mlpack/core/data/tokenizers/split_by_any_of.hpp +++ b/src/mlpack/core/data/tokenizers/split_by_any_of.hpp @@ -14,7 +14,7 @@ #define MLPACK_CORE_DATA_TOKENIZERS_SPLIT_BY_ANY_OF_HPP #include -#include + #include namespace mlpack { @@ -27,7 +27,7 @@ class SplitByAnyOf { public: //! The type of the token which the tokenizer extracts. - using TokenType = boost::string_view; + using TokenType = STRING_VIEW; //! A convenient alias for the mask type. using MaskType = std::array; @@ -37,7 +37,7 @@ class SplitByAnyOf * * @param delimiters The given delimiters. */ - SplitByAnyOf(const boost::string_view delimiters) + SplitByAnyOf(const STRING_VIEW delimiters) { mask.fill(false); @@ -51,9 +51,13 @@ class SplitByAnyOf * * @param str String view to retrieve the token from. */ - boost::string_view operator()(boost::string_view& str) const + STRING_VIEW operator()(STRING_VIEW& str) const { - boost::string_view retval; + STRING_VIEW retval; + // std::basic_string_view does not have empty function. + // Therefore, we are assiging an empty string when reaching the last + // delimiter. + STRING_VIEW empty_string{""}; while (retval.empty()) { @@ -61,7 +65,7 @@ class SplitByAnyOf if (pos == str.npos) { retval = str; - str.clear(); + str.swap(empty_string); return retval; } retval = str.substr(0, pos); @@ -75,7 +79,7 @@ class SplitByAnyOf * * @param token The given token. */ - static bool IsTokenEmpty(const boost::string_view token) + static bool IsTokenEmpty(const STRING_VIEW token) { return token.empty(); } @@ -89,11 +93,11 @@ class SplitByAnyOf /** * The function finds the first character in the given string view equal to * any of the delimiters and returns the position of the character or - * boost::string_view::npos if no such character is found. + * STRING_VIEW::npos if no such character is found. * * @param str String where to find the character. */ - size_t FindFirstDelimiter(const boost::string_view str) const + size_t FindFirstDelimiter(const STRING_VIEW str) const { for (size_t pos = 0; pos < str.size(); pos++) { diff --git a/src/mlpack/core/std_backport/LICENSE.txt b/src/mlpack/core/std_backport/LICENSE.txt new file mode 100644 index 0000000000..c1bedba5cd --- /dev/null +++ b/src/mlpack/core/std_backport/LICENSE.txt @@ -0,0 +1,12 @@ +Copyright © 2013 - 2015 MNMLSTC + +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this software except in compliance with the License. You may +obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + diff --git a/src/mlpack/core/std_backport/README.md b/src/mlpack/core/std_backport/README.md new file mode 100644 index 0000000000..7cf95af5bb --- /dev/null +++ b/src/mlpack/core/std_backport/README.md @@ -0,0 +1,15 @@ +The files in this directory are taken from MNMLSTC Core 1.1.0 in order to +backport features from C++ 17 standard library: + + * C++17 STL algorithms such as std::any and std::basic_string_view. + * Dependencies files that are used to implement these features. + +These files are licensed under the Apache 2.0 License, available in LICENSE.txt +in this directory. + +If you want a copy of mlpack without a dependence on the Apache License or +without the backported version then you will need to + + * Remove this entire directory. + * Remove the line "std_backport" from src/mlpack/core/CMakeLists.txt. + * Use the C++17 standard by modifying the mlpack/CMakeLists.txt. diff --git a/src/mlpack/core/std_backport/algorithm.hpp b/src/mlpack/core/std_backport/algorithm.hpp new file mode 100644 index 0000000000..9935e9521f --- /dev/null +++ b/src/mlpack/core/std_backport/algorithm.hpp @@ -0,0 +1,2280 @@ +/** + * Copyright © 2013 - 2015 MNMLSTC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this software except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +#ifndef CORE_ALGORITHM_HPP +#define CORE_ALGORITHM_HPP + +#include + +#include "functional.hpp" +#include "utility.hpp" +#include "range.hpp" + +namespace core { +inline namespace v2 { +namespace impl { + +template +bool equal ( + range r1, + range r2, + Predicate&& p, + ::std::random_access_iterator_tag, + ::std::random_access_iterator_tag +) { + if (r1.size() != r2.size()) { return false; } + return ::std::equal( + begin(r1), + end(r1), + begin(r2), + ::core::forward(p) + ); +} + +template +bool equal ( + range r1, + range r2, + Predicate&& p, + ::std::input_iterator_tag, + ::std::input_iterator_tag +) { + while (not r1.empty() and not r2.empty()) { + if ( + not ::core::invoke( + ::core::forward(p), + r1.front(), + r2.front()) + ) { return false; } + r1.pop_front(); + r2.pop_front(); + } + return r1.empty() and r2.empty(); +} + +} /* namespace impl */ + +/* non-range based algorithms */ +template +constexpr T const& min (T const& lhs, T const& rhs) { + return (rhs < lhs) ? rhs : lhs; +} + +template +constexpr T const& min (T const& lhs, T const& rhs, Compare compare) { + return compare(rhs, lhs) ? rhs : lhs; +} + +template +constexpr T const& max (T const& lhs, T const& rhs) { + return (lhs < rhs) ? rhs : lhs; +} + +template +constexpr T const& max (T const& lhs, T const& rhs, Compare compare) { + return compare(lhs, rhs) ? rhs : lhs; +} + +/* extensions */ +template > +constexpr T const& clamp ( + T const& value, + T const& low, + T const& high, + Compare compare = Compare { } +) { + return compare(value, low) + ? low + : compare(high, value) + ? high + : value; +} + +/* N4318 (modified) */ +template < + class T, + class Compare = ::core::less<>, + class Difference = ::core::minus<> +> constexpr auto abs_diff ( + T const& a, + T const& b, + Compare compare = Compare { }, + Difference diff = Difference { } +) -> decltype(compare(a, b) ? diff(b, a) : diff(a, b)) { + return compare(a, b) ? diff(b, a) : diff(a, b); +} + +/* non-modifying sequence algorithms */ +template +auto all_of (Range&& rng, UnaryPredicate&& p) -> meta::when< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "all_of requires InputIterators"); + return ::std::all_of( + ::std::begin(range), + ::std::end(range), + ::core::forward(p) + ); +} + +template +auto any_of (Range&& rng, UnaryPredicate&& p) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "any_of requires InputIterators"); + return ::std::any_of( + ::std::begin(range), + ::std::end(range), + ::core::forward(p) + ); +} + +template +auto none_of (Range&& rng, UnaryPredicate&& p) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "none_of requires InputIterators"); + return ::std::none_of( + ::std::begin(range), + ::std::end(range), + ::core::forward(p) + ); +} + +template +auto for_each (Range&& rng, UnaryFunction&& f) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "for_each requires InputIterators"); + return ::std::for_each( + ::std::begin(range), + ::std::end(range), + ::core::forward(f) + ); +} + +template +UnaryFunction for_each_if (Range&& r, UnaryFunction uf, UnaryPredicate up) { + auto range = make_range(::core::forward(r)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "for_each_if requires InputIterators"); + while (not range.empty()) { + if (up(range.front())) { uf(range.front()); } + range.pop_front(); + } + return uf; +} + +template +auto for_each_while ( + Range&& r, + UnaryFunction f, + UnaryPredicate p +) -> decltype(begin(make_range(::core::forward(r)))) { + auto range = make_range(::core::forward(r)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "for_each_while requires InputIterators"); + while (not range.empty()) { + if (not p(range.front())) { break; } + f(range.front()); + range.pop_front(); + } + return range.begin(); +} + +template +auto for_each_until ( + Range&& r, + UnaryFunction f, + T const& value +) -> decltype(begin(make_range(::core::forward(r)))) { + auto range = make_range(::core::forward(r)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "for_each_until requires InputIterators"); + while (not range.empty()) { + if (range.front() == value) { break; } + f(range.front()); + range.pop_front(); + } + return range.begin(); +} + +template +auto count (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + decltype( + ::std::count( + ::std::begin(::core::forward(rng)), + ::std::end(::core::forward(rng)), + value + ) + ) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "count requires InputIterators"); + return ::std::count(::std::begin(range), ::std::end(range), value); +} + +template +auto count_if (Range&& rng, UnaryPredicate&& p) -> enable_if_t< + is_range::value, + decltype( + ::std::count_if( + ::std::begin(::core::forward(rng)), + ::std::end(::core::forward(rng)), + ::core::forward(p) + ) + ) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "count_if requires InputIterators"); + return ::std::count_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(p) + ); +} + +template +::std::pair mismatch ( + InputIt1 first1, + InputIt1 last1, + InputIt2 first2, + InputIt2 last2, + BinaryPredicate predicate +) { + auto r1 = make_range(first1, last1); + auto r2 = make_range(first2, last2); + while (not r1.empty() and not r2.empty()) { + if (not predicate(r1.front(), r2.front())) { break; } + r1.pop_front(); + r2.pop_front(); + } + return ::std::make_pair(r1.begin(), r2.begin()); +} + +template +::std::pair mismatch ( + InputIt1 first1, + InputIt1 last1, + InputIt2 first2, + InputIt2 last2 +) { return (mismatch)(first1, last1, first2, last2, equal_to<> { }); } + +template < + class Range1, + class Range2, + class BinaryPred, + meta::require< + meta::all_of, is_range>() + > = __LINE__ +> auto mismatch (Range1&& r1, Range2&& r2, BinaryPred&& bp) -> ::std::pair< + decltype(::std::begin(::core::forward(r1))), + decltype(::std::begin(::core::forward(r2))) +> { + auto range1 = make_range(::core::forward(r1)); + auto range2 = make_range(::core::forward(r2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1 and is_input2, "mismatch requires InputIterators"); + return (mismatch)( + range1.begin(), + range1.end(), + range2.begin(), + range2.end(), + ::core::forward(bp)); +} + +template < + class Range, + class InputIt, + meta::require< + meta::all::value, meta::none::value>()>() + > = __LINE__ +> auto mismatch(Range&& rng, InputIt&& it) -> ::std::pair< + decltype(make_range(::core::forward(rng)).begin()), + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "mismatch requires InputIterators"); + return ::std::mismatch( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template < + class Range, + class InputIt, + class BinaryPredicate, + meta::require< + meta::all::value, meta::none>()>() + > = __LINE__ +> auto mismatch(Range&& r, InputIt&& it, BinaryPredicate&& bp) -> ::std::pair< + decltype(core::make_range(::core::forward(r).begin())), + decay_t +> { + auto range = make_range(::core::forward(r)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "mismatch requires InputIterators"); + return ::std::mismatch( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(bp) + ); +} + +template +bool equal ( + InputIt1 first1, + InputIt1 last1, + InputIt2 first2, + InputIt2 last2, + BinaryPredicate bp +) { + auto r1 = make_range(first1, last1); + auto r2 = make_range(first2, last2); + using tag1 = typename decltype(r1)::iterator_category; + using tag2 = typename decltype(r2)::iterator_category; + return impl::equal(r1, r2, bp, tag1 { }, tag2 { }); +} + +template +bool equal (InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) { + return equal(first1, last1, first2, last2, equal_to<> { }); +} + +template < + class Range1, + class Range2, + meta::require< + meta::all_of, is_range>() + > = __LINE__ +> bool equal (Range1&& range1, Range2&& range2) { + auto r1 = make_range(::core::forward(range1)); + auto r2 = make_range(::core::forward(range2)); + static constexpr auto is_input1 = decltype(r1)::is_input; + static constexpr auto is_input2 = decltype(r2)::is_input; + static_assert(is_input1, "equal requires InputIterators"); + static_assert(is_input2, "equal requires InputIterators"); + return (equal)(r1.begin(), r1.end(), r2.begin(), r2.end()); +} + +template < + class Range1, + class Range2, + class BinaryPredicate, + meta::require< + meta::all_of, is_range>() + > = __LINE__ +> bool equal (Range1&& range1, Range2&& range2, BinaryPredicate&& bp) { + auto r1 = make_range(::core::forward(range1)); + auto r2 = make_range(::core::forward(range2)); + static constexpr auto is_input1 = decltype(r1)::is_input; + static constexpr auto is_input2 = decltype(r2)::is_input; + static_assert(is_input1, "equal requires InputIterators"); + static_assert(is_input2, "equal requires InputIterators"); + return equal( + r1.begin(), + r1.end(), + r2.begin(), + r2.end(), + ::core::forward(bp) + ); +} + +template < + class Range, + class InputIt, + meta::require< + meta::all::value, meta::none::value>()>() + > = __LINE__ +> bool equal (Range&& rng, InputIt&& it) { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "equal requires InputIterators"); + return ::std::equal( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template < + class Range, + class InputIt, + class BinaryPredicate, + meta::require< + meta::all::value, meta::none>()>() + > = __LINE__ +> bool equal (Range&& rng, InputIt&& it, BinaryPredicate&& bp) { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "equal requires InputIterators"); + return ::std::equal( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(bp) + ); +} + +template +auto find (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "find requires InputIterators"); + return ::std::find(::std::begin(range), ::std::end(range), value); +} + +template +auto find_if (Range&& rng, UnaryPredicate&& p) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "find_if requires InputIterators"); + return ::std::find_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(p) + ); +} + +template +auto find_if_not (Range&& rng, UnaryPredicate&& p) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "find_if_not requires InputIterators"); + return ::std::find_if_not( + ::std::begin(range), + ::std::end(range), + ::core::forward(p) + ); +} + +template +auto find_end (Range1&& rng1, Range2&& rng2) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(rng1))) +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "find_end requires ForwardIterators"); + static_assert(is_forward2, "find_end requires ForwardIterators"); + return ::std::find_end( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2) + ); +} + +template +auto find_end (Range1&& rng1, Range2&& rng2, BinaryPred& bp) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(rng1))) +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "find_end requires ForwardIterators"); + static_assert(is_forward2, "find_end requires ForwardIterators"); + return ::std::find_end( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(bp) + ); +} + +template +auto find_first_of (IRange&& irng, FRange&& frng) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(irng))) +> { + auto irange = make_range(::core::forward(irng)); + auto frange = make_range(::core::forward(frng)); + static constexpr auto is_input = decltype(irange)::is_input; + static constexpr auto is_forward = decltype(frange)::is_forward; + static_assert(is_input, "find_first_of requires InputIterators"); + static_assert(is_forward, "find_first_of requires ForwardIterators"); + return ::std::find_first_of( + ::std::begin(irange), + ::std::end(irange), + ::std::begin(frange), + ::std::end(frange) + ); +} + +template +auto find_first_of ( + IRange&& irng, + FRange&& frng, + BinaryPred&& bp +) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(irng))) +> { + auto irange = make_range(::core::forward(irng)); + auto frange = make_range(::core::forward(frng)); + static constexpr auto is_input = decltype(irange)::is_input; + static constexpr auto is_forward = decltype(frange)::is_forward; + static_assert(is_input, "find_first_of requires InputIterators"); + static_assert(is_forward, "find_first_of requires ForwardIterators"); + return ::std::find_first_of( + ::std::begin(irange), + ::std::end(irange), + ::std::begin(frange), + ::std::end(frange), + ::core::forward(bp) + ); +} + +template +auto adjacent_find (Range&& rng) -> meta::when< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "adjacent_find requires ForwardIterators"); + return ::std::adjacent_find(::std::begin(range), ::std::end(range)); +} + +template +auto adjacent_find (Range&& rng, BinaryPredicate&& bp) -> meta::when< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "adjacent_find requires ForwardIterators"); + return ::std::adjacent_find( + ::std::begin(range), + ::std::end(range), + ::core::forward(bp) + ); +} + +template +auto search (Range1&& rng1, Range2&& rng2) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(rng1))) +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "search requires ForwardIterators"); + static_assert(is_forward2, "search requires ForwardIterators"); + return ::std::search( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2) + ); +} + +template +auto search (Range1&& rng1, Range2&& rng2, BinaryPred&& bp) -> enable_if_t< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(rng1))) +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "search requires ForwardIterators"); + static_assert(is_forward2, "search requires ForwardIterators"); + return ::std::search( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(bp) + ); +} + +template +auto search_n (Range&& rng, Size&& count, T const& value) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "search_n requires ForwardIterators"); + return ::std::search_n( + ::std::begin(range), + ::std::end(range), + ::core::forward(count), + value + ); +} + +template +auto search_n ( + Range&& rng, + Size&& count, + T const& value, + BinaryPred&& bp +) -> meta::when< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "search_n requires ForwardIterators"); + return ::std::search_n( + ::std::begin(range), + ::std::end(range), + ::core::forward(count), + value, + ::core::forward(bp) + ); +} + +/* modifying sequence algorithms */ +template +auto copy (Range&& rng, OutputIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "copy requires InputIterators"); + return ::std::copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto copy_if (Range&& rng, OutputIt&& it, UnaryPredicate&& up) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "copy_if requires InputIterators"); + return ::std::copy_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(up) + ); +} + +template +OutputIt copy_until (Range&& r, OutputIt it, T const& value) { + auto range = make_range(::core::forward(r)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "copy_until requires InputIterators"); + while (not range.empty()) { + if (range.front() == value) { break; } + *it++ = range.front(); + range.pop_front(); + } + return it; +} + +template +auto copy_backward (Range&& rng, BidirIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "copy_backward requires BidirectionalIterators"); + return ::std::copy_backward( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto move (Range&& rng, OutputIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "move requires InputIterators"); + return ::std::move( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto move_backward (Range&& rng, BidirIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "move_backward requires BidirectionalIterators"); + return ::std::move_backward( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto fill (Range&& rng, T const& value) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "fill requires ForwardIterators"); + return ::std::fill(::std::begin(range), ::std::end(range), value); +} + +template +auto transform ( + Range&& rng, + OutputIt&& it, + UnaryOperation&& op +) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "transform requires InputIterators"); + return ::std::transform( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(op) + ); +} + +template +auto transform_if ( + Range&& rng, + OutputIt it, + UnaryOperation op, + UnaryPred up +) -> enable_if_t< + is_range::value, + OutputIt +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "transform_if requires ForwardIterators"); + while (not range.empty()) { + if (invoke(up, range.front())) { + *it = invoke(op, range.front()); + ++it; + } + range.pop_front(); + } + return it; +} + +template +OutputIt transform_n (InputIt in, Size count, OutputIt out, UnaryOp op) { + while (count > 0) { + *out = invoke(op, *in); + ++out; + ++in; + --count; + } + return out; +} + +template < + class InputIt1, + class InputIt2, + class Size, + class OutputIt, + class UnaryOp +> OutputIt transform_n ( + InputIt1 in1, + InputIt2 in2, + Size count, + OutputIt out, + UnaryOp op +) { + while (count > 0) { + *out = invoke(op, *in1, *in2); + ++out; + ++in1; + ++in2; + --count; + } + return out; +} + + +template < + class Range, + class InputIt, + class OutputIt, + class BinaryOperation, + meta::require< + meta::all::value, meta::none::value>()>() + > = __LINE__ +> decay_t transform ( + Range&& r, + InputIt&& in, + OutputIt&& out, + BinaryOperation&& op +) { + auto range = make_range(::core::forward(r)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "transform requires InputIterators"); + return ::std::transform( + range.begin(), + range.end(), + ::core::forward(in), + ::core::forward(out), + ::core::forward(op)); +} + +template < + class Range1, + class Range2, + class OutputIt, + class BinaryOperation, + meta::require< + meta::all_of, is_range>() + > = __LINE__ +> decay_t transform ( + Range1&& rng1, + Range2&& rng2, + OutputIt&& it, + BinaryOperation&& op +) { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "transform requires InputIterators"); + static_assert(is_input2, "transform requires InputIterators"); + return ::std::transform( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::core::forward(it), + ::core::forward(op) + ); +} + +template < + class Range1, + class Range2, + class OutputIt, + class BinaryOperation, + class BinaryPredicate +> auto transform_if ( + Range1&& rng1, + Range2&& rng2, + OutputIt it, + BinaryOperation op, + BinaryPredicate bp +) -> meta::when< + meta::all_of, is_range>(), + OutputIt +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "transform_if requires ForwardIterators"); + static_assert(is_forward2, "transform_if requires ForwardIterators"); + while (not range1.empty()) { + if (bp(range1.front(), range2.front())) { + *it = op(range1.front(), range2.front()); + ++it; + } + range1.pop_front(); + range2.pop_front(); + } + return it; +} + +template +auto remove (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "remove requires ForwardIterators"); + return ::std::remove(::std::begin(range), ::std::end(range), value); +} + +template +auto remove_if (Range&& rng, UnaryPredicate&& up) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "remove_if requires ForwardIterators"); + return ::std::remove_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(up) + ); +} + +template +auto remove_copy (Range&& rng, OutputIt&& it, T const& value) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "remove_copy requires InputIterators"); + return ::std::remove_copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + value + ); +} + +template +auto remove_copy_if (Range&& rng, OutputIt&& it, UnaryPred&& up) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "remove_copy_if requires InputIterators"); + return ::std::remove_copy_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(up) + ); +} + +template +auto remove_erase (Range&& rng, T const& val) -> enable_if_t< + is_range::value +> { + ::core::forward(rng).erase( + remove(::core::forward(rng), val), + ::std::end(::core::forward(rng)) + ); +} + +template +auto remove_erase_if (Range&& rng, UnaryPred&& up) -> enable_if_t< + is_range::value +> { + ::core::forward(rng).erase( + remove_if( + ::core::forward(rng), + ::core::forward(up) + ), + ::std::end(::core::forward(rng)) + ); +} + +template +auto replace (Range&& rng, T const& old, T const& value) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_input; + static_assert(is_forward, "replace requires ForwardIterators"); + return ::std::replace( + ::std::begin(range), + ::std::end(range), + old, + value + ); +} + +template +auto replace_if (Range&& rng, UnaryPred&& up, T const& value) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "replace_if requires ForwardIterators"); + return ::std::replace_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(up), + value + ); +} + +template +auto replace_copy ( + Range&& rng, + OutputIt&& it, + T const& old, + T const& value +) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "replace_copy requires InputIterators"); + return ::std::replace_copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + old, + value + ); +} + +template +auto replace_copy_if ( + Range&& rng, + OutputIt&& it, + UnaryPred&& up, + T const& value +) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "replace_copy_if requires InputIterators"); + return ::std::replace_copy_if( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(up), + value + ); +} + +template +auto swap_ranges (Range&& rng, ForwardIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "swap_ranges requires ForwardIterators"); + return ::std::swap_ranges( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto reverse (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "reverse requires BidirectionalIterators"); + return ::std::reverse(::std::begin(range), ::std::end(range)); +} + +template +auto reverse_copy (Range&& rng, OutputIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "reverse_copy requires BidirectionalIterators"); + return ::std::reverse_copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto rotate (Range&& rng, ForwardIt&& it) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "rotate requires ForwardIterators"); + ::std::rotate( + ::std::begin(range), + ::core::forward(it), + ::std::end(range) + ); +} + +template +auto rotate_copy (Range&& rng, ForwardIt&& it, OutputIt&& ot) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "rotate_copy requires ForwardIterators"); + return ::std::rotate_copy( + ::std::begin(range), + ::core::forward(it), + ::std::end(range), + ::core::forward(ot) + ); +} + +template +auto shuffle (Range&& rng, URNG&& g) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "shuffle requires RandomAccessIterators"); + return ::std::shuffle( + ::std::begin(range), + ::std::end(range), + ::core::forward(g) + ); +} + +template +auto unique (Range&& rng) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "unique requires ForwardIterators"); + return ::std::unique(::std::begin(range), ::std::end(range)); +} + +template +auto unique (Range&& rng, BinaryPredicate&& bp) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "unique requires ForwardIterators"); + return ::std::unique( + ::std::begin(range), + ::std::end(range), + ::core::forward(bp) + ); +} + +template +auto unique_copy (Range&& rng, OutputIt&& it) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "unique_copy requires InputIterators"); + return ::std::unique_copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(it) + ); +} + +template +auto unique_copy (Range&& rng, OutputIt&& it, BinaryPred&& bp) -> enable_if_t< + is_range::value, + decay_t +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "unique_copy requires InputIterators"); + return ::std::unique_copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(it), + ::core::forward(bp) + ); +} + +/* partitioning operations */ +template +auto is_partitioned (Range&& rng, UnaryPredicate&& up) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "is_partitioned requires InputIterators"); + return ::std::is_partitioned( + ::std::begin(range), + ::std::end(range), + ::core::forward(up) + ); +} + +template +auto partition (Range&& rng, UnaryPredicate&& up) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "partition requires ForwardIterators"); + return ::std::partition( + ::std::begin(range), + ::std::end(range), + ::core::forward(up) + ); +} + +template +auto partition_copy ( + Range&& rng, + OutputTrue&& ot, + OutputFalse&& of, + UnaryPred&& up +) -> enable_if_t< + is_range::value, + ::std::pair, decay_t> +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_input = decltype(range)::is_input; + static_assert(is_input, "partition_copy requires InputIterators"); + return ::std::partition_copy( + ::std::begin(range), + ::std::end(range), + ::core::forward(ot), + ::core::forward(of), + ::core::forward(up) + ); +} + +template +auto stable_partition (Range&& rng, UnaryPredicate&& up) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "stable_partition requires BidirectionalIterators"); + return ::std::stable_partition( + ::std::begin(range), + ::std::end(range), + ::core::forward(up) + ); +} + +template +auto partition_point (Range&& rng, UnaryPredicate&& up) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "partition_point requires ForwardIterators"); + return ::std::partition_point( + ::std::begin(range), + ::std::end(range), + ::core::forward(up) + ); +} + +/* sorting operations */ + +template +auto is_sorted (Range&& rng) -> enable_if_t::value, bool> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "is_sorted requires ForwardIterators"); + return ::std::is_sorted(::std::begin(range), ::std::end(range)); +} + +template +auto is_sorted (Range&& rng, Compare&& compare) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "is_sorted requires ForwardIterators"); + return ::std::is_sorted( + ::std::begin(range), + ::std::end(range), + ::core::forward(compare) + ); +} + +template +auto is_sorted_until (Range&& rng) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "is_sorted_until requires ForwardIterators"); + return ::std::is_sorted_until(::std::begin(range), ::std::end(range)); +} + +template +auto is_sorted_until (Range&& rng, Compare&& compare) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "is_sorted_until requires ForwardIterators"); + return ::std::is_sorted_until( + ::std::begin(range), + ::std::end(range), + ::core::forward(compare) + ); +} + +template +auto sort (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "sort requires RandomAccessIterators"); + return ::std::sort(::std::begin(range), ::std::end(range)); +} + +template +auto sort (Range&& rng, Compare&& cmp) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "sort requires RandomAccessIterators"); + return ::std::sort( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto partial_sort (Range&& rng, RandomIt&& it) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "partial_sort requires RandomAccessIterators"); + return ::std::partial_sort( + ::std::begin(range), + ::core::forward(it), + ::std::end(range) + ); +} + +template +auto partial_sort (Range&& rng, RandomIt&& it, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "partial_sort requires RandomAccessIterators"); + return ::std::partial_sort( + ::std::begin(range), + ::core::forward(it), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto partial_sort_copy (IRange&& irng, RRange&& rrng) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(rrng))) +> { + auto irange = make_range(::core::forward(irng)); + auto rrange = make_range(::core::forward(rrng)); + static constexpr auto is_input = decltype(irange)::is_input; + static constexpr auto is_random = decltype(rrange)::is_random_access; + static_assert(is_input, "partial_sort_copy requires InputIterators"); + static_assert(is_random, "partial_sort_copy requires RandomAccessIterators"); + return ::std::partial_sort_copy( + ::std::begin(irange), + ::std::end(irange), + ::std::begin(rrange), + ::std::end(rrange) + ); +} + +template +auto partial_sort_copy ( + IRange&& irng, + RRange&& rrng, + Compare&& cmp +) -> meta::when< + meta::all_of, is_range>(), + decltype(::std::begin(::core::forward(rrng))) +> { + auto irange = make_range(::core::forward(irng)); + auto rrange = make_range(::core::forward(rrng)); + static constexpr auto is_input = decltype(irange)::is_input; + static constexpr auto is_random = decltype(rrange)::is_random_access; + static_assert(is_input, "partial_sort_copy requires InputIterators"); + static_assert(is_random, "partial_sort_copy requires RandomAccessIterators"); + return ::std::partial_sort_copy( + ::std::begin(irange), + ::std::end(irange), + ::std::begin(rrange), + ::std::end(rrange), + ::core::forward(cmp) + ); +} + +template +auto stable_sort (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "stable_sort requires RandomAccessIterators"); + return ::std::stable_sort(::std::begin(range), ::std::end(range)); +} + +template +auto stable_sort (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "stable_sort requires RandomAccessIterators"); + return ::std::stable_sort( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto nth_element (Range&& rng, RandomIt&& it) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "nth_element requires RandomAccessIterators"); + return ::std::nth_element( + ::std::begin(range), + ::core::forward(it), + ::std::end(range) + ); +} + +template +auto nth_element (Range&& rng, RandomIt&& it, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "nth_element requires RandomAccessIterators"); + return ::std::nth_element( + ::std::begin(range), + ::core::forward(it), + ::std::end(range), + ::core::forward(cmp) + ); +} + +/* binary search operations (on sorted ranges) */ +template +auto lower_bound (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "lower_bound requires ForwardIterators"); + return ::std::lower_bound(::std::begin(range), ::std::end(range), value); +} + +template +auto lower_bound (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "lower_bound requires ForwardIterators"); + return ::std::lower_bound( + ::std::begin(range), + ::std::end(range), + value, + ::core::forward(cmp) + ); +} + +template +auto upper_bound (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "upper_bound requires ForwardIterators"); + return ::std::upper_bound(::std::begin(range), ::std::end(range), value); +} + +template +auto upper_bound (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "upper_bound requires ForwardIterators"); + return ::std::upper_bound( + ::std::begin(range), + ::std::end(range), + value, + ::core::forward(cmp) + ); +} + +template +auto binary_search (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "binary_search requires ForwardIterators"); + return ::std::binary_search(::std::begin(range), ::std::end(range), value); +} + +template +auto binary_search (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "binary_search requires ForwardIterators"); + return ::std::binary_search( + ::std::begin(range), + ::std::end(range), + value, + ::core::forward(cmp) + ); +} + +template +auto equal_range (Range&& rng, T const& value) -> enable_if_t< + is_range::value, + range(rng)))> +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "equal_range requires ForwardIterators"); + return ::std::equal_range(::std::begin(range), ::std::end(range), value); +} + +template +auto equal_range (Range&& rng, T const& value, Compare&& cmp) -> enable_if_t< + is_range::value, + range(rng)))> +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "equal_range requires ForwardIterators"); + return ::std::equal_range( + ::std::begin(range), + ::std::end(range), + value, + ::core::forward(cmp) + ); +} + +/* set operations (on sorted ranges) */ +template +auto merge (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> meta::when< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "merge requires InputIterators"); + static_assert(is_input2, "merge requires InputIterators"); + return ::std::merge( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it) + ); +} + +template +auto merge ( + Range1&& rng1, + Range2&& rng2, + OutputIt&& it, + Compare&& cmp +) -> enable_if_t< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "merge requires InputIterators"); + static_assert(is_input2, "merge requires InputIterators"); + return ::std::merge( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it), + ::core::forward(cmp) + ); +} + +template +auto inplace_merge (Range&& rng, BidirIt&& it) -> meta::when< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "inplace_merge requires BidirectionalIterators"); + return ::std::inplace_merge( + ::std::begin(range), + ::core::forward(it), + ::std::end(range) + ); +} + +template +auto inplace_merge (Range&& rng, BidirIt&& it, Compare&& cmp) -> meta::when< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "inplace_merge requires BidirectionalIterators"); + return ::std::inplace_merge( + ::std::begin(range), + ::core::forward(it), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto includes (Range1&& rng1, Range2&& rng2) -> meta::when< + meta::all_of, is_range>(), + bool +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "includes requires InputIterators"); + static_assert(is_input2, "includes requires InputIterators"); + return ::std::includes( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2) + ); +} + +template +auto includes (Range1&& rng1, Range2&& rng2, Compare&& cmp) -> meta::when< + meta::all_of, is_range>(), + bool +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "includes requires InputIterators"); + static_assert(is_input2, "includes requires InputIterators"); + return ::std::includes( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(cmp) + ); +} + +template +auto set_difference (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> meta::when< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_difference requires InputIterators"); + static_assert(is_input2, "set_difference requires InputIterators"); + return ::std::set_difference( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it) + ); +} + +template +auto set_difference ( + Range1&& rng1, + Range2&& rng2, + OutputIt&& it, + Compare&& cmp +) -> meta::when< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_difference requires InputIterators"); + static_assert(is_input2, "set_difference requires InputIterators"); + return ::std::set_difference( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it), + ::core::forward(cmp) + ); +} + +template +auto set_intersection (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> meta::when< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_intersection requires InputIterators"); + static_assert(is_input2, "set_intersection requires InputIterators"); + return ::std::set_intersection( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it) + ); +} + +template +auto set_intersection ( + Range1&& rng1, + Range2&& rng2, + OutputIt&& it, + Compare&& cmp +) -> enable_if_t< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_intersection requires InputIterators"); + static_assert(is_input2, "set_intersection requires InputIterators"); + return ::std::set_intersection( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it), + ::core::forward(cmp) + ); +} + +template +auto set_symmetric_difference (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> enable_if_t< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_symmetric_difference requires InputIterators"); + static_assert(is_input2, "set_symmetric_difference requires InputIterators"); + return ::std::set_symmetric_difference( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it) + ); +} + +template +auto set_symmetric_difference ( + Range1&& rng1, + Range2&& rng2, + OutputIt&& it, + Compare&& cmp +) -> enable_if_t< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_symmetric_difference requires InputIterators"); + static_assert(is_input2, "set_symmetric_difference requires InputIterators"); + return ::std::set_symmetric_difference( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it), + ::core::forward(cmp) + ); +} + +template +auto set_union (Range1&& rng1, Range2&& rng2, OutputIt&& it) -> enable_if_t< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_union requires InputIterators"); + static_assert(is_input2, "set_union requires InputIterators"); + return ::std::set_union( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it) + ); +} + +template +auto set_union ( + Range1&& rng1, + Range2&& rng2, + OutputIt&& it, + Compare&& cmp +) -> enable_if_t< + meta::all_of, is_range>(), + decay_t +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "set_union requires InputIterators"); + static_assert(is_input2, "set_union requires InputIterators"); + return ::std::set_union( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(it), + ::core::forward(cmp) + ); +} + +/* heap operations */ +template +auto is_heap (Range&& rng) -> enable_if_t::value, bool> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "is_heap requires RandomAccessIterators"); + return ::std::is_heap(::std::begin(range), ::std::end(range)); +} + +template +auto is_heap (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "is_heap requires RandomAccessIterators"); + return ::std::is_heap( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto is_heap_until (Range&& rng) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "is_heap_until requires RandomAccessIterators"); + return ::std::is_heap_until(::std::begin(range), ::std::end(range)); +} + +template +auto is_heap_until (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "is_heap_until requires RandomAccessIterators"); + return ::std::is_heap_until( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto make_heap (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "make_heap requires RandomAccessIterators"); + return ::std::make_heap(::std::begin(range), ::std::end(range)); +} + +template +auto make_heap (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "make_heap requires RandomAccessIterators"); + return ::std::make_heap( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto push_heap (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "push_heap requires RandomAccessIterators"); + return ::std::push_heap(::std::begin(range), ::std::end(range)); +} + +template +auto push_heap (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "push_heap requires RandomAccessIterators"); + return ::std::push_heap( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto pop_heap (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "pop_heap requires RandomAccessIterators"); + return ::std::pop_heap(::std::begin(range), ::std::end(range)); +} + +template +auto pop_heap (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "pop_heap requires RandomAccessIterators"); + return ::std::pop_heap( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto sort_heap (Range&& rng) -> enable_if_t::value> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "sort_heap requires RandomAccessIterators"); + return ::std::sort_heap(::std::begin(range), ::std::end(range)); +} + +template +auto sort_heap (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_random = decltype(range)::is_random_access; + static_assert(is_random, "sort_heap requires RandomAccessIterators"); + return ::std::sort_heap( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +/* min/max operations */ +template +auto max_element (Range&& rng) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "max_element requires ForwardIterators"); + return ::std::max_element(::std::begin(range), ::std::end(range)); +} + +template +auto max_element (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "max_element requires ForwardIterators"); + return ::std::max_element( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto min_element (Range&& rng) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "min_element requires ForwardIterators"); + return ::std::min_element(::std::begin(range), ::std::end(range)); +} + +template +auto min_element (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + decltype(::std::begin(::core::forward(rng))) +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "min_element requires ForwardIterators"); + return ::std::min_element( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto minmax_element (Range&& rng) -> enable_if_t< + is_range::value, + ::std::pair< + decltype(::std::begin(::core::forward(rng))), + decltype(::std::end(::core::forward(rng))) + > +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "minmax_element requires ForwardIterators"); + return ::std::minmax_element(::std::begin(range), ::std::end(range)); +} + +template +auto minmax_element (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + ::std::pair< + range(rng)))>, + range(rng)))> + > +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_forward = decltype(range)::is_forward; + static_assert(is_forward, "minmax_element requires ForwardIterators"); + return ::std::minmax_element( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto lexicographical_compare (Range1&& rng1, Range2&& rng2) -> enable_if_t< + meta::all_of, is_range>(), + bool +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "lexicographical_compare requires InputIterators"); + static_assert(is_input2, "lexicographical_compare requires InputIterators"); + return ::std::lexicographical_compare( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2) + ); +} + +template +auto lexicographical_compare ( + Range1&& rng1, + Range2&& rng2, + Compare&& cmp +) -> enable_if_t< + meta::all_of, is_range>(), + bool +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_input1 = decltype(range1)::is_input; + static constexpr auto is_input2 = decltype(range2)::is_input; + static_assert(is_input1, "lexicographical_compare requires InputIterators"); + static_assert(is_input2, "lexicographical_compare requires InputIterators"); + return ::std::lexicographical_compare( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::std::end(range2), + ::core::forward(cmp) + ); +} + +template +auto is_permutation (Range1&& rng1, Range2&& rng2) -> enable_if_t< + meta::all_of, is_range>(), + bool +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "is_permutation requires ForwardIterators"); + static_assert(is_forward2, "is_permutation requires ForwardIterators"); + return ::std::is_permutation( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2) + ); +} + +template +auto is_permutation ( + Range1&& rng1, + Range2&& rng2, + BinaryPredicate&& bp +) -> meta::when< + meta::all_of, is_range>(), + bool +> { + auto range1 = make_range(::core::forward(rng1)); + auto range2 = make_range(::core::forward(rng2)); + static constexpr auto is_forward1 = decltype(range1)::is_forward; + static constexpr auto is_forward2 = decltype(range2)::is_forward; + static_assert(is_forward1, "is_permutation requires ForwardIterators"); + static_assert(is_forward2, "is_permutation requires ForwardIterators"); + return ::std::is_permutation( + ::std::begin(range1), + ::std::end(range1), + ::std::begin(range2), + ::core::forward(bp) + ); +} + +template +auto next_permutation (Range&& rng) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "next_permutation requires BidirectionalIterators"); + return ::std::next_permutation(::std::begin(range), ::std::end(range)); +} + +template +auto next_permutation (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "next_permutation requires BidirectionalIterators"); + return ::std::next_permutation( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +template +auto prev_permutation (Range&& rng) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "prev_permutation requires BidirectionalIterators"); + return ::std::prev_permutation(::std::begin(range), ::std::end(range)); +} + +template +auto prev_permutation (Range&& rng, Compare&& cmp) -> enable_if_t< + is_range::value, + bool +> { + auto range = make_range(::core::forward(rng)); + static constexpr auto is_bidir = decltype(range)::is_bidirectional; + static_assert(is_bidir, "prev_permutation requires BidirectionalIterators"); + return ::std::prev_permutation( + ::std::begin(range), + ::std::end(range), + ::core::forward(cmp) + ); +} + +}} /* namespace core::v2 */ + +#endif /* CORE_ALGORITHM_HPP */ diff --git a/src/mlpack/core/std_backport/any.hpp b/src/mlpack/core/std_backport/any.hpp new file mode 100644 index 0000000000..010ae9d7e3 --- /dev/null +++ b/src/mlpack/core/std_backport/any.hpp @@ -0,0 +1,337 @@ +/** + * Copyright © 2013 - 2015 MNMLSTC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this software except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +#ifndef CORE_ANY_HPP +#define CORE_ANY_HPP + +#include + +#include +#include + +#include "type_traits.hpp" +#include "algorithm.hpp" +#include "typeinfo.hpp" +#include "utility.hpp" + +#ifndef CORE_NO_EXCEPTIONS +#include +#endif /* CORE_NO_EXCEPTIONS */ + +namespace core { +inline namespace v2 { +namespace impl { + +using data_type = add_pointer_t; + +template +struct is_small final : meta::all_t< + sizeof(decay_t) <= sizeof(data_type), + alignof(decay_t) <= alignof(data_type), + ::std::is_nothrow_copy_constructible>::value +> { }; +template <> struct is_small final : ::std::true_type { }; + +template ::value> struct dispatch; +template <> struct dispatch { + dispatch () noexcept = default; + virtual ~dispatch () noexcept = default; + + virtual void clone (data_type const&, data_type&) const { } + virtual void move (data_type&, data_type&) const noexcept { } + virtual void destroy (data_type&) const noexcept { } + virtual type_info const& type () const noexcept { return type_of(); } +}; + +template +struct dispatch final : dispatch<> { + using value_type = T; + using const_pointer = add_pointer_t>; + using pointer = add_pointer_t; + using allocator_type = ::std::allocator; + using allocator_traits = ::std::allocator_traits; + + virtual void clone (data_type const& src, data_type& dst) const final { + allocator_type alloc { }; + auto val = reinterpret_cast>(&src); + auto ptr = reinterpret_cast(&dst); + allocator_traits::construct(alloc, ptr, *val); + } + + virtual void move (data_type& src, data_type& dst) const noexcept final { + allocator_type alloc { }; + auto val = reinterpret_cast(&src); + auto ptr = reinterpret_cast(&dst); + allocator_traits::construct(alloc, ptr, ::core::move(*val)); + } + + virtual void destroy (data_type& src) const noexcept final { + allocator_type alloc { }; + auto ptr = reinterpret_cast(&src); + allocator_traits::destroy(alloc, ptr); + } + + virtual type_info const& type () const noexcept final { + return type_of(); + } +}; + +template +struct dispatch final : dispatch<> { + using value_type = T; + using pointer = add_pointer_t; + using allocator_type = ::std::allocator; + using allocator_traits = ::std::allocator_traits; + + virtual void clone (data_type const& src, data_type& dst) const final { + allocator_type alloc { }; + auto const& value = *static_cast>(src); + auto ptr = allocator_traits::allocate(alloc, 1); + auto scope = make_scope_guard([&alloc, ptr] { + allocator_traits::deallocate(alloc, ptr, 1); + }); + allocator_traits::construct(alloc, ptr, value); + scope.dismiss(); + dst = ptr; + } + + virtual void move (data_type& src, data_type& dst) const noexcept final { + allocator_type alloc { }; + auto& value = *static_cast(src); + auto ptr = allocator_traits::allocate(alloc, 1); + auto scope = make_scope_guard([&alloc, ptr] { + allocator_traits::deallocate(alloc, ptr, 1); + }); + allocator_traits::construct(alloc, ptr, ::core::move(value)); + scope.dismiss(); + dst = ptr; + } + + virtual void destroy (data_type& src) const noexcept final { + allocator_type alloc { }; + auto ptr = static_cast(src); + allocator_traits::destroy(alloc, ptr); + allocator_traits::deallocate(alloc, ptr, 1); + } + + virtual type_info const& type () const noexcept final { + return type_of(); + } +}; + +template dispatch<> const* lookup () noexcept { + static dispatch instance; + return ::std::addressof(instance); +} + +template <> inline dispatch<> const* lookup () noexcept { + static dispatch<> instance; + return ::std::addressof(instance); +} + +} /* namespace impl */ + +#ifndef CORE_NO_EXCEPTIONS +class bad_any_cast final : public ::std::bad_cast { +public: + virtual char const* what () const noexcept override { + return "bad any cast"; + } +}; + +[[noreturn]] inline void throw_bad_any_cast () { throw bad_any_cast { }; } +#else /* CORE_NO_EXCEPTIONS */ +[[noreturn]] inline void throw_bad_any_cast () { ::std::abort(); } +#endif /* CORE_NO_EXCEPTIONS */ + +struct any final { + + template friend T const* any_cast (any const*) noexcept; + template friend T* any_cast (any*) noexcept; + + any (any const& that) : + table { that.table }, + data { nullptr } + { this->table->clone(that.data, this->data); } + + any (any&& that) noexcept : + table { that.table }, + data { nullptr } + { this->table->move(that.data, this->data); } + + any () noexcept : + table { impl::lookup() }, + data { nullptr } + { } + + template < + class T, + class=enable_if_t>::value> + > any (T&& value) : + any { ::std::forward(value), impl::is_small { } } + { } + + ~any () noexcept { this->clear(); } + + any& operator = (any const& that) { + any { that }.swap(*this); + return *this; + } + + any& operator = (any&& that) noexcept { + any { ::std::move(that) }.swap(*this); + return *this; + } + + template < + class T, + class=enable_if_t>::value> + > any& operator = (T&& value) { + any { + ::std::forward(value), + impl::is_small { } + }.swap(*this); + return *this; + } + + void swap (any& that) noexcept { + using ::std::swap; + swap(this->table, that.table); + swap(this->data, that.data); + } + + void clear () noexcept { + this->table->destroy(this->data); + this->table = impl::lookup(); + } + + type_info const& type () const noexcept { return this->table->type(); } + + bool empty () const noexcept { return this->table == impl::lookup(); } + +private: + impl::dispatch<> const* table; + impl::data_type data; + + template + any (T&& value, ::std::true_type&&) : + table { impl::lookup>() }, + data { nullptr } + { + using value_type = decay_t; + using allocator_type = ::std::allocator; + using allocator_traits = ::std::allocator_traits; + allocator_type alloc { }; + auto pointer = reinterpret_cast(::std::addressof(this->data)); + allocator_traits::construct(alloc, pointer, ::core::forward(value)); + } + + template + any (T&& value, ::std::false_type&&) : + table { impl::lookup>() }, + data { nullptr } + { + using value_type = decay_t; + using allocator_type = ::std::allocator; + using allocator_traits = ::std::allocator_traits; + allocator_type alloc { }; + auto pointer = allocator_traits::allocate(alloc, 1); + allocator_traits::construct(alloc, pointer, ::core::forward(value)); + this->data = pointer; + } + + template + T const* cast (::std::true_type&&) const { + return reinterpret_cast(::std::addressof(this->data)); + } + + template + T* cast (::std::true_type&&) { + return reinterpret_cast(::std::addressof(this->data)); + } + + template + T const* cast (::std::false_type&&) const { + return static_cast(this->data); + } + + template + T* cast (::std::false_type&&) { + return static_cast(this->data); + } +}; + +template +T const* any_cast (any const* operand) noexcept { + return operand and operand->type() == type_of() + ? operand->cast(impl::is_small { }) + : nullptr; +} + +template +T* any_cast (any* operand) noexcept { + return operand and operand->type() == type_of() + ? operand->cast(impl::is_small { }) + : nullptr; +} + +template < + class T, + class=meta::when< + meta::any< + ::std::is_reference::value, + ::std::is_copy_constructible::value + >() + > +> T any_cast (any const& operand) { + using type = remove_reference_t; + auto pointer = any_cast>(::std::addressof(operand)); + if (not pointer) { throw_bad_any_cast(); } + return *pointer; +} + +template < + class T, + class=meta::when< + meta::any< + ::std::is_reference::value, + ::std::is_copy_constructible::value + >() + > +> T any_cast (any&& operand) { + using type = remove_reference_t; + auto pointer = any_cast(::std::addressof(operand)); + if (not pointer) { throw_bad_any_cast(); } + return *pointer; +} + +template < + class T, + class=meta::when< + meta::any< + ::std::is_reference::value, + ::std::is_copy_constructible::value + >() + > +> T any_cast (any& operand) { + using type = remove_reference_t; + auto pointer = any_cast(::std::addressof(operand)); + if (not pointer) { throw_bad_any_cast(); } + return *pointer; +} + +inline void swap (any& lhs, any& rhs) noexcept { lhs.swap(rhs); } + +}} /* namespace core::v2 */ + +#endif /* CORE_ANY_HPP */ diff --git a/src/mlpack/core/std_backport/functional.hpp b/src/mlpack/core/std_backport/functional.hpp new file mode 100644 index 0000000000..b1eaaf0fc2 --- /dev/null +++ b/src/mlpack/core/std_backport/functional.hpp @@ -0,0 +1,435 @@ +/** + * Copyright © 2013 - 2015 MNMLSTC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this software except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +#ifndef CORE_FUNCTIONAL_HPP +#define CORE_FUNCTIONAL_HPP + +#include +#include +#include + +#include "type_traits.hpp" +#include "utility.hpp" + +namespace core { +inline namespace v2 { + +template using is_reference_wrapper = meta::is_specialization_of< + remove_cv_t, + ::std::reference_wrapper +>; + +template struct function_traits; + +template +struct function_traits : function_traits { }; + +template +struct function_traits : function_traits { }; + +template +struct function_traits : function_traits { }; + +template +struct function_traits : + function_traits +{ }; + +template +struct function_traits : + function_traits +{ }; + +template +struct function_traits : + function_traits +{ }; + +template +struct function_traits { + using typelist = meta::list; + using return_type = R; + + using pointer = add_pointer_t; + static constexpr auto arity = typelist::size(); + + template <::std::size_t N> using argument = meta::get; +}; + +template struct function_traits { + using functor_type = function_traits::operator())>; + using return_type = typename functor_type::return_type; + using pointer = typename functor_type::pointer; + static constexpr auto arity = functor_type::arity - 1; + template <::std::size_t N> + using argument = typename functor_type::template argument; +}; + +/* N3727 */ +template +auto invoke (Functor&& f, Args&&... args) -> enable_if_t< + ::std::is_member_pointer>::value, + result_of_t +> { return ::std::mem_fn(f)(core::forward(args)...); } + +template +auto invoke (Functor&& f, Args&&... args) -> enable_if_t< + not ::std::is_member_pointer>::value, + result_of_t +> { return core::forward(f)(core::forward(args)...); } + +template +auto apply (F&& f, T&& t, index_sequence) -> decltype( + invoke(core::forward(f), ::std::get(core::forward(t))...) +) { return invoke(core::forward(f), ::std::get(core::forward(t))...); } + +template < + class Functor, + class T, + class I = make_index_sequence<::std::tuple_size>::value> +> auto apply (Functor&& f, T&& t) -> decltype( + apply(core::forward(f), core::forward(t), I { }) +) { return apply(core::forward(f), core::forward(t), I { }); } + +template +struct apply_functor { + template + explicit apply_functor (G&& g) : f(core::forward(g)) { } + + template + auto operator () (Applicable&& args) -> decltype( + core::apply(core::forward(this->f), core::forward(args)) + ) { return apply(core::forward(f), core::forward(args)); } +private: + F f; +}; + +template +auto make_apply (F&& f) -> apply_functor { + return apply_functor { core::forward(f) }; +} + +template +struct not_fn_functor { + template + explicit not_fn_functor (G&& g) : f(core::forward(g)) { } + + template + auto operator () (Args&&... args) const -> decltype( + not (invoke)(::std::declval(), core::forward(args)...) + ) { return not (invoke)(f, core::forward(args)...); } + + template + auto operator () (Args&&... args) -> decltype( + not (invoke)(::std::declval(), core::forward(args)...) + ) { return not (invoke)(f, core::forward(args)...); } + +private: + F f; +}; + +/* Were this C++14, we could just use a lambda with a capture. Oh Well! */ +template +not_fn_functor> not_fn (F&& f) { + return not_fn_functor> { core::forward(f) }; +} + +/* converter function object */ +template +struct converter { + template + constexpr T operator () (Args&&... args) const { + return T(core::forward(args)...); + } +}; + +/* function objects -- arithmetic */ +template +struct plus { + constexpr T operator () (T const& l, T const& r) const { return l + r; } +}; + +template +struct minus { + constexpr T operator () (T const& l, T const& r) const { return l - r; } +}; + +template +struct multiplies { + constexpr T operator () (T const& l, T const& r) const { return l * r; } +}; + +template +struct divides { + constexpr T operator () (T const& l, T const& r) const { return l / r; } +}; + +template +struct modulus { + constexpr T operator () (T const& l, T const& r) const { return l % r; } +}; + +template +struct negate { + constexpr T operator () (T const& arg) const { return -arg; } +}; + +/* function objects -- comparisons */ +template +struct equal_to { + constexpr bool operator () (T const& l, T const& r) const { return l == r; } +}; + +template +struct not_equal_to { + constexpr bool operator () (T const& l, T const& r) const { return l != r; } +}; + +template +struct greater_equal { + constexpr bool operator () (T const& l, T const& r) const { return l >= r; } +}; + +template +struct less_equal { + constexpr bool operator () (T const& l, T const& r) const { return l <= r; } +}; + +template +struct greater { + constexpr bool operator () (T const& l, T const& r) const { return l > r; } +}; + +template +struct less { + constexpr bool operator () (T const& l, T const& r) const { return l < r; } +}; + +/* function objects -- logical */ +template +struct logical_and { + constexpr bool operator () (T const& l, T const& r) const { return l and r; } +}; + +template +struct logical_or { + constexpr bool operator () (T const& l, T const& r) const { return l or r; } +}; + +template +struct logical_not { + constexpr bool operator () (T const& arg) const { return not arg; } +}; + +/* function objects -- bitwise */ + +template +struct bit_and { + constexpr bool operator () (T const& l, T const& r) const { return l & r; } +}; + +template +struct bit_or { + constexpr bool operator () (T const& l, T const& r) const { return l | r; } +}; + +template +struct bit_xor { + constexpr bool operator () (T const& l, T const& r) const { return l ^ r; } +}; + +template +struct bit_not { + constexpr bool operator () (T const& arg) const { return ~arg; } +}; + +/* function objects -- arithmetic specializations */ +template <> struct plus { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) + core::forward(u) + ) { return core::forward(t) + core::forward(u); } +}; + +template <> struct minus { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) - core::forward(u) + ) { return core::forward(t) - core::forward(u); } +}; + +template <> struct multiplies { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) * core::forward(u) + ) { return core::forward(t) * core::forward(u); } +}; + +template <> struct divides { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) / core::forward(u) + ) { return core::forward(t) / core::forward(u); } +}; + +template <> struct modulus { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) % core::forward(u) + ) { return core::forward(t) % core::forward(u); } +}; + +template <> struct negate { + using is_transparent = void; + + template + constexpr auto operator () (T&& t) const -> decltype(core::forward(t)) { + return core::forward(t); + } +}; + +/* function objects -- comparison specialization */ +template <> struct equal_to { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) == core::forward(u) + ) { return core::forward(t) == core::forward(u); } +}; + +template <> struct not_equal_to { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) != core::forward(u) + ) { return core::forward(t) != core::forward(u); } +}; + +template <> struct greater_equal { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) >= core::forward(u) + ) { return core::forward(t) >= core::forward(u); } +}; + +template <> struct less_equal { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) <= core::forward(u) + ) { return core::forward(t) <= core::forward(u); } +}; + +template <> struct greater { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) > core::forward(u) + ) { return core::forward(t) > core::forward(u); } +}; + +template <> struct less { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) < core::forward(u) + ) { return core::forward(t) < core::forward(u); } +}; + +/* function objects -- logical specializations */ +template <> struct logical_and { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) and core::forward(u) + ) { return core::forward(t) and core::forward(u); } +}; + +template <> struct logical_or { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) or core::forward(u) + ) { return core::forward(t) or core::forward(u); } +}; + +template <> struct logical_not { + using is_transparent = void; + + template + constexpr auto operator () (T&& t) const -> decltype( + not core::forward(t) + ) { return not core::forward(t); } +}; + +/* function objects -- bitwise specializations */ +template <> struct bit_and { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) & core::forward(u) + ) { return core::forward(t) & core::forward(u); } +}; + +template <> struct bit_or { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) | core::forward(u) + ) { return core::forward(t) | core::forward(u); } +}; + +template <> struct bit_xor { + using is_transparent = void; + + template + constexpr auto operator () (T&& t, U&& u) const -> decltype( + core::forward(t) ^ core::forward(u) + ) { return core::forward(t) ^ core::forward(u); } +}; + +template <> struct bit_not { + using is_transparent = void; + + template + constexpr auto operator () (T&& t) const -> decltype(~core::forward(t)) { + return ~core::forward(t); + } +}; + +/* N3980 Implementation */ + +}} /* namespace core::v2 */ + +#endif /* CORE_FUNCTIONAL_HPP */ diff --git a/src/mlpack/core/std_backport/internal.hpp b/src/mlpack/core/std_backport/internal.hpp new file mode 100644 index 0000000000..ffd177cded --- /dev/null +++ b/src/mlpack/core/std_backport/internal.hpp @@ -0,0 +1,156 @@ +/** + * Copyright © 2013 - 2015 MNMLSTC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this software except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +#ifndef CORE_INTERNAL_HPP +#define CORE_INTERNAL_HPP + +/* This is a header containing common implementation specific code, to + * reduce the complexity of the other headers, especially those that are + * closely intertwined, such as and + * + * Additionally, some of this code is duplicated elsewhere (such as class_of, + * and meta::identity), but aliases are placed to lessen any impact that this + * might have. + */ + +#include +#include +#include +#include + +#include "meta.hpp" + +namespace core { +inline namespace v2 { +namespace impl { + +template class, class...> +struct make_detect : meta::identity { using value_t = ::std::false_type; }; +template class U, class... Args> +struct make_detect>, U, Args...> : + meta::identity> +{ using value_t = ::std::true_type; }; + +/* extremely useful custom type traits */ +template struct class_of : meta::identity { }; +template +struct class_of : meta::identity { }; + +/* aliases */ +template using class_of_t = typename class_of::type; +template using decay_t = typename ::std::decay::type; +template +using remove_reference_t = typename ::std::remove_reference::type; +template +using enable_if_t = typename ::std::enable_if::type; + +/* is_nothrow_swappable plumbing */ +using ::std::declval; +using ::std::swap; + +// MSVC 2015 workaround +template +struct is_swappable_with { + template + static auto test (void*) noexcept(true) -> decltype( + swap(declval(), declval()) + ); + + template + static void test (...) noexcept(false); + + static constexpr bool value = noexcept(test(nullptr)); +}; + +// MSVC 2015 workaround +template +struct is_noexcept_swappable_with { + template < + class X, + class Y, + bool B=noexcept(swap(declval(), declval())) + > static void test (enable_if_t*) noexcept(true); + + template + static void test (...) noexcept(false); + + static constexpr bool value = noexcept(test(nullptr)); +}; + +template +struct is_swappable : ::std::false_type { }; + +template +struct is_swappable< + T, + U, + meta::deduce< + is_swappable_with, + is_swappable_with + > +> : ::std::true_type { }; + +template +struct is_nothrow_swappable : meta::all_t< + is_swappable::value, + is_noexcept_swappable_with::value, + is_noexcept_swappable_with::value +> { }; + +/* + * If I can't amuse myself when working with C++ templates, then life isn't + * worth living. Bury me with my chevrons. + */ +template +constexpr T&& pass (remove_reference_t& t) noexcept { + return static_cast(t); +} + +template +constexpr T&& pass (remove_reference_t&& t) noexcept { + return static_cast(t); +} + +/* INVOKE pseudo-expression plumbing, *much* more simplified than previous + * versions of Core + */ +struct undefined { constexpr undefined (...) noexcept { } }; + +/* We get some weird warnings under clang, so we actually give these functions + * a body to get rid of it. + */ +template +constexpr undefined INVOKE (undefined, Args&&...) noexcept { + return undefined { }; +} + +template +constexpr auto INVOKE (Functor&& f, Args&&... args) -> enable_if_t< + not ::std::is_member_pointer>::value, + decltype(pass(f)(pass(args)...)) +> { return pass(f)(pass(args)...); } + +template +auto INVOKE (Functor&& f, Args&&... args) -> enable_if_t< + ::std::is_member_pointer>::value, + decltype(::std::mem_fn(pass(f))(pass(args)...)) +> { return ::std::mem_fn(pass(f))(pass(args)...); } + +template struct invoke_of { }; +template struct invoke_of : + meta::identity()...))> +{ }; + +}}} /* namespace core::v2::impl */ + +#endif /* CORE_INTERNAL_HPP */ diff --git a/src/mlpack/core/std_backport/iterator.hpp b/src/mlpack/core/std_backport/iterator.hpp new file mode 100644 index 0000000000..690c983e30 --- /dev/null +++ b/src/mlpack/core/std_backport/iterator.hpp @@ -0,0 +1,272 @@ +/** + * Copyright © 2013 - 2015 MNMLSTC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this software except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +#ifndef CORE_ITERATOR_HPP +#define CORE_ITERATOR_HPP + +#include +#include +#include + +#include "type_traits.hpp" +#include "utility.hpp" + +namespace core { +inline namespace v2 { + +/* capacity */ +template +constexpr auto size (Container const& container) noexcept -> decltype( + container.size() +) { return container.size(); } + +template +constexpr ::std::size_t size (T const (&)[N]) noexcept { return N; } + +template +constexpr bool empty (Container const& container) noexcept { + return container.empty(); +} + +template +constexpr bool empty (T const (&)[N]) noexcept { return false; } + +/* element access */ +template +constexpr auto front (Container const& container) -> decltype( + container.front() +) { return container.front(); } + +template +constexpr auto front (Container& container) -> decltype(container.front()) { + return container.front(); +} + +template +constexpr T const& front (T const (&array)[N]) noexcept { return array[0]; } + +template +constexpr T& front (T (&array)[N]) noexcept { return array[0]; } + +template +constexpr auto back (Container const& container) -> decltype( + container.back() +) { return container.back(); } + +template +constexpr auto back (Container& container) -> decltype(container.back()) { + return container.back(); +} + +template +constexpr T const& back (T const (&array)[N]) noexcept { return array[N - 1]; } + +template +constexpr T& back (T (&array)[N]) noexcept { return array[N - 1]; } + +/* data access */ +template +constexpr auto data (Container const& container) noexcept -> decltype( + container.data() +) { return container.data(); } + +template +constexpr auto data (Container& container) noexcept -> decltype( + container.data() +) { return container.data(); } + +template +constexpr T const* data (T const (&array)[N]) noexcept { return array; } + +template +constexpr T* data (T (&array)[N]) noexcept { return array; } + +/* iteration */ +template +auto cbegin (Container const& container) -> decltype(::std::begin(container)) { + return ::std::begin(container); +} + +template +auto cend (Container const& container) -> decltype(::std::end(container)) { + return ::std::end(container); +} + +template +auto rbegin (Container const& container) -> decltype(container.rbegin()) { + return container.rbegin(); +} + +template +auto rbegin (Container& container) -> decltype(container.rbegin()) { + return container.rbegin(); +} + +template +auto crbegin (Container const& container) -> decltype(rbegin(container)) { + return rbegin(container); +} + +template +auto rend (Container const& container) -> decltype(container.rend()) { + return container.rend(); +} + +template +auto rend (Container& container) -> decltype(container.rend()) { + return container.rend(); +} + +template +auto crend (Container const& container) -> decltype(rend(container)) { + return rend(container); +} + +template +::std::reverse_iterator make_reverse_iterator (Iterator iter) { + return ::std::reverse_iterator(iter); +} + +template < + class DelimT, + class CharT=char, + class Traits=::std::char_traits +> struct ostream_joiner final : ::std::iterator< + ::std::output_iterator_tag, + void, + void, + void, + void +> { + using delimiter_type = DelimT; + using ostream_type = ::std::basic_ostream; + using traits_type = Traits; + using char_type = CharT; + + ostream_joiner (ostream_type& stream, delimiter_type const& delimiter) : + stream(stream), + delimiter { delimiter } + { } + + ostream_joiner (ostream_type& stream, delimiter_type&& delimiter) : + stream(stream), + delimiter { ::core::move(delimiter) }, + first { true } + { } + + template + ostream_joiner& operator = (T const& item) { + if (not first and delimiter) { this->stream << delimiter; } + this->stream << item; + this->first = false; + return *this; + } + + ostream_joiner& operator ++ (int) noexcept { return *this; } + ostream_joiner& operator ++ () noexcept { return *this; } + ostream_joiner& operator * () noexcept { return *this; } + +private: + ostream_type& stream; + delimiter_type delimiter; + bool first; +}; + +template +struct number_iterator { + using iterator_category = ::std::bidirectional_iterator_tag; + using difference_type = T; + using value_type = T; + using reference = add_lvalue_reference_t; + using pointer = add_pointer_t; + + static_assert(::std::is_integral::value, ""); + + explicit number_iterator (value_type value, value_type step=1) noexcept : + value { value }, + step { step } + { } + + number_iterator (number_iterator const&) noexcept = default; + number_iterator () noexcept = default; + ~number_iterator () noexcept = default; + + number_iterator& operator = (number_iterator const&) noexcept = default; + + void swap (number_iterator& that) noexcept { + ::std::swap(this->value, that.value); + ::std::swap(this->step, that.step); + } + + reference operator * () noexcept { return this->value; } + + number_iterator& operator ++ () noexcept { + this->value += this->step; + return *this; + } + + number_iterator& operator -- () noexcept { + this->value -= this->step; + return *this; + } + + number_iterator operator ++ (int) const noexcept { + return number_iterator { this->value + this->step }; + } + + number_iterator operator -- (int) const noexcept { + return number_iterator { this->value - this->step }; + } + + bool operator == (number_iterator const& that) const noexcept { + return this->value == that.value and this->step == that.step; + } + + bool operator != (number_iterator const& that) const noexcept { + return this->value != that.value and this->step == that.step; + } + +private: + value_type value { }; + value_type step { static_cast(1) }; +}; + +template +void swap (number_iterator& lhs, number_iterator& rhs) noexcept { + lhs.swap(rhs); +} + +template +ostream_joiner, CharT, Traits> make_ostream_joiner ( + ::std::basic_ostream& stream, + DelimT&& delimiter +) { + return ostream_joiner, CharT, Traits> { + stream, + ::core::forward(delimiter) + }; +} + +template +number_iterator make_number_iterator (T value, T step) noexcept { + return number_iterator { value, step }; +} + +template +number_iterator make_number_iterator (T value) noexcept { + return number_iterator { value }; +} + +}} /* namespace core::v2 */ + +#endif /* CORE_ITERATOR_HPP */ diff --git a/src/mlpack/core/std_backport/meta.hpp b/src/mlpack/core/std_backport/meta.hpp new file mode 100644 index 0000000000..85d5da1bc3 --- /dev/null +++ b/src/mlpack/core/std_backport/meta.hpp @@ -0,0 +1,325 @@ +/** + * Copyright © 2013 - 2015 MNMLSTC + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this software except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +#ifndef CORE_META_HPP +#define CORE_META_HPP + +#include +#include +#include + +#include +#include + +namespace core { +inline namespace v2 { +namespace meta { +namespace impl { + +using false_t = ::std::false_type; +using true_t = ::std::true_type; + +template using integral = ::std::integral_constant; +template using boolean = integral; + +template struct identity { using type = T; }; + +template struct deducer : identity { }; +template using deduce = typename deducer::type; + +template class Detector, class... Args> +struct detect : identity { using value = false_t; }; + +template class Detector, class... Args> +struct detect>, Detector, Args...> : + identity> +{ using value = true_t; }; + +template +struct list { + static constexpr ::std::size_t size () noexcept { return sizeof...(Ts); } + static constexpr bool empty () noexcept { return size() == 0u; } +}; + +template class> struct convert; +template struct rebind; +template struct into; + +template class, class...> struct filter; +template class, class...> struct map; +template struct join; + +template