Skip to content

Commit 169205f

Browse files
committed
Add user-defined literals, operator "" sv()
1 parent 3a90dcc commit 169205f

File tree

2 files changed

+260
-20
lines changed

2 files changed

+260
-20
lines changed

include/nonstd/string_view.hpp

Lines changed: 106 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
# define nssv_MSVC_LANG 0
5353
#endif
5454

55+
#define nssv_CPP11 (__cplusplus == 201103L )
5556
#define nssv_CPP11_OR_GREATER (__cplusplus >= 201103L || nssv_MSVC_LANG >= 201103L )
5657
#define nssv_CPP14_OR_GREATER (__cplusplus >= 201402L || nssv_MSVC_LANG >= 201703L )
5758
#define nssv_CPP17_OR_GREATER (__cplusplus >= 201703L || nssv_MSVC_LANG >= 201703L )
@@ -141,12 +142,23 @@ using std::operator<<;
141142
# define nssv_COMPILER_MSVC_VERSION 0
142143
#endif
143144

145+
#define nssv_COMPILER_VERSION( major, minor, patch ) (10 * ( 10 * major + minor) + patch)
146+
147+
#if defined __clang__
148+
# define nssv_COMPILER_CLANG_VERSION nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
149+
#else
150+
# define nssv_COMPILER_CLANG_VERSION 0
151+
#endif
152+
144153
#if defined __GNUC__
145-
# define nssv_COMPILER_GNUC_VERSION __GNUC__
154+
# define nssv_COMPILER_GNUC_VERSION nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
146155
#else
147156
# define nssv_COMPILER_GNUC_VERSION 0
148157
#endif
149158

159+
// half-open range [lo..hi):
160+
#define nssv_BETWEEN( v, lo, hi ) ( lo <= v && v < hi )
161+
150162
// Presence of C++11 language features:
151163

152164
#if nssv_CPP11_OR_GREATER || nssv_COMPILER_MSVC_VERSION >= 10
@@ -167,10 +179,15 @@ using std::operator<<;
167179
# define nssv_HAVE_CONSTEXPR_11 1
168180
# define nssv_HAVE_ENUM_CLASS 1
169181
# define nssv_HAVE_EXPLICIT_CONVERSION 1
182+
# define nssv_HAVE_INLINE_NAMESPACE 1
170183
# define nssv_HAVE_IS_DEFAULT 1
171184
# define nssv_HAVE_IS_DELETE 1
172185
# define nssv_HAVE_NOEXCEPT 1
173186
# define nssv_HAVE_REF_QUALIFIER 1
187+
# define nssv_HAVE_USER_DEFINED_LITERALS 1
188+
# if ! ( ( nssv_CPP11 && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) )
189+
# define nssv_HAVE_STD_DEFINED_LITERALS 1
190+
# endif
174191
#endif
175192

176193
// Presence of C++14 language features:
@@ -218,6 +235,12 @@ using std::operator<<;
218235
# define nssv_explicit /*explicit*/
219236
#endif
220237

238+
#if nssv_HAVE_INLINE_NAMESPACE
239+
# define nssv_inline_ns inline
240+
#else
241+
# define nssv_inline_ns /*inline*/
242+
#endif
243+
221244
#if nssv_HAVE_NOEXCEPT
222245
# define nssv_noexcept noexcept
223246
#else
@@ -244,10 +267,7 @@ using std::operator<<;
244267
# define nssv_nodiscard /*[[nodiscard]]*/
245268
#endif
246269

247-
// additional includes:
248-
249-
#if nssv_CPP11_OR_GREATER
250-
#endif
270+
// Additional includes:
251271

252272
#include <algorithm>
253273
#include <cassert>
@@ -257,26 +277,47 @@ using std::operator<<;
257277
#include <stdexcept>
258278
#include <string> // std::char_traits<>
259279

260-
// MSVC warning suppression macros:
280+
// Clang, GNUC, MSVC warning suppression macros:
281+
282+
#ifdef __clang__
283+
# pragma clang diagnostic ignored "-Wreserved-user-defined-literal"
284+
# pragma clang diagnostic push
285+
# pragma clang diagnostic ignored "-Wuser-defined-literals"
286+
#elif defined __GNUC__
287+
# pragma GCC diagnostic push
288+
# pragma GCC diagnostic ignored "-Wliteral-suffix"
289+
#endif // __clang__
261290

