Skip to content

Commit aeecef0

Browse files
committedNov 23, 2022
[libc++] Remove default definition of std::char_traits
This patch removes the base template implementation for std::char_traits. If my reading of http://eel.is/c++draft/char.traits is correct, the Standard mandates that the library provides specializations for several types like char and wchar_t, but not any implementation in the base template. Indeed, such an implementation is bound to be incorrect for most types anyways, since things like `eof()` and `int_type` will definitely have to be customized. Since the base template implementation should not have worked for anyone, this shouldn't be a breaking change (I expect that anyone defining a custom character type today will already have to provide their own specialization of char_traits). However, since we're aware of some users of char_traits for unsigned char and signed char, we're keeping those two specializations around for two releases to give people some time to migrate. Differential Revision: https://reviews.llvm.org/D138307
1 parent 647ddc0 commit aeecef0

File tree

6 files changed

+459
-136
lines changed

6 files changed

+459
-136
lines changed
 

Diff for: ‎libcxx/docs/ReleaseNotes.rst

+11
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,19 @@ Deprecations and Removals
100100
- The ``_LIBCPP_DEBUG`` macro is not honored anymore, and it is an error to try to use it. Please migrate to
101101
``_LIBCPP_ENABLE_DEBUG_MODE`` instead.
102102

103+
- A base template for ``std::char_traits`` is not provided anymore. The Standard mandates that the library
104+
provides specializations for several types like ``char`` and ``wchar_t``, which libc++ does. However, libc++
105+
used to additionally provide a default implementation for ``std::char_traits<T>`` for arbitrary ``T``. Not
106+
only does the Standard not mandate that one is provided, but such an implementation is bound to be incorrect
107+
for some types, so it has been removed. As an exception, ``std::char_traits<unsigned char>`` and
108+
``std::char_traits<signed char>`` are kept for a limited period of time and marked as deprecated to let people
109+
move off of those, since we know there were some users of those. They will be removed in LLVM 18.
110+
103111
Upcoming Deprecations and Removals
104112
----------------------------------
113+
- The specializations of ``std::char_traits`` for ``unsigned char`` and ``signed char`` are provided until
114+
LLVM 18. Those non-standard specializations are provided for a transition period and marked as deprecated
115+
but will be removed in the future.
105116

106117
API Changes
107118
-----------

Diff for: ‎libcxx/include/__string/char_traits.h

+224-124
Original file line numberDiff line numberDiff line change
@@ -39,132 +39,37 @@ _LIBCPP_PUSH_MACROS
3939
_LIBCPP_BEGIN_NAMESPACE_STD
4040

