diff --git a/CMakeLists.txt b/CMakeLists.txt index 6acfcf2c8..68e5bdaef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,7 @@ if (NOT (CMAKE_VERSION VERSION_LESS 3.13)) endif() add_subdirectory(vendor/xtl) +set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl) add_subdirectory(vendor/xtensor) target_link_libraries(xtensor INTERFACE xtl) diff --git a/docs/source/publications.rst b/docs/source/publications.rst index 24bcc66a1..7439d2e34 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -142,6 +142,11 @@ Geometry and Visualization Miscellaneous ------------- +- Govatsa Acharya, "`Investigating the Application of Self-Actuated Passive + Shutdown System in a Small Lead-Cooled Reactor + `_," M.S. Thesis, KTH Royal + Institute of Technology (2019). + - Shikhar Kumar, Benoit Forget, and Kord Smith, "Analysis of fission source convergence for a 3-D SMR core using functional expansion tallies," *Proc. M&C*, 937-947, Portland, Oregon, Aug. 25-29 (2019). diff --git a/examples/jupyter/chain_simple.xml b/examples/jupyter/chain_simple.xml index 8b1b45535..96f6fa881 120000 --- a/examples/jupyter/chain_simple.xml +++ b/examples/jupyter/chain_simple.xml @@ -1 +1 @@ -/home/romano/openmc/tests/chain_simple.xml \ No newline at end of file +../../tests/chain_simple.xml \ No newline at end of file diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index 0d25b5b97..3b4e9a359 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -298,4 +298,4 @@ if __name__ == '__main__': move(fname, fname + '.original') # Write a new geometry file. - tree.write(fname) + tree.write(fname, xml_declaration=True) diff --git a/src/cell.cpp b/src/cell.cpp index 3a7d0cdd4..94bae32eb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -307,6 +307,10 @@ CSGCell::CSGCell(pugi::xml_node cell_node) if (fill_present) { fill_ = std::stoi(get_node_value(cell_node, "fill")); + if (fill_ == universe_) { + fatal_error("Cell " + std::to_string(id_) + + " is filled with the same universe that it is contained in."); + } } else { fill_ = C_NONE; } diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index a0b7f82c5..894157c5b 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -572,8 +572,9 @@ void ufs_count_sites() // distributed so that effectively the production of fission sites is not // biased - auto s = xt::view(simulation::source_frac, xt::all()); - s = simulation::ufs_mesh->volume_frac_; + std::size_t n = simulation::ufs_mesh->n_bins(); + double vol_frac = simulation::ufs_mesh->volume_frac_; + simulation::source_frac = xt::xtensor({n}, vol_frac); } else { // count number of source sites in each ufs mesh cell diff --git a/src/mesh.cpp b/src/mesh.cpp index 9e27fc4e6..915679dd3 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -149,14 +149,16 @@ RegularMesh::RegularMesh(pugi::xml_node node) "the coordinates on a tally mesh."); } - // Set width and upper right coordinate - width_ = xt::eval((upper_right_ - lower_left_) / shape_); + // Set width + if (shape_.size() > 0) { + width_ = xt::eval((upper_right_ - lower_left_) / shape_); + } } else { fatal_error("Must specify either and on a mesh."); } - // TODO: Change to zero when xtensor is updated - if (shape_.size() > 1) { + // Make sure lower_left and dimension match + if (shape_.size() > 0) { if (shape_.size() != lower_left_.size()) { fatal_error("Number of entries on must be the same " "as the number of entries on ."); diff --git a/src/photon.cpp b/src/photon.cpp index 929822bfc..ddde4bd6c 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -180,9 +180,8 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) // Read Compton profiles read_dataset(rgroup, "J", profile_pdf_); - // Get Compton profile momentum grid. By deafult, an xtensor has a size of 1. - // TODO: Change to zero when xtensor is updated - if (data::compton_profile_pz.size() == 1) { + // Get Compton profile momentum grid + if (data::compton_profile_pz.size() == 0) { read_dataset(rgroup, "pz", data::compton_profile_pz); } close_group(rgroup); @@ -213,8 +212,7 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) // Get energy grids used for bremsstrahlung DCS and for stopping powers xt::xtensor electron_energy; read_dataset(rgroup, "electron_energy", electron_energy); - // TODO: Change to zero when xtensor is updated - if (data::ttb_k_grid.size() == 1) { + if (data::ttb_k_grid.size() == 0) { read_dataset(rgroup, "photon_energy", data::ttb_k_grid); } @@ -255,8 +253,7 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) } // Set incident particle energy grid - // TODO: Change to zero when xtensor is updated - if (data::ttb_e_grid.size() == 1) { + if (data::ttb_e_grid.size() == 0) { data::ttb_e_grid = electron_energy; } diff --git a/src/settings.cpp b/src/settings.cpp index 796a2862a..b647d32e8 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -512,8 +512,7 @@ void read_settings_xml() if (!m) fatal_error("Only regular meshes can be used as an entropy mesh"); simulation::entropy_mesh = m; - // TODO: Change to zero when xtensor is updated - if (m->shape_.size() == 1) { + if (m->shape_.size() == 0) { // If the user did not specify how many mesh cells are to be used in // each direction, we automatically determine an appropriate number of // cells diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index eea43989e..852918a0c 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -810,8 +810,7 @@ void Tally::init_results() void Tally::reset() { n_realizations_ = 0; - // TODO: Change to zero when xtensor is updated - if (results_.size() != 1) { + if (results_.size() != 0) { xt::view(results_, xt::all()) = 0.0; } } @@ -1399,8 +1398,7 @@ openmc_tally_results(int32_t index, double** results, size_t* shape) } const auto& t {model::tallies[index]}; - // TODO: Change to zero when xtensor is updated - if (t->results_.size() == 1) { + if (t->results_.size() == 0) { set_errmsg("Tally results have not been allocated yet."); return OPENMC_E_ALLOCATE; } diff --git a/vendor/vendor.txt b/vendor/vendor.txt new file mode 100644 index 000000000..4291ee375 --- /dev/null +++ b/vendor/vendor.txt @@ -0,0 +1,4 @@ +gsl-lite==0.34.0 +pugixml==1.8 +xtensor==0.20.8 +xtl==0.6.5 diff --git a/vendor/xtensor/CMakeLists.txt b/vendor/xtensor/CMakeLists.txt index d4d3b355d..ce5fe9e6a 100644 --- a/vendor/xtensor/CMakeLists.txt +++ b/vendor/xtensor/CMakeLists.txt @@ -1,5 +1,6 @@ ############################################################################ -# Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # @@ -28,16 +29,71 @@ message(STATUS "Building xtensor v${${PROJECT_NAME}_VERSION}") # Dependencies # ============ -#find_package(xtl 0.4.9 REQUIRED) +set(xtl_REQUIRED_VERSION 0.6.7) +find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED) +message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") -#message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") +find_package(nlohmann_json 3.1.1 QUIET) -#find_package(nlohmann_json 3.1.1) +# Optional dependencies +# ===================== + +OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) +OPTION(XTENSOR_USE_TBB "enable parallelization using intel TBB" OFF) +OPTION(XTENSOR_USE_OPENMP "enable parallelization using OpenMP" OFF) +if(XTENSOR_USE_TBB AND XTENSOR_USE_OPENMP) + message( + FATAL + "XTENSOR_USE_TBB and XTENSOR_USE_OPENMP cannot both be active at once" + ) +endif() + +if(XTENSOR_USE_XSIMD) + set(xsimd_REQUIRED_VERSION 7.4.0) + find_package(xsimd ${xsimd_REQUIRED_VERSION} REQUIRED) + message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") +endif() + +if(XTENSOR_USE_TBB) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + find_package(TBB REQUIRED) + message(STATUS "Found intel TBB: ${TBB_INCLUDE_DIRS}") +endif() + +if(XTENSOR_USE_OPENMP) + find_package(OpenMP REQUIRED) + if (OPENMP_FOUND) + # Set openmp variables now + + # Create private target just for this lib + # https://cliutils.gitlab.io/modern-cmake/chapters/packages/OpenMP.html + # Probably not safe for cmake < 3.4 .. + find_package(Threads REQUIRED) + add_library(OpenMP::OpenMP_CXX_xtensor IMPORTED INTERFACE) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS} + ) + # Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS} Threads::Threads) + + message(STATUS "OpenMP Found") + else() + message(FATAL "Failed to locate OpenMP") + endif() +endif() # Build # ===== set(XTENSOR_HEADERS + ${XTENSOR_INCLUDE_DIR}/xtensor/xaccessible.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xaccumulator.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xadapt.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xarray.hpp @@ -47,16 +103,19 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xbuffer_adaptor.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xbuilder.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcomplex.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xconcepts.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcontainer.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcsv.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xdynamic_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xeval.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xexception.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_holder.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_traits.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfixed.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfunction.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfunctor_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xgenerator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xhistogram.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xindex_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xinfo.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xio.hpp @@ -64,7 +123,10 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xiterator.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xjson.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xlayout.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmanipulation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmasked_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xmath.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmime.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnoalias.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnorm.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnpy.hpp @@ -74,6 +136,7 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_base.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_storage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xpad.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xrandom.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xreducer.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp @@ -102,13 +165,13 @@ target_link_libraries(xtensor INTERFACE xtl) OPTION(XTENSOR_ENABLE_ASSERT "xtensor bound check" OFF) OPTION(XTENSOR_CHECK_DIMENSION "xtensor dimension check" OFF) -OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) OPTION(BUILD_TESTS "xtensor test suite" OFF) OPTION(BUILD_BENCHMARK "xtensor benchmark" OFF) OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) OPTION(DOWNLOAD_GBENCHMARK "download google benchmark and build from source" ON) OPTION(DEFAULT_COLUMN_MAJOR "set default layout to column major" OFF) OPTION(DISABLE_VS2017 "disables the compilation of some test with Visual Studio 2017" OFF) +OPTION(CPP17 "enables C++17" OFF) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) set(BUILD_TESTS ON) @@ -122,13 +185,6 @@ if(XTENSOR_CHECK_DIMENSION) add_definitions(-DXTENSOR_ENABLE_CHECK_DIMENSION) endif() -if(XTENSOR_USE_XSIMD) - add_definitions(-DXTENSOR_USE_XSIMD) - find_package(xsimd 4.1.6 REQUIRED) - message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") - target_link_libraries(xtensor INTERFACE xsimd) -endif() - if(DEFAULT_COLUMN_MAJOR) add_definitions(-DXTENSOR_DEFAULT_LAYOUT=layout_type::column_major) endif() @@ -145,6 +201,11 @@ if(BUILD_BENCHMARK) add_subdirectory(benchmark) endif() +if(XTENSOR_USE_OPENMP) + # Link xtensor itself to OpenMP to propagate to user projects + target_link_libraries(xtensor INTERFACE OpenMP::OpenMP_CXX_xtensor) +endif() + # Installation # ============ diff --git a/vendor/xtensor/include/xtensor/xaccessible.hpp b/vendor/xtensor/include/xtensor/xaccessible.hpp new file mode 100644 index 000000000..8d8c6b3b2 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaccessible.hpp @@ -0,0 +1,307 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ACCESSIBLE_HPP +#define XTENSOR_ACCESSIBLE_HPP + +#include "xexception.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + /** + * @class xconst_accessible + * @brief Base class for implementation of common expression constant access methods. + * + * The xaccessible class implements constant access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xconst_accessible + * + * + */ + template + class xconst_accessible + { + public: + + using derived_type = D; + using inner_types = xcontainer_inner_types; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using size_type = typename inner_types::size_type; + + size_type size() const noexcept; + size_type dimension() const noexcept; + size_type shape(size_type index) const; + + template + const_reference at(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference periodic(Args... args) const; + + template + bool in_bounds(Args... args) const; + + protected: + + xconst_accessible() = default; + ~xconst_accessible() = default; + + xconst_accessible(const xconst_accessible&) = default; + xconst_accessible& operator=(const xconst_accessible&) = default; + + xconst_accessible(xconst_accessible&&) = default; + xconst_accessible& operator=(xconst_accessible&&) = default; + + private: + + const derived_type& derived_cast() const noexcept; + }; + + /** + * @class xaccessible + * @brief Base class for implementation of common expression access methods. + * + * The xaccessible class implements access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xaccessible + * provides the interface. + */ + template + class xaccessible : public xconst_accessible + { + public: + + using base_type = xconst_accessible; + using derived_type = typename base_type::derived_type; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + + template + reference at(Args... args); + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference periodic(Args... args); + + using base_type::at; + using base_type::operator[]; + using base_type::periodic; + + protected: + + xaccessible() = default; + ~xaccessible() = default; + + xaccessible(const xaccessible&) = default; + xaccessible& operator=(const xaccessible&) = default; + + xaccessible(xaccessible&&) = default; + xaccessible& operator=(xaccessible&&) = default; + + private: + + derived_type& derived_cast() noexcept; + }; + + /************************************ + * xconst_accessible implementation * + ************************************/ + + /** + * Returns the size of the expression. + */ + template + inline auto xconst_accessible::size() const noexcept -> size_type + { + return compute_size(derived_cast().shape()); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xconst_accessible::dimension() const noexcept -> size_type + { + return derived_cast().shape().size(); + } + + /** + * Returns the i-th dimension of the expression. + */ + template + inline auto xconst_accessible::shape(size_type index) const -> size_type + { + return derived_cast().shape()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xconst_accessible::at(Args... args) const -> const_reference + { + check_access(derived_cast().shape(), static_cast(args)...); + return derived_cast().operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xconst_accessible::operator[](const S& index) const + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xconst_accessible::operator[](std::initializer_list index) const -> const_reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xconst_accessible::operator[](size_type i) const -> const_reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xconst_accessible::periodic(Args... args) const -> const_reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + /** + * Returns ``true`` only if the the specified position is a valid entry in the expression. + * @param args a list of indices specifying the position in the expression. + * @return bool + */ + template + template + inline bool xconst_accessible::in_bounds(Args... args) const + { + return check_in_bounds(derived_cast().shape(), args...); + } + + template + inline auto xconst_accessible::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + /****************************** + * xaccessible implementation * + ******************************/ + + /** + * Returns a reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xaccessible::at(Args... args) -> reference + { + check_access(derived_cast().shape(), static_cast(args)...); + return derived_cast().operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xaccessible::operator[](const S& index) + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xaccessible::operator[](std::initializer_list index) -> reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xaccessible::operator[](size_type i) -> reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xaccessible::periodic(Args... args) -> reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + + template + inline auto xaccessible::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + +} + +#endif + diff --git a/vendor/xtensor/include/xtensor/xaccumulator.hpp b/vendor/xtensor/include/xtensor/xaccumulator.hpp index f2b446ff3..7bba8a5ae 100644 --- a/vendor/xtensor/include/xtensor/xaccumulator.hpp +++ b/vendor/xtensor/include/xtensor/xaccumulator.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -21,7 +22,7 @@ namespace xt { -#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate +#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate_type /************** * accumulate * @@ -73,13 +74,13 @@ namespace xt template xarray::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS) { - static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); } template xarray::value_type> accumulator_impl(F&&, E&&, EVS) { - static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); } template @@ -88,15 +89,57 @@ namespace xt using type = xarray; }; - template - struct xaccumulator_return_type, R> + template + struct xaccumulator_return_type, R> { - using type = xtensor; + using type = xarray; + }; + + template + struct xaccumulator_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_return_type, L>, R> + { + using type = xtensor_fixed, L>; }; template using xaccumulator_return_type_t = typename xaccumulator_return_type::type; + template + struct fixed_compute_size; + + template + struct xaccumulator_linear_return_type + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, L>, R> + { + using type = xtensor_fixed>::value>, L>; + }; + + template + using xaccumulator_linear_return_type_t = typename xaccumulator_linear_return_type::type; + template inline auto accumulator_init_with_f(F&& f, E& e, std::size_t axis) { @@ -104,7 +147,8 @@ namespace xt // e[:, 0, :, :, ...] = f(e[:, 0, :, :, ...]) // so that all "first" values are initialized in a first pass - std::size_t outer_loop_size, inner_loop_size, outer_stride, inner_stride, pos = 0; + std::size_t outer_loop_size, inner_loop_size, pos = 0; + std::size_t outer_stride, inner_stride; auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { outer_loop_size = std::accumulate(first, first + ax, @@ -113,9 +157,10 @@ namespace xt std::size_t(1), std::multiplies()); }; + // Note: add check that strides > 0 auto set_loop_strides = [&outer_stride, &inner_stride](auto first, auto last, std::ptrdiff_t ax) { - outer_stride = ax == 0 ? 1 : *std::min_element(first, first + ax); - inner_stride = (ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last); + outer_stride = static_cast(ax == 0 ? 1 : *std::min_element(first, first + ax)); + inner_stride = static_cast((ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last)); }; set_loop_sizes(e.shape().begin(), e.shape().end(), static_cast(axis)); @@ -140,9 +185,9 @@ namespace xt } template - inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate) + inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate_type) { - using accumulate_functor = std::decay_t(f))>; + using accumulate_functor = std::decay_t(f))>; using function_return_type = typename accumulate_functor::result_type; using result_type = xaccumulator_return_type_t, function_return_type>; @@ -153,74 +198,80 @@ namespace xt result_type result = e; // assign + make a copy, we need it anyways - std::size_t inner_stride = result.strides()[axis]; - std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) - std::size_t outer_loop_size = 0; - std::size_t inner_loop_size = 0; - - auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { - outer_loop_size = std::accumulate(first, - first + ax, - std::size_t(1), std::multiplies()); - - inner_loop_size = std::accumulate(first + ax, - last, - std::size_t(1), std::multiplies()); - }; - - if (result_type::static_layout == layout_type::row_major) + if(result.shape(axis) != std::size_t(0)) { - set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); - } - else - { - set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); - std::swap(inner_loop_size, outer_loop_size); - } + std::size_t inner_stride = static_cast(result.strides()[axis]); + std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) + std::size_t outer_loop_size = 0; + std::size_t inner_loop_size = 0; + std::size_t init_size = e.shape()[axis] != std::size_t(1) ? std::size_t(1) : std::size_t(0); - std::size_t pos = 0; + auto set_loop_sizes = [&outer_loop_size, &inner_loop_size, init_size](auto first, auto last, std::ptrdiff_t ax) { + outer_loop_size = std::accumulate(first, + first + ax, + init_size, std::multiplies()); - inner_loop_size = inner_loop_size - inner_stride; + inner_loop_size = std::accumulate(first + ax, + last, + std::size_t(1), std::multiplies()); + }; - // activate the init loop if we have an init function other than identity - if (!std::is_same(f)), xtl::identity>::value) - { - accumulator_init_with_f(std::get<1>(f), result, axis); - } - - pos = 0; - for (std::size_t i = 0; i < outer_loop_size; ++i) - { - for (std::size_t j = 0; j < inner_loop_size; ++j) + if (result_type::static_layout == layout_type::row_major) { - result.storage()[pos + inner_stride] = std::get<0>(f)(result.storage()[pos], - result.storage()[pos + inner_stride]); - pos += outer_stride; + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); + } + else + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); + std::swap(inner_loop_size, outer_loop_size); + } + + std::size_t pos = 0; + + inner_loop_size = inner_loop_size - inner_stride; + + // activate the init loop if we have an init function other than identity + if (!std::is_same(f))>, xtl::identity>::value) + { + accumulator_init_with_f(xt::get<1>(f), result, axis); + } + + pos = 0; + for (std::size_t i = 0; i < outer_loop_size; ++i) + { + for (std::size_t j = 0; j < inner_loop_size; ++j) + { + result.storage()[pos + inner_stride] = xt::get<0>(f)(result.storage()[pos], + result.storage()[pos + inner_stride]); + pos += outer_stride; + } + pos += inner_stride; } - pos += inner_stride; } return result; } template - inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate) + inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate_type) { - using accumulate_functor = std::decay_t(f))>; + using accumulate_functor = std::decay_t(f))>; using T = typename accumulate_functor::result_type; - using result_type = xtensor; + using result_type = xaccumulator_linear_return_type_t, T>; std::size_t sz = e.size(); auto result = result_type::from_shape({sz}); - auto it = e.template begin(); - - result.storage()[0] = std::get<1>(f)(*it); - ++it; - - for (std::size_t idx = 0; it != e.template end(); ++it) + if(sz != std::size_t(0)) { - result.storage()[idx + 1] = std::get<0>(f)(result.storage()[idx], *it); - ++idx; + auto it = e.template begin(); + result.storage()[0] = xt::get<1>(f)(*it); + ++it; + + for (std::size_t idx = 0; it != e.template end(); ++it) + { + result.storage()[idx + 1] = xt::get<0>(f)(result.storage()[idx], *it); + ++idx; + } } return result; } @@ -237,7 +288,7 @@ namespace xt * @return returns xarray filled with accumulated values */ template ::value, int> = 0> + XTL_REQUIRES(is_evaluation_strategy)> inline auto accumulate(F&& f, E&& e, EVS evaluation_strategy = EVS()) { // Note we need to check is_integral above in order to prohibit EVS = int, and not taking the std::size_t @@ -257,9 +308,10 @@ namespace xt * @return returns xarray filled with accumulated values */ template - inline auto accumulate(F&& f, E&& e, std::size_t axis, EVS evaluation_strategy = EVS()) + inline auto accumulate(F&& f, E&& e, std::ptrdiff_t axis, EVS evaluation_strategy = EVS()) { - return detail::accumulator_impl(std::forward(f), std::forward(e), axis, evaluation_strategy); + std::size_t ax = normalize_axis(e.dimension(), axis); + return detail::accumulator_impl(std::forward(f), std::forward(e), ax, evaluation_strategy); } } diff --git a/vendor/xtensor/include/xtensor/xadapt.hpp b/vendor/xtensor/include/xtensor/xadapt.hpp index b080bd0b7..5dac517a2 100644 --- a/vendor/xtensor/include/xtensor/xadapt.hpp +++ b/vendor/xtensor/include/xtensor/xadapt.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -18,6 +19,8 @@ #include "xarray.hpp" #include "xtensor.hpp" +#include "xfixed.hpp" +#include "xbuffer_adaptor.hpp" namespace xt { @@ -34,6 +37,24 @@ namespace xt template using array_size = array_size_impl>; + + template + struct default_allocator_for_ptr + { + using type = std::allocator>>>; + }; + + template + using default_allocator_for_ptr_t = typename default_allocator_for_ptr