262291
#if nssv_COMPILER_MSVC_VERSION >= 14
263292
# define nssv_SUPPRESS_MSGSL_WARNING(expr) [[gsl::suppress(expr)]]
264293
# define nssv_SUPPRESS_MSVC_WARNING(code, descr) __pragma(warning(suppress: code) )
265294
# define nssv_DISABLE_MSVC_WARNINGS(codes) __pragma(warning(push)) __pragma(warning(disable: codes))
266-
# define nssv_RESTORE_MSVC_WARNINGS() __pragma(warning(pop ))
267295
#else
268296
# define nssv_SUPPRESS_MSGSL_WARNING(expr)
269297
# define nssv_SUPPRESS_MSVC_WARNING(code, descr)
270298
# define nssv_DISABLE_MSVC_WARNINGS(codes)
271-
# define nssv_RESTORE_MSVC_WARNINGS()
272299
#endif
273300

274-
// Suppress the following MSVC GSL warnings:
301+
#ifdef __clang__
302+
# define nssv_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
303+
#elif defined __GNUC__
304+
# define nssv_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
305+
#elif nssv_COMPILER_MSVC_VERSION >= 14
306+
# define nssv_RESTORE_WARNINGS() __pragma(warning(pop ))
307+
#else
308+
# define nssv_RESTORE_WARNINGS()
309+
#endif
310+
311+
// Suppress the following MSVC (GSL) warnings:
312+
// - C4455, non-gsl : 'operator ""sv': literal suffix identifiers that do not
313+
// start with an underscore are reserved
275314
// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;
276315
// use brace initialization, gsl::narrow_cast or gsl::narow
277316
// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead
278317

279-
nssv_DISABLE_MSVC_WARNINGS( 26481 26472 )
318+
nssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 )
319+
//nssv_DISABLE_CLANG_WARNINGS( "-Wuser-defined-literals" )
320+
//nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix )
280321

281322
namespace nonstd { namespace sv_lite {
282323

@@ -846,22 +887,65 @@ typedef basic_string_view<char16_t> u16string_view;
846887
typedef basic_string_view<char32_t> u32string_view;
847888
#endif
848889

890+
}} // namespace nonstd::sv_lite
891+
849892
//
850893
// 24.4.6 Suffix for basic_string_view literals:
851894
//
852895

853-
namespace string_view_literals {
896+
#if nssv_HAVE_USER_DEFINED_LITERALS
897+
898+
namespace nonstd {
899+
nssv_inline_ns namespace literals {
900+
nssv_inline_ns namespace string_view_literals {
854901

855-
// msvc warning C4455: 'operator ""sv': literal suffix identifiers that do not start with an underscore are reserved
902+
#if nssv_HAVE_STD_DEFINED_LITERALS
856903

857-
//nssv_constexpr string_view operator "" sv(const char* str, size_t len) nssv_noexcept; // (1)
858-
//nssv_constexpr u16string_view operator "" sv(const char16_t* str, size_t len) nssv_noexcept; // (2)
859-
//nssv_constexpr u32string_view operator "" sv(const char32_t* str, size_t len) nssv_noexcept; // (3)
860-
//nssv_constexpr wstring_view operator "" sv(const wchar_t* str, size_t len) nssv_noexcept; // (4)
904+
nssv_constexpr nonstd::sv_lite::string_view operator "" sv( const char* str, size_t len ) nssv_noexcept // (1)
905+
{
906+
return nonstd::sv_lite::string_view{ str, len };
907+
}
861908

862-
} // namespace string_view_literals
909+
nssv_constexpr nonstd::sv_lite::u16string_view operator "" sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
910+
{
911+
return nonstd::sv_lite::u16string_view{ str, len };
912+
}
863913

864-
}} // namespace nonstd::sv_lite
914+
nssv_constexpr nonstd::sv_lite::u32string_view operator "" sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
915+
{
916+
return nonstd::sv_lite::u32string_view{ str, len };
917+
}
918+
919+
nssv_constexpr nonstd::sv_lite::wstring_view operator "" sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
920+
{
921+
return nonstd::sv_lite::wstring_view{ str, len };
922+
}
923+
924+
#endif // nssv_HAVE_STD_DEFINED_LITERALS
925+
926+
nssv_constexpr nonstd::sv_lite::string_view operator "" _sv( const char* str, size_t len ) nssv_noexcept // (1)
927+
{
928+
return nonstd::sv_lite::string_view{ str, len };
929+
}
930+
931+
nssv_constexpr nonstd::sv_lite::u16string_view operator "" _sv( const char16_t* str, size_t len ) nssv_noexcept // (2)
932+
{
933+
return nonstd::sv_lite::u16string_view{ str, len };
934+
}
935+
936+
nssv_constexpr nonstd::sv_lite::u32string_view operator "" _sv( const char32_t* str, size_t len ) nssv_noexcept // (3)
937+
{
938+
return nonstd::sv_lite::u32string_view{ str, len };
939+
}
940+
941+
nssv_constexpr nonstd::sv_lite::wstring_view operator "" _sv( const wchar_t* str, size_t len ) nssv_noexcept // (4)
942+
{
943+
return nonstd::sv_lite::wstring_view{ str, len };
944+
}
945+
946+
}}} // namespace nonstd::literals::string_view_literals
947+
948+
#endif
865949