4141
template <class _CharT>
42-
struct _LIBCPP_TEMPLATE_VIS char_traits
42+
struct char_traits;
43+
/*
44+
The Standard does not define the base template for char_traits because it is impossible to provide
45+
a correct definition for arbitrary character types. Instead, it requires implementations to provide
46+
specializations for predefined character types like `char`, `wchar_t` and others. We provide this as
47+
exposition-only to document what members a char_traits specialization should provide:
4348
{
4449
using char_type = _CharT;
45-
using int_type = int;
46-
using off_type = streamoff;
47-
using pos_type = streampos;
48-
using state_type = mbstate_t;
49-
50-
static inline void _LIBCPP_CONSTEXPR_SINCE_CXX17
51-
assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
52-
static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
53-
{return __c1 == __c2;}
54-
static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
55-
{return __c1 < __c2;}
56-
57-
static _LIBCPP_CONSTEXPR_SINCE_CXX17
58-
int compare(const char_type* __s1, const char_type* __s2, size_t __n);
59-
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
60-
size_t length(const char_type* __s);
61-
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
62-
const char_type* find(const char_type* __s, size_t __n, const char_type& __a);
63-
static _LIBCPP_CONSTEXPR_SINCE_CXX20
64-
char_type* move(char_type* __s1, const char_type* __s2, size_t __n);
65-
_LIBCPP_INLINE_VISIBILITY
66-
static _LIBCPP_CONSTEXPR_SINCE_CXX20
67-
char_type* copy(char_type* __s1, const char_type* __s2, size_t __n);
68-
_LIBCPP_INLINE_VISIBILITY
69-
static _LIBCPP_CONSTEXPR_SINCE_CXX20
70-
char_type* assign(char_type* __s, size_t __n, char_type __a);
71-
72-
static inline _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
73-
{return eq_int_type(__c, eof()) ? ~eof() : __c;}
74-
static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
75-
{return char_type(__c);}
76-
static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
77-
{return int_type(__c);}
78-
static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
79-
{return __c1 == __c2;}
80-
static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
81-
{return int_type(EOF);}
50+
using int_type = ...;
51+
using off_type = ...;
52+
using pos_type = ...;
53+
using state_type = ...;
54+
55+
static void assign(char_type&, const char_type&);
56+
static bool eq(char_type, char_type);
57+
static bool lt(char_type, char_type);
58+
59+
static int compare(const char_type*, const char_type*, size_t);
60+
static size_t length(const char_type*);
61+
static const char_type* find(const char_type*, size_t, const char_type&);
62+
static char_type* move(char_type*, const char_type*, size_t);
63+
static char_type* copy(char_type*, const char_type* __s2, size_t);
64+
static char_type* assign(char_type*, size_t, char_type);
65+
66+
static int_type not_eof(int_type);
67+
static char_type to_char_type(int_type);
68+
static int_type to_int_type(char_type);
69+
static bool eq_int_type(int_type, int_type);
70+
static int_type eof();
8271
};
83-
84-
template <class _CharT>
85-
_LIBCPP_CONSTEXPR_SINCE_CXX17 int
86-
char_traits<_CharT>::compare(const char_type* __s1, const char_type* __s2, size_t __n)
87-
{
88-
for (; __n; --__n, ++__s1, ++__s2)
89-
{
90-
if (lt(*__s1, *__s2))
91-
return -1;
92-
if (lt(*__s2, *__s1))
93-
return 1;
94-
}
95-
return 0;
96-
}
97-
98-
template <class _CharT>
99-
inline
100-
_LIBCPP_CONSTEXPR_SINCE_CXX17 size_t
101-
char_traits<_CharT>::length(const char_type* __s)
102-
{
103-
size_t __len = 0;
104-
for (; !eq(*__s, char_type(0)); ++__s)
105-
++__len;
106-
return __len;
107-
}
108-
109-
template <class _CharT>
110-
inline
111-
_LIBCPP_CONSTEXPR_SINCE_CXX17 const _CharT*
112-
char_traits<_CharT>::find(const char_type* __s, size_t __n, const char_type& __a)
113-
{
114-
for (; __n; --__n)
115-
{
116-
if (eq(*__s, __a))
117-
return __s;
118-
++__s;
119-
}
120-
return nullptr;
121-
}
122-
123-
template <class _CharT>
124-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _CharT*
125-
char_traits<_CharT>::move(char_type* __s1, const char_type* __s2, size_t __n)
126-
{
127-
if (__n == 0) return __s1;
128-
char_type* __r = __s1;
129-
if (__s1 < __s2)
130-
{
131-
for (; __n; --__n, ++__s1, ++__s2)
132-
assign(*__s1, *__s2);
133-
}
134-
else if (__s2 < __s1)
135-
{
136-
__s1 += __n;
137-
__s2 += __n;
138-
for (; __n; --__n)
139-
assign(*--__s1, *--__s2);
140-
}
141-
return __r;
142-
}
143-
144-
template <class _CharT>
145-
inline _LIBCPP_CONSTEXPR_SINCE_CXX20
146-
_CharT*
147-
char_traits<_CharT>::copy(char_type* __s1, const char_type* __s2, size_t __n)
148-
{
149-
if (!__libcpp_is_constant_evaluated()) {
150-
_LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
151-
}
152-
char_type* __r = __s1;
153-
for (; __n; --__n, ++__s1, ++__s2)
154-
assign(*__s1, *__s2);
155-
return __r;
156-
}
157-
158-
template <class _CharT>
159-
inline _LIBCPP_CONSTEXPR_SINCE_CXX20
160-
_CharT*
161-
char_traits<_CharT>::assign(char_type* __s, size_t __n, char_type __a)
162-
{
163-
char_type* __r = __s;
164-
for (; __n; --__n, ++__s)
165-
assign(*__s, __a);
166-
return __r;
167-
}
72+
*/
16873

