Skip to content

Commit bd0f709

Browse files
Copilotcrtrottmhoemmen
authored
Add constant_wrapper header with divide/multiply/increment and C++26 CMake support (P3663 piece 1 of N) (#449)
* Initial plan * Piece 1: foundational infrastructure for conforming strided_slice and integral_constant_like - Add C++26 CMake standard support and MDSPAN_ENABLE_P3663 option (default ON) - Add utility headers: remove_cvref.hpp, equality_comparable.hpp, integral_constant_like.hpp, constant_wrapper.hpp - Fix strided_slice static_assert to use conforming is_integral_constant_like_v - Fix one_slice_out_of_bounds to handle convertible-to-index-type slices - Add config.hpp default for MDSPAN_ENABLE_P3663 - Add tests: test_strided_slice, test_constant_wrapper, test_convertible_to_index_type Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> * Add _codeql_build_dir to .gitignore Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> * Trim to minimal first piece: constant_wrapper + C++26 CMake support only Remove the extra utility headers (remove_cvref, equality_comparable, integral_constant_like), revert strided_slice.hpp and one_slice_out_of_bounds to original, remove test_strided_slice and test_convertible_to_index_type. Keep only: - CMakeLists.txt: C++26 standard + MDSPAN_ENABLE_P3663 option - config.hpp: MDSPAN_ENABLE_P3663 default - constant_wrapper.hpp: new header - test_constant_wrapper.cpp: test for constant_wrapper Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> * Rename MDSPAN_ENABLE_P3663 to MDSPAN_IMPL_ENABLE_P3663; make test_constant_wrapper unconditional - CMakeLists.txt: option renamed MDSPAN_IMPL_ENABLE_P3663 - tests/CMakeLists.txt: define renamed MDSPAN_IMPL_ENABLE_P3663; test_constant_wrapper registered unconditionally (not under if-guard) - config.hpp: default macro renamed MDSPAN_IMPL_ENABLE_P3663 - test_constant_wrapper.cpp: unconditional include of constant_wrapper.hpp (no #if MDSPAN_ENABLE_P3663 / #error guard) Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> * Apply suggestion from @mhoemmen Co-authored-by: Mark Hoemmen <mhoemmen@users.noreply.github.com> * Move constant_wrapper and cw into detail namespace - constant_wrapper.hpp: move constant_wrapper, cw, increment, and is_constant_wrapper all into MDSPAN_IMPL_STANDARD_NAMESPACE::detail (previously constant_wrapper/cw were in the enclosing namespace); in the back-port path, constant_wrapper now aliases integral_constant directly (no full qualification needed inside detail) - test_constant_wrapper.cpp: update all using-declarations to MDSPAN_IMPL_STANDARD_NAMESPACE::detail::cw / ::constant_wrapper Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> * Move divide/multiply to constant_wrapper.hpp; add cw overloads; add Arithmetic test - constant_wrapper.hpp: restructure into #if/__cpp_lib_constant_wrapper sections; fix increment/is_constant_wrapper to use single-NTTP form for std path and correct back-port form; add const-stripping specialization for is_constant_wrapper (constexpr variables are const, so is_constant_wrapper<const T> must work); move generic divide/multiply + std::integral_constant overloads here from submdspan_extents.hpp; add constant_wrapper overloads for both paths - submdspan_extents.hpp: add #include "constant_wrapper.hpp"; remove divide/multiply - test_constant_wrapper.cpp: add TestConstantWrapper.Arithmetic testing increment, divide, and multiply with size_t, including is_constant_wrapper checks Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> * Only have one increment definition Signed-off-by: Christian Trott <crtrott@sandia.gov> --------- Signed-off-by: Christian Trott <crtrott@sandia.gov> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crtrott <9490481+crtrott@users.noreply.github.com> Co-authored-by: Christian Trott <crtrott@sandia.gov> Co-authored-by: Mark Hoemmen <mhoemmen@users.noreply.github.com>
1 parent 3b0c6e2 commit bd0f709

7 files changed

Lines changed: 330 additions & 33 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ CMakeUserPresets.json
44
out
55
build*
66
Makefile
7+
_codeql_build_dir/
8+
_codeql_detected_source_root

CMakeLists.txt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ option(MDSPAN_GENERATE_STD_NAMESPACE_TARGETS "Whether to generate and install ta
2828

2929
# Option to override which C++ standard to use
3030
set(MDSPAN_CXX_STANDARD DETECT CACHE STRING "Override the default CXX_STANDARD to compile with.")
31-
set_property(CACHE MDSPAN_CXX_STANDARD PROPERTY STRINGS DETECT 14 17 20 23)
31+
set_property(CACHE MDSPAN_CXX_STANDARD PROPERTY STRINGS DETECT 14 17 20 23 26)
3232

3333
option(MDSPAN_ENABLE_CONCEPTS "Try to enable concepts support by giving extra flags." On)
3434

35+
option(MDSPAN_IMPL_ENABLE_P3663 "Enable implementation of P3663 (Future-proof submdspan_mapping)." On)
36+
3537
################################################################################
3638

3739
# Decide on the standard to use
@@ -63,8 +65,18 @@ elseif(MDSPAN_CXX_STANDARD STREQUAL "23")
6365
else()
6466
message(FATAL_ERROR "Requested MDSPAN_CXX_STANDARD \"23\" not supported by provided C++ compiler")
6567
endif()
68+
elseif(MDSPAN_CXX_STANDARD STREQUAL "26")
69+
if("cxx_std_26" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
70+
message(STATUS "Using C++26 standard")
71+
set(CMAKE_CXX_STANDARD 26)
72+
else()
73+
message(WARNING "Requested MDSPAN_CXX_STANDARD \"26\" not supported by provided C++ compiler")
74+
endif()
6675
else()
67-
if("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
76+
if("cxx_std_26" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
77+
set(CMAKE_CXX_STANDARD 26)
78+
message(STATUS "Detected support for C++26 standard")
79+
elseif("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
6880
set(CMAKE_CXX_STANDARD 23)
6981
message(STATUS "Detected support for C++23 standard")
7082
elseif("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)

include/experimental/__p0009_bits/config.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,7 @@ static_assert(MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_14, "mdspan requires C++14
303303
# define MDSPAN_IMPL_OP5(mds, a, b, c, d, e) mds(a,b,c,d,e)
304304
# define MDSPAN_IMPL_OP6(mds, a, b, c, d, e, f) mds(a,b,c,d,e,f)
305305
#endif
306+
307+
#if ! defined(MDSPAN_IMPL_ENABLE_P3663)
308+
# define MDSPAN_IMPL_ENABLE_P3663 1
309+
#endif
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//@HEADER
2+
// ************************************************************************
3+
//
4+
// Kokkos v. 4.0
5+
// Copyright (2022) National Technology & Engineering
6+
// Solutions of Sandia, LLC (NTESS).
7+
//
8+
// Under the terms of Contract DE-NA0003525 with NTESS,
9+
// the U.S. Government retains certain rights in this software.
10+
//
11+
// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
12+
// See https://kokkos.org/LICENSE for license information.
13+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14+
//
15+
//@HEADER
16+
17+
#pragma once
18+
19+
#include "../__p0009_bits/utility.hpp"
20+
#include <type_traits>
21+
22+
namespace MDSPAN_IMPL_STANDARD_NAMESPACE {
23+
namespace detail {
24+
25+
// ============================================================
26+
// constant_wrapper, cw, increment, is_constant_wrapper
27+
// ============================================================
28+
29+
#if defined(__cpp_lib_constant_wrapper)
30+
31+
using std::constant_wrapper;
32+
using std::cw;
33+
34+
template<class T>
35+
constexpr bool is_constant_wrapper = false;
36+
37+
template<class T>
38+
constexpr bool is_constant_wrapper<const T> = is_constant_wrapper<T>;
39+
40+
template<auto Value>
41+
constexpr bool is_constant_wrapper<constant_wrapper<Value>> = true;
42+
43+
#else // back-port: constant_wrapper = detail::integral_constant
44+
45+
template<auto Value, class T = decltype(Value)>
46+
using constant_wrapper = integral_constant<T, Value>;
47+
48+
template<auto Value>
49+
constexpr auto cw = constant_wrapper<Value>{};
50+
51+
template<class T>
52+
constexpr bool is_constant_wrapper = false;
53+
54+
template<class T>
55+
constexpr bool is_constant_wrapper<const T> = is_constant_wrapper<T>;
56+
57+
// integral_constant is the underlying type of the back-port constant_wrapper
58+
// (alias templates can't be used in partial specialization patterns)
59+
template<class Type, Type Value>
60+
constexpr bool is_constant_wrapper<integral_constant<Type, Value>> = true;
61+
62+
#endif // __cpp_lib_constant_wrapper
63+
64+
// ============================================================
65+
// increment function for constant wrapper
66+
// ============================================================
67+
68+
template<auto Value>
69+
MDSPAN_INLINE_FUNCTION
70+
constexpr auto
71+
increment([[maybe_unused]] constant_wrapper<Value> x) {
72+
using value_type = typename decltype(x)::value_type;
73+
return cw< value_type(Value) + value_type(1) >;
74+
}
75+
76+
77+
// ============================================================
78+
// Generic divide / multiply (scalar fall-through)
79+
// ============================================================
80+
81+
template <class IndexT, class T0, class T1>
82+
MDSPAN_INLINE_FUNCTION
83+
constexpr auto divide(const T0 &v0, const T1 &v1) {
84+
return IndexT(v0) / IndexT(v1);
85+
}
86+
87+
template <class IndexT, class T0, class T1>
88+
MDSPAN_INLINE_FUNCTION
89+
constexpr auto multiply(const T0 &v0, const T1 &v1) {
90+
return IndexT(v0) * IndexT(v1);
91+
}
92+
93+
// ============================================================
94+
// Compile-time-preserving overloads for std::integral_constant
95+
// (used when strided_slice template parameters are std::integral_constant)
96+
// ============================================================
97+
98+
template <class IndexT, class T0, T0 v0, class T1, T1 v1>
99+
MDSPAN_INLINE_FUNCTION
100+
constexpr auto divide(const std::integral_constant<T0, v0> &,
101+
const std::integral_constant<T1, v1> &) {
102+
// Short-circuit division by zero
103+
// (used for strided_slice with zero extent/stride)
104+
return integral_constant<IndexT, v0 == 0 ? 0 : v0 / v1>();
105+
}
106+
107+
template <class IndexT, class T0, T0 v0, class T1, T1 v1>
108+
MDSPAN_INLINE_FUNCTION
109+
constexpr auto multiply(const std::integral_constant<T0, v0> &,
110+
const std::integral_constant<T1, v1> &) {
111+
return integral_constant<IndexT, v0 * v1>();
112+
}
113+
114+
// ============================================================
115+
// Compile-time-preserving overloads for constant_wrapper
116+
// ============================================================
117+
118+
#if defined(__cpp_lib_constant_wrapper)
119+
120+
// std::constant_wrapper takes a single NTTP <auto V>
121+
template <class IndexT, auto v0, auto v1>
122+
MDSPAN_INLINE_FUNCTION
123+
constexpr auto divide(const constant_wrapper<v0> &,
124+
const constant_wrapper<v1> &) {
125+
constexpr IndexT result =
126+
IndexT(v0) == IndexT(0) ? IndexT(0) : IndexT(v0) / IndexT(v1);
127+
return cw<result>;
128+
}
129+
130+
template <class IndexT, auto v0, auto v1>
131+
MDSPAN_INLINE_FUNCTION
132+
constexpr auto multiply(const constant_wrapper<v0> &,
133+
const constant_wrapper<v1> &) {
134+
constexpr IndexT result = IndexT(v0) * IndexT(v1);
135+
return cw<result>;
136+
}
137+
138+
#else // back-port: constant_wrapper<v, T> = integral_constant<T, v>
139+
140+
template <class IndexT, class T0, T0 v0, class T1, T1 v1>
141+
MDSPAN_INLINE_FUNCTION
142+
constexpr auto divide(const constant_wrapper<v0, T0> &,
143+
const constant_wrapper<v1, T1> &) {
144+
return integral_constant<IndexT, v0 == 0 ? 0 : v0 / v1>();
145+
}
146+
147+
template <class IndexT, class T0, T0 v0, class T1, T1 v1>
148+
MDSPAN_INLINE_FUNCTION
149+
constexpr auto multiply(const constant_wrapper<v0, T0> &,
150+
const constant_wrapper<v1, T1> &) {
151+
return integral_constant<IndexT, v0 * v1>();
152+
}
153+
154+
#endif // __cpp_lib_constant_wrapper
155+
156+
} // namespace detail
157+
} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE

include/experimental/__p2630_bits/submdspan_extents.hpp

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <complex>
2020

21+
#include "constant_wrapper.hpp"
2122
#include "strided_slice.hpp"
2223
#include "../__p0009_bits/utility.hpp"
2324

@@ -261,36 +262,6 @@ stride_of(const strided_slice<OffsetType, ExtentType, StrideType> &r) {
261262
return r.stride;
262263
}
263264

264-
// divide which can deal with integral constant preservation
265-
template <class IndexT, class T0, class T1>
266-
MDSPAN_INLINE_FUNCTION
267-
constexpr auto divide(const T0 &v0, const T1 &v1) {
268-
return IndexT(v0) / IndexT(v1);
269-
}
270-
271-
template <class IndexT, class T0, T0 v0, class T1, T1 v1>
272-
MDSPAN_INLINE_FUNCTION
273-
constexpr auto divide(const std::integral_constant<T0, v0> &,
274-
const std::integral_constant<T1, v1> &) {
275-
// cutting short division by zero
276-
// this is used for strided_slice with zero extent/stride
277-
return integral_constant<IndexT, v0 == 0 ? 0 : v0 / v1>();
278-
}
279-
280-
// multiply which can deal with integral constant preservation
281-
template <class IndexT, class T0, class T1>
282-
MDSPAN_INLINE_FUNCTION
283-
constexpr auto multiply(const T0 &v0, const T1 &v1) {
284-
return IndexT(v0) * IndexT(v1);
285-
}
286-
287-
template <class IndexT, class T0, T0 v0, class T1, T1 v1>
288-
MDSPAN_INLINE_FUNCTION
289-
constexpr auto multiply(const std::integral_constant<T0, v0> &,
290-
const std::integral_constant<T1, v1> &) {
291-
return integral_constant<IndexT, v0 * v1>();
292-
}
293-
294265
// compute new static extent from range, preserving static knowledge
295266
template <class Arg0, class Arg1> struct StaticExtentFromRange {
296267
constexpr static size_t value = dynamic_extent;

tests/CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ function(mdspan_add_test name)
2626
target_compile_definitions(${name}
2727
PUBLIC
2828
MDSPAN_IMPL_CHECK_PRECONDITION=$<BOOL:${ARGUMENT_ENABLE_PRECONDITIONS}>
29-
)
29+
)
30+
if(MDSPAN_IMPL_ENABLE_P3663)
31+
target_compile_definitions(${name}
32+
PUBLIC
33+
MDSPAN_IMPL_ENABLE_P3663=1
34+
)
35+
endif()
3036
endfunction()
3137

3238
if(MDSPAN_USE_SYSTEM_GTEST)
@@ -105,3 +111,5 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL Clang) OR ((CMAKE_CXX_COMPILER_ID STREQUAL GN
105111
add_subdirectory(libcxx-backports)
106112
endif()
107113
endif()
114+
115+
mdspan_add_test(test_constant_wrapper)

0 commit comments

Comments
 (0)