Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ CMakeUserPresets.json
out
build*
Makefile
_codeql_build_dir/
_codeql_detected_source_root
16 changes: 14 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ option(MDSPAN_GENERATE_STD_NAMESPACE_TARGETS "Whether to generate and install ta

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

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

option(MDSPAN_ENABLE_P3663 "Enable implementation of P3663 (Future-proof submdspan_mapping)." On)
Comment thread
crtrott marked this conversation as resolved.
Outdated

################################################################################

# Decide on the standard to use
Expand Down Expand Up @@ -63,8 +65,18 @@ elseif(MDSPAN_CXX_STANDARD STREQUAL "23")
else()
message(FATAL_ERROR "Requested MDSPAN_CXX_STANDARD \"23\" not supported by provided C++ compiler")
endif()
elseif(MDSPAN_CXX_STANDARD STREQUAL "26")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested this with GCC trunk (16.0.1). It emits the warning but accepts the CMake option nevertheless.

if("cxx_std_26" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
message(STATUS "Using C++26 standard")
set(CMAKE_CXX_STANDARD 26)
else()
message(WARNING "Requested MDSPAN_CXX_STANDARD \"26\" not supported by provided C++ compiler")
endif()
else()
if("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
if("cxx_std_26" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
set(CMAKE_CXX_STANDARD 26)
message(STATUS "Detected support for C++26 standard")
elseif("cxx_std_23" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
set(CMAKE_CXX_STANDARD 23)
message(STATUS "Detected support for C++23 standard")
elseif("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
Expand Down
4 changes: 4 additions & 0 deletions include/experimental/__p0009_bits/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,7 @@ static_assert(MDSPAN_IMPL_CPLUSPLUS >= MDSPAN_CXX_STD_14, "mdspan requires C++14
# define MDSPAN_IMPL_OP5(mds, a, b, c, d, e) mds(a,b,c,d,e)
# define MDSPAN_IMPL_OP6(mds, a, b, c, d, e, f) mds(a,b,c,d,e,f)
#endif

#if ! defined(MDSPAN_ENABLE_P3663)
# define MDSPAN_ENABLE_P3663 1
Comment thread
crtrott marked this conversation as resolved.
Outdated
#endif
71 changes: 71 additions & 0 deletions include/experimental/__p2630_bits/constant_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//@HEADER
// ************************************************************************
//
// Kokkos v. 4.0
// Copyright (2022) National Technology & Engineering
// Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
// See https://kokkos.org/LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//@HEADER

#pragma once

#include "../__p0009_bits/utility.hpp"
#include <type_traits>

namespace MDSPAN_IMPL_STANDARD_NAMESPACE {
Comment thread
crtrott marked this conversation as resolved.

#if defined(__cpp_lib_constant_wrapper)

using std::constant_wrapper;
using std::cw;

#else

namespace detail {

template<class T, T Value>
struct constant_wrapper_impl
{
static constexpr T value = Value;
using value_type = T;
using type = constant_wrapper_impl;
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; }
};

} // namespace detail

template<auto Value, class T = decltype(Value)>
using constant_wrapper = detail::constant_wrapper_impl<T, Value>;
Comment thread
crtrott marked this conversation as resolved.
Outdated

template<auto Value>
constexpr auto cw = constant_wrapper<Value>{};

#endif // __cpp_lib_constant_wrapper

namespace detail {
Comment thread
crtrott marked this conversation as resolved.
Outdated

template<auto Value, class T>
constexpr auto
increment([[maybe_unused]] constant_wrapper<Value, T> x) {
Comment thread
crtrott marked this conversation as resolved.
Outdated
using value_type = typename decltype(x)::value_type;
return cw< decltype(x)::value + value_type(1) >;
}

template<class T>
constexpr bool is_constant_wrapper = false;

template<auto Value, class Type>
constexpr bool is_constant_wrapper<constant_wrapper<Value, Type>> = true;

} // namespace detail


Comment thread
crtrott marked this conversation as resolved.
} // namespace MDSPAN_IMPL_STANDARD_NAMESPACE
12 changes: 11 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ function(mdspan_add_test name)
target_compile_definitions(${name}
PUBLIC
MDSPAN_IMPL_CHECK_PRECONDITION=$<BOOL:${ARGUMENT_ENABLE_PRECONDITIONS}>
)
)
if(MDSPAN_ENABLE_P3663)
target_compile_definitions(${name}
PUBLIC
MDSPAN_ENABLE_P3663=1
Comment thread
crtrott marked this conversation as resolved.
Outdated
)
endif()
endfunction()

if(MDSPAN_USE_SYSTEM_GTEST)
Expand Down Expand Up @@ -105,3 +111,7 @@ if((CMAKE_CXX_COMPILER_ID STREQUAL Clang) OR ((CMAKE_CXX_COMPILER_ID STREQUAL GN
add_subdirectory(libcxx-backports)
endif()
endif()

if(MDSPAN_ENABLE_P3663)
mdspan_add_test(test_constant_wrapper)
endif()
Comment thread
crtrott marked this conversation as resolved.
Outdated
114 changes: 114 additions & 0 deletions tests/test_constant_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//@HEADER
// ************************************************************************
//
// Kokkos v. 4.0
// Copyright (2022) National Technology & Engineering
// Solutions of Sandia, LLC (NTESS).
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
// See https://kokkos.org/LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//@HEADER
#include <type_traits>
#include <gtest/gtest.h>

#if defined(MDSPAN_ENABLE_P3663)
# include "../include/experimental/__p2630_bits/constant_wrapper.hpp"
#else
# error "This test requires that the CMake option MDSPAN_ENABLE_P3663 be ON."
#endif
Comment thread
crtrott marked this conversation as resolved.
Outdated

namespace { // (anonymous)

#if defined(__cpp_lib_constant_wrapper)

template<class Integral, Integral Value>
using IC = std::integral_constant<Integral, Value>;

template<class Integral, Integral Value>
constexpr void test_integral_constant_wrapper(IC<Integral, Value> ic) {
using MDSPAN_IMPL_STANDARD_NAMESPACE::cw;
using MDSPAN_IMPL_STANDARD_NAMESPACE::constant_wrapper;
Comment thread
crtrott marked this conversation as resolved.
Outdated

constexpr auto c = cw<Value>;

static_assert(std::is_same_v<
std::remove_const_t<decltype(cw<Value>)>,
constant_wrapper<Value>>);
Comment thread
mhoemmen marked this conversation as resolved.
static_assert(decltype(c)::value == Value);
static_assert(std::is_same_v<
typename decltype(c)::type,
constant_wrapper<Value>>);
Comment thread
crtrott marked this conversation as resolved.
static_assert(std::is_same_v<
typename decltype(c)::value_type,
Integral>);

constexpr auto c2 = cw<Value>;
// Casting the arithmetic result back to Integral undoes
// any integer promotions (e.g., short + short -> int).
constexpr auto val_plus_1 = Integral(Value + Integral(1));
constexpr auto c_assigned = (c2 = IC<Integral, val_plus_1>{});
Comment thread
crtrott marked this conversation as resolved.
static_assert(c_assigned == val_plus_1);
}

TEST(TestConstantWrapper, Construction) {
test_integral_constant_wrapper(IC<signed char, -3>{});
test_integral_constant_wrapper(IC<signed char, 3>{});
test_integral_constant_wrapper(IC<unsigned char, 3u>{});
test_integral_constant_wrapper(IC<short, -3>{});
test_integral_constant_wrapper(IC<short, 3>{});
test_integral_constant_wrapper(IC<unsigned short, 3u>{});
test_integral_constant_wrapper(IC<int, -5>{});
test_integral_constant_wrapper(IC<int, 5>{});
test_integral_constant_wrapper(IC<unsigned, 5u>{});
test_integral_constant_wrapper(IC<long, -7>{});
test_integral_constant_wrapper(IC<long, 7>{});
test_integral_constant_wrapper(IC<unsigned long, 7u>{});
test_integral_constant_wrapper(IC<long long, -11>{});
test_integral_constant_wrapper(IC<long long, 11>{});
test_integral_constant_wrapper(IC<unsigned long long, 11u>{});
}
#endif

TEST(TestConstantWrapper, IntegerPlus) {
using MDSPAN_IMPL_STANDARD_NAMESPACE::cw;
using MDSPAN_IMPL_STANDARD_NAMESPACE::constant_wrapper;

constant_wrapper<size_t(11)> cw_11;
constexpr size_t value = cw_11;
constexpr size_t value2 = constant_wrapper<size_t(11)>::value;
static_assert(value == value2);
constexpr size_t value3 = decltype(cw_11)();
static_assert(value == value3);

#if defined(__cpp_lib_constant_wrapper)
static_assert(std::is_same_v<
decltype(cw_11),
std::remove_const_t<decltype(cw<size_t(11)>)>>);
#endif

[[maybe_unused]] auto expected_result = cw<size_t(12)>;
using expected_type = constant_wrapper<size_t(12)>;
static_assert(std::is_same_v<decltype(expected_result), expected_type>);

#if defined(__cpp_lib_constant_wrapper)
[[maybe_unused]] auto cw_11_plus_one = cw_11 + cw<size_t(1)>;
[[maybe_unused]] auto one_plus_cw_11 = cw<size_t(1)> + cw_11;

static_assert(! std::is_same_v<
decltype(cw_11 + cw<size_t(1)>),
size_t>);
static_assert(std::is_same_v<
decltype(cw_11 + cw<size_t(1)>),
constant_wrapper<value + size_t(1)>>);
static_assert(std::is_same_v<
decltype(cw<size_t(1)> + cw_11),
constant_wrapper<value + size_t(1)>>);
#endif
}

} // namespace (anonymous)