16974
template <class _CharT>
17075
_LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -300,7 +205,6 @@ char_traits<char>::find(const char_type* __s, size_t __n, const char_type& __a)
300205
#endif
301206
}
302207

303-
304208
// char_traits<wchar_t>
305209

306210
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -713,6 +617,202 @@ char_traits<char32_t>::find(const char_type* __s, size_t __n, const char_type& _
713617
return nullptr;
714618
}
715619

620+
//
621+
// Temporary extensions for std::char_traits<unsigned char> and std::char_traits<signed char>.
622+
// TODO: Remove those in LLVM 18.
623+
//
624+
template <>
625+
struct _LIBCPP_TEMPLATE_VIS
626+
_LIBCPP_DEPRECATED_("char_traits<unsigned char> is non-standard and is provided for a temporary period. It will be removed in LLVM 18, so please migrate off of it.")
627+
char_traits<unsigned char>
628+
{
629+
using char_type = unsigned char;
630+
using int_type = int;
631+
using off_type = streamoff;
632+
using pos_type = streampos;
633+
using state_type = mbstate_t;
634+
635+
static inline void _LIBCPP_CONSTEXPR_SINCE_CXX17
636+
assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
637+
static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
638+
{return __c1 == __c2;}
639+
static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
640+
{return __c1 < __c2;}
641+
642+
static _LIBCPP_CONSTEXPR_SINCE_CXX17
643+
int compare(const char_type* __s1, const char_type* __s2, size_t __n) {
644+
for (; __n; --__n, ++__s1, ++__s2)
645+
{
646+
if (lt(*__s1, *__s2))
647+
return -1;
648+
if (lt(*__s2, *__s1))
649+
return 1;
650+
}
651+
return 0;
652+
}
653+
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
654+
size_t length(const char_type* __s) {
655+
size_t __len = 0;
656+
for (; !eq(*__s, char_type(0)); ++__s)
657+
++__len;
658+
return __len;
659+
}
660+
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
661+
const char_type* find(const char_type* __s, size_t __n, const char_type& __a) {
662+
for (; __n; --__n)
663+
{
664+
if (eq(*__s, __a))
665+
return __s;
666+
++__s;
667+
}
668+
return nullptr;
669+
}
670+
static _LIBCPP_CONSTEXPR_SINCE_CXX20
671+
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) {
672+
if (__n == 0) return __s1;
673+
char_type* __r = __s1;
674+
if (__s1 < __s2)
675+
{
676+
for (; __n; --__n, ++__s1, ++__s2)
677+
assign(*__s1, *__s2);
678+
}
679+
else if (__s2 < __s1)
680+
{
681+
__s1 += __n;
682+
__s2 += __n;
683+
for (; __n; --__n)
684+
assign(*--__s1, *--__s2);
685+
}
686+
return __r;
687+
}
688+
_LIBCPP_INLINE_VISIBILITY
689+
static _LIBCPP_CONSTEXPR_SINCE_CXX20
690+
char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) {
691+
if (!__libcpp_is_constant_evaluated()) {
692+
_LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
693+
}
694+
char_type* __r = __s1;
695+
for (; __n; --__n, ++__s1, ++__s2)
696+
assign(*__s1, *__s2);
697+
return __r;
698+
}
699+
_LIBCPP_INLINE_VISIBILITY
700+
static _LIBCPP_CONSTEXPR_SINCE_CXX20
701+
char_type* assign(char_type* __s, size_t __n, char_type __a) {
702+
char_type* __r = __s;
703+
for (; __n; --__n, ++__s)
704+
assign(*__s, __a);
705+
return __r;
706+
}
707+
708+
static inline _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
709+
{return eq_int_type(__c, eof()) ? ~eof() : __c;}
710+
static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
711+
{return char_type(__c);}
712+
static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
713+
{return int_type(__c);}
714+
static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
715+
{return __c1 == __c2;}
716+
static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
717+
{return int_type(EOF);}
718+
};
719+
720+
template <>
721+
struct _LIBCPP_TEMPLATE_VIS
722+
_LIBCPP_DEPRECATED_("char_traits<signed char> is non-standard and is provided for a temporary period. It will be removed in LLVM 18, so please migrate off of it.")
723+
char_traits<signed char>
724+
{
725+
using char_type = signed char;
726+
using int_type = int;
727+
using off_type = streamoff;
728+
using pos_type = streampos;
729+
using state_type = mbstate_t;
730+
731+
static inline void _LIBCPP_CONSTEXPR_SINCE_CXX17
732+
assign(char_type& __c1, const char_type& __c2) _NOEXCEPT {__c1 = __c2;}
733+
static inline _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT
734+
{return __c1 == __c2;}
735+
static inline _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT
736+
{return __c1 < __c2;}
737+
738+
static _LIBCPP_CONSTEXPR_SINCE_CXX17
739+
int compare(const char_type* __s1, const char_type* __s2, size_t __n) {
740+
for (; __n; --__n, ++__s1, ++__s2)
741+
{
742+
if (lt(*__s1, *__s2))
743+
return -1;
744+
if (lt(*__s2, *__s1))
745+
return 1;
746+
}
747+
return 0;
748+
}
749+
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
750+
size_t length(const char_type* __s) {
751+
size_t __len = 0;
752+
for (; !eq(*__s, char_type(0)); ++__s)
753+
++__len;
754+
return __len;
755+
}
756+
_LIBCPP_INLINE_VISIBILITY static _LIBCPP_CONSTEXPR_SINCE_CXX17
757+
const char_type* find(const char_type* __s, size_t __n, const char_type& __a) {
758+
for (; __n; --__n)
759+
{
760+
if (eq(*__s, __a))
761+
return __s;
762+
++__s;
763+
}
764+
return nullptr;
765+
}
766+
static _LIBCPP_CONSTEXPR_SINCE_CXX20
767+
char_type* move(char_type* __s1, const char_type* __s2, size_t __n) {
768+
if (__n == 0) return __s1;
769+
char_type* __r = __s1;
770+
if (__s1 < __s2)
771+
{
772+
for (; __n; --__n, ++__s1, ++__s2)
773+
assign(*__s1, *__s2);
774+
}
775+
else if (__s2 < __s1)
776+
{
777+
__s1 += __n;
778+
__s2 += __n;
779+
for (; __n; --__n)
780+
assign(*--__s1, *--__s2);
781+
}
782+
return __r;
783+
}
784+
_LIBCPP_INLINE_VISIBILITY
785+
static _LIBCPP_CONSTEXPR_SINCE_CXX20
786+
char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) {
787+
if (!__libcpp_is_constant_evaluated()) {
788+
_LIBCPP_ASSERT(__s2 < __s1 || __s2 >= __s1+__n, "char_traits::copy overlapped range");
789+
}
790+
char_type* __r = __s1;
791+
for (; __n; --__n, ++__s1, ++__s2)
792+
assign(*__s1, *__s2);
793+
return __r;
794+
}
795+
_LIBCPP_INLINE_VISIBILITY
796+
static _LIBCPP_CONSTEXPR_SINCE_CXX20
797+
char_type* assign(char_type* __s, size_t __n, char_type __a) {
798+
char_type* __r = __s;
799+
for (; __n; --__n, ++__s)
800+
assign(*__s, __a);
801+
return __r;
802+
}
803+
804+
static inline _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT
805+
{return eq_int_type(__c, eof()) ? ~eof() : __c;}
806+
static inline _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT
807+
{return char_type(__c);}
808+
static inline _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT
809+
{return int_type(__c);}
810+
static inline _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT
811+
{return __c1 == __c2;}
812+
static inline _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT
813+
{return int_type(EOF);}
814+
};
815+
716816
// helper fns for basic_string and string_view
717817