::type; + + template + using not_an_array = xtl::negation>; + + template + using not_a_pointer = xtl::negation>; + + template + using not_a_layout = xtl::negation>; } /************************** @@ -48,9 +69,31 @@ namespace xt * @param l the layout_type of the xarray_adaptor */ template >::value, int> = 0> - xarray_adaptor, L, std::decay_t> - adapt(C&& container, const SC& shape, layout_type l = L); + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_pointer)> + inline xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l = L) + { + using return_type = xarray_adaptor, L, std::decay_t>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xarray_adaptor from a pointer with the specified shape and layout. + * @param pointer the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >, + std::is_pointer)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xarray_adaptor>; + std::size_t size = compute_size(shape); + return return_type(buffer_type(pointer, size), shape, l); + } /** * Constructs an xarray_adaptor of the given stl-like container, @@ -60,10 +103,16 @@ namespace xt * @param strides the strides of the xarray_adaptor */ template >::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, layout_type::dynamic, std::decay_t> - adapt(C&& container, SC&& shape, SS&& strides); + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_layout>)> + inline xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides) + { + using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } /** * Constructs an xarray_adaptor of the given dynamically allocated C array, @@ -71,32 +120,79 @@ namespace xt * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param shape the shape of the xarray_adaptor * @param l the layout_type of the xarray_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, O, A>, L, SC> - adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + template , + XTL_REQUIRES(detail::not_an_array>)> + inline xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()) + { + (void)ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } /** * Constructs an xarray_adaptor of the given dynamically allocated C array, - * with the specified shape and layout. + * with the specified shape and strides. * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param shape the shape of the xarray_adaptor * @param strides the strides of the xarray_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>, - typename std::enable_if_t>::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> - adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + template , + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_layout>)> + inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) + { + (void)ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor>; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + /** + * Contructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Contructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >, + detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), + std::forward(shape), + std::forward(strides)); + } /*************************** * xtensor_adaptor builder * @@ -109,8 +205,13 @@ namespace xt * @param l the layout_type of the xtensor_adaptor */ template - xtensor_adaptor - adapt(C&& container, layout_type l = L); + inline xtensor_adaptor + adapt(C&& container, layout_type l = L) + { + const std::array::size_type, 1> shape{container.size()}; + using return_type = xtensor_adaptor, 1, L>; + return return_type(std::forward(container), shape, l); + } /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -120,9 +221,32 @@ namespace xt * @param l the layout_type of the xtensor_adaptor */ template >::value, int> = 0> - xtensor_adaptor::value, L> - adapt(C&& container, const SC& shape, layout_type l = L); + XTL_REQUIRES(detail::is_array>, + detail::not_a_pointer)> + inline xtensor_adaptor::value, L> + adapt(C&& container, const SC& shape, layout_type l = L) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, L>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xtensor_adaptor from a pointer with the specified shape and layout. + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template >, + std::is_pointer)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + using buffer_type = xbuffer_adaptor>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + return return_type(buffer_type(pointer, compute_size(shape)), shape, l); + } /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -132,10 +256,17 @@ namespace xt * @param strides the strides of the xtensor_adaptor */ template >::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor::value, layout_type::dynamic> - adapt(C&& container, SC&& shape, SS&& strides); + XTL_REQUIRES(detail::is_array>, + detail::not_a_layout>)> + inline xtensor_adaptor::value, layout_type::dynamic> + adapt(C&& container, SC&& shape, SS&& strides) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, layout_type::dynamic>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } /** * Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array, @@ -143,145 +274,15 @@ namespace xt * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param l the layout_type of the xtensor_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>> - xtensor_adaptor, O, A>, 1, L> - adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()); - - /** - * Constructs an xtensor_adaptor of the given dynamically allocated C array, - * with the specified shape and layout. - * @param pointer the pointer to the beginning of the dynamic array - * @param size the size of the dynamic array - * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` - * @param shape the shape of the xtensor_adaptor - * @param l the layout_type of the xtensor_adaptor - * @param alloc the allocator used for allocating / deallocating the dynamic array - */ - template >>>, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor, O, A>, detail::array_size::value, L> - adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); - - /** - * Constructs an xtensor_adaptor of the given dynamically allocated C array, - * with the specified shape and strides. - * @param pointer the pointer to the beginning of the dynamic array - * @param size the size of the dynamic array - * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` - * @param shape the shape of the xtensor_adaptor - * @param strides the strides of the xtensor_adaptor - * @param alloc the allocator used for allocating / deallocating the dynamic array - */ - template >>>, - typename std::enable_if_t>::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> - adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); - - /***************************************** - * xarray_adaptor builder implementation * - *****************************************/ - - // shape only - container version - template >::value, int>> - inline xarray_adaptor, L, std::decay_t> - adapt(C&& container, const SC& shape, layout_type l) - { - using return_type = xarray_adaptor, L, std::decay_t>; - return return_type(std::forward(container), shape, l); - } - - // shape and strides - container version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xarray_adaptor, layout_type::dynamic, std::decay_t> - adapt(C&& container, SC&& shape, SS&& strides) - { - using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; - return return_type(std::forward(container), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - // shape only - buffer version - template >::value, int>> - inline xarray_adaptor, O, A>, L, SC> - adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) - { - using buffer_type = xbuffer_adaptor, O, A>; - using return_type = xarray_adaptor; - buffer_type buf(std::forward

(pointer), size, alloc); - return return_type(std::move(buf), shape, l); - } - - // shape and strides - buffer version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> - adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) - { - using buffer_type = xbuffer_adaptor, O, A>; - using return_type = xarray_adaptor>; - buffer_type buf(std::forward

(pointer), size, alloc); - return return_type(std::move(buf), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - /****************************************** - * xtensor_adaptor builder implementation * - ******************************************/ - - // 1-D case - container version - template - inline xtensor_adaptor - adapt(C&& container, layout_type l) - { - const std::array::size_type, 1> shape{container.size()}; - using return_type = xtensor_adaptor, 1, L>; - return return_type(std::forward(container), shape, l); - } - - // shape only - container version - template >::value, int>> - inline xtensor_adaptor::value, L> - adapt(C&& container, const SC& shape, layout_type l) - { - constexpr std::size_t N = detail::array_size::value; - using return_type = xtensor_adaptor, N, L>; - return return_type(std::forward(container), shape, l); - } - - // shape and strides - container version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xtensor_adaptor::value, layout_type::dynamic> - adapt(C&& container, SC&& shape, SS&& strides) - { - constexpr std::size_t N = detail::array_size::value; - using return_type = xtensor_adaptor, N, layout_type::dynamic>; - return return_type(std::forward(container), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - // 1-D case - buffer version - template + template > inline xtensor_adaptor, O, A>, 1, L> - adapt(P&& pointer, typename A::size_type size, O, layout_type l, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; using return_type = xtensor_adaptor; buffer_type buf(std::forward

(pointer), size, alloc); @@ -289,12 +290,23 @@ namespace xt return return_type(std::move(buf), shape, l); } - // shape only - buffer version - template >::value, int>> + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template , + XTL_REQUIRES(detail::is_array>)> inline xtensor_adaptor, O, A>, detail::array_size::value, L> - adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; constexpr std::size_t N = detail::array_size::value; using return_type = xtensor_adaptor; @@ -302,21 +314,185 @@ namespace xt return return_type(std::move(buf), shape, l); } - // shape and strides - buffer version - template >::value, int>, - typename std::enable_if_t>::value, int>> + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template , + XTL_REQUIRES(detail::is_array>, + detail::not_a_layout>)> inline xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> - adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; constexpr std::size_t N = detail::array_size::value; using return_type = xtensor_adaptor; buffer_type buf(std::forward

(pointer), size, alloc); return return_type(std::move(buf), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); } + + /** + * Contructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Contructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >, + detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), + std::forward(shape), + std::forward(strides)); + } + /** + * Constructs an non-owning xtensor_fixed_adaptor from a pointer with the + * specified shape and layout. + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_fixed_adaptor + */ + template )> + inline auto adapt(C&& ptr, const fixed_shape& /*shape*/) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xfixed_adaptor, L>; + return return_type(buffer_type(ptr, detail::fixed_compute_size>::value)); + } + +#ifndef X_OLD_CLANG + template + inline auto adapt(C&& ptr, const T(&shape)[N]) + { + using shape_type = std::array; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } +#else + template + inline auto adapt(C&& ptr, std::initializer_list shape) + { + using shape_type = xt::dynamic_shape; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } +#endif + +#ifndef X_OLD_CLANG + /** + * Adapt a smart pointer to a typed memory block (unique_ptr or shared_ptr) + * + * \code{.cpp} + * #include + * #include + * + * std::shared_ptr sptr(new double[8], std::default_delete()); + * sptr.get()[2] = 321.; + * auto xptr = adapt_smart_ptr(sptr, {4, 2}); + * xptr(1, 3) = 123.; + * std::cout << xptr; + * \endcode + * + * @param smart_ptr a smart pointer to a memory block of T[] + * @param shape The desired shape + * + * @return xtensor_adaptor for memory + */ + template + auto adapt_smart_ptr(P&& smart_ptr, const I(&shape)[N]) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>(shape); + return xtensor_adaptor( + buffer_adaptor(smart_ptr.get(), compute_size(fshape), + std::forward

