From 6bb722454a7e8538c81297355ae7be7b11b2ddfb Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Thu, 30 Nov 2023 14:24:53 -0500 Subject: [PATCH 1/2] make SpanRC API match std::mdspan (#758) * HDF5 1.14.2 source code * extract HDF5 source code * files added by 'configure' * build HDF5 1.14.2 * build HDF5 1.14.2 * build HDF5 1.14.2 * remove generated files * compile HDF5 1.14.2 on Windows * build on Windows * update version numbers * WIN32_LEAN_AND_MEAN may already be #define'd * H5Tinit.c for each compiler * Update H5Tinit_MSVC.c_ * regenerate files for Linux/GCC * Get Xerces to build with WAF on Windows * fix typo * remove extracted HDF5 code; what we build is in source/ and include/ * update to HDF5 1.14.2 * HighFive-2.8.0 https://github.com/BlueBrain/HighFive/releases/tag/v2.8.0 * update CODA-OSS to HighFive-2.8.0 * update CODA-OSS to HighFive-2.8.0 * updates from HighFive2.8.0 * fix GCC build errors * SpanRC changes to match std::mdspan API --- modules/c++/gsl/CMakeLists.txt | 2 - .../c++/hdf5.lite/include/hdf5/lite/SpanRC.h | 76 ++++++++++++------- .../hdf5.lite/include/hdf5/lite/highfive.h | 6 +- .../c++/hdf5.lite/unittests/test_highfive.cpp | 22 +++--- modules/c++/types/include/types/RowCol.h | 8 +- 5 files changed, 70 insertions(+), 44 deletions(-) diff --git a/modules/c++/gsl/CMakeLists.txt b/modules/c++/gsl/CMakeLists.txt index 6f17aa779..10d694163 100644 --- a/modules/c++/gsl/CMakeLists.txt +++ b/modules/c++/gsl/CMakeLists.txt @@ -4,5 +4,3 @@ coda_add_module( ${MODULE_NAME} VERSION 1.0 DEPS config-c++) - - diff --git a/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h b/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h index 9392890bb..92dbbae78 100644 --- a/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h +++ b/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h @@ -20,9 +20,9 @@ * */ +#pragma once #ifndef CODA_OSS_hdf5_lite_SpanRC_h_INCLUDED_ #define CODA_OSS_hdf5_lite_SpanRC_h_INCLUDED_ -#pragma once /*! * \file SpanRC.h @@ -33,81 +33,101 @@ #include +#include +#include +#include + #include "config/Exports.h" #include "coda_oss/span.h" #include "types/RowCol.h" +#if CODA_OSS_cpp17 // can't even #include this file with older C++14 compilers! :-( +#if __has_include("coda_oss/mdspan.h") +#include "coda_oss/mdspan.h" +#endif +#endif + namespace hdf5 { namespace lite { +namespace details +{ +#if CODA_OSS_cpp20 && CODA_OSS_mdspan +// https://github.com/kokkos/mdspan/wiki/A-Gentle-Introduction-to-mdspan +template +using msdpan_2 = coda_oss::mdspan>; +#endif -template -struct SpanRC final +template +struct SpanRC final // TODO: use std::mdspan { - using size_type = types::RowCol; + using size_type = size_t; using element_type = T; using pointer = T*; using reference = T&; SpanRC() = default; - SpanRC(pointer p, size_type rc) noexcept : s_(p, rc.area()), rc_(rc) - { - } - SpanRC(pointer p, size_t r, size_t c) noexcept : SpanRC(p, size_type(r, c)) + SpanRC(pointer p, const std::array& dims) noexcept : SpanRC(p, types::RowCol(dims)) { } SpanRC(const SpanRC&) noexcept = default; - constexpr pointer data() const noexcept + constexpr pointer data_handle() const noexcept { return s_.data(); } - + /*constexpr*/ reference operator[](size_t idx) const noexcept { assert(idx < size()); // prevents "constexpr" in C++11 - return data()[idx]; + return data_handle()[idx]; } /*constexpr*/ reference operator()(size_t r, size_t c) const noexcept { - const auto offset = (r * dims().col) + c; + const auto offset = (r * rc_.col) + c; return (*this)[offset]; } - /*constexpr*/ reference operator[](size_type idx) const noexcept - { - return (*this)(idx.row, idx.col); - } constexpr size_t size() const noexcept { assert(s_.size() == rc_.area()); return s_.size(); } - constexpr size_t area() const noexcept - { - return size(); - } - constexpr size_type size_bytes() const noexcept + constexpr bool empty() const noexcept { - return s_.size_bytes(); + return s_.empty(); } - constexpr bool empty() const noexcept + static constexpr auto rank() noexcept { - return s_.empty(); + return 2; } - const auto& dims() const + auto extent(size_t rank) const { - return rc_; + if (rank == 0) return rc_.row; + if (rank == 1) return rc_.col; + throw std::invalid_argument("rank"); } - private: +private: coda_oss::span s_; - types::RowCol rc_; + types::RowCol rc_; + SpanRC(pointer p, types::RowCol rc) noexcept : s_(p, rc.area()), rc_(std::move(rc)) + { + } }; +} + +#if CODA_OSS_cpp20 && CODA_OSS_mdspan +template +using SpanRC = details::msdpan_2; +#else +template +using SpanRC = details::SpanRC; // TODO: get mdspan working with other compilers +#endif } } diff --git a/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h b/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h index fb276e681..d5d91987b 100644 --- a/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h +++ b/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h @@ -56,10 +56,10 @@ inline auto vv_load(const H5Easy::File& file, const std::string& dataset_name) template inline HighFive::DataSet writeDataSet(H5Easy::File& file, const std::string& dataset_name, SpanRC data /*, TODO ...*/) { - const std::vector dims{data.dims().row, data.dims().col}; + const std::vector dims{data.extent(0), data.extent(1)}; const HighFive::DataSpace dataspace{dims}; auto retval = file.createDataSet(dataset_name, dataspace); - retval.write_raw(data.data()); + retval.write_raw(data.data_handle()); return retval; } @@ -87,7 +87,7 @@ inline SpanRC readDataSet(const HighFive::DataSet& dataSet, std::vector& r result.resize(dims.area()); dataSet.read(result.data()); - return SpanRC(result.data(), dims); + return SpanRC(result.data(), std::array{dims.row, dims.col}); } template diff --git a/modules/c++/hdf5.lite/unittests/test_highfive.cpp b/modules/c++/hdf5.lite/unittests/test_highfive.cpp index f54526ab9..9fbfd7654 100644 --- a/modules/c++/hdf5.lite/unittests/test_highfive.cpp +++ b/modules/c++/hdf5.lite/unittests/test_highfive.cpp @@ -53,10 +53,11 @@ TEST_CASE(test_highfive_load) { std::vector lat; const auto rc = hdf5::lite::loadDataSet(file, "/g4/lat", lat); + static_assert(decltype(rc)::rank() == 2, "wrong rank()"); TEST_ASSERT_EQ(lat.size(), 19); - TEST_ASSERT_EQ(lat.size(), rc.area()); - TEST_ASSERT_EQ(rc.dims().row, 19); - TEST_ASSERT_EQ(rc.dims().col, 1); + TEST_ASSERT_EQ(lat.size(), rc.size()); + TEST_ASSERT_EQ(rc.extent(0), 19); + TEST_ASSERT_EQ(rc.extent(1), 1); TEST_ASSERT_ALMOST_EQ(lat[0], -90.0); TEST_ASSERT_ALMOST_EQ(lat[0], -lat[18]); } @@ -103,9 +104,9 @@ template static auto read_complex(const HighFive::DataSet& r, const HighFive::DataSet& i) { std::vector r_result; - hdf5::lite::readDataSet(r, r_result); + std::ignore = hdf5::lite::readDataSet(r, r_result); std::vector i_result; - hdf5::lite::readDataSet(i, i_result); + std::ignore = hdf5::lite::readDataSet(i, i_result); return std::make_pair(r, i); } template @@ -405,11 +406,11 @@ TEST_CASE(test_highfive_write) const types::RowCol dims{10, 20}; std::vector data_(dims.area()); - const hdf5::lite::SpanRC data(data_.data(), dims); + hdf5::lite::SpanRC data(data_.data(), std::array{dims.row, dims.col}); double d = 0.0; - for (size_t r = 0; r result; const auto rc = hdf5::lite::loadDataSet(file, "/DS1", result); - TEST_ASSERT(rc.dims() == dims); + TEST_ASSERT(rc.extent(0) == dims.row); + TEST_ASSERT(rc.extent(1) == dims.col); TEST_ASSERT_EQ(dims.area(), result.size()); for (size_t i = 0; i < result.size(); i++) { diff --git a/modules/c++/types/include/types/RowCol.h b/modules/c++/types/include/types/RowCol.h index e13f125a2..846280aaa 100644 --- a/modules/c++/types/include/types/RowCol.h +++ b/modules/c++/types/include/types/RowCol.h @@ -19,7 +19,7 @@ * see . * */ - + #pragma once #ifndef __TYPES_ROW_COL_H__ #define __TYPES_ROW_COL_H__ @@ -28,6 +28,7 @@ #include #include #include +#include #include "gsl/gsl.h" @@ -78,6 +79,11 @@ template class RowCol row = p.first; col = p.second; } + explicit RowCol(const std::array& a) noexcept + { + row = a[0]; + col = a[1]; + } template RowCol& operator=(const RowCol& p) noexcept { From 28926b673931c3f148882ceca7d3de203accfa4e Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Fri, 1 Dec 2023 09:31:53 -0500 Subject: [PATCH 2/2] provide our own (simple) mdspan implementation (#759) * C++23's mdspan implementation for older compilers; https://github.com/kokkos/mdspan C++23's mdspan implementation for older compilers; https://github.com/kokkos/mdspan * copy mdspan code from drivers/mdspan * our wrappers around mdspan/ * hook up mdspan into coda-oss builds * build in Visual Studio * Settings from https://tea-age.solutions/2022/10/14/the-best-visual-studio-settings-for-modern-c/ https://tea-age.solutions/2022/10/14/the-best-visual-studio-settings-for-modern-c/ * try to get mdspan building with VS, no joy :-( * latest mdspan * update to mdspan-0.6.0 * make our SpanRC look a bit more like std::mdspan * trying containment to get a better handle on compiler errors * make our SpanRC look even more like std::mdspan * #ifdefs for C++17 and C++20 * old C++14 compilers don't like mdspan.h * Squashed commit of the following: commit b333dfd4eae77955580bfb177cf9f58086a979dc Author: Dan Smith Date: Thu Nov 30 13:51:03 2023 -0500 SpanRC changes to match std::mdspan API commit 03ff20928897e44f80ae49a7214b613659c3aacb Merge: 34085c8a df4e0fc1 Author: Dan Smith Date: Thu Nov 30 13:42:28 2023 -0500 Merge branch 'main' into feature/hdf5 commit 34085c8a98110f1e449b53b111d814f3ccab9eba Author: Dan Smith Date: Thu Nov 9 12:25:39 2023 -0500 fix GCC build errors commit a79b08529b497552d774d086942f9f30aea9b09f Merge: 7b822aac b2e2b3df Author: Dan Smith Date: Thu Nov 9 12:08:26 2023 -0500 Merge branch 'feature/hdf5' of https://github.com/mdaus/coda-oss into feature/hdf5 commit 7b822aac5f3ed1fd427e417c9869e64dc22662ff Author: Dan Smith Date: Thu Nov 9 11:23:02 2023 -0500 updates from HighFive2.8.0 commit 606b4f410c05d8183afcea9137644af32bd02b27 Author: Dan Smith Date: Thu Nov 9 09:48:19 2023 -0500 update CODA-OSS to HighFive-2.8.0 commit b2e2b3df643ed12aff4d02559dcaeacdfc3ab2cf Author: Dan Smith Date: Thu Nov 9 09:48:19 2023 -0500 update CODA-OSS to HighFive-2.8.0 commit c66c982df16cdc9382e3940226c25afb62013525 Author: Dan Smith Date: Thu Nov 9 09:38:26 2023 -0500 HighFive-2.8.0 https://github.com/BlueBrain/HighFive/releases/tag/v2.8.0 commit 28067f1b972e81a312b4db260dea8d7225eff78b Merge: e007a674 92f8b88c Author: Dan Smith Date: Thu Nov 9 09:21:54 2023 -0500 Merge branch 'main' into feature/hdf5 commit e007a67443bff119c698aa57c1f54512a1160380 Author: Dan Smith Date: Thu Aug 17 13:04:04 2023 -0400 update to HDF5 1.14.2 commit acd3bd99807b45c193e2a22ee883e47ff6edbd04 Author: Dan Smith Date: Thu Aug 17 13:00:24 2023 -0400 remove extracted HDF5 code; what we build is in source/ and include/ commit d165c81dc25cfb17d686af195b8af787743c88de Author: Dan Smith Date: Thu Aug 17 12:46:12 2023 -0400 fix typo commit 66ec9d6f3375bd81f71b5178d7a14129b3c9e93e Author: Dan Smith Date: Thu Aug 17 12:39:58 2023 -0400 Get Xerces to build with WAF on Windows commit 565c76b97e591c195461775239580414992f590e Merge: 3b70a148 fcc96ec6 Author: Dan Smith Date: Thu Aug 17 12:01:22 2023 -0400 Merge branch 'main' into feature/hdf5 commit 3b70a148ad74cbad0dc307c9c2541e4648e55d7d Author: Dan Smith Date: Thu Aug 17 11:20:39 2023 -0400 regenerate files for Linux/GCC commit 240392528fc960fd14529b6c11b9f4911337a7aa Author: Dan Smith Date: Thu Aug 17 11:01:05 2023 -0400 Update H5Tinit_MSVC.c_ commit a616ede1730fe1fb4e9a2b4df26d01f3e7bc4e4f Author: Dan Smith Date: Thu Aug 17 10:34:25 2023 -0400 H5Tinit.c for each compiler commit 9323f85a6d475b1812af239c188f3d0bcf63f85a Author: Dan Smith Date: Thu Aug 17 10:11:37 2023 -0400 WIN32_LEAN_AND_MEAN may already be #define'd commit c5f71ec2d8ff45bcecc0e28b0412762206d07dae Author: Dan Smith Date: Thu Aug 17 09:04:59 2023 -0400 update version numbers commit 4ad1e1da145332fcd4f85607cb60c4cf50434124 Merge: 12f29ff6 68f13493 Author: Dan Smith Date: Wed Aug 16 16:56:44 2023 -0400 Merge branch 'feature/hdf5' of github.com:mdaus/coda-oss into feature/hdf5 commit 12f29ff634d6679980f2c012e9cf7505dfc85222 Merge: 9f58fef9 bb82a94c Author: Dan Smith Date: Wed Aug 16 16:56:31 2023 -0400 Merge branch 'main' into feature/hdf5 commit 68f13493b61d381e9c34bd65a0374ab167a86864 Author: Dan Smith Date: Wed Aug 16 16:02:38 2023 -0400 build on Windows commit 9f58fef9476fbf3bb819e94b4529c0815e6ef540 Author: Dan Smith Date: Wed Aug 16 13:43:30 2023 -0400 compile HDF5 1.14.2 on Windows commit 7d1fe10a807667ef603c3fc35a436a4d4fe89a88 Author: Dan Smith Date: Wed Aug 16 13:03:11 2023 -0400 remove generated files commit 5eccf89e604f3b9ed0d5c69f0a243758a9d7965a Author: Dan Smith Date: Wed Aug 16 12:40:38 2023 -0400 build HDF5 1.14.2 commit 2ca35b6119ea0e78c3653efbac6aae66353e44f3 Author: Dan Smith Date: Wed Aug 16 12:40:09 2023 -0400 build HDF5 1.14.2 commit a4eeec6c75cea453103c858ff42f666a393685b8 Author: Dan Smith Date: Wed Aug 16 12:39:50 2023 -0400 build HDF5 1.14.2 commit 0d9055b320fff3a368b4561cefae7fe1b61622c5 Author: Dan Smith Date: Wed Aug 16 11:39:59 2023 -0400 files added by 'configure' commit 720d74880d738e07eabeec3dabe6d01e27aa6d02 Author: Dan Smith Date: Wed Aug 16 11:31:22 2023 -0400 extract HDF5 source code commit c5368de6ce894c54400c37122ffcfa60d9a3c0e8 Author: Dan Smith Date: Wed Aug 16 11:24:52 2023 -0400 HDF5 1.14.2 source code * mdspan feature-test macros * mdspan is header-only; don't need a separate project * turn SpanRC into mdspan * don't need SpanRC as a class anymore * code can't be #included with older C++17 compilers either :-( * only mdspan and dextens in coda_oss * trying to fix compiler error * make experimental/mdspan "optional" * Remove Kokkos mdspan implementation; our simple one is good enough for now. --- modules/c++/coda-oss.vcxproj | 3 + modules/c++/coda-oss.vcxproj.filters | 9 ++ .../c++/coda_oss/include/coda_oss/mdspan.h | 73 +++++++++ .../c++/coda_oss/include/coda_oss/mdspan_.h | 151 ++++++++++++++++++ .../c++/coda_oss/include/coda_oss/optional.h | 7 +- .../c++/hdf5.lite/include/hdf5/lite/SpanRC.h | 97 +---------- modules/c++/std/include/import/std.h | 1 + modules/c++/std/include/std/mdspan | 46 ++++++ 8 files changed, 287 insertions(+), 100 deletions(-) create mode 100644 modules/c++/coda_oss/include/coda_oss/mdspan.h create mode 100644 modules/c++/coda_oss/include/coda_oss/mdspan_.h create mode 100644 modules/c++/std/include/std/mdspan diff --git a/modules/c++/coda-oss.vcxproj b/modules/c++/coda-oss.vcxproj index 0f376dc0c..6aacf1781 100644 --- a/modules/c++/coda-oss.vcxproj +++ b/modules/c++/coda-oss.vcxproj @@ -19,6 +19,8 @@ + + @@ -509,6 +511,7 @@ + diff --git a/modules/c++/coda-oss.vcxproj.filters b/modules/c++/coda-oss.vcxproj.filters index 50db46175..a94b8aafd 100644 --- a/modules/c++/coda-oss.vcxproj.filters +++ b/modules/c++/coda-oss.vcxproj.filters @@ -951,6 +951,12 @@ str + + coda_oss + + + coda_oss + @@ -1559,5 +1565,8 @@ sys + + std + \ No newline at end of file diff --git a/modules/c++/coda_oss/include/coda_oss/mdspan.h b/modules/c++/coda_oss/include/coda_oss/mdspan.h new file mode 100644 index 000000000..3569440f4 --- /dev/null +++ b/modules/c++/coda_oss/include/coda_oss/mdspan.h @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of coda_oss-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * � Copyright 2023, Maxar Technologies, Inc. + * + * coda_oss-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#pragma once + +#include "coda_oss/CPlusPlus.h" + +// This should always work ... it's in a `details` namespace +#include "coda_oss/mdspan_.h" + +// This logic needs to be here rather than so that `coda_oss::mdspan` will +// be the same as `std::mdspan`. +#ifndef CODA_OSS_HAVE_std_mdspan_ + #define CODA_OSS_HAVE_std_mdspan_ 0 // assume no +#endif +#ifndef CODA_OSS_HAVE_experimental_mdspan_ + #define CODA_OSS_HAVE_experimental_mdspan_ 0 // assume no std::experimental::mdspan +#endif +#if CODA_OSS_cpp17 // __has_include + #if __has_include() // not until C++23 + #include + #undef CODA_OSS_HAVE_std_mdspan_ + #define CODA_OSS_HAVE_std_mdspan_ 1 // provided by the implementation, probably C++23 + #endif + + #if CODA_OSS_cpp20 // Can't even #include this file with older C++14/17 compilers! :-( + // Put this in a __has_include so that it's optional. Our simple implemtnation works + // for our needs, and this brings along a lot of code that our older compilers don't + // like. By the time we need more functionality, maybe we'll be using C++23? + // + // Until then, having this available allows checking our implementation against + // something much more real. https://github.com/kokkos/mdspan + #if __has_include("coda_oss/experimental/mdspan") + #include "coda_oss/experimental/mdspan" + #undef CODA_OSS_HAVE_experimental_mdspan_ + #define CODA_OSS_HAVE_experimental_mdspan_ 1 // provided coda_oss/experimental/mdspan + #endif + #endif +#endif // CODA_OSS_cpp17 + +namespace coda_oss +{ + #if CODA_OSS_HAVE_std_mdspan_ + using std::mdspan; + using std::dextents; + #elif CODA_OSS_HAVE_experimental_mdspan_ + using std::experimental::mdspan; + using std::experimental::dextents; + #else + using details::mdspan; + using details::dextents; + #endif +} + diff --git a/modules/c++/coda_oss/include/coda_oss/mdspan_.h b/modules/c++/coda_oss/include/coda_oss/mdspan_.h new file mode 100644 index 000000000..b678051d8 --- /dev/null +++ b/modules/c++/coda_oss/include/coda_oss/mdspan_.h @@ -0,0 +1,151 @@ +/* ========================================================================= + * This file is part of coda_oss-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * � Copyright 2023, Maxar Technologies, Inc. + * + * coda_oss-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#pragma once + +#include + +#include + +#include "coda_oss/span.h" + +// This is a simple, partial, and incomplete implementation of `std::mdspan` (in C++23). +// https://en.cppreference.com/w/cpp/container/mdspan +// +// Why? Our (current) needs are much more limited than all the use-cases for `std::mdspan`: +// dynamic (not static) extents, rank of 2 (rows � cols), contiguous memory, ... +// By the time we really need more features, maybe we'll be using C++23? +namespace coda_oss +{ +namespace details +{ + // https://en.cppreference.com/w/cpp/container/mdspan/extents +template +struct dextents final // this is actually supposed to be an alias template with all dynamic extents +{ + static_assert(Rank == 2, "Rank must have a value of 2"); + using index_type = IndexType; + using size_type = index_type; + using rank_type = size_t; + + constexpr dextents() = default; + + // These are supposed to be templates, but we don't need that complication right now. + constexpr dextents(index_type i0, index_type i1) noexcept : exts_{i0, i1} + { + } + constexpr explicit dextents(const std::array& exts) noexcept : exts_(exts) + { + } + + dextents(const dextents&) = default; + dextents& operator=(const dextents&) = default; + dextents(dextents&&) = default; + dextents& operator=(dextents&&) = default; + + constexpr index_type extent(rank_type r) const noexcept + { + return exts_[r]; + } + + static constexpr auto rank() noexcept + { + return Rank; + } + +private: + std::array exts_; +}; + +template +class mdspan final +{ + coda_oss::span s_; // `span` instead of a raw pointer to get more range checking. + TExtents ext_; + + // c.f., `types::RowCol` + template + static size_t area(const dextents& exts) + { + return exts.extent(0) * exts.extent(1); + } + +public: + using extents_type = TExtents; + using size_type = typename extents_type::size_type; + using data_handle_type = T*; + using reference = T&; + + constexpr mdspan() = default; + + // Again, these are supposed to be templates ... + mdspan(data_handle_type p, const extents_type& ext) noexcept : s_(p, area(ext)), ext_(ext) + { + } + mdspan(data_handle_type p, const std::array& dims) noexcept : mdspan(p, extents_type(dims)) + { + } + + mdspan(const mdspan&) = default; + mdspan& operator=(const mdspan&) = default; + mdspan(mdspan&&) = default; + mdspan& operator=(mdspan&&) = default; + + constexpr data_handle_type data_handle() const noexcept + { + return s_.data(); + } + + /*constexpr*/ reference operator[](size_t idx) const noexcept + { + assert(idx < size()); // prevents "constexpr" in C++11 + return data_handle()[idx]; + } + /*constexpr*/ reference operator()(size_t r, size_t c) const noexcept + { + const auto offset = (r * extent(1)) + c; + return (*this)[offset]; + } + + constexpr size_t size() const noexcept + { + return s_.size(); + } + + constexpr bool empty() const noexcept + { + return s_.empty(); + } + + auto extent(size_type rank) const + { + return ext_.extent(rank); + } + + static constexpr auto rank() noexcept + { + return extents_type::rank(); + } +}; +} +} + diff --git a/modules/c++/coda_oss/include/coda_oss/optional.h b/modules/c++/coda_oss/include/coda_oss/optional.h index f1fab3a0b..86298871c 100644 --- a/modules/c++/coda_oss/include/coda_oss/optional.h +++ b/modules/c++/coda_oss/include/coda_oss/optional.h @@ -24,6 +24,9 @@ #include "coda_oss/CPlusPlus.h" +// always compile; it's in a details namespace +#include "coda_oss/optional_.h" + // This logic needs to be here rather than so that `coda_oss::optional` will // be the same as `std::optional`. #ifndef CODA_OSS_HAVE_std_optional_ @@ -37,10 +40,6 @@ #endif #endif // CODA_OSS_cpp17 -#if !CODA_OSS_HAVE_std_optional_ -#include "coda_oss/optional_.h" -#endif - namespace coda_oss { #if CODA_OSS_HAVE_std_optional_ diff --git a/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h b/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h index 92dbbae78..aea2d9c51 100644 --- a/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h +++ b/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h @@ -24,110 +24,15 @@ #ifndef CODA_OSS_hdf5_lite_SpanRC_h_INCLUDED_ #define CODA_OSS_hdf5_lite_SpanRC_h_INCLUDED_ -/*! - * \file SpanRC.h - * - * This is a super-simple version of C++23's mdspan. It's here because 1) don't want widespread use, and - * 2) CODA already has a View2D. - */ - -#include - -#include -#include -#include - -#include "config/Exports.h" -#include "coda_oss/span.h" -#include "types/RowCol.h" - -#if CODA_OSS_cpp17 // can't even #include this file with older C++14 compilers! :-( -#if __has_include("coda_oss/mdspan.h") #include "coda_oss/mdspan.h" -#endif -#endif namespace hdf5 { namespace lite { -namespace details -{ -#if CODA_OSS_cpp20 && CODA_OSS_mdspan -// https://github.com/kokkos/mdspan/wiki/A-Gentle-Introduction-to-mdspan -template -using msdpan_2 = coda_oss::mdspan>; -#endif - -template -struct SpanRC final // TODO: use std::mdspan -{ - using size_type = size_t; - using element_type = T; - using pointer = T*; - using reference = T&; - - SpanRC() = default; - SpanRC(pointer p, const std::array& dims) noexcept : SpanRC(p, types::RowCol(dims)) - { - } - SpanRC(const SpanRC&) noexcept = default; - constexpr pointer data_handle() const noexcept - { - return s_.data(); - } - - /*constexpr*/ reference operator[](size_t idx) const noexcept - { - assert(idx < size()); // prevents "constexpr" in C++11 - return data_handle()[idx]; - } - /*constexpr*/ reference operator()(size_t r, size_t c) const noexcept - { - const auto offset = (r * rc_.col) + c; - return (*this)[offset]; - } - - constexpr size_t size() const noexcept - { - assert(s_.size() == rc_.area()); - return s_.size(); - } - - constexpr bool empty() const noexcept - { - return s_.empty(); - } - - static constexpr auto rank() noexcept - { - return 2; - } - - auto extent(size_t rank) const - { - if (rank == 0) return rc_.row; - if (rank == 1) return rc_.col; - throw std::invalid_argument("rank"); - } - -private: - coda_oss::span s_; - types::RowCol rc_; - SpanRC(pointer p, types::RowCol rc) noexcept : s_(p, rc.area()), rc_(std::move(rc)) - { - } -}; -} - -#if CODA_OSS_cpp20 && CODA_OSS_mdspan -template -using SpanRC = details::msdpan_2; -#else template -using SpanRC = details::SpanRC; // TODO: get mdspan working with other compilers -#endif +using SpanRC = coda_oss::mdspan>; } } diff --git a/modules/c++/std/include/import/std.h b/modules/c++/std/include/import/std.h index 32702da30..5c41ee61b 100644 --- a/modules/c++/std/include/import/std.h +++ b/modules/c++/std/include/import/std.h @@ -102,6 +102,7 @@ CODA_OSS_disable_warning_system_header_push #include #include #include +#include CODA_OSS_disable_warning_pop diff --git a/modules/c++/std/include/std/mdspan b/modules/c++/std/include/std/mdspan new file mode 100644 index 000000000..b25c5447d --- /dev/null +++ b/modules/c++/std/include/std/mdspan @@ -0,0 +1,46 @@ +/* ========================================================================= + * This file is part of std-c++ + * ========================================================================= + * + * � Copyright 2023, Maxar Technologies, Inc. + * + * std-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, http://www.gnu.org/licenses/. + * + */ +#pragma once + +#include "coda_oss/mdspan.h" +#include "coda_oss/CPlusPlus.h" + +// Make it (too?) easy for clients to get our various std:: implementations +#ifndef CODA_OSS_NO_std_mdspan + #if CODA_OSS_cpp23 + #include + #define CODA_OSS_NO_std_mdspan 1 // part of C++23 + #else + #define CODA_OSS_NO_std_mdspan 0 // use our own + #endif +#endif + +#if !CODA_OSS_NO_std_mdspan +namespace std // This is slightly uncouth: we're not supposed to augment "std". +{ + using coda_oss::mdspan; + using coda_oss::dextents; +} +#ifndef __cpp_lib_mdspan +#define __cpp_lib_mdspan 202002L // https://en.cppreference.com/w/cpp/feature_test#cpp_lib_mdspan +#endif + +#endif // CODA_OSS_NO_std_mdspan