718818
// __str_find
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <string>
10+
11+
// template<> struct char_traits<unsigned char>
12+
// template<> struct char_traits<signed char>
13+
14+
// Make sure we issue deprecation warnings.
15+
16+
#include <string>
17+
18+
void f() {
19+
std::char_traits<unsigned char> uc; // expected-warning{{'char_traits<unsigned char>' is deprecated}}
20+
std::char_traits<signed char> sc; // expected-warning{{'char_traits<signed char>' is deprecated}}
21+
22+
(void)uc;
23+
(void)sc;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <string>
10+
11+
// template<> struct char_traits<unsigned char>
12+
// template<> struct char_traits<signed char>
13+
14+
// Non-standard but provided temporarily for users to migrate.
15+
16+
// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated
17+
18+
#include <string>
19+
#include <cassert>
20+
#include <type_traits>
21+
22+
#include "test_macros.h"
23+
24+
template <class Char>
25+
TEST_CONSTEXPR_CXX20 bool test() {
26+
static_assert(std::is_same<typename std::char_traits<Char>::char_type, Char>::value, "");
27+
static_assert(std::is_same<typename std::char_traits<Char>::int_type, int>::value, "");
28+
static_assert(std::is_same<typename std::char_traits<Char>::off_type, std::streamoff>::value, "");
29+
static_assert(std::is_same<typename std::char_traits<Char>::pos_type, std::streampos>::value, "");
30+
static_assert(std::is_same<typename std::char_traits<Char>::state_type, std::mbstate_t>::value, "");
31+
32+
assert(std::char_traits<Char>::to_int_type(Char('a')) == Char('a'));
33+
assert(std::char_traits<Char>::to_int_type(Char('A')) == Char('A'));
34+
assert(std::char_traits<Char>::to_int_type(0) == 0);
35+
36+
assert(std::char_traits<Char>::to_char_type(Char('a')) == Char('a'));
37+
assert(std::char_traits<Char>::to_char_type(Char('A')) == Char('A'));
38+
assert(std::char_traits<Char>::to_char_type(0) == 0);
39+
40+
assert(std::char_traits<Char>::eof() == EOF);
41+
42+
assert(std::char_traits<Char>::not_eof(Char('a')) == Char('a'));
43+
assert(std::char_traits<Char>::not_eof(Char('A')) == Char('A'));
44+
assert(std::char_traits<Char>::not_eof(0) == 0);
45+
assert(std::char_traits<Char>::not_eof(std::char_traits<Char>::eof()) !=
46+
std::char_traits<Char>::eof());
47+
48+
assert(std::char_traits<Char>::lt(Char('\0'), Char('A')) == (Char('\0') < Char('A')));
49+
assert(std::char_traits<Char>::lt(Char('A'), Char('\0')) == (Char('A') < Char('\0')));
50+
assert(std::char_traits<Char>::lt(Char('a'), Char('a')) == (Char('a') < Char('a')));
51+
assert(std::char_traits<Char>::lt(Char('A'), Char('a')) == (Char('A') < Char('a')));
52+
assert(std::char_traits<Char>::lt(Char('a'), Char('A')) == (Char('a') < Char('A')));
53+
54+
assert( std::char_traits<Char>::eq(Char('a'), Char('a')));
55+
assert(!std::char_traits<Char>::eq(Char('a'), Char('A')));
56+
57+
assert( std::char_traits<Char>::eq_int_type(Char('a'), Char('a')));
58+
assert(!std::char_traits<Char>::eq_int_type(Char('a'), Char('A')));
59+
assert(!std::char_traits<Char>::eq_int_type(std::char_traits<Char>::eof(), Char('A')));
60+
assert( std::char_traits<Char>::eq_int_type(std::char_traits<Char>::eof(), std::char_traits<Char>::eof()));
61+
62+
{
63+
Char s1[] = {1, 2, 3, 0};
64+
Char s2[] = {0};
65+
assert(std::char_traits<Char>::length(s1) == 3);
66+
assert(std::char_traits<Char>::length(s2) == 0);
67+
}
68+
69+
{
70+
Char s1[] = {1, 2, 3};
71+
assert(std::char_traits<Char>::find(s1, 3, Char(1)) == s1);
72+
assert(std::char_traits<Char>::find(s1, 3, Char(2)) == s1+1);
73+
assert(std::char_traits<Char>::find(s1, 3, Char(3)) == s1+2);
74+
assert(std::char_traits<Char>::find(s1, 3, Char(4)) == 0);
75+
assert(std::char_traits<Char>::find(s1, 3, Char(0)) == 0);
76+
assert(std::char_traits<Char>::find(NULL, 0, Char(0)) == 0);
77+
}
78+
79+
{
80+
Char s1[] = {1, 2, 3};
81+
Char s2[3] = {0};
82+
assert(std::char_traits<Char>::copy(s2, s1, 3) == s2);
83+
assert(s2[0] == Char(1));
84+
assert(s2[1] == Char(2));
85+
assert(s2[2] == Char(3));
86+
assert(std::char_traits<Char>::copy(NULL, s1, 0) == NULL);
87+
assert(std::char_traits<Char>::copy(s1, NULL, 0) == s1);
88+
}
89+
90+
{
91+
Char s1[] = {1, 2, 3};
92+
assert(std::char_traits<Char>::move(s1, s1+1, 2) == s1);
93+
assert(s1[0] == Char(2));
94+
assert(s1[1] == Char(3));
95+
assert(s1[2] == Char(3));
96+
s1[2] = Char(0);
97+
assert(std::char_traits<Char>::move(s1+1, s1, 2) == s1+1);
98+
assert(s1[0] == Char(2));
99+
assert(s1[1] == Char(2));
100+
assert(s1[2] == Char(3));
101+
assert(std::char_traits<Char>::move(NULL, s1, 0) == NULL);
102+
assert(std::char_traits<Char>::move(s1, NULL, 0) == s1);
103+
}
104+
105+
{
106+
Char s1[] = {0};
107+
assert(std::char_traits<Char>::compare(s1, s1, 0) == 0);
108+
assert(std::char_traits<Char>::compare(NULL, NULL, 0) == 0);
109+
110+
Char s2[] = {1, 0};
111+
Char s3[] = {2, 0};
112+
assert(std::char_traits<Char>::compare(s2, s2, 1) == 0);
113+
assert(std::char_traits<Char>::compare(s2, s3, 1) < 0);
114+
assert(std::char_traits<Char>::compare(s3, s2, 1) > 0);
115+
}
116+
117+
{
118+
Char s2[3] = {0};
119+
assert(std::char_traits<Char>::assign(s2, 3, Char(5)) == s2);
120+
assert(s2[0] == Char(5));
121+
assert(s2[1] == Char(5));
122+
assert(s2[2] == Char(5));
123+
assert(std::char_traits<Char>::assign(NULL, 0, Char(5)) == NULL);
124+
}
125+
126+
{
127+
Char c = Char('\0');
128+
std::char_traits<Char>::assign(c, Char('a'));
129+
assert(c == Char('a'));
130+
}
131+
132+
return true;
133+
}
134+
135+
int main(int, char**) {
136+
test<unsigned char>();
137+
test<signed char>();
138+
139+
#if TEST_STD_VER > 17
140+
static_assert(test<unsigned char>());
141+
static_assert(test<signed char>());
142+
#endif
143+
144+
return 0;
145+
}

Diff for: ‎libcxx/test/std/ranges/range.adaptors/range.lazy.split/general.pass.cpp

+16-7
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,36 @@
1919
#include <algorithm>
2020
#include <array>
2121
#include <cassert>
22+
#include <concepts>
2223
#include <map>
23-
#include <string>
2424
#include <string_view>
25+
#include <string>
2526
#include <utility>
2627
#include <vector>
2728
#include "types.h"
2829

29-
// A constexpr-friendly lightweight string, primarily useful for comparisons.
30-
// Unlike `std::string_view`, it copies the given string into an
31-
// internal buffer and can work with non-contiguous inputs.
30+
// Basic utility to convert a range to a string-like type. This handles ranges
31+
// that do not contain character types and can work with non-contiguous inputs.
3232
template <class Char>
3333
class BasicSmallString {
34-
std::basic_string<Char> buffer_{};
34+
std::vector<Char> buffer_{};
3535

3636
public:
37-
constexpr BasicSmallString(std::basic_string_view<Char> v) : buffer_(v) {}
37+
constexpr BasicSmallString(std::basic_string_view<Char> v)
38+
requires (std::same_as<Char, char> ||
39+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
40+
std::same_as<Char, wchar_t> ||
41+
#endif
42+
std::same_as<Char, char8_t> ||
43+
std::same_as<Char, char16_t> ||
44+
std::same_as<Char, char32_t>)
45+
: buffer_(v.begin(), v.end())
46+
{}
3847

3948
template <class I, class S>
4049
constexpr BasicSmallString(I b, const S& e) {
4150
for (; b != e; ++b) {
42-
buffer_ += *b;
51+
buffer_.push_back(*b);
4352
}
4453
}
4554

Diff for: ‎libcxx/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp

+39-5
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,51 @@
1111
// void push_back(charT c) // constexpr since C++20
1212

1313
#include <string>
14+
#include <algorithm>
1415
#include <cassert>
1516

1617
#include "test_macros.h"
1718
#include "min_allocator.h"
1819

19-
struct veryLarge
20-
{
20+
struct VeryLarge {
2121
long long a;
2222
char b;
2323
};
2424

25+
namespace std {
26+
template <>
27+
struct char_traits<VeryLarge> {
28+
using char_type = VeryLarge;
29+
using int_type = int;
30+
using off_type = streamoff;
31+
using pos_type = streampos;
32+
using state_type = mbstate_t;
33+
34+
static TEST_CONSTEXPR_CXX20 void assign(char_type& c1, const char_type& c2) { c1 = c2; }
35+
static bool eq(char_type c1, char_type c2);
36+
static bool lt(char_type c1, char_type c2);
37+
38+
static int compare(const char_type* s1, const char_type* s2, size_t n);
39+
static size_t length(const char_type* s);
40+
static const char_type* find(const char_type* s, size_t n, const char_type& a);
41+
static char_type* move(char_type* s1, const char_type* s2, size_t n);
42+
static TEST_CONSTEXPR_CXX20 char_type* copy(char_type* s1, const char_type* s2, size_t n) {
43+
std::copy_n(s2, n, s1);
44+
return s1;
45+
}
46+
static TEST_CONSTEXPR_CXX20 char_type* assign(char_type* s, size_t n, char_type a) {
47+
std::fill_n(s, n, a);
48+
return s;
49+
}
50+
51+
static int_type not_eof(int_type c);
52+
static char_type to_char_type(int_type c);
53+
static int_type to_int_type(char_type c);
54+
static bool eq_int_type(int_type c1, int_type c2);
55+
static int_type eof();
56+
};
57+
} // end namespace std
58+
2559
template <class S>
2660
TEST_CONSTEXPR_CXX20 void
2761
test(S s, typename S::value_type c, S expected)
@@ -48,9 +82,9 @@ TEST_CONSTEXPR_CXX20 bool test() {
4882
#endif
4983

5084
{
51-
// https://llvm.org/PR31454
52-
std::basic_string<veryLarge> s;
53-
veryLarge vl = {};
85+
// https://llvm.org/PR31454
86+
std::basic_string<VeryLarge> s;
87+
VeryLarge vl = {};
5488
s.push_back(vl);
5589
s.push_back(vl);
5690
s.push_back(vl);

0 commit comments

Comments
 (0)
Please sign in to comment.