(smart_ptr)), + std::move(fshape) + ); + } + + /** + * Adapt a smart pointer (shared_ptr or unique_ptr) + * + * This function allows to automatically adapt a shared or unique pointer to + * a given shape and operate naturally on it. Memory will be automatically + * handled by the smart pointer implementation. + * + * \code{.cpp} + * #include + * #include + * + * struct Buffer { + * Buffer(std::vector& buf) : m_buf(buf) {} + * ~Buffer() { std::cout << "deleted" << std::endl; } + * std::vector m_buf; + * }; + * + * auto data = std::vector{1,2,3,4,5,6,7,8}; + * auto shared_buf = std::make_shared(data); + * auto unique_buf = std::make_unique(data); + * + * std::cout << shared_buf.use_count() << std::endl; + * { + * auto obj = adapt_smart_ptr(shared_buf.get()->m_buf.data(), + * {2, 4}, shared_buf); + * // Use count increased to 2 + * std::cout << shared_buf.use_count() << std::endl; + * std::cout << obj << std::endl; + * } + * // Use count reset to 1 + * std::cout << shared_buf.use_count() << std::endl; + * + * { + * auto obj = adapt_smart_ptr(unique_buf.get()->m_buf.data(), + * {2, 4}, std::move(unique_buf)); + * std::cout << obj << std::endl; + * } + * \endcode + * + * @param data_ptr A pointer to a typed data block (e.g. double*) + * @param shape The desired shape + * @param smart_ptr A smart pointer to move or copy, in order to manage memory + * + * @return xtensor_adaptor on the memory + */ + template + auto adapt_smart_ptr(P&& data_ptr, const I(&shape)[N], D&& smart_ptr) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>(shape); + + return xtensor_adaptor( + buffer_adaptor(data_ptr, compute_size(fshape), std::forward(smart_ptr)), + std::move(fshape) + ); + } +#endif } #endif diff --git a/vendor/xtensor/include/xtensor/xarray.hpp b/vendor/xtensor/include/xtensor/xarray.hpp index 7c51f2812..69bdb474e 100644 --- a/vendor/xtensor/include/xtensor/xarray.hpp +++ b/vendor/xtensor/include/xtensor/xarray.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -26,13 +27,31 @@ namespace xt * xarray_container declaration * ********************************/ + namespace extension + { + template + struct xarray_container_base; + + template + struct xarray_container_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_container_base_t = typename xarray_container_base::type; + } + template struct xcontainer_inner_types> { using storage_type = EC; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; - using strides_type = shape_type; - using backstrides_type = shape_type; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; @@ -57,17 +76,19 @@ namespace xt * @tparam L The layout_type of the container. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. - * @sa xarray + * @sa xarray, xstrided_container, xcontainer */ template class xarray_container : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_container_base_t { public: using self_type = xarray_container; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_container_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; @@ -80,6 +101,7 @@ namespace xt using strides_type = typename base_type::strides_type; using backstrides_type = typename base_type::backstrides_type; using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; @@ -108,6 +130,11 @@ namespace xt xarray_container(xarray_container&&) = default; xarray_container& operator=(xarray_container&&) = default; + template + explicit xarray_container(xtensor_container&& rhs); + template + xarray_container& operator=(xtensor_container&& rhs); + template xarray_container(const xexpression& e); @@ -128,13 +155,31 @@ namespace xt * xarray_adaptor declaration * ******************************/ + namespace extension + { + template + struct xarray_adaptor_base; + + template + struct xarray_adaptor_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_adaptor_base_t = typename xarray_adaptor_base::type; + } + template struct xcontainer_inner_types> { using storage_type = std::remove_reference_t; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; - using strides_type = shape_type; - using backstrides_type = shape_type; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; @@ -162,10 +207,12 @@ namespace xt * @tparam L The layout_type of the adaptor. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. + * @sa xstrided_container, xcontainer */ template class xarray_adaptor : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_adaptor_base_t { public: @@ -174,6 +221,7 @@ namespace xt using self_type = xarray_adaptor; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_adaptor_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using shape_type = typename base_type::shape_type; @@ -210,7 +258,6 @@ namespace xt storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - friend class xcontainer>; }; @@ -386,10 +433,33 @@ namespace xt template inline xarray_container xarray_container::from_shape(S&& s) { - shape_type shape = xtl::forward_sequence(s); + shape_type shape = xtl::forward_sequence(s); return self_type(shape); } + template + template + inline xarray_container::xarray_container(xtensor_container&& rhs) + : base_type(inner_shape_type(rhs.shape().cbegin(), rhs.shape().cend()), + inner_strides_type(rhs.strides().cbegin(), rhs.strides().cend()), + inner_backstrides_type(rhs.backstrides().cbegin(), rhs.backstrides().cend()), + std::move(rhs.layout())), + m_storage(std::move(rhs.storage())) + { + } + + template + template + inline xarray_container& xarray_container::operator=(xtensor_container&& rhs) + { + this->shape_impl().assign(rhs.shape().cbegin(), rhs.shape().cend()); + this->strides_impl().assign(rhs.strides().cbegin(), rhs.strides().cend()); + this->backstrides_impl().assign(rhs.backstrides().cbegin(), rhs.backstrides().cend()); + this->mutable_layout() = rhs.layout(); + m_storage = std::move(rhs.storage()); + return *this; + } + /** * @name Extended copy semantic */ diff --git a/vendor/xtensor/include/xtensor/xassign.hpp b/vendor/xtensor/include/xtensor/xassign.hpp index 1b2f4c00d..86ea51ff3 100644 --- a/vendor/xtensor/include/xtensor/xassign.hpp +++ b/vendor/xtensor/include/xtensor/xassign.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -15,12 +16,16 @@ #include -#include "xconcepts.hpp" #include "xexpression.hpp" #include "xiterator.hpp" #include "xstrides.hpp" #include "xtensor_forward.hpp" #include "xutils.hpp" +#include "xfunction.hpp" + +#if defined(XTENSOR_USE_TBB) +#include +#endif namespace xt { @@ -74,7 +79,7 @@ namespace xt using base_type = xexpression_assigner_base; template - static void assign_xexpression(xexpression& e1, const xexpression& e2); + static void assign_xexpression(E1& e1, const E2& e2); template static void computed_assign(xexpression& e1, const xexpression& e2); @@ -88,15 +93,19 @@ namespace xt private: template - static bool resize(xexpression& e1, const xexpression& e2); + static bool resize(E1& e1, const E2& e2); + + template + static bool resize(E1& e1, const xfunction& e2); + }; - /***************** - * data_assigner * - *****************/ + /******************** + * stepper_assigner * + ********************/ template - class data_assigner + class stepper_assigner { public: @@ -107,7 +116,7 @@ namespace xt using size_type = typename lhs_iterator::size_type; using difference_type = typename lhs_iterator::difference_type; - data_assigner(E1& e1, const E2& e2); + stepper_assigner(E1& e1, const E2& e2); void run(); @@ -127,13 +136,45 @@ namespace xt index_type m_index; }; - /******************** - * trivial_assigner * - ********************/ + /******************* + * linear_assigner * + *******************/ template - struct trivial_assigner + class linear_assigner { + public: + + template + static void run(E1& e1, const E2& e2); + }; + + template <> + class linear_assigner + { + public: + + template + static void run(E1& e1, const E2& e2); + + private: + + template + static void run_impl(E1& e1, const E2& e2, std::true_type); + + template + static void run_impl(E1& e1, const E2& e2, std::false_type); + }; + + /************************* + * strided_loop_assigner * + *************************/ + + template + class strided_loop_assigner + { + public: + template static void run(E1& e1, const E2& e2); }; @@ -190,59 +231,28 @@ namespace xt namespace detail { template - inline bool is_trivial_broadcast(const E1& e1, const E2& e2) + constexpr bool linear_static_layout() { - return (E1::contiguous_layout && E2::contiguous_layout && (E1::static_layout == E2::static_layout)) - || e2.is_trivial_broadcast(e1.strides()); + // A row_major or column_major container with a dimension <= 1 is computed as + // layout any, leading to some performance improvements, for example when + // assigning a col-major vector to a row-major vector etc + return compute_layout(select_layout::value, + select_layout::value) != layout_type::dynamic; } - template - inline bool is_trivial_broadcast(const xview&, const E2&) + template + inline auto is_linear_assign(const E1& e1, const E2& e2) -> std::enable_if_t::value, bool> + { + return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout()) || + (e1.layout() != layout_type::dynamic && e2.has_linear_assign(e1.strides())); + } + + template + inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t::value, bool> { return false; } - template > - struct forbid_simd_assign - { - static constexpr bool value = true; - }; - - // Double steps check for xfunction because the default - // parameter void_t of forbid_simd_assign prevents additional - // specializations. - template - struct xfunction_forbid_simd; - - template - struct forbid_simd_assign().template load_simd(typename E::size_type(0)))>> - { - static constexpr bool value = false || xfunction_forbid_simd::value; - }; - - template - struct xfunction_forbid_simd - { - static constexpr bool value = false; - }; - - template - struct xfunction_forbid_simd> - { - static constexpr bool value = xtl::disjunction< - std::integral_constant::type>::value>...>::value; - }; - - template - struct has_simd_apply : std::false_type {}; - - template - struct has_simd_apply)>> - : std::true_type - { - }; - template struct has_step_leading : std::false_type { @@ -267,25 +277,49 @@ namespace xt static constexpr bool value = true; }; - template - struct use_strided_loop> + template + struct use_strided_loop> { - static constexpr bool value = xtl::conjunction>...>::value && - has_simd_apply>::value; + static constexpr bool value = xtl::conjunction>...>::value; }; } template - struct xassign_traits + class xassign_traits { - // constexpr methods instead of constexpr data members avoid the need of difinitions at namespace - // scope of these data members (since they are odr-used). + private: + + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + + template + using is_bool = std::is_same; + static constexpr bool contiguous_layout() { return E1::contiguous_layout && E2::contiguous_layout; } - static constexpr bool same_type() { return std::is_same::value; } - static constexpr bool simd_size() { return xsimd::simd_traits::size > 1; } - static constexpr bool forbid_simd() { return detail::forbid_simd_assign::value; } - static constexpr bool simd_assign() { return contiguous_layout() && same_type() && simd_size() && !forbid_simd(); } - static constexpr bool simd_strided_loop() { return same_type() && simd_size() && detail::use_strided_loop::value && detail::use_strided_loop::value; } + static constexpr bool convertible_types() { return std::is_convertible::value; } + + static constexpr bool use_xsimd() { return xt_simd::simd_traits::size > 1; } + + template + static constexpr bool simd_size_impl() { return xt_simd::simd_traits::size > 1 || (is_bool::value && use_xsimd()); } + static constexpr bool simd_size() { return simd_size_impl() && simd_size_impl(); } + static constexpr bool simd_interface() { return has_simd_interface(); } + static constexpr bool simd_assign() { return convertible_types() && simd_size() && simd_interface(); } + + public: + + // constexpr methods instead of constexpr data members avoid the need of definitions at namespace + // scope of these data members (since they are odr-used). + + static constexpr bool linear_assign(const E1& e1, const E2& e2, bool trivial) { return trivial && detail::is_linear_assign(e1, e2); } + static constexpr bool strided_assign() { return detail::use_strided_loop::value && detail::use_strided_loop::value; } + static constexpr bool simd_linear_assign() { return contiguous_layout() && simd_assign(); } + static constexpr bool simd_strided_assign() { return strided_assign() && simd_assign(); } + + using requested_value_type = std::conditional_t::value, + typename E2::bool_load_type, + e2_value_type>; + }; template @@ -293,30 +327,31 @@ namespace xt { E1& de1 = e1.derived_cast(); const E2& de2 = e2.derived_cast(); + using traits = xassign_traits; - bool trivial_broadcast = trivial && detail::is_trivial_broadcast(de1, de2); - - if (trivial_broadcast) + bool linear_assign = traits::linear_assign(de1, de2, trivial); + constexpr bool simd_linear_assign = traits::simd_linear_assign(); + constexpr bool simd_strided_assign = traits::simd_strided_assign(); + if (linear_assign) { - constexpr bool simd_assign = xassign_traits::simd_assign(); - trivial_assigner::run(de1, de2); + linear_assigner::run(de1, de2); } - else if (xassign_traits::simd_strided_loop()) + else if (simd_strided_assign) { - strided_assign(de1, de2, std::integral_constant::simd_strided_loop()>{}); + strided_loop_assigner::run(de1, de2); } else { - data_assigner assigner(de1, de2); + stepper_assigner assigner(de1, de2); assigner.run(); } } template template - inline void xexpression_assigner::assign_xexpression(xexpression& e1, const xexpression& e2) + inline void xexpression_assigner::assign_xexpression(E1& e1, const E2& e2) { - bool trivial_broadcast = resize(e1, e2); + bool trivial_broadcast = resize(e1.derived_cast(), e2.derived_cast()); base_type::assign_data(e1, e2, trivial_broadcast); } @@ -331,7 +366,7 @@ namespace xt const E2& de2 = e2.derived_cast(); size_type dim = de2.dimension(); - shape_type shape = xtl::make_sequence(dim, size_type(0)); + shape_type shape = uninitialized_shape(dim); bool trivial_broadcast = de2.broadcast_shape(shape, true); if (dim > de1.dimension() || shape > de1.shape()) @@ -372,26 +407,98 @@ namespace xt } } - template - template - inline bool xexpression_assigner::resize(xexpression& e1, const xexpression& e2) + namespace detail { - using shape_type = typename E1::shape_type; - using size_type = typename E1::size_type; - const E2& de2 = e2.derived_cast(); - size_type size = de2.dimension(); - shape_type shape = xtl::make_sequence(size, size_type(0)); - bool trivial_broadcast = de2.broadcast_shape(shape, true); - e1.derived_cast().resize(std::move(shape)); - return trivial_broadcast; + template + struct static_trivial_broadcast; + + template + struct static_trivial_broadcast + { + static constexpr bool value = detail::promote_index::shape_type...>::value; + }; + + template + struct static_trivial_broadcast + { + static constexpr bool value = false; + }; } - /******************************** - * data_assigner implementation * - ********************************/ + template + template + inline bool xexpression_assigner::resize(E1& e1, const E2& e2) + { + // If our RHS is not a xfunction, we know that the RHS is at least potentially trivial + // We check the strides of the RHS in detail::is_trivial_broadcast to see if they match up! + // So we can skip a shape copy and a call to broadcast_shape(...) + e1.resize(e2.shape()); + return true; + } + + template + template + inline bool xexpression_assigner::resize(E1& e1, const xfunction& e2) + { + return xtl::mpl::static_if::shape_type>::value>( + [&](auto /*self*/) { + /* + * If the shape of the xfunction is statically known, we can compute the broadcast triviality + * at compile time plus we can resize right away. + */ + // resize in case LHS is not a fixed size container. If it is, this is a NOP + e1.resize(typename xfunction::shape_type{}); + return detail::static_trivial_broadcast::shape_type>::value, CT...>::value; + }, + /* else */ [&](auto /*self*/) + { + using index_type = xindex_type_t; + using size_type = typename E1::size_type; + size_type size = e2.dimension(); + index_type shape = uninitialized_shape(size); + bool trivial_broadcast = e2.broadcast_shape(shape, true); + e1.resize(std::move(shape)); + return trivial_broadcast; + } + ); + } + + /*********************************** + * stepper_assigner implementation * + ***********************************/ + + template + struct is_narrowing_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_arithmetic::value && + (sizeof(result_type) < sizeof(argument_type) || + (std::is_integral::value && std::is_floating_point::value)); + }; + + template + struct has_sign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_signed::value != std::is_signed::value; + }; + + template + struct has_assign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = is_narrowing_conversion::value || + has_sign_conversion::value; + }; template - inline data_assigner::data_assigner(E1& e1, const E2& e2) + inline stepper_assigner::stepper_assigner(E1& e1, const E2& e2) : m_e1(e1), m_lhs(e1.stepper_begin(e1.shape())), m_rhs(e2.stepper_begin(e1.shape())), m_index(xtl::make_sequence(e1.shape().size(), size_type(0))) @@ -399,128 +506,152 @@ namespace xt } template - inline void data_assigner::run() + inline void stepper_assigner::run() { using size_type = typename E1::size_type; using argument_type = std::decay_t; using result_type = std::decay_t; - constexpr bool is_narrowing = is_narrowing_conversion::value; + constexpr bool needs_cast = has_assign_conversion::value; size_type s = m_e1.size(); for (size_type i = 0; i < s; ++i) { - *m_lhs = conditional_cast(*m_rhs); + *m_lhs = conditional_cast(*m_rhs); stepper_tools::increment_stepper(*this, m_index, m_e1.shape()); } } template - inline void data_assigner::step(size_type i) + inline void stepper_assigner::step(size_type i) { m_lhs.step(i); m_rhs.step(i); } template - inline void data_assigner::step(size_type i, size_type n) + inline void stepper_assigner::step(size_type i, size_type n) { m_lhs.step(i, n); m_rhs.step(i, n); } template - inline void data_assigner::reset(size_type i) + inline void stepper_assigner::reset(size_type i) { m_lhs.reset(i); m_rhs.reset(i); } template - inline void data_assigner::to_end(layout_type l) + inline void stepper_assigner::to_end(layout_type l) { m_lhs.to_end(l); m_rhs.to_end(l); } - /*********************************** - * trivial_assigner implementation * - ***********************************/ + /********************************** + * linear_assigner implementation * + **********************************/ template template - inline void trivial_assigner::run(E1& e1, const E2& e2) + inline void linear_assigner::run(E1& e1, const E2& e2) { - using lhs_align_mode = xsimd::container_alignment_t; + using lhs_align_mode = xt_simd::container_alignment_t; constexpr bool is_aligned = std::is_same::value; using rhs_align_mode = std::conditional_t; - using value_type = std::common_type_t; - using simd_type = xsimd::simd_type; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = xt_simd::simd_type; using size_type = typename E1::size_type; size_type size = e1.size(); - size_type simd_size = simd_type::size; + constexpr size_type simd_size = simd_type::size; + constexpr bool needs_cast = has_assign_conversion::value; - size_type align_begin = is_aligned ? 0 : xsimd::get_alignment_offset(e1.data(), size, simd_size); + size_type align_begin = is_aligned ? 0 : xt_simd::get_alignment_offset(e1.data(), size, simd_size); size_type align_end = align_begin + ((size - align_begin) & ~(simd_size - 1)); for (size_type i = 0; i < align_begin; ++i) { - e1.data_element(i) = e2.data_element(i); + e1.data_element(i) = conditional_cast(e2.data_element(i)); } + +#if defined(XTENSOR_USE_TBB) + tbb::parallel_for(align_begin, align_end, simd_size, [&](size_t i) + { + e1.template store_simd(i, e2.template load_simd(i)); + }); +#elif defined(XTENSOR_USE_OPENMP) + #pragma omp parallel for default(none) shared(align_begin, align_end, e1, e2) for (size_type i = align_begin; i < align_end; i += simd_size) { - e1.template store_simd(i, e2.template load_simd(i)); + e1.template store_simd(i, e2.template load_simd(i)); } +#else + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } +#endif for (size_type i = align_end; i < size; ++i) { - e1.data_element(i) = e2.data_element(i); + e1.data_element(i) = conditional_cast(e2.data_element(i)); } } - namespace assigner_detail - { - template - inline void assign_loop(It src, Ot dst, std::size_t n) - { - for(; n > 0; --n) - { - *dst = static_cast(*src); - ++src; - ++dst; - } - } - - template - inline void trivial_assigner_run_impl(E1& e1, const E2& e2, std::true_type) - { - using size_type = typename E1::size_type; - auto src = e2.storage_cbegin(); - auto dst = e1.storage_begin(); - assign_loop(src, dst, e1.size()); - } - - template - inline void trivial_assigner_run_impl(E1&, const E2&, std::false_type) - { - XTENSOR_PRECONDITION(false, - "Internal error: trivial_assigner called with unrelated types."); - } - } - - template <> template - inline void trivial_assigner::run(E1& e1, const E2& e2) + inline void linear_assigner::run(E1& e1, const E2& e2) { - using is_convertible = std::is_convertible::value_type, - typename std::decay_t::value_type>; + using is_convertible = std::is_convertible::value_type, + typename std::decay_t::value_type>; // If the types are not compatible, this function is still instantiated but never called. // To avoid compilation problems in effectively unused code trivial_assigner_run_impl is // empty in this case. - assigner_detail::trivial_assigner_run_impl(e1, e2, is_convertible()); + run_impl(e1, e2, is_convertible()); } - /*********************** - * Strided assign loop * - ***********************/ + template + inline void linear_assigner::run_impl(E1& e1, const E2& e2, std::true_type /*is_convertible*/) + { + using value_type = typename E1::value_type; + using size_type = typename E1::size_type; + auto src = linear_begin(e2); + auto dst = linear_begin(e1); + size_type n = e1.size(); + +#if defined(XTENSOR_USE_TBB) + tbb::parallel_for(std::ptrdiff_t(0), static_cast(n), [&](std::ptrdiff_t i) + { + *(dst + i) = static_cast(*(src + i)); + }); +#elif defined(XTENSOR_USE_OPENMP) + #pragma omp parallel for default(none) shared(src, dst, n) + for (std::ptrdiff_t i = std::ptrdiff_t(0); i < static_cast(n) ; i++) + { + *(dst + i) = static_cast(*(src + i)); + } +#else + for (; n > size_type(0); --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } +#endif + } + + template + inline void linear_assigner::run_impl(E1&, const E2&, std::false_type /*is_convertible*/) + { + XTENSOR_PRECONDITION(false, + "Internal error: linear_assigner called with unrelated types."); + + } + + /**************************************** + * strided_loop_assigner implementation * + ****************************************/ namespace strided_assign_detail { @@ -614,35 +745,35 @@ namespace xt return m_cut; } - template - std::size_t operator()(const xt::xfunction& xf) + template + std::size_t operator()(const xt::xfunction& xf) { xt::for_each(*this, xf.arguments()); return m_cut; } - private: + private: std::size_t m_cut; const strides_type& m_strides; }; template - auto get_loop_sizes(const E1& e1, const E2& e2) + auto get_loop_sizes(const E1& e1, const E2& e2, bool is_row_major) { std::size_t cut = 0; - // TODO! if E1 is !contigous --> initialize cut to sensible value! - if (e1.strides().back() == 1) + // TODO! if E1 is !contiguous --> initialize cut to sensible value! + if (E1::static_layout == layout_type::row_major || is_row_major) { auto csf = check_strides_functor(e1.strides()); cut = csf(e2); } - else if (e1.strides().front() == 1) + else if (E1::static_layout == layout_type::column_major || !is_row_major) { auto csf = check_strides_functor(e1.strides()); cut = csf(e2); - } + } // can't reach here because this would have already triggered the fallback using shape_value_type = typename E1::shape_type::value_type; std::size_t outer_loop_size = static_cast( @@ -652,7 +783,7 @@ namespace xt std::accumulate(e1.shape().begin() + static_cast(cut), e1.shape().end(), shape_value_type(1), std::multiplies{})); - if (e1.strides().back() != 1) // column major mode + if (E1::static_layout == layout_type::column_major || !is_row_major) { std::swap(outer_loop_size, inner_loop_size); } @@ -661,73 +792,80 @@ namespace xt } } + template template - void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/) + inline void strided_loop_assigner::run(E1& e1, const E2& e2) { - bool fallback = false, is_row_major = true; + bool is_row_major = true; + using fallback_assigner = stepper_assigner; - std::size_t inner_loop_size, outer_loop_size, cut; - std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2); - - if (E1::static_layout == layout_type::row_major || e1.strides().back() == 1) // row major case + if (E1::static_layout == layout_type::dynamic) { - if (cut == e1.dimension()) + layout_type dynamic_layout = e1.layout(); + switch (dynamic_layout) { - fallback = true; + case layout_type::row_major: + is_row_major = true; + break; + case layout_type::column_major: + is_row_major = false; + break; + default: + return fallback_assigner(e1, e2).run(); } } - else if (E1::static_layout == layout_type::column_major || e1.strides().front() == 1) // col major case + else if (E1::static_layout == layout_type::row_major) + { + is_row_major = true; + } + else if (E1::static_layout == layout_type::column_major) { is_row_major = false; - if (cut == 0) - { - fallback = true; - } } else { - fallback = true; + throw std::runtime_error("Illegal layout set (layout_type::any?)."); } - if (fallback) + std::size_t inner_loop_size, outer_loop_size, cut; + std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2, is_row_major); + + if ((is_row_major && cut == e1.dimension()) || (!is_row_major && cut == 0)) { - data_assigner assigner(e1, e2); - assigner.run(); - return; + return fallback_assigner(e1, e2).run(); } // TODO can we get rid of this and use `shape_type`? - dynamic_shape idx; + dynamic_shape idx, max_shape; - using iterator_type = decltype(e1.shape().begin()); - iterator_type max_shape_begin, max_shape_end; if (is_row_major) { xt::resize_container(idx, cut); - max_shape_begin = e1.shape().begin(); - max_shape_end = e1.shape().begin() + static_cast(cut); + max_shape.assign(e1.shape().begin(), e1.shape().begin() + static_cast(cut)); } else { xt::resize_container(idx, e1.shape().size() - cut); - max_shape_begin = e1.shape().begin() + static_cast(cut); - max_shape_end = e1.shape().end(); + max_shape.assign(e1.shape().begin() + static_cast(cut), e1.shape().end()); } // add this when we have std::array index! // std::fill(idx.begin(), idx.end(), 0); - - dynamic_shape max(max_shape_begin, max_shape_end); - - using simd_type = xsimd::simd_type; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + constexpr bool needs_cast = has_assign_conversion::value; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = std::conditional_t::value, + xt_simd::simd_bool_type, + xt_simd::simd_type>; std::size_t simd_size = inner_loop_size / simd_type::size; std::size_t simd_rest = inner_loop_size % simd_type::size; auto fct_stepper = e2.stepper_begin(e1.shape()); auto res_stepper = e1.stepper_begin(e1.shape()); - - // TODO in 1D case this is ambigous -- could be RM or CM. + + // TODO in 1D case this is ambigous -- could be RM or CM. // Use default layout to make decision std::size_t step_dim = 0; if (!is_row_major) // row major case @@ -737,20 +875,20 @@ namespace xt for (std::size_t ox = 0; ox < outer_loop_size; ++ox) { - for (std::size_t i = 0; i < simd_size; i++) + for (std::size_t i = 0; i < simd_size; ++i) { - res_stepper.template store_simd(fct_stepper.template step_simd()); + res_stepper.template store_simd(fct_stepper.template step_simd()); } for (std::size_t i = 0; i < simd_rest; ++i) { - *(res_stepper) = *(fct_stepper); + *(res_stepper) = conditional_cast(*(fct_stepper)); res_stepper.step_leading(); fct_stepper.step_leading(); } is_row_major ? - strided_assign_detail::idx_tools::next_idx(idx, max) : - strided_assign_detail::idx_tools::next_idx(idx, max); + strided_assign_detail::idx_tools::next_idx(idx, max_shape) : + strided_assign_detail::idx_tools::next_idx(idx, max_shape); fct_stepper.to_begin(); @@ -774,8 +912,9 @@ namespace xt } } + template <> template - inline void strided_assign(E1& /*e1*/, const E2& /*e2*/, std::false_type /*disable*/) + inline void strided_loop_assigner::run(E1& /*e1*/, const E2& /*e2*/) { } } diff --git a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp index e544791b8..3c3cfb632 100644 --- a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp +++ b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * diff --git a/vendor/xtensor/include/xtensor/xbroadcast.hpp b/vendor/xtensor/include/xtensor/xbroadcast.hpp index 77c04f041..121981dae 100644 --- a/vendor/xtensor/include/xtensor/xbroadcast.hpp +++ b/vendor/xtensor/include/xtensor/xbroadcast.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -19,6 +20,7 @@ #include +#include "xaccessible.hpp" #include "xexpression.hpp" #include "xiterable.hpp" #include "xscalar.hpp" @@ -43,6 +45,31 @@ namespace xt auto broadcast(E&& e, const I (&s)[L]); #endif + /************************* + * xbroadcast extensions * + *************************/ + + namespace extension + { + template + struct xbroadcast_base_impl; + + template + struct xbroadcast_base_impl + { + using type = xtensor_empty_base; + }; + + template + struct xbroadcast_base + : xbroadcast_base_impl, CT, X> + { + }; + + template + using xbroadcast_base_t = typename xbroadcast_base::type; + } + /************** * xbroadcast * **************/ @@ -59,6 +86,43 @@ namespace xt using stepper = const_stepper; }; + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using reference = typename xexpression_type::const_reference; + using const_reference = typename xexpression_type::const_reference; + using size_type = typename xexpression_type::size_type; + }; + + /***************************** + * linear_begin / linear_end * + *****************************/ + + template + XTENSOR_CONSTEXPR_RETURN auto linear_begin(xbroadcast& c) noexcept + { + return linear_begin(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_end(xbroadcast& c) noexcept + { + return linear_end(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xbroadcast& c) noexcept + { + return linear_begin(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_end(const xbroadcast& c) noexcept + { + return linear_end(c.expression()); + } + /** * @class xbroadcast * @brief Broadcasted xexpression to a specified shape. @@ -73,20 +137,25 @@ namespace xt * @sa broadcast */ template - class xbroadcast : public xexpression>, - public xconst_iterable> + class xbroadcast : public xsharable_expression>, + public xconst_iterable>, + public xconst_accessible>, + public extension::xbroadcast_base_t { public: using self_type = xbroadcast; using xexpression_type = std::decay_t; + using extension_base = extension::xbroadcast_base_t; + using expression_tag = typename extension_base::expression_tag; + using inner_types = xcontainer_inner_types; using value_type = typename xexpression_type::value_type; - using reference = typename xexpression_type::reference; - using const_reference = typename xexpression_type::const_reference; - using pointer = typename xexpression_type::pointer; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename xexpression_type::const_pointer; using const_pointer = typename xexpression_type::const_pointer; - using size_type = typename xexpression_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename xexpression_type::difference_type; using iterable_base = xconst_iterable; @@ -96,41 +165,37 @@ namespace xt using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; - static constexpr layout_type static_layout = xexpression_type::static_layout; - //static constexpr bool contiguous_layout = xexpression_type::contiguous_layout; + using bool_load_type = typename xexpression_type::bool_load_type; + + static constexpr layout_type static_layout = layout_type::dynamic; static constexpr bool contiguous_layout = false; template - xbroadcast(CTA&& e, S&& s); + xbroadcast(CTA&& e, const S& s); + + template + xbroadcast(CTA&& e, shape_type&& s); - size_type size() const noexcept; - size_type dimension() const noexcept; const inner_shape_type& shape() const noexcept; + size_type shape(size_type i) const noexcept; layout_type layout() const noexcept; template const_reference operator()(Args... args) const; - template - const_reference at(Args... args) const; - template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; - template const_reference element(It first, It last) const; + const xexpression_type& expression() const noexcept; + template bool broadcast_shape(S& shape, bool reuse_cache = false) const; template - bool is_trivial_broadcast(const S& strides) const noexcept; + bool has_linear_assign(const S& strides) const noexcept; template const_stepper stepper_begin(const S& shape) const noexcept; @@ -140,6 +205,12 @@ namespace xt template ::value>> void assign_to(xexpression& e) const; + template + using rebind_t = xbroadcast; + + template + rebind_t build_broadcast(E&& e) const; + private: CT m_e; @@ -164,8 +235,7 @@ namespace xt inline auto broadcast(E&& e, const S& s) { using broadcast_type = xbroadcast, S>; - using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), s); } #ifdef X_OLD_CLANG @@ -174,7 +244,7 @@ namespace xt { using broadcast_type = xbroadcast, std::vector>; using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); } #else template @@ -182,7 +252,7 @@ namespace xt { using broadcast_type = xbroadcast, std::array>; using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); } #endif @@ -203,8 +273,29 @@ namespace xt */ template template - inline xbroadcast::xbroadcast(CTA&& e, S&& s) - : m_e(std::forward(e)), m_shape(std::forward(s)) + inline xbroadcast::xbroadcast(CTA&& e, const S& s) + : m_e(std::forward(e)) + { + if (s.size() < m_e.dimension()) + { + throw xt::broadcast_error("Broadcast shape has fewer elements than original expression."); + } + xt::resize_container(m_shape, s.size()); + std::copy(s.begin(), s.end(), m_shape.begin()); + xt::broadcast_shape(m_e.shape(), m_shape); + } + + /** + * Constructs an xbroadcast expression broadcasting the specified + * \ref xexpression to the given shape + * + * @param e the expression to broadcast + * @param s the shape to apply + */ + template + template + inline xbroadcast::xbroadcast(CTA&& e, shape_type&& s) + : m_e(std::forward(e)), m_shape(std::move(s)) { xt::broadcast_shape(m_e.shape(), m_shape); } @@ -213,24 +304,7 @@ namespace xt /** * @name Size and shape */ - /** - * Returns the size of the expression. - */ - template - inline auto xbroadcast::size() const noexcept -> size_type - { - return compute_size(shape()); - } - - /** - * Returns the number of dimensions of the expression. - */ - template - inline auto xbroadcast::dimension() const noexcept -> size_type - { - return m_shape.size(); - } - + //@{ /** * Returns the shape of the expression. */ @@ -240,6 +314,15 @@ namespace xt return m_shape; } + /** + * Returns the shape of the expression. + */ + template + inline auto xbroadcast::shape(size_type i) const noexcept -> size_type + { + return m_shape[i]; + } + /** * Returns the layout_type of the expression. */ @@ -266,23 +349,6 @@ namespace xt return m_e(args...); } - /** - * Returns a constant reference to the element at the specified position in the expression, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the function. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the expression. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xbroadcast::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a constant reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the expression. Indices @@ -309,33 +375,6 @@ namespace xt return this->operator()(args...); } - /** - * Returns a constant reference to the element at the specified position in the expression. - * @param index a sequence of indices specifying the position in the function. Indices - * must be unsigned integers, the number of indices in the sequence should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xbroadcast::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xbroadcast::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xbroadcast::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a constant reference to the element at the specified position in the expression. * @param first iterator starting the sequence of indices @@ -347,7 +386,16 @@ namespace xt template inline auto xbroadcast::element(It, It last) const -> const_reference { - return m_e.element(last - dimension(), last); + return m_e.element(last - this->dimension(), last); + } + + /** + * Returns a constant reference to the underlying expression of the broadcast expression. + */ + template + inline auto xbroadcast::expression() const noexcept -> const xexpression_type& + { + return m_e; } //@} @@ -369,17 +417,17 @@ namespace xt } /** - * Compares the specified strides with those of the container to see whether - * the broadcasting is trivial. - * @return a boolean indicating whether the broadcasting is trivial + * Checks whether the xbroadcast can be linearly assigned to an expression + * with the specified strides. + * @return a boolean indicating whether a linear assign is possible */ template template - inline bool xbroadcast::is_trivial_broadcast(const S& strides) const noexcept + inline bool xbroadcast::has_linear_assign(const S& strides) const noexcept { - return dimension() == m_e.dimension() && + return this->dimension() == m_e.dimension() && std::equal(m_shape.cbegin(), m_shape.cend(), m_e.shape().cbegin()) && - m_e.is_trivial_broadcast(strides); + m_e.has_linear_assign(strides); } //@} @@ -407,6 +455,13 @@ namespace xt ed.resize(m_shape); std::fill(ed.begin(), ed.end(), m_e()); } + + template + template + inline auto xbroadcast::build_broadcast(E&& e) const -> rebind_t + { + return rebind_t(std::forward(e), inner_shape_type(m_shape)); + } } #endif diff --git a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp index d8d331685..6bec4f3be 100644 --- a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp +++ b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -21,14 +22,13 @@ namespace xt { - /****************************** - * xbuffer_adator declaration * - ******************************/ struct no_ownership { }; + using smart_ownership = no_ownership; + struct acquire_ownership { }; @@ -36,9 +36,9 @@ namespace xt template >>> class xbuffer_adaptor; - /********************************* - * xbuffer_adator implementation * - *********************************/ + /******************** + * buffer_storage_t * + ********************/ namespace detail { @@ -49,6 +49,7 @@ namespace xt using self_type = xbuffer_storage; using allocator_type = A; + using destructor_type = allocator_type; using value_type = typename allocator_type::value_type; using reference = std::conditional_t>>::value, typename allocator_type::const_reference, @@ -80,6 +81,46 @@ namespace xt size_type m_size; }; + template + class xbuffer_smart_pointer + { + public: + + using self_type = xbuffer_storage; + using destructor_type = D; + using value_type = std::remove_const_t>>; + using allocator_type = std::allocator; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_smart_pointer(); + + template + xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + pointer p_data; + size_type m_size; + destructor_type m_destruct; + }; + template class xbuffer_owner_storage { @@ -87,6 +128,7 @@ namespace xt using self_type = xbuffer_owner_storage; using allocator_type = A; + using destructor_type = allocator_type; using value_type = typename allocator_type::value_type; using reference = std::conditional_t>>::value, typename allocator_type::const_reference, @@ -130,10 +172,41 @@ namespace xt allocator_type m_allocator; }; + // Workaround for MSVC2015: using void_t results in some + // template instantiation caching that leads to wrong + // type deduction later in xfunction. + template + struct msvc2015_void + { + using type = void; + }; + + template + using msvc2015_void_t = typename msvc2015_void::type; + + template + struct is_lambda_type : std::false_type + { + }; + + // check if operator() is available + template + struct is_lambda_type> + : std::true_type + { + }; + + template + struct self_type + { + using type = T; + }; template struct get_buffer_storage { - using type = xbuffer_storage; + using type = xtl::mpl::eval_if_t, + self_type>, + self_type>>; }; template @@ -142,37 +215,165 @@ namespace xt using type = xbuffer_owner_storage; }; + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + template using buffer_storage_t = typename get_buffer_storage::type; } - template - class xbuffer_adaptor : private detail::buffer_storage_t + /************************ + * xbuffer_adaptor_base * + ************************/ + + template + struct buffer_inner_types; + + template + class xbuffer_adaptor_base { public: + using self_type = xbuffer_adaptor_base; + using derived_type = D; + using inner_types = buffer_inner_types; + using value_type = typename inner_types::value_type; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename inner_types::pointer; + using const_pointer = typename inner_types::const_pointer; + using size_type = typename inner_types::size_type; + using difference_type = typename inner_types::difference_type; + using iterator = typename inner_types::iterator; + using const_iterator = typename inner_types::const_iterator; + using reverse_iterator = typename inner_types::reverse_iterator; + using const_reverse_iterator = typename inner_types::const_reverse_iterator; + using index_type = typename inner_types::index_type; + + bool empty() const noexcept; + + reference operator[](size_type i); + const_reference operator[](size_type i) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + iterator begin() noexcept; + iterator end() noexcept; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + reverse_iterator rbegin() noexcept; + reverse_iterator rend() noexcept; + + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + derived_type& derived_cast() noexcept; + const derived_type& derived_cast() const noexcept; + + protected: + + xbuffer_adaptor_base() = default; + ~xbuffer_adaptor_base() = default; + + xbuffer_adaptor_base(const self_type&) = default; + self_type& operator=(const self_type&) = default; + + xbuffer_adaptor_base(self_type&&) = default; + self_type& operator=(self_type&&) = default; + }; + + template + bool operator==(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator!=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator<(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator<=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator>(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator>=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + /******************* + * xbuffer_adaptor * + *******************/ + + template + struct buffer_inner_types> + { using base_type = detail::buffer_storage_t; - using self_type = xbuffer_adaptor; - using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using pointer = typename base_type::pointer; using const_pointer = typename base_type::const_pointer; - using temporary_type = uvector; - using size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; - using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using index_type = size_type; + }; + + template + class xbuffer_adaptor : private detail::buffer_storage_t, + public xbuffer_adaptor_base> + { + public: + + using self_type = xbuffer_adaptor; + using base_type = detail::buffer_storage_t; + using buffer_base_type = xbuffer_adaptor_base; + using allocator_type = typename base_type::allocator_type; + using destructor_type = typename base_type::destructor_type; + using value_type = typename buffer_base_type::value_type; + using reference = typename buffer_base_type::reference; + using const_reference = typename buffer_base_type::const_reference; + using pointer = typename buffer_base_type::pointer; + using const_pointer = typename buffer_base_type::const_pointer; + using size_type = typename buffer_base_type::size_type; + using difference_type = typename buffer_base_type::difference_type; + using iterator = typename buffer_base_type::iterator; + using const_iterator = typename buffer_base_type::const_iterator; + using reverse_iterator = typename buffer_base_type::reverse_iterator; + using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator; + using temporary_type = uvector; xbuffer_adaptor() = default; - template - xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + using base_type::base_type; ~xbuffer_adaptor() = default; @@ -184,67 +385,93 @@ namespace xt self_type& operator=(temporary_type&&); - bool empty() const noexcept; using base_type::size; using base_type::resize; - - reference operator[](size_type i); - const_reference operator[](size_type i) const; - - reference front(); - const_reference front() const; - - reference back(); - const_reference back() const; - - iterator begin(); - iterator end(); - - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; - - reverse_iterator rbegin(); - reverse_iterator rend(); - - const_reverse_iterator rbegin() const; - const_reverse_iterator rend() const; - const_reverse_iterator crbegin() const; - const_reverse_iterator crend() const; - using base_type::data; using base_type::swap; }; - template - bool operator==(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator!=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator<(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator<=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator>(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator>=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - template void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept; + /********************* + * xiterator_adaptor * + *********************/ + + template + class xiterator_adaptor; + + template + struct buffer_inner_types> + { + using traits = std::iterator_traits; + using const_traits = std::iterator_traits; + + using value_type = std::common_type_t; + using reference = typename traits::reference; + using const_reference = typename const_traits::reference; + using pointer = typename traits::pointer; + using const_pointer = typename const_traits::pointer; + using difference_type = std::common_type_t; + using size_type = std::make_unsigned_t; + + using iterator = I; + using const_iterator = CI; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using index_type = difference_type; + }; + + template + class xiterator_adaptor : public xbuffer_adaptor_base> + { + public: + + using self_type = xiterator_adaptor; + using base_type = xbuffer_adaptor_base; + using value_type = typename base_type::value_type; + using allocator_type = std::allocator; + using size_type = typename base_type::size_type; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using temporary_type = uvector; + + xiterator_adaptor() = default; + xiterator_adaptor(I it, CI cit, size_type size); + + ~xiterator_adaptor() = default; + + xiterator_adaptor(const self_type&) = default; + xiterator_adaptor& operator=(const self_type&) = default; + + xiterator_adaptor(self_type&&) = default; + xiterator_adaptor& operator=(self_type&&) = default; + + xiterator_adaptor& operator=(const temporary_type& rhs); + xiterator_adaptor& operator=(temporary_type&& rhs); + + size_type size() const noexcept; + void resize(size_type size); + + iterator data() noexcept; + const_iterator data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + I m_it; + CI m_cit; + size_type m_size; + }; + + template + void swap(xiterator_adaptor& lhs, + xiterator_adaptor& rhs) noexcept; + /************************************ * temporary_container metafunction * ************************************/ @@ -261,6 +488,12 @@ namespace xt using type = typename xbuffer_adaptor::temporary_type; }; + template + struct temporary_container> + { + using type = typename xiterator_adaptor::temporary_type; + }; + template using temporary_container_t = typename temporary_container::type; @@ -378,7 +611,6 @@ namespace xt inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& { swap(rhs); - rhs.m_moved_from = true; return *this; } @@ -429,195 +661,320 @@ namespace xt } } + /**************************************** + * xbuffer_smart_pointer implementation * + ****************************************/ + + namespace detail + { + template + template + xbuffer_smart_pointer::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct) + : p_data(data_ptr), m_size(size), m_destruct(std::forward

