Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use C++20 for ""_s if available #521

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ option(BOOST_HANA_ENABLE_DEBUG_MODE "Enable Hana's debug mode." OFF)

option(BOOST_HANA_ENABLE_STRING_UDL
"Enable the GNU extension allowing the special string literal operator\
template, which enables the _s suffix for creating compile-time strings." ON)
template, which enables the _s suffix for creating compile-time strings\
(unnecessary if you have a C++20 compiler)." ON)

option(BOOST_HANA_ENABLE_EXCEPTIONS
"Build with exceptions enabled. Note that Hana does not make use of exceptions,\
Expand Down
2 changes: 1 addition & 1 deletion example/string/literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace hana = boost::hana;
using namespace hana::literals;


// By default, this is disabled
// This requires C++20 or a compiler extension which is disabled by default
#ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL

constexpr auto str = "Hello world!"_s;
Expand Down
49 changes: 41 additions & 8 deletions include/boost/hana/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,35 @@ Distributed under the Boost Software License, Version 1.0.
# endif
#endif

//////////////////////////////////////////////////////////////////////////////
// C++20 string literal UDL suport
//////////////////////////////////////////////////////////////////////////////
#if defined(_MSC_VER) && !defined(__clang__)
# if _MSVC_LANG > 201703 && _MSC_FULL_VER >= 192829921
# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
# endif
#elif defined(__clang__)
# if (__cplusplus > 201703 && \
BOOST_HANA_CONFIG_CLANG >= BOOST_HANA_CONFIG_VERSION(12, 0, 0))
# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
# if BOOST_HANA_CONFIG_CLANG < BOOST_HANA_CONFIG_VERSION(18, 0, 0)
# define BOOST_HANA_CONFIG_CXX20_STRING_UDL_CLANG_WORKAROUND
# endif
# endif
#elif defined(__GNUC__)
# if (__cplusplus > 201703 && \
BOOST_HANA_CONFIG_GCC >= BOOST_HANA_CONFIG_VERSION(9, 3, 0))
# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
# endif
#elif (__cpp_deduction_guides >= 201703 && \
__cpp_nontype_template_args >= 201911)
# define BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
#endif
#if defined(BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL) && \
!defined(BOOST_HANA_CONFIG_ENABLE_STRING_UDL)
# define BOOST_HANA_CONFIG_ENABLE_STRING_UDL
#endif

//////////////////////////////////////////////////////////////////////////////
// Caveats and other compiler-dependent options
//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -145,17 +174,21 @@ Distributed under the Boost Software License, Version 1.0.
# define BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
#endif

#if defined(BOOST_HANA_DOXYGEN_INVOKED)
#if defined(BOOST_HANA_DOXYGEN_INVOKED) && \
!defined(BOOST_HANA_CONFIG_ENABLE_STRING_UDL)
//! @ingroup group-config
//! Enables usage of the "string literal operator template" GNU extension.
//! Enables usage of the "string literal operator template" GNU extension
//! before C++20.
//!
//! That operator is not part of the language yet, but it is supported by
//! both Clang and GCC. This operator allows Hana to provide the nice `_s`
//! user-defined literal for creating compile-time strings.
//! C++20 added functionality allowing Hana to provide the nice `_s`
//! user-defined literal for creating compile-time strings; prior to that,
//! both Clang and GCC supported an extension allowing the same
//! functionality but via a different mechanism.
//!
//! When this macro is not defined, the GNU extension will be not used
//! by Hana. Because this is a non-standard extension, the macro is not
//! defined by default.
//! When C++20 support is detected, this macro is defined by default and
//! the C++20 mechanism is used. Otherwise, if this macro is not defined,
//! the macro is not defined by default and the GNU extension will not be
//! used by Hana because it is a non-standard extension.
# define BOOST_HANA_CONFIG_ENABLE_STRING_UDL
#endif