866950
//
867951
// Extensions for std::string:
@@ -936,6 +1020,7 @@ using sv_lite::operator<<;
9361020
using sv_lite::to_string;
9371021
using sv_lite::to_string_view;
9381022
#endif
1023+
9391024
} // namespace nonstd
9401025

9411026
// 24.4.5 Hash support (C++11):
@@ -977,5 +1062,8 @@ struct hash< nonstd::u32string_view >
9771062
} // namespace std
9781063

9791064
#endif // nssv_HAVE_STD_HASH
1065+
1066+
nssv_RESTORE_WARNINGS()
1067+
9801068
#endif // nssv_HAVE_STD_STRING_VIEW
9811069
#endif // NONSTD_SV_LITE_H_INCLUDED

test/string-view.t.cpp

Lines changed: 154 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,160 @@ CASE( "string_view: Allows to search backwards for the first character not equa
792792
EXPECT( sv.find_last_not_of( "heo " , 2 ) == size_type( 2 ) );
793793
EXPECT( sv.find_last_not_of( "x" ) == size_type( 10 ) );
794794
}
795-
#if 0
796-
#endif // 0
795+
796+
CASE( "string_view: Allows to create a string_view, wstring_view, u16string_view, u32string_view via literal \"sv\"" )
797+
{
798+
#if nssv_HAVE_STD_DEFINED_LITERALS
799+
using namespace nonstd::literals::string_view_literals;
800+
801+
string_view sv1 = "abc"sv;
802+
wstring_view sv2 = L"abc"sv;
803+
804+
EXPECT( sv1.size() == size_type( 3 ) );
805+
EXPECT( sv2.size() == size_type( 3 ) );
806+
807+
#if nssv_HAVE_WCHAR16_T
808+
u16string_view sv3 = u"abc"sv;
809+
EXPECT( sv3.size() == size_type( 3 ) );
810+
#endif
811+
#if nssv_HAVE_WCHAR32_T
812+
u32string_view sv4 = U"abc"sv;
813+
EXPECT( sv4.size() == size_type( 3 ) );
814+
#endif
815+
#else
816+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
817+
#endif // nssv_HAVE_STD_DEFINED_LITERALS
818+
}
819+
820+
CASE( "string_view: Allows to create a string_view via literal \"sv\", using namespace nonstd::literals::string_view_literals" )
821+
{
822+
#if nssv_HAVE_STD_DEFINED_LITERALS
823+
using namespace nonstd::literals::string_view_literals;
824+
825+
string_view sv1 = "abc\0\0def";
826+
string_view sv2 = "abc\0\0def"sv;
827+
828+
EXPECT( sv1.size() == size_type( 3 ) );
829+
EXPECT( sv2.size() == size_type( 8 ) );
830+
#else
831+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
832+
#endif // nssv_HAVE_STD_DEFINED_LITERALS
833+
}
834+
835+
CASE( "string_view: Allows to create a string_view via literal \"sv\", using namespace nonstd::string_view_literals" )
836+
{
837+
#if nssv_HAVE_STD_DEFINED_LITERALS
838+
#if nssv_HAVE_INLINE_NAMESPACE
839+
using namespace nonstd::string_view_literals;
840+
841+
string_view sv1 = "abc\0\0def";
842+
string_view sv2 = "abc\0\0def"sv;
843+
844+
EXPECT( sv1.size() == size_type( 3 ) );
845+
EXPECT( sv2.size() == size_type( 8 ) );
846+
#else
847+
EXPECT( !!"Inline namespaces for user-defined literals for string_view not available (no C++11)." );
848+
#endif
849+
#else
850+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
851+
#endif // nssv_HAVE_STD_DEFINED_LITERALS
852+
}
853+
854+
CASE( "string_view: Allows to create a string_view via literal \"sv\", using namespace nonstd::literals" )
855+
{
856+
#if nssv_HAVE_STD_DEFINED_LITERALS
857+
#if nssv_HAVE_INLINE_NAMESPACE
858+
using namespace nonstd::literals;
859+
860+
string_view sv1 = "abc\0\0def";
861+
string_view sv2 = "abc\0\0def"sv;
862+
863+
EXPECT( sv1.size() == size_type( 3 ) );
864+
EXPECT( sv2.size() == size_type( 8 ) );
865+
#else
866+
EXPECT( !!"Inline namespaces for user-defined literals for string_view not available (no C++11)." );
867+
#endif
868+
#else
869+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
870+
#endif // nssv_HAVE_STD_DEFINED_LITERALS
871+
}
872+
873+
CASE( "string_view: Allows to create a string_view, wstring_view, u16string_view, u32string_view via literal \"_sv\"" )
874+
{
875+
#if nssv_HAVE_USER_DEFINED_LITERALS
876+
using namespace nonstd::literals::string_view_literals;
877+
878+
string_view sv1 = "abc"_sv;
879+
wstring_view sv2 = L"abc"_sv;
880+
881+
EXPECT( sv1.size() == size_type( 3 ) );
882+
EXPECT( sv2.size() == size_type( 3 ) );
883+
884+
#if nssv_HAVE_WCHAR16_T
885+
u16string_view sv3 = u"abc"_sv;
886+
EXPECT( sv3.size() == size_type( 3 ) );
887+
#endif
888+
#if nssv_HAVE_WCHAR32_T
889+
u32string_view sv4 = U"abc"_sv;
890+
EXPECT( sv4.size() == size_type( 3 ) );
891+
#endif
892+
#else
893+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
894+
#endif // nssv_HAVE_USER_DEFINED_LITERALS
895+
}
896+
897+
CASE( "string_view: Allows to create a string_view via literal \"_sv\", using namespace nonstd::literals::string_view_literals" )
898+
{
899+
#if nssv_HAVE_USER_DEFINED_LITERALS
900+
using namespace nonstd::literals::string_view_literals;
901+
902+
string_view sv1 = "abc\0\0def";
903+
string_view sv2 = "abc\0\0def"_sv;
904+
905+
EXPECT( sv1.size() == size_type( 3 ) );
906+
EXPECT( sv2.size() == size_type( 8 ) );
907+
#else
908+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
909+
#endif // nssv_HAVE_USER_DEFINED_LITERALS
910+
}
911+
912+
CASE( "string_view: Allows to create a string_view via literal \"_sv\", using namespace nonstd::string_view_literals" )
913+
{
914+
#if nssv_HAVE_USER_DEFINED_LITERALS
915+
#if nssv_HAVE_INLINE_NAMESPACE
916+
using namespace nonstd::string_view_literals;
917+
918+
string_view sv1 = "abc\0\0def";
919+
string_view sv2 = "abc\0\0def"_sv;
920+
921+
EXPECT( sv1.size() == size_type( 3 ) );
922+
EXPECT( sv2.size() == size_type( 8 ) );
923+
#else
924+
EXPECT( !!"Inline namespaces for user-defined literals for string_view not available (no C++11)." );
925+
#endif
926+
#else
927+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
928+
#endif // nssv_HAVE_USER_DEFINED_LITERALS
929+
}
930+
931+
CASE( "string_view: Allows to create a string_view via literal \"_sv\", using namespace nonstd::literals" )
932+
{
933+
#if nssv_HAVE_USER_DEFINED_LITERALS
934+
#if nssv_HAVE_INLINE_NAMESPACE
935+
using namespace nonstd::literals;
936+
937+
string_view sv1 = "abc\0\0def";
938+
string_view sv2 = "abc\0\0def"_sv;
939+
940+
EXPECT( sv1.size() == size_type( 3 ) );
941+
EXPECT( sv2.size() == size_type( 8 ) );
942+
#else
943+
EXPECT( !!"Inline namespaces for user-defined literals for string_view not available (no C++11)." );
944+
#endif
945+
#else
946+
EXPECT( !!"User-defined literals for string_view not available (no C++11)." );
947+
#endif // nssv_HAVE_USER_DEFINED_LITERALS
948+
}
797949

798950
// 24.4.3 Non-member comparison functions:
799951

0 commit comments

Comments
 (0)