(destruct)) + { + } + + template + auto xbuffer_smart_pointer::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_smart_pointer::resize(size_type size) + { + if (m_size != size) + { + throw std::runtime_error("xbuffer_storage not resizable"); + } + } + + template + auto xbuffer_smart_pointer::data() noexcept -> pointer + { + return p_data; + } + template + auto xbuffer_smart_pointer::data() const noexcept -> const_pointer + { + return p_data; + } + + template + void xbuffer_smart_pointer::swap(self_type& rhs) noexcept + { + using std::swap; + swap(p_data, rhs.p_data); + swap(m_size, rhs.m_size); + swap(m_destruct, rhs.m_destruct); + } + } + + /*************************************** + * xbuffer_adaptor_base implementation * + ***************************************/ + + template + inline bool xbuffer_adaptor_base::empty() const noexcept + { + return derived_cast().size() == size_type(0); + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) -> reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) const -> const_reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::front() -> reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::front() const -> const_reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::back() -> reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::back() const -> const_reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::begin() noexcept -> iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() noexcept-> iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::begin() const noexcept -> const_iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() const noexcept -> const_iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::cbegin() const noexcept -> const_iterator + { + return begin(); + } + + template + inline auto xbuffer_adaptor_base::cend() const noexcept -> const_iterator + { + return end(); + } + + template + inline auto xbuffer_adaptor_base::rbegin() noexcept-> reverse_iterator + { + return reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() noexcept -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::rbegin() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + template + inline auto xbuffer_adaptor_base::crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + template + inline bool operator==(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return lhs.derived_cast().size() == rhs.derived_cast().size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + inline bool operator!=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less()); + } + + template + inline bool operator<=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less_equal()); + } + + template + inline bool operator>(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater()); + } + + template + inline bool operator>=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater_equal()); + } + /********************************** * xbuffer_adaptor implementation * **********************************/ - template - template - inline xbuffer_adaptor::xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc) - : base_type(std::forward

(data), size, alloc) - { - } - template inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& { base_type::resize(tmp.size()); - std::copy(tmp.cbegin(), tmp.cend(), begin()); + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); return *this; } - template - bool xbuffer_adaptor::empty() const noexcept - { - return size() == 0; - } - - template - inline auto xbuffer_adaptor::operator[](size_type i) -> reference - { - return data()[i]; - } - - template - inline auto xbuffer_adaptor::operator[](size_type i) const -> const_reference - { - return data()[i]; - } - - template - inline auto xbuffer_adaptor::front() -> reference - { - return data()[0]; - } - - template - inline auto xbuffer_adaptor::front() const -> const_reference - { - return data()[0]; - } - - template - inline auto xbuffer_adaptor::back() -> reference - { - return data()[size() - 1]; - } - - template - inline auto xbuffer_adaptor::back() const -> const_reference - { - return data()[size() - 1]; - } - - template - inline auto xbuffer_adaptor::begin() -> iterator - { - return data(); - } - - template - inline auto xbuffer_adaptor::end() -> iterator - { - return data() + size(); - } - - template - inline auto xbuffer_adaptor::begin() const -> const_iterator - { - return data(); - } - - template - inline auto xbuffer_adaptor::end() const -> const_iterator - { - return data() + size(); - } - - template - inline auto xbuffer_adaptor::cbegin() const -> const_iterator - { - return begin(); - } - - template - inline auto xbuffer_adaptor::cend() const -> const_iterator - { - return end(); - } - - template - inline auto xbuffer_adaptor::rbegin() -> reverse_iterator - { - return reverse_iterator(end()); - } - - template - inline auto xbuffer_adaptor::rend() -> reverse_iterator - { - return reverse_iterator(begin()); - } - - template - inline auto xbuffer_adaptor::rbegin() const -> const_reverse_iterator - { - return const_reverse_iterator(end()); - } - - template - inline auto xbuffer_adaptor::rend() const -> const_reverse_iterator - { - return const_reverse_iterator(begin()); - } - - template - inline auto xbuffer_adaptor::crbegin() const -> const_reverse_iterator - { - return rbegin(); - } - - template - inline auto xbuffer_adaptor::crend() const -> const_reverse_iterator - { - return rend(); - } - - template - inline bool operator==(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - - template - inline bool operator!=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return !(lhs == rhs); - } - - template - inline bool operator<(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::less()); - } - - template - inline bool operator<=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::less_equal()); - } - - template - inline bool operator>(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::greater()); - } - - template - inline bool operator>=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::greater_equal()); - } - template inline void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept { lhs.swap(rhs); } + + /************************************ + * xiterator_adaptor implementation * + ************************************/ + + template + inline xiterator_adaptor::xiterator_adaptor(I it, CI cit, size_type size) + : m_it(it), m_cit(cit), m_size(size) + { + } + + template + inline auto xiterator_adaptor::operator=(const temporary_type& rhs) -> self_type& + { + resize(rhs.size()); + std::copy(rhs.cbegin(), rhs.cend(), m_it); + return *this; + } + + template + inline auto xiterator_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + return (*this = rhs); + } + + template + inline auto xiterator_adaptor::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xiterator_adaptor::resize(size_type size) + { + if (m_size != size) + { + throw std::runtime_error("xiterator_adaptor not resizable"); + } + } + + template + inline auto xiterator_adaptor::data() noexcept -> iterator + { + return m_it; + } + + template + inline auto xiterator_adaptor::data() const noexcept -> const_iterator + { + return m_cit; + } + + template + inline void xiterator_adaptor::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_it, rhs.m_it); + swap(m_cit, rhs.m_cit); + swap(m_size, rhs.m_size); + } + + template + inline void swap(xiterator_adaptor& lhs, + xiterator_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } } #endif diff --git a/vendor/xtensor/include/xtensor/xbuilder.hpp b/vendor/xtensor/include/xtensor/xbuilder.hpp index c3e34b8ac..dfbb2f3cd 100644 --- a/vendor/xtensor/include/xtensor/xbuilder.hpp +++ b/vendor/xtensor/include/xtensor/xbuilder.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -14,6 +15,7 @@ #define XTENSOR_BUILDER_HPP #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include +#include #include "xbroadcast.hpp" #include "xfunction.hpp" @@ -111,7 +114,7 @@ namespace xt inline xtensor empty(const std::array& shape) { using shape_type = typename xtensor::shape_type; - return xtensor(xtl::forward_sequence(shape)); + return xtensor(xtl::forward_sequence(shape)); } #ifndef X_OLD_CLANG @@ -119,7 +122,13 @@ namespace xt inline xtensor empty(const I(&shape)[N]) { using shape_type = typename xtensor::shape_type; - return xtensor(xtl::forward_sequence(shape)); + return xtensor(xtl::forward_sequence(shape)); + } +#else + template + inline xarray empty(const std::initializer_list& init) + { + return xarray::from_shape(init); } #endif @@ -136,9 +145,10 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type empty_like(const xexpression& e) + inline auto empty_like(const xexpression& e) { - typename E::temporary_type res(e.derived_cast().shape()); + using xtype = temporary_type_t; + auto res = xtype::from_shape(e.derived_cast().shape()); return res; } @@ -150,9 +160,11 @@ namespace xt * @param fill_value the value used to set each element of the returned xcontainer. */ template - inline typename E::temporary_type full_like(const xexpression& e, typename E::value_type fill_value) + inline auto full_like(const xexpression& e, typename E::value_type fill_value) { - typename E::temporary_type res(e.derived_cast().shape(), fill_value); + using xtype = temporary_type_t; + auto res = xtype::from_shape(e.derived_cast().shape()); + res.fill(fill_value); return res; } @@ -166,7 +178,7 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type zeros_like(const xexpression& e) + inline auto zeros_like(const xexpression& e) { return full_like(e, typename E::value_type(0)); } @@ -181,68 +193,130 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type ones_like(const xexpression& e) + inline auto ones_like(const xexpression& e) { return full_like(e, typename E::value_type(1)); } namespace detail { - template - class arange_impl + template + struct get_mult_type_impl + { + using type = T; + }; + + template + struct get_mult_type_impl> + { + using type = R; + }; + + template + using get_mult_type = typename get_mult_type_impl::type; + + // These methods should be private methods of arange_generator, however thi leads + // to ICE on VS2015 + template )> + inline void arange_assign_to(xexpression& e, U start, X step) noexcept + { + auto& de = e.derived_cast(); + U value = start; + + for (auto&& el : de.storage()) + { + el = static_cast(value); + value += step; + } + } + + template >)> + inline void arange_assign_to(xexpression& e, U start, X step) noexcept + { + auto& buf = e.derived_cast().storage(); + using size_type = decltype(buf.size()); + using mult_type = get_mult_type; + for(size_type i = 0; i < buf.size(); ++i) + { + buf[i] = static_cast(start + step * mult_type(i)); + } + } + + template + class arange_generator { public: - using value_type = T; + using value_type = R; + using step_type = S; - arange_impl(T start, T stop, T step) + arange_generator(T start, T stop, S step) : m_start(start), m_stop(stop), m_step(step) { } template - inline T operator()(Args... args) const + inline R operator()(Args... args) const { return access_impl(args...); } template - inline T element(It first, It) const + inline R element(It first, It) const { - return m_start + m_step * T(*first); + // Avoids warning when T = char (because char + char => int!) + using mult_type = get_mult_type; + return static_cast(m_start + m_step * mult_type(*first)); } template inline void assign_to(xexpression& e) const noexcept { - auto& de = e.derived_cast(); - value_type value = m_start; - - for (auto& el : de.storage()) - { - el = value; - value += m_step; - } + arange_assign_to(e, m_start, m_step); } private: - value_type m_start; - value_type m_stop; - value_type m_step; + T m_start; + T m_stop; + step_type m_step; template - inline T access_impl(T1 t, Args...) const + inline R access_impl(T1 t, Args...) const { - return m_start + m_step * T(t); + using mult_type = get_mult_type; + return static_cast(m_start + m_step * mult_type(t)); } - inline T access_impl() const + inline R access_impl() const { - return m_start; + return static_cast(m_start); } }; + template + using both_integer = xtl::conjunction, std::is_integral>; + + template >)> + inline auto arange_impl(T start, T stop, S step = 1) noexcept + { + std::size_t shape = static_cast(std::ceil((stop - start) / step)); + return detail::make_xgenerator(detail::arange_generator(start, stop, step), {shape}); + } + + template )> + inline auto arange_impl(T start, T stop, S step = 1) noexcept + { + bool empty_cond = (stop - start) / step <= 0; + std::size_t shape = 0; + if(!empty_cond) + { + shape = stop > start ? static_cast((stop - start + step - S(1)) / step) + : static_cast((start - stop - step - S(1)) / -step); + } + return detail::make_xgenerator(detail::arange_generator(start, stop, step), {shape}); + } + template class fn_impl { @@ -301,12 +375,12 @@ namespace xt inline T operator()(const It& /*begin*/, const It& end) const { using lvalue_type = typename std::iterator_traits::value_type; - return *(end - 1) == *(end - 2) + static_cast(static_cast(m_k)) ? T(1) : T(0); + return *(end - 1) == *(end - 2) + static_cast(m_k) ? T(1) : T(0); } private: - int m_k; + std::ptrdiff_t m_k; }; } @@ -348,11 +422,10 @@ namespace xt * @tparam T value_type of xexpression * @return xgenerator that generates the values on access */ - template - inline auto arange(T start, T stop, T step = 1) noexcept + template + inline auto arange(T start, T stop, S step = 1) noexcept { - std::size_t shape = static_cast(std::ceil((stop - start) / step)); - return detail::make_xgenerator(detail::arange_impl(start, stop, step), {shape}); + return detail::arange_impl(start, stop, step); } /** @@ -381,8 +454,8 @@ namespace xt inline auto linspace(T start, T stop, std::size_t num_samples = 50, bool endpoint = true) noexcept { using fp_type = std::common_type_t; - fp_type step = fp_type(stop - start) / fp_type(num_samples - (endpoint ? 1 : 0)); - return cast(detail::make_xgenerator(detail::arange_impl(fp_type(start), fp_type(stop), step), {num_samples})); + fp_type step = fp_type(stop - start) / std::fmax(fp_type(1), fp_type(num_samples - (endpoint ? 1 : 0))); + return detail::make_xgenerator(detail::arange_generator(fp_type(start), fp_type(stop), step), {num_samples}); } /** @@ -398,7 +471,7 @@ namespace xt template inline auto logspace(T start, T stop, std::size_t num_samples, T base = 10, bool endpoint = true) noexcept { - return cast(pow(std::move(base), linspace(start, stop, num_samples, endpoint))); + return pow(std::move(base), linspace(start, stop, num_samples, endpoint)); } namespace detail @@ -409,7 +482,7 @@ namespace xt public: using size_type = std::size_t; - using value_type = promote_type_t::value_type...>; + using value_type = xtl::promote_type_t::value_type...>; inline concatenate_impl(std::tuple&& t, size_type axis) : m_t(t), m_axis(axis) @@ -468,7 +541,7 @@ namespace xt public: using size_type = std::size_t; - using value_type = promote_type_t::value_type...>; + using value_type = xtl::promote_type_t::value_type...>; inline stack_impl(std::tuple&& t, size_type axis) : m_t(t), m_axis(axis) @@ -569,11 +642,28 @@ namespace xt inline auto concatenate(std::tuple&& t, std::size_t axis = 0) { using shape_type = promote_shape_t::shape_type...>; - shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + using source_shape_type = decltype(std::get<0>(t).shape()); + shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + + auto check_shape = [&axis, &new_shape](auto& arr) { + std::size_t s = new_shape.size(); + bool res = s == arr.dimension(); + for(std::size_t i = 0; i < s; ++i) + { + res = res && (i == axis || new_shape[i] == arr.shape(i)); + } + if(!res) + { + throw_concatenate_error(new_shape, arr.shape()); + } + }; + for_each(check_shape, t); + auto shape_at_axis = [&axis](std::size_t prev, auto& arr) -> std::size_t { return prev + arr.shape()[axis]; }; new_shape[axis] += accumulate(shape_at_axis, std::size_t(0), t) - new_shape[axis]; + return detail::make_xgenerator(detail::concatenate_impl(std::forward>(t), axis), new_shape); } @@ -620,7 +710,8 @@ namespace xt inline auto stack(std::tuple&& t, std::size_t axis = 0) { using shape_type = promote_shape_t::shape_type...>; - auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); + using source_shape_type = decltype(std::get<0>(t).shape()); + auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); return detail::make_xgenerator(detail::stack_impl(std::forward>(t), axis), new_shape); } diff --git a/vendor/xtensor/include/xtensor/xcomplex.hpp b/vendor/xtensor/include/xtensor/xcomplex.hpp index e47842aa1..5bae3266d 100644 --- a/vendor/xtensor/include/xtensor/xcomplex.hpp +++ b/vendor/xtensor/include/xtensor/xcomplex.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -20,7 +21,6 @@ namespace xt { - /****************************** * real and imag declarations * ******************************/ @@ -61,7 +61,7 @@ namespace xt template static inline decltype(auto) real(E&& e) noexcept { - return e; + return std::forward(e); } template @@ -75,15 +75,15 @@ namespace xt struct complex_expression_helper { template - static inline auto real(E&& e) noexcept + static inline decltype(auto) real(E&& e) noexcept { - return detail::complex_helper::value_type>::value>::real(e); + return detail::complex_helper::value_type>::value>::real(std::forward(e)); } template - static inline auto imag(E&& e) noexcept + static inline decltype(auto) imag(E&& e) noexcept { - return detail::complex_helper::value_type>::value>::imag(e); + return detail::complex_helper::value_type>::value>::imag(std::forward(e)); } }; @@ -132,56 +132,70 @@ namespace xt return detail::complex_expression_helper>::value>::imag(std::forward(e)); } -#define UNARY_COMPLEX_FUNCTOR(NAME) \ - template \ +#define UNARY_COMPLEX_FUNCTOR(NS, NAME) \ struct NAME##_fun \ { \ - using argument_type = T; \ - using result_type = decltype(std::NAME(std::declval())); \ - constexpr result_type operator()(const T& t) const \ + template \ + constexpr auto operator()(const T& t) const \ { \ - using std::NAME; \ + using NS::NAME; \ + return NAME(t); \ + } \ + \ + template \ + constexpr auto simd_apply(const B& t) const \ + { \ + using NS::NAME; \ return NAME(t); \ } \ } namespace math { - UNARY_COMPLEX_FUNCTOR(norm); - UNARY_COMPLEX_FUNCTOR(arg); - namespace detail { - // libc++ (OSX) conj is unfortunately broken and returns - // std::complex instead of T. template - constexpr T conj(const T& c) - { - return c; - } - - template - constexpr std::complex conj(const std::complex& c) + constexpr std::complex conj_impl(const std::complex& c) { return std::complex(c.real(), -c.imag()); } + +#ifdef XTENSOR_USE_XSIMD + template + constexpr X conj_impl(const xsimd::simd_complex_batch& z) + { + return xsimd::conj(z); + } + + template + struct not_complex_batch + : xtl::negation, T>> + { + }; + + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + // This function must be deactivated for complex batches, + // otherwise it will be a better match than the previous one. + template )> + constexpr T conj_impl(const T& c) + { + return c; + } +#else + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + template + constexpr T conj_impl(const T& c) + { + return c; + } +#endif } - template - struct conj_fun - { - using argument_type = T; - using result_type = decltype(detail::conj(std::declval())); - using simd_value_type = xsimd::simd_type; - constexpr result_type operator()(const T& t) const - { - return detail::conj(t); - } - constexpr simd_value_type simd_apply(const simd_value_type& t) const - { - return detail::conj(t); - } - }; + UNARY_COMPLEX_FUNCTOR(std, norm); + UNARY_COMPLEX_FUNCTOR(std, arg); + UNARY_COMPLEX_FUNCTOR(detail, conj_impl); } #undef UNARY_COMPLEX_FUNCTOR @@ -194,10 +208,8 @@ namespace xt template inline auto conj(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::conj_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::conj_impl_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } @@ -208,10 +220,8 @@ namespace xt template inline auto arg(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::arg_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::arg_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } @@ -241,10 +251,8 @@ namespace xt template inline auto norm(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::norm_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::norm_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } } diff --git a/vendor/xtensor/include/xtensor/xcontainer.hpp b/vendor/xtensor/include/xtensor/xcontainer.hpp index 80df1907f..129016a7b 100644 --- a/vendor/xtensor/include/xtensor/xcontainer.hpp +++ b/vendor/xtensor/include/xtensor/xcontainer.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -11,13 +12,13 @@ #include #include -#include #include #include #include #include +#include "xaccessible.hpp" #include "xiterable.hpp" #include "xiterator.hpp" #include "xmath.hpp" @@ -36,8 +37,6 @@ namespace xt using const_stepper = xstepper; }; -#define DL XTENSOR_DEFAULT_LAYOUT - namespace detail { template @@ -56,7 +55,6 @@ namespace xt template using allocator_type_t = typename detail::allocator_type_impl::type; - /** * @class xcontainer * @brief Base class for dense multidimensional containers. @@ -69,7 +67,8 @@ namespace xt * provides the interface. */ template - class xcontainer : private xiterable + class xcontainer : public xcontiguous_iterable, + private xaccessible { public: @@ -79,15 +78,14 @@ namespace xt using storage_type = typename inner_types::storage_type; using allocator_type = allocator_type_t>; using value_type = typename storage_type::value_type; - using reference = std::conditional_t::value, - typename storage_type::const_reference, - typename storage_type::reference>; - using const_reference = typename storage_type::const_reference; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; using pointer = typename storage_type::pointer; using const_pointer = typename storage_type::const_pointer; - using size_type = typename storage_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename storage_type::difference_type; - using simd_value_type = xsimd::simd_type; + using simd_value_type = xt_simd::simd_type; + using bool_load_type = xt::bool_load_type; using shape_type = typename inner_types::shape_type; using strides_type = typename inner_types::strides_type; @@ -97,24 +95,31 @@ namespace xt using inner_strides_type = typename inner_types::inner_strides_type; using inner_backstrides_type = typename inner_types::inner_backstrides_type; - using iterable_base = xiterable; + using iterable_base = xcontiguous_iterable; using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; + using accessible_base = xaccessible; + static constexpr layout_type static_layout = inner_types::layout; static constexpr bool contiguous_layout = static_layout != layout_type::dynamic; - using data_alignment = xsimd::container_alignment_t; - using simd_type = xsimd::simd_type; + using data_alignment = xt_simd::container_alignment_t; + using simd_type = xt_simd::simd_type; + + using storage_iterator = typename iterable_base::storage_iterator; + using const_storage_iterator = typename iterable_base::const_storage_iterator; + using reverse_storage_iterator = typename iterable_base::reverse_storage_iterator; + using const_reverse_storage_iterator = typename iterable_base::const_reverse_storage_iterator; static_assert(static_layout != layout_type::any, "Container layout can never be layout_type::any!"); size_type size() const noexcept; - constexpr size_type dimension() const noexcept; + XTENSOR_CONSTEXPR_RETURN size_type dimension() const noexcept; - constexpr const inner_shape_type& shape() const noexcept; - constexpr const inner_strides_type& strides() const noexcept; - constexpr const inner_backstrides_type& backstrides() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides() const noexcept; template void fill(const T& value); @@ -125,29 +130,17 @@ namespace xt template const_reference operator()(Args... args) const; - template - reference at(Args... args); - - template - const_reference at(Args... args) const; - template reference unchecked(Args... args); template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index); - template - reference operator[](std::initializer_list index); - reference operator[](size_type i); - - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; + using accessible_base::shape; + using accessible_base::at; + using accessible_base::operator[]; + using accessible_base::periodic; + using accessible_base::in_bounds; template reference element(It first, It last); @@ -165,8 +158,7 @@ namespace xt bool broadcast_shape(S& shape, bool reuse_cache = false) const; template - bool is_trivial_broadcast(const S& strides) const noexcept; - + bool has_linear_assign(const S& strides) const noexcept; template stepper stepper_begin(const S& shape) noexcept; template @@ -180,149 +172,30 @@ namespace xt reference data_element(size_type i); const_reference data_element(size_type i) const; - template - using simd_return_type = xsimd::simd_return_type; + template + using simd_return_type = xt_simd::simd_return_type; - template + template void store_simd(size_type i, const simd& e); - template - simd_return_type load_simd(size_type i) const; + template ::size> + container_simd_return_type_t + /*simd_return_type*/ load_simd(size_type i) const; -#if defined(_MSC_VER) && _MSC_VER >= 1910 - // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type parameters. - template - using layout_iterator = xiterator; - template - using const_layout_iterator = xiterator; - template - using reverse_layout_iterator = std::reverse_iterator>; - template - using const_reverse_layout_iterator = std::reverse_iterator>; -#else - template - using layout_iterator = typename iterable_base::template layout_iterator; - template - using const_layout_iterator = typename iterable_base::template const_layout_iterator; - template - using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; - template - using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; -#endif - - template - using broadcast_iterator = typename iterable_base::template broadcast_iterator; - template - using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; - template - using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; - template - using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; - - using storage_iterator = typename storage_type::iterator; - using const_storage_iterator = typename storage_type::const_iterator; - using reverse_storage_iterator = typename storage_type::reverse_iterator; - using const_reverse_storage_iterator = typename storage_type::const_reverse_iterator; - - template - using select_iterator_impl = std::conditional_t; - - template - using select_iterator = select_iterator_impl>; - template - using select_const_iterator = select_iterator_impl>; - template - using select_reverse_iterator = select_iterator_impl>; - template - using select_const_reverse_iterator = select_iterator_impl>; - - using iterator = select_iterator