Expand Down
40 changes: 29 additions & 11 deletions include/boost/hana/fwd/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,21 @@ namespace boost { namespace hana {
#endif

#ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL
# ifdef BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
namespace string_detail {
template<unsigned N>
struct literal_helper;
}
# endif

namespace literals {
//! Creates a compile-time string from a string literal.
//! @relatesalso boost::hana::string
//!
//! The string literal is parsed at compile-time and the result is
//! returned as a `hana::string`. This feature is an extension that
//! is disabled by default; see below for details.
//! returned as a `hana::string`. This feature requires C++20 or a
//! compiler extension that is disabled by default; see below for
//! details.
//!
//! @note
//! Only narrow string literals are supported right now; support for
Expand All @@ -248,24 +256,34 @@ namespace boost { namespace hana {
//! [Hana.issue80] if you need this.
//!
//! @warning
//! This user-defined literal is an extension which requires a special
//! string literal operator that is not part of the standard yet.
//! That operator is supported by both Clang and GCC, and several
//! proposals were made for it to enter C++17. However, since it is
//! not standard, it is disabled by default and defining the
//! `BOOST_HANA_CONFIG_ENABLE_STRING_UDL` config macro is required
//! to get this operator. Hence, if you want to stay safe, just use
//! the `BOOST_HANA_STRING` macro instead. If you want to be fast and
//! furious (I do), define `BOOST_HANA_CONFIG_ENABLE_STRING_UDL`.
//! This user-defined literal requires a special string literal operator
//! that was added to the standard in C++20. Prior to that, an extension
//! supported by both Clang and GCC provides similar functionality, but
//! since it is not standard, it is disabled by default in pre=C++20
//! mode and defining the `BOOST_HANA_CONFIG_ENABLE_STRING_UDL` config
//! macro is required to get this operator. Hence, if you do not have
//! C++20 and want to stay safe, just use the `BOOST_HANA_STRING` macro
//! instead. If you want to be fast and furious (I do), define
//! `BOOST_HANA_CONFIG_ENABLE_STRING_UDL`.
//!
//!
//! Example
//! -------
//! @include example/string/literal.cpp
//!
//! [Hana.issue80]: https://github.com/boostorg/hana/issues/80
# if defined(BOOST_HANA_DOXYGEN_INVOKED)
template <implementation_defined>
constexpr auto operator"" _s();
# elif defined(BOOST_HANA_CONFIG_CXX20_STRING_UDL_CLANG_WORKAROUND)
// Older versions of clang get confused by a forward declaration.
# elif defined(BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL)
template <string_detail::literal_helper>
constexpr auto operator"" _s();
# else
template <typename CharT, CharT ...s>
constexpr auto operator"" _s();
# endif
}
#endif
}} // end namespace boost::hana
Expand Down
25 changes: 25 additions & 0 deletions include/boost/hana/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,34 @@ namespace boost { namespace hana {
/**/

#ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL
# ifdef BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
namespace string_detail {
template<unsigned N>
struct literal_helper {
constexpr literal_helper(char const (&s)[N]) {
for (unsigned i = 0; i != N; ++i)
buf[i] = s[i];
}
static constexpr unsigned size() { return N - 1; }
char buf[N] = {};
};
template<unsigned N>
literal_helper(char const (&)[N]) -> literal_helper<N>;
}
# endif

//////////////////////////////////////////////////////////////////////////
// _s user-defined literal
//////////////////////////////////////////////////////////////////////////
namespace literals {
# ifdef BOOST_HANA_CONFIG_HAS_CXX20_STRING_UDL
template<string_detail::literal_helper s>
constexpr auto operator"" _s() {
return []<std::size_t... I>(std::index_sequence<I...>) {
return hana::string_c<s.buf[I]...>;
}(std::make_index_sequence<s.size()>());
}
# else
template <typename CharT, CharT ...s>
constexpr auto operator"" _s() {
static_assert(std::is_same<CharT, char>::value,
Expand All @@ -121,6 +145,7 @@ namespace boost { namespace hana {
"if you need support for fancier types of compile-time strings.");
return hana::string_c<s...>;
}
# endif
}
#endif

Expand Down