; - using const_iterator = select_const_iterator
; - using reverse_iterator = select_reverse_iterator
; - using const_reverse_iterator = select_const_reverse_iterator
; - - template - select_iterator begin() noexcept; - template - select_iterator end() noexcept; - - template - select_const_iterator begin() const noexcept; - template - select_const_iterator end() const noexcept; - template - select_const_iterator cbegin() const noexcept; - template - select_const_iterator cend() const noexcept; - - template - select_reverse_iterator rbegin() noexcept; - template - select_reverse_iterator rend() noexcept; - - template - select_const_reverse_iterator rbegin() const noexcept; - template - select_const_reverse_iterator rend() const noexcept; - template - select_const_reverse_iterator crbegin() const noexcept; - template - select_const_reverse_iterator crend() const noexcept; - - template - broadcast_iterator begin(const S& shape) noexcept; - template - broadcast_iterator end(const S& shape) noexcept; - - template - const_broadcast_iterator begin(const S& shape) const noexcept; - template - const_broadcast_iterator end(const S& shape) const noexcept; - template - const_broadcast_iterator cbegin(const S& shape) const noexcept; - template - const_broadcast_iterator cend(const S& shape) const noexcept; - - - template - reverse_broadcast_iterator rbegin(const S& shape) noexcept; - template - reverse_broadcast_iterator rend(const S& shape) noexcept; - - template - const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator rend(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator crend(const S& shape) const noexcept; - - template storage_iterator storage_begin() noexcept; - template storage_iterator storage_end() noexcept; - template const_storage_iterator storage_begin() const noexcept; - template const_storage_iterator storage_end() const noexcept; - template const_storage_iterator storage_cbegin() const noexcept; - template const_storage_iterator storage_cend() const noexcept; - template reverse_storage_iterator storage_rbegin() noexcept; - template reverse_storage_iterator storage_rend() noexcept; - template const_reverse_storage_iterator storage_rbegin() const noexcept; - template const_reverse_storage_iterator storage_rend() const noexcept; - template const_reverse_storage_iterator storage_crbegin() const noexcept; - template const_reverse_storage_iterator storage_crend() const noexcept; using container_iterator = storage_iterator; @@ -341,8 +214,8 @@ namespace xt container_iterator data_xbegin() noexcept; const_container_iterator data_xbegin() const noexcept; - container_iterator data_xend(layout_type l) noexcept; - const_container_iterator data_xend(layout_type l) const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; protected: @@ -352,21 +225,19 @@ namespace xt private: - friend class xiterable; - friend class xconst_iterable; - - template - friend class xstepper; - template - It data_xend_impl(It end, layout_type l) const noexcept; + It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept; inner_shape_type& mutable_shape(); inner_strides_type& mutable_strides(); inner_backstrides_type& mutable_backstrides(); - }; -#undef DL + template + friend class xstepper; + + friend class xaccessible; + friend class xconst_accessible; + }; /** * @class xstrided_container @@ -409,6 +280,9 @@ namespace xt template void reshape(S&& shape, layout_type layout = base_type::static_layout); + template + void reshape(std::initializer_list shape, layout_type layout = base_type::static_layout); + layout_type layout() const noexcept; protected: @@ -423,6 +297,7 @@ namespace xt xstrided_container& operator=(xstrided_container&&) = default; explicit xstrided_container(inner_shape_type&&, inner_strides_type&&) noexcept; + explicit xstrided_container(inner_shape_type&&, inner_strides_type&&, inner_backstrides_type&&, layout_type&&) noexcept; inner_shape_type& shape_impl() noexcept; const inner_shape_type& shape_impl() const noexcept; @@ -433,6 +308,16 @@ namespace xt inner_backstrides_type& backstrides_impl() noexcept; const inner_backstrides_type& backstrides_impl() const noexcept; + template + void reshape_impl(S&& shape, std::true_type, layout_type layout = base_type::static_layout); + template + void reshape_impl(S&& shape, std::false_type, layout_type layout = base_type::static_layout); + + layout_type& mutable_layout() noexcept + { + return m_layout; + } + private: inner_shape_type m_shape; @@ -447,9 +332,9 @@ namespace xt template template - inline It xcontainer::data_xend_impl(It end, layout_type l) const noexcept + inline It xcontainer::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept { - return strided_data_end(*this, end, l); + return strided_data_end(*this, begin, l, offset); } template @@ -487,7 +372,7 @@ namespace xt * Returns the number of dimensions of the container. */ template - inline constexpr auto xcontainer::dimension() const noexcept -> size_type + XTENSOR_CONSTEXPR_RETURN auto xcontainer::dimension() const noexcept -> size_type { return shape().size(); } @@ -496,7 +381,7 @@ namespace xt * Returns the shape of the container. */ template - constexpr inline auto xcontainer::shape() const noexcept -> const inner_shape_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::shape() const noexcept -> const inner_shape_type& { return derived_cast().shape_impl(); } @@ -505,7 +390,7 @@ namespace xt * Returns the strides of the container. */ template - constexpr inline auto xcontainer::strides() const noexcept -> const inner_strides_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::strides() const noexcept -> const inner_strides_type& { return derived_cast().strides_impl(); } @@ -514,7 +399,7 @@ namespace xt * Returns the backstrides of the container. */ template - constexpr inline auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& { return derived_cast().backstrides_impl(); } @@ -548,7 +433,7 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), static_cast(args)...); return storage()[index]; } @@ -564,44 +449,10 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), static_cast(args)...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) -> reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - - /** - * Returns a constant reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a reference to the element at the specified position in the container. * @param args a list of indices specifying the position in the container. Indices @@ -625,7 +476,7 @@ namespace xt template inline auto xcontainer::unchecked(Args... args) -> reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); return storage()[index]; } @@ -652,64 +503,10 @@ namespace xt template inline auto xcontainer::unchecked(Args... args) const -> const_reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) -> reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) -> reference - { - return operator()(i); - } - - /** - * Returns a constant reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a reference to the element at the specified position in the container. * @param first iterator starting the sequence of indices @@ -809,397 +606,19 @@ namespace xt } /** - * Compares the specified strides with those of the container to see whether - * the broadcasting is trivial. - * @return a boolean indicating whether the broadcasting is trivial + * Checks whether the xcontainer can be linearly assigned to an expression + * with the specified strides. + * @return a boolean indicating whether a linear assign is possible */ template template - inline bool xcontainer::is_trivial_broadcast(const S& str) const noexcept + inline bool xcontainer::has_linear_assign(const S& str) const noexcept { return str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin()); } //@} - /**************** - * Iterator api * - ****************/ - - template - template - inline auto xcontainer::begin() noexcept -> select_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_begin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template begin(); - }); - } - - template - template - inline auto xcontainer::end() noexcept -> select_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_end(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template end(); - }); - } - - template - template - inline auto xcontainer::begin() const noexcept -> select_const_iterator - { - return this->template cbegin(); - } - - template - template - inline auto xcontainer::end() const noexcept -> select_const_iterator - { - return this->template cend(); - } - - template - template - inline auto xcontainer::cbegin() const noexcept -> select_const_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_cbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template cbegin(); - }); - } - - template - template - inline auto xcontainer::cend() const noexcept -> select_const_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_cend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template cend(); - }); - } - - template - template - inline auto xcontainer::rbegin() noexcept -> select_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_rbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template rbegin(); - }); - } - - template - template - inline auto xcontainer::rend() noexcept -> select_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_rend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template rend(); - }); - } - - template - template - inline auto xcontainer::rbegin() const noexcept -> select_const_reverse_iterator - { - return this->template crbegin(); - } - - template - template - inline auto xcontainer::rend() const noexcept -> select_const_reverse_iterator - { - return this->template crend(); - } - - template - template - inline auto xcontainer::crbegin() const noexcept -> select_const_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_crbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template crbegin(); - }); - } - - template - template - inline auto xcontainer::crend() const noexcept -> select_const_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_crend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template crend(); - }); - } - - /***************************** - * Broadcasting iterator api * - *****************************/ - - template - template - inline auto xcontainer::begin(const S& shape) noexcept -> broadcast_iterator - { - return iterable_base::template begin(shape); - } - - template - template - inline auto xcontainer::end(const S& shape) noexcept -> broadcast_iterator - { - return iterable_base::template end(shape); - } - - template - template - inline auto xcontainer::begin(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template begin(shape); - } - - template - template - inline auto xcontainer::end(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template end(shape); - } - - template - template - inline auto xcontainer::cbegin(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template cbegin(shape); - } - - template - template - inline auto xcontainer::cend(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template cend(shape); - } - - template - template - inline auto xcontainer::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator - { - return iterable_base::template rbegin(shape); - } - - template - template - inline auto xcontainer::rend(const S& shape) noexcept -> reverse_broadcast_iterator - { - return iterable_base::template rend(shape); - } - - template - template - inline auto xcontainer::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template rbegin(shape); - } - - template - template - inline auto xcontainer::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template rend(shape); - } - - template - template - inline auto xcontainer::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template crbegin(shape); - } - - template - template - inline auto xcontainer::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template crend(shape); - } - - /*********************** - * Linear iterator api * - ***********************/ - - template - template - inline auto xcontainer::storage_begin() noexcept -> storage_iterator - { - return storage().begin(); - } - - template - template - inline auto xcontainer::storage_end() noexcept -> storage_iterator - { - return storage().end(); - } - - template - template - inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator - { - return storage().begin(); - } - - template - template - inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator - { - return storage().end(); - } - - template - template - inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator - { - return storage().cbegin(); - } - - template - template - inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator - { - return storage().cend(); - } - - template - template - inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator - { - return storage().rbegin(); - } - - template - template - inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator - { - return storage().rend(); - } - - template - template - inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator - { - return storage().rbegin(); - } - - template - template - inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator - { - return storage().rend(); - } - - template - template - inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator - { - return storage().crbegin(); - } - - template - template - inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator - { - return storage().crend(); - } - - /*************** - * stepper api * - ***************/ - - template - template - inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper - { - size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xbegin(), offset); - } - - template - template - inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper - { - size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xend(l), offset); - } - - template - template - inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper - { - size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xbegin(), offset); - } - - template - template - inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper - { - size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xend(l), offset); - } - - template - inline auto xcontainer::data_xbegin() noexcept -> container_iterator - { - return storage().begin(); - } - - template - inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator - { - return storage().begin(); - } - - template - inline auto xcontainer::data_xend(layout_type l) noexcept -> container_iterator - { - return data_xend_impl(storage().end(), l); - } - - template - inline auto xcontainer::data_xend(layout_type l) const noexcept -> const_container_iterator - { - return data_xend_impl(storage().end(), l); - } - - template - inline auto xcontainer::derived_cast() & noexcept -> derived_type& - { - return *static_cast(this); - } - template inline auto xcontainer::derived_cast() const & noexcept -> const derived_type& { @@ -1224,20 +643,160 @@ namespace xt return storage()[i]; } + /*************** + * stepper api * + ***************/ + + template + template + inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xend(l, offset), offset); + } + + template + template + inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xend(l, offset), offset); + } + + template + inline auto xcontainer::data_xbegin() noexcept -> container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator + { + return storage().cbegin(); + } + + template + inline auto xcontainer::data_xend(layout_type l, size_type offset) noexcept -> container_iterator + { + return data_xend_impl(storage().begin(), l, offset); + } + + template + inline auto xcontainer::data_xend(layout_type l, size_type offset) const noexcept -> const_container_iterator + { + return data_xend_impl(storage().cbegin(), l, offset); + } + template template inline void xcontainer::store_simd(size_type i, const simd& e) { using align_mode = driven_align_mode_t; - xsimd::store_simd(&(storage()[i]), e, align_mode()); + xt_simd::store_simd(&(storage()[i]), e, align_mode()); } template - template - inline auto xcontainer::load_simd(size_type i) const -> simd_return_type + template + inline auto xcontainer::load_simd(size_type i) const + -> container_simd_return_type_t + //-> simd_return_type { using align_mode = driven_align_mode_t; - return xsimd::load_simd(&(storage()[i]), align_mode()); + return xt_simd::load_simd(&(storage()[i]), align_mode()); + } + + template + inline auto xcontainer::storage_begin() noexcept -> storage_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::storage_end() noexcept -> storage_iterator + { + return storage().end(); + } + + template + inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator + { + return storage().cbegin(); + } + + template + inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator + { + return storage().rbegin(); + } + + template + inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator + { + return storage().rend(); + } + + template + inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().rbegin(); + } + + template + inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage().rend(); + } + + template + inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().crbegin(); + } + + template + inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return storage().crend(); + } + + template + inline auto xcontainer::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); } /************************************* @@ -1248,7 +807,7 @@ namespace xt inline xstrided_container::xstrided_container() noexcept : base_type() { - m_shape = xtl::make_sequence(base_type::dimension(), 1); + m_shape = xtl::make_sequence(base_type::dimension(), 0); m_strides = xtl::make_sequence(base_type::dimension(), 0); m_backstrides = xtl::make_sequence(base_type::dimension(), 0); } @@ -1261,6 +820,12 @@ namespace xt adapt_strides(m_shape, m_strides, m_backstrides); } + template + inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides, inner_backstrides_type&& backstrides, layout_type&& layout) noexcept + : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)), m_backstrides(std::move(backstrides)), m_layout(std::move(layout)) + { + } + template inline auto xstrided_container::shape_impl() noexcept -> inner_shape_type& { @@ -1325,7 +890,9 @@ namespace xt } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param force force reshaping, even if the shape stays the same (default: false) */ @@ -1333,22 +900,25 @@ namespace xt template inline void xstrided_container::resize(S&& shape, bool force) { - if (m_shape.size() != shape.size() || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) + std::size_t dim = shape.size(); + if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) { - if (m_layout == layout_type::dynamic || m_layout == layout_type::any) + if (D::static_layout == layout_type::dynamic && m_layout == layout_type::dynamic) { m_layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - m_shape = xtl::forward_sequence(shape); - resize_container(m_strides, m_shape.size()); - resize_container(m_backstrides, m_shape.size()); - size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, dim); + resize_container(m_backstrides, dim); + size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); detail::resize_data_container(this->storage(), data_size); } } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param l the new layout_type */ @@ -1366,6 +936,8 @@ namespace xt /** * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param strides the new strides */ @@ -1377,7 +949,7 @@ namespace xt { throw std::runtime_error("Cannot resize with custom strides when layout() is != layout_type::dynamic."); } - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); m_strides = strides; resize_container(m_backstrides, m_strides.size()); adapt_strides(m_shape, m_strides, m_backstrides); @@ -1386,7 +958,14 @@ namespace xt } /** - * Reshapes the container and keeps old elements + * Reshapes the container and keeps old elements. The `shape` argument can have one of its value + * equal to `-1`, in this case the value is inferred from the number of elements in the container + * and the remaining values in the `shape`. + * \code{.cpp} + * xt::xarray a = { 1, 2, 3, 4, 5, 6, 7, 8 }; + * a.reshape({-1, 4}); + * //a.shape() is {2, 4} + * \endcode * @param shape the new shape (has to have same number of elements as the original container) * @param layout the layout to compute the strides (defaults to static layout of the container, * or for a container with dynamic layout to XTENSOR_DEFAULT_LAYOUT) @@ -1394,24 +973,74 @@ namespace xt template template inline void xstrided_container::reshape(S&& shape, layout_type layout) + { + reshape_impl(std::forward(shape), std::is_signed::value_type>>(), std::forward(layout)); + } + + template + template + inline void xstrided_container::reshape(std::initializer_list shape, layout_type layout) + { + using sh_type = rebind_container_t; + sh_type sh = xtl::make_sequence(shape.size()); + std::copy(shape.begin(), shape.end(), sh.begin()); + reshape_impl(std::move(sh), std::is_signed(), std::forward(layout)); + } + + template + template + inline void xstrided_container::reshape_impl(S&& shape, std::false_type /* is unsigned */, layout_type layout) { if (compute_size(shape) != this->size()) { throw std::runtime_error("Cannot reshape with incorrect number of elements. Do you mean to resize?"); } - if (layout == layout_type::dynamic || layout == layout_type::any) + if (D::static_layout == layout_type::dynamic && layout == layout_type::dynamic) { layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - if (layout != base_type::static_layout && base_type::static_layout != layout_type::dynamic) + if (D::static_layout != layout_type::dynamic && layout != D::static_layout) { throw std::runtime_error("Cannot reshape with different layout if static layout != dynamic."); } m_layout = layout; - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); resize_container(m_strides, m_shape.size()); resize_container(m_backstrides, m_shape.size()); - compute_strides(m_shape, m_layout, m_strides, m_backstrides); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); + } + template + template + inline void xstrided_container::reshape_impl(S&& _shape, std::true_type /* is signed */, layout_type layout) + { + using value_type = typename std::decay_t::value_type; + if (this->size() % compute_size(_shape)) + { + throw std::runtime_error("Negative axis size cannot be inferred. Shape mismatch."); + } + std::decay_t shape = _shape; + value_type accumulator = 1; + std::size_t neg_idx = 0; + std::size_t i = 0; + for(auto it = shape.begin(); it != shape.end(); ++it, i++) + { + auto&& dim = *it; + if(dim < 0) + { + XTENSOR_ASSERT(dim == -1 && !neg_idx); + neg_idx = i; + } + accumulator *= dim; + } + if(accumulator < 0) + { + shape[neg_idx] = static_cast(this->size()) / std::abs(accumulator); + } + m_layout = layout; + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); } } diff --git a/vendor/xtensor/include/xtensor/xcsv.hpp b/vendor/xtensor/include/xtensor/xcsv.hpp index 4a2716d40..6a98fa449 100644 --- a/vendor/xtensor/include/xtensor/xcsv.hpp +++ b/vendor/xtensor/include/xtensor/xcsv.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -29,7 +30,7 @@ namespace xt using xcsv_tensor = xtensor_container, 2, layout_type::row_major>; template > - xcsv_tensor load_csv(std::istream& stream); + xcsv_tensor load_csv(std::istream& stream, const char delimiter = ',', const std::size_t skip_rows = 0, const ptrdiff_t max_rows = -1, const std::string comments = "#"); template void dump_csv(std::ostream& stream, const xexpression& e); @@ -49,6 +50,17 @@ namespace xt return res; } + template <> + inline std::string lexical_cast(const std::string& cell) + { + size_t first = cell.find_first_not_of(' '); + if (first == std::string::npos) + return cell; + + size_t last = cell.find_last_not_of(' '); + return cell.substr(first, last==std::string::npos?cell.size():last+1); + } + template <> inline float lexical_cast(const std::string& cell) { return std::stof(cell); } @@ -77,10 +89,10 @@ namespace xt inline unsigned long long lexical_cast(const std::string& cell) { return std::stoull(cell); } template - ST load_csv_row(std::istream& row_stream, OI output, std::string cell) + ST load_csv_row(std::istream& row_stream, OI output, std::string cell, const char delimiter = ',') { ST length = 0; - while (std::getline(row_stream, cell, ',')) + while (std::getline(row_stream, cell, delimiter)) { *output++ = lexical_cast(cell); ++length; @@ -94,9 +106,13 @@ namespace xt * * Returns an \ref xexpression for the parsed CSV * @param stream the input stream containing the CSV encoded values + * @param delimiter the character used to separate values. [default: ','] + * @param skip the first skip_rows lines. [default: 0] + * @param read max_rows lines of content after skip_rows lines; the default is to read all the lines. [default: -1] + * @param comments the string used to indicate the start of a comment. [default: "#"] */ template - xcsv_tensor load_csv(std::istream& stream) + xcsv_tensor load_csv(std::istream& stream, const char delimiter, const std::size_t skip_rows, const std::ptrdiff_t max_rows, const std::string comments) { using tensor_type = xcsv_tensor; using storage_type = typename tensor_type::storage_type; @@ -106,14 +122,27 @@ namespace xt using output_iterator = std::back_insert_iterator; storage_type data; - size_type nbrow = 0, nbcol = 0; + size_type nbrow = 0, nbcol = 0, nhead = 0; { output_iterator output(data); std::string row, cell; while (std::getline(stream, row)) { + if (nhead < skip_rows) + { + ++nhead; + continue; + } + if (std::equal(comments.begin(), comments.end(), row.begin())) + { + continue; + } + if (0 < max_rows && max_rows <= static_cast(nbrow)) + { + break; + } std::stringstream row_stream(row); - nbcol = detail::load_csv_row(row_stream, output, cell); + nbcol = detail::load_csv_row(row_stream, output, cell, delimiter); ++nbrow; } } diff --git a/vendor/xtensor/include/xtensor/xdynamic_view.hpp b/vendor/xtensor/include/xtensor/xdynamic_view.hpp new file mode 100644 index 000000000..345cb1420 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xdynamic_view.hpp @@ -0,0 +1,704 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_DYNAMIC_VIEW_HPP +#define XTENSOR_DYNAMIC_VIEW_HPP + +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xlayout.hpp" +#include "xsemantic.hpp" +#include "xstrided_view_base.hpp" + +namespace xt +{ + + template + class xdynamic_view; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using undecay_expression = CT; + using reference = inner_reference_t; + using const_reference = typename xexpression_type::const_reference; + using size_type = typename xexpression_type::size_type; + using shape_type = std::decay_t; + using undecay_shape = S; + using storage_getter = FST; + using inner_storage_type = typename storage_getter::type; + using temporary_type = xarray, xexpression_type::static_layout>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + { + using inner_shape_type = S; + using inner_strides_type = inner_shape_type; + using inner_backstrides_type = inner_shape_type; + +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 8 + constexpr static auto random_instantiation_var_for_gcc8_data_iface = has_data_interface>::value; + constexpr static auto random_instantiation_var_for_gcc8_has_strides = has_strides>::value; +#endif + + // TODO: implement efficient stepper specific to the dynamic_view + using const_stepper = xindexed_stepper, true>; + using stepper = xindexed_stepper, false>; + }; + + /**************************** + * xdynamic_view extensions * + ****************************/ + + namespace extension + { + template + struct xdynamic_view_base_impl; + + template + struct xdynamic_view_base_impl + { + using type = xtensor_empty_base; + }; + + template + struct xdynamic_view_base + : xdynamic_view_base_impl, CT, S, L, FST> + { + }; + + template + using xdynamic_view_base_t = typename xdynamic_view_base::type; + } + + /***************** + * xdynamic_view * + *****************/ + + namespace detail + { + template + class xfake_slice; + } + + template > + class xdynamic_view : public xview_semantic>, + public xiterable>, + public extension::xdynamic_view_base_t, + private xstrided_view_base> + { + public: + + using self_type = xdynamic_view; + using base_type = xstrided_view_base; + using semantic_base = xview_semantic; + using extension_base = extension::xdynamic_view_base_t; + using expression_tag = typename extension_base::expression_tag; + + using xexpression_type = typename base_type::xexpression_type; + using base_type::is_const; + + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + + using inner_storage_type = typename base_type::inner_storage_type; + using storage_type = typename base_type::storage_type; + + using iterable_base = xiterable; + using inner_shape_type = typename iterable_base::inner_shape_type; + using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + using base_type::static_layout; + using base_type::contiguous_layout; + + using temporary_type = typename xcontainer_inner_types::temporary_type; + using base_index_type = xindex_type_t; + + using simd_value_type = typename base_type::simd_value_type; + using bool_load_type = typename base_type::bool_load_type; + + using strides_vt = typename strides_type::value_type; + using slice_type = xtl::variant, xkeep_slice, xdrop_slice>; + using slice_vector_type = std::vector; + + template + xdynamic_view(CTA&& e, SA&& shape, get_strides_t&& strides, std::size_t offset, layout_type layout, + slice_vector_type&& slices, get_strides_t&& adj_strides) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + using base_type::size; + using base_type::dimension; + using base_type::shape; + using base_type::layout; + + // Explicitly deleting strides method to avoid compilers complaining + // about not being able to call the strides method from xstrided_view_base + // private base + const inner_strides_type& strides() const noexcept = delete; + + reference operator()(); + const_reference operator()() const; + + template + reference operator()(Args... args); + + template + const_reference operator()(Args... args) const; + + template + reference unchecked(Args... args); + + template + const_reference unchecked(Args... args) const; + + using base_type::operator[]; + using base_type::at; + using base_type::periodic; + using base_type::in_bounds; + + template + reference element(It first, It last); + + template + const_reference element(It first, It last) const; + + size_type data_offset() const noexcept; + + // Explicitly deleting data methods so has_data_interface results + // to false instead of having compilers complaining about not being + // able to call the methods from the private base + value_type* data() noexcept = delete; + const value_type* data() const noexcept = delete; + + using base_type::storage; + using base_type::expression; + using base_type::broadcast_shape; + + template + bool has_linear_assign(const O& str) const noexcept; + + template + void fill(const T& value); + + template + stepper stepper_begin(const ST& shape); + template + stepper stepper_end(const ST& shape, layout_type l); + + template + const_stepper stepper_begin(const ST& shape) const; + template + const_stepper stepper_end(const ST& shape, layout_type l) const; + + using container_iterator = std::conditional_t; + using const_container_iterator = typename storage_type::const_iterator; + + template + using rebind_t = xdynamic_view>; + + template + rebind_t build_view(E&& e) const; + + private: + + using offset_type = typename base_type::offset_type; + + slice_vector_type m_slices; + inner_strides_type m_adj_strides; + + container_iterator data_xbegin() noexcept; + const_container_iterator data_xbegin() const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; + + template + It data_xbegin_impl(It begin) const noexcept; + + template + It data_xend_impl(It end, layout_type l, size_type offset) const noexcept; + + void assign_temporary_impl(temporary_type&& tmp); + + template + offset_type adjust_offset(offset_type offset, T idx, Args... args) const noexcept; + offset_type adjust_offset(offset_type offset) const noexcept; + + template + offset_type adjust_offset_impl(offset_type offset, size_type idx_offset, T idx, Args... args) const noexcept; + offset_type adjust_offset_impl(offset_type offset, size_type idx_offset) const noexcept; + + template + offset_type adjust_element_offset(offset_type offset, It first, It last) const noexcept; + + template + friend class xstepper; + friend class xview_semantic; + friend class xaccessible; + friend class xconst_accessible; + }; + + /************************** + * xdynamic_view builders * + **************************/ + + template + using xdynamic_slice = xtl::variant< + T, + + xrange_adaptor, + xrange_adaptor, + xrange_adaptor, + + xrange_adaptor, + xrange_adaptor, + xrange_adaptor, + + xrange_adaptor, + xrange_adaptor, + + xrange, + xstepped_range, + + xkeep_slice, + xdrop_slice, + + xall_tag, + xellipsis_tag, + xnewaxis_tag + >; + + using xdynamic_slice_vector = std::vector>; + + template + auto dynamic_view(E&& e, const xdynamic_slice_vector& slices); + + /****************************** + * xfake_slice implementation * + ******************************/ + + namespace detail + { + template + class xfake_slice : public xslice> + { + public: + + using size_type = T; + using self_type = xfake_slice; + + xfake_slice() = default; + + size_type operator()(size_type /*i*/) const noexcept + { + return size_type(0); + } + + size_type size() const noexcept + { + return size_type(1); + } + + size_type step_size() const noexcept + { + return size_type(0); + } + + size_type step_size(std::size_t /*i*/, std::size_t /*n*/ = 1) const noexcept + { + return size_type(0); + } + + size_type revert_index(std::size_t i) const noexcept + { + return i; + } + + bool contains(size_type /*i*/) const noexcept + { + return true; + } + + bool operator==(const self_type& /*rhs*/) const noexcept + { + return true; + } + + bool operator!=(const self_type& /*rhs*/) const noexcept + { + return false; + } + }; + } + + /******************************** + * xdynamic_view implementation * + ********************************/ + + template + template + inline xdynamic_view::xdynamic_view(CTA&& e, SA&& shape, get_strides_t&& strides, + std::size_t offset, layout_type layout, + slice_vector_type&& slices, get_strides_t&& adj_strides) noexcept + : base_type(std::forward(e), std::forward(shape), std::move(strides), offset, layout), + m_slices(std::move(slices)), m_adj_strides(std::move(adj_strides)) + { + } + + template + template + inline auto xdynamic_view::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + template + template + inline auto xdynamic_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(this->begin(), this->end(), e); + return *this; + } + + template + inline auto xdynamic_view::operator()() -> reference + { + return base_type::storage()[data_offset()]; + } + + template + inline auto xdynamic_view::operator()() const -> const_reference + { + return base_type::storage()[data_offset()]; + } + + template + template + inline auto xdynamic_view::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(base_type::shape(), args...)); + XTENSOR_CHECK_DIMENSION(base_type::shape(), args...); + offset_type offset = base_type::compute_index(args...); + offset = adjust_offset(offset, args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(base_type::shape(), args...)); + XTENSOR_CHECK_DIMENSION(base_type::shape(), args...); + offset_type offset = base_type::compute_index(args...); + offset = adjust_offset(offset, args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline bool xdynamic_view::has_linear_assign(const O&) const noexcept + { + return false; + } + + template + template + inline auto xdynamic_view::unchecked(Args... args) -> reference + { + offset_type offset = base_type::compute_unchecked_index(args...); + offset = adjust_offset(args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::unchecked(Args... args) const -> const_reference + { + offset_type offset = base_type::compute_unchecked_index(args...); + offset = adjust_offset(args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::element(It first, It last) -> reference + { + XTENSOR_TRY(check_element_index(base_type::shape(), first, last)); + offset_type offset = base_type::compute_element_index(first, last); + offset = adjust_element_offset(offset, first, last); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::element(It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(base_type::shape(), first, last)); + offset_type offset = base_type::compute_element_index(first, last); + offset = adjust_element_offset(offset, first, last); + return base_type::storage()[static_cast(offset)]; + } + + template + inline auto xdynamic_view::data_offset() const noexcept -> size_type + { + size_type offset = base_type::data_offset(); + size_type sl_offset = xtl::visit([](const auto& sl) { return sl(size_type(0)); }, m_slices[0]); + return offset + sl_offset * m_adj_strides[0]; + } + + template + template + inline void xdynamic_view::fill(const T& value) + { + return std::fill(this->storage_begin(), this->storage_end(), value); + } + + template + template + inline auto xdynamic_view::stepper_begin(const ST& shape) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset); + } + + template + template + inline auto xdynamic_view::stepper_end(const ST& shape, layout_type /*l*/) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset, true); + } + + template + template + inline auto xdynamic_view::stepper_begin(const ST& shape) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xdynamic_view::stepper_end(const ST& shape, layout_type /*l*/) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset, true); + } + + template + template + inline auto xdynamic_view::build_view(E&& e) const -> rebind_t + { + inner_shape_type sh(this->shape()); + inner_strides_type str(base_type::strides()); + slice_vector_type svt(m_slices); + inner_strides_type adj_str(m_adj_strides); + return rebind_t(std::forward(e), std::move(sh), std::move(str), + base_type::data_offset(), this->layout(), std::move(svt), std::move(adj_str)); + } + + template + inline auto xdynamic_view::data_xbegin() noexcept -> container_iterator + { + return data_xbegin_impl(this->storage().begin()); + } + + template + inline auto xdynamic_view::data_xbegin() const noexcept -> const_container_iterator + { + return data_xbegin_impl(this->storage().cbegin()); + } + + template + inline auto xdynamic_view::data_xend(layout_type l, size_type offset) noexcept -> container_iterator + { + return data_xend_impl(this->storage().begin(), l, offset); + } + + template + inline auto xdynamic_view::data_xend(layout_type l, size_type offset) const noexcept -> const_container_iterator + { + return data_xend_impl(this->storage().cbegin(), l, offset); + } + + template + template + inline It xdynamic_view::data_xbegin_impl(It begin) const noexcept + { + return begin + static_cast(data_offset()); + } + + // TODO: fix the data_xend implementation and assign_temporary_impl + + template + template + inline It xdynamic_view::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept + { + return strided_data_end(*this, begin + std::ptrdiff_t(data_offset()), l, offset); + } + + template + inline void xdynamic_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); + } + + template + template + inline auto xdynamic_view::adjust_offset(offset_type offset, T idx, Args... args) const noexcept -> offset_type + { + constexpr size_type nb_args = sizeof...(Args) + 1; + size_type dim = base_type::dimension(); + offset_type res = nb_args > dim ? adjust_offset(offset, args...) : adjust_offset_impl(offset, dim - nb_args, idx, args...); + return res; + } + + template + inline auto xdynamic_view::adjust_offset(offset_type offset) const noexcept -> offset_type + { + return offset; + } + + template + template + inline auto xdynamic_view::adjust_offset_impl(offset_type offset, size_type idx_offset, T idx, Args... args) const noexcept + -> offset_type + { + offset_type sl_offset = xtl::visit([idx](const auto& sl) { + using type = typename std::decay_t::size_type; + return sl(type(idx)); + }, m_slices[idx_offset]); + offset_type res = offset + sl_offset * m_adj_strides[idx_offset]; + return adjust_offset_impl(res, idx_offset + 1, args...); + } + + template + inline auto xdynamic_view::adjust_offset_impl(offset_type offset, size_type) const noexcept + -> offset_type + { + return offset; + } + + template + template + inline auto xdynamic_view::adjust_element_offset(offset_type offset, It first, It last) const noexcept -> offset_type + { + auto dst = std::distance(first, last); + offset_type dim = static_cast(dimension()); + offset_type loop_offset = dst < dim ? dim - dst : offset_type(0); + offset_type idx_offset = dim < dst ? dst - dim : offset_type(0); + offset_type res = offset; + for (offset_type i = loop_offset; i < dim; ++i, ++first) + { + offset_type j = static_cast(first[idx_offset]); + offset_type sl_offset = xtl::visit([j](const auto& sl) { return static_cast(sl(j)); }, m_slices[static_cast(i)]); + res += sl_offset * m_adj_strides[static_cast(i)]; + } + return res; + } + + /***************************************** + * xdynamic_view builders implementation * + *****************************************/ + + namespace detail + { + template + struct adj_strides_policy + { + using slice_vector = V; + using strides_type = dynamic_shape; + + slice_vector new_slices; + strides_type new_adj_strides; + + protected: + + inline void resize(std::size_t size) + { + new_slices.resize(size); + new_adj_strides.resize(size); + } + + inline void set_fake_slice(std::size_t idx) + { + new_slices[idx] = xfake_slice(); + new_adj_strides[idx] = std::ptrdiff_t(0); + } + + template + bool fill_args(const xdynamic_slice_vector& slices, std::size_t sl_idx, + std::size_t i, std::size_t old_shape, + const ST& old_stride, + S& shape, get_strides_t& strides) + { + return fill_args_impl>(slices, sl_idx, i, old_shape, old_stride, shape, strides) + || fill_args_impl>(slices, sl_idx, i, old_shape, old_stride, shape, strides); + } + + template + bool fill_args_impl(const xdynamic_slice_vector& slices, std::size_t sl_idx, + std::size_t i, std::size_t old_shape, + const ST& old_stride, + S& shape, get_strides_t& strides) + { + auto* sl = xtl::get_if(&slices[sl_idx]); + if (sl != nullptr) + { + new_slices[i] = *sl; + auto& ns = xtl::get(new_slices[i]); + ns.normalize(old_shape); + shape[i] = static_cast(ns.size()); + strides[i] = std::ptrdiff_t(0); + new_adj_strides[i] = static_cast(old_stride); + } + return sl != nullptr; + } + }; + } + + template + inline auto dynamic_view(E&& e, const xdynamic_slice_vector& slices) + { + using view_type = xdynamic_view, dynamic_shape>; + using slice_vector = typename view_type::slice_vector_type; + using policy = detail::adj_strides_policy; + detail::strided_view_args args; + args.fill_args(e.shape(), detail::get_strides(e), detail::get_offset(e), e.layout(), slices); + return view_type(std::forward(e), std::move(args.new_shape), std::move(args.new_strides), args.new_offset, + args.new_layout, std::move(args.new_slices), std::move(args.new_adj_strides)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xeval.hpp b/vendor/xtensor/include/xtensor/xeval.hpp index 18d53beea..04fc5fd26 100644 --- a/vendor/xtensor/include/xtensor/xeval.hpp +++ b/vendor/xtensor/include/xtensor/xeval.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -10,6 +11,7 @@ #define XTENSOR_EVAL_HPP #include "xtensor_forward.hpp" +#include "xshape.hpp" namespace xt { @@ -40,17 +42,25 @@ namespace xt /// @cond DOXYGEN_INCLUDE_SFINAE template > inline auto eval(T&& t) - -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> + -> std::enable_if_t::value && detail::is_array::value && !detail::is_fixed::value, xtensor::value>> { return xtensor::value>(std::forward(t)); } template > inline auto eval(T&& t) - -> std::enable_if_t::value && !detail::is_array::value, xt::xarray> + -> std::enable_if_t::value && !detail::is_array::value && !detail::is_fixed::value, xt::xarray> { return xarray(std::forward(t)); } + + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && detail::is_fixed::value && !detail::is_array::value, + xt::xtensor_fixed> + { + return xtensor_fixed(std::forward(t)); + } /// @endcond } diff --git a/vendor/xtensor/include/xtensor/xexception.hpp b/vendor/xtensor/include/xtensor/xexception.hpp index 689ce31e0..4daa90be5 100644 --- a/vendor/xtensor/include/xtensor/xexception.hpp +++ b/vendor/xtensor/include/xtensor/xexception.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -34,10 +35,49 @@ namespace xt template [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs); + /********************* + * concatenate_error * + *********************/ + + class concatenate_error : public std::runtime_error + { + public: + + explicit concatenate_error(const char* msg) + : std::runtime_error(msg) + { + } + }; + + template + [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs); + /********************************** * broadcast_error implementation * **********************************/ + namespace detail + { + template + inline std::string shape_error_message(const S1& lhs, const S2& rhs) + { + std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + + buf << "\n LHS shape = ("; + using size_type1 = typename S1::value_type; + std::ostream_iterator iter1(buf, ", "); + std::copy(lhs.cbegin(), lhs.cend(), iter1); + + buf << ")\n RHS shape = ("; + using size_type2 = typename S2::value_type; + std::ostream_iterator iter2(buf, ", "); + std::copy(rhs.cbegin(), rhs.cend(), iter2); + buf << ")"; + + return buf.str(); + } + } + #ifdef NDEBUG // Do not inline this function template @@ -49,20 +89,28 @@ namespace xt template [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs) { - std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + std::string msg = detail::shape_error_message(lhs, rhs); + throw broadcast_error(msg.c_str()); + } +#endif - buf << "\n LHS shape = ("; - using size_type1 = typename S1::value_type; - std::ostream_iterator iter1(buf, ", "); - std::copy(lhs.cbegin(), lhs.cend(), iter1); + /************************************ + * concatenate_error implementation * + ************************************/ - buf << ")\n RHS shape = ("; - using size_type2 = typename S2::value_type; - std::ostream_iterator iter2(buf, ", "); - std::copy(rhs.cbegin(), rhs.cend(), iter2); - buf << ")"; - - throw broadcast_error(buf.str().c_str()); +#ifdef NDEBUG + // Do not inline this function + template + [[noreturn]] void throw_concatenate_error(const S1&, const S2&) + { + throw concatenate_error("Incompatible dimension of arrays, compile in DEBUG for more info"); + } +#else + template + [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs) + { + std::string msg = detail::shape_error_message(lhs, rhs); + throw concatenate_error(msg.c_str()); } #endif @@ -97,8 +145,8 @@ namespace xt { } - template - inline void check_index_impl(const S& shape, std::size_t arg, Args... args) + template + inline void check_index_impl(const S& shape, T arg, Args... args) { if (sizeof...(Args) + 1 > shape.size()) { @@ -106,7 +154,7 @@ namespace xt } else { - if (arg >= std::size_t(shape[dim]) && shape[dim] != 1) + if (std::size_t(arg) >= std::size_t(shape[dim]) && shape[dim] != 1) { throw std::out_of_range("index " + std::to_string(arg) + " is out of bounds for axis " + std::to_string(dim) + " with size " + std::to_string(shape[dim])); @@ -127,17 +175,33 @@ namespace xt inline void check_element_index(const S& shape, It first, It last) { using value_type = typename std::iterator_traits::value_type; - auto dst = static_cast(last - first); + using size_type = typename S::size_type; + auto dst = static_cast(last - first); It efirst = last - static_cast((std::min)(shape.size(), dst)); std::size_t axis = 0; - while (efirst != last) + + if(shape.empty()) { - if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + if(first != last && *(--last) != value_type(0)) { - throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " - + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + throw std::out_of_range("index out of bound (empty array)"); + } + else + { + return; + } + } + else + { + while (efirst != last) + { + if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + { + throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " + + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + } + ++efirst, ++axis; } - ++efirst, ++axis; } } diff --git a/vendor/xtensor/include/xtensor/xexpression.hpp b/vendor/xtensor/include/xtensor/xexpression.hpp index a83ea0c58..caf914d58 100644 --- a/vendor/xtensor/include/xtensor/xexpression.hpp +++ b/vendor/xtensor/include/xtensor/xexpression.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -14,9 +15,12 @@ #include #include +#include #include +#include "xlayout.hpp" #include "xshape.hpp" +#include "xtensor_forward.hpp" #include "xutils.hpp" namespace xt @@ -61,6 +65,43 @@ namespace xt xexpression& operator=(xexpression&&) = default; }; + /************************************ + * xsharable_expression declaration * + ************************************/ + + template + class xshared_expression; + + template + class xsharable_expression; + + namespace detail + { + template + xshared_expression make_xshared_impl(xsharable_expression&&); + } + + template + class xsharable_expression : public xexpression + { + protected: + + xsharable_expression(); + ~xsharable_expression() = default; + + xsharable_expression(const xsharable_expression&) = default; + xsharable_expression& operator=(const xsharable_expression&) = default; + + xsharable_expression(xsharable_expression&&) = default; + xsharable_expression& operator=(xsharable_expression&&) = default; + + private: + + std::shared_ptr p_shared; + + friend xshared_expression detail::make_xshared_impl(xsharable_expression&&); + }; + /****************************** * xexpression implementation * ******************************/ @@ -97,21 +138,41 @@ namespace xt } //@} - namespace detail - { - template - struct is_xexpression_impl : std::is_base_of>, std::decay_t> - { - }; + /*************************************** + * xsharable_expression implementation * + ***************************************/ - template - struct is_xexpression_impl> : std::true_type - { - }; + template + inline xsharable_expression::xsharable_expression() + : p_shared(nullptr) + { } + /** + * is_crtp_base_of + * Resembles std::is_base_of, but adresses the problem of whether _some_ instantiation + * of a CRTP templated class B is a base of class E. A CRTP templated class is correctly + * templated with the most derived type in the CRTP hierarchy. Using this assumption, + * this implementation deals with either CRTP final classes (checks for inheritance + * with E as the CRTP parameter of B) or CRTP base classes (which are singly templated + * by the most derived class, and that's pulled out to use as a templete parameter for B). + */ + + namespace detail + { + template