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 | // UNSUPPORTED: c++03, c++11 |
10 | // UNSUPPORTED: no-localization |
11 | |
12 | // <experimental/iterator> |
13 | // |
14 | // template <class _Delim, class _CharT = char, class _Traits = char_traits<_CharT>> |
15 | // class ostream_joiner; |
16 | // |
17 | // template<typename T> |
18 | // ostream_joiner & operator=(const T&) |
19 | // |
20 | |
21 | #include <experimental/iterator> |
22 | #include <iostream> |
23 | #include <sstream> |
24 | #include <cassert> |
25 | |
26 | #include "test_macros.h" |
27 | #include "test_iterators.h" |
28 | |
29 | struct mutating_delimiter { |
30 | mutating_delimiter(char c = ' ') : c_(c) {} |
31 | char get () const { return c_++; } |
32 | mutable char c_; |
33 | }; |
34 | |
35 | template<class _CharT, class _Traits> |
36 | std::basic_ostream<_CharT, _Traits>& |
37 | operator<<(std::basic_ostream<_CharT, _Traits>& os, const mutating_delimiter &d) |
38 | { return os << d.get(); } |
39 | |
40 | |
41 | struct mutating_delimiter2 { // same as above, w/o the const and the mutable |
42 | mutating_delimiter2(char c = ' ') : c_(c) {} |
43 | char get () { return c_++; } |
44 | char c_; |
45 | }; |
46 | |
47 | template<class _CharT, class _Traits> |
48 | std::basic_ostream<_CharT, _Traits>& |
49 | operator<<(std::basic_ostream<_CharT, _Traits>& os, mutating_delimiter2 &d) |
50 | { return os << d.get(); } |
51 | |
52 | |
53 | namespace exper = std::experimental; |
54 | |
55 | template <class Delim, class Iter, class CharT = char, class Traits = std::char_traits<CharT>> |
56 | void test (Delim &&d, Iter first, Iter last, const CharT *expected ) { |
57 | typedef exper::ostream_joiner<typename std::decay<Delim>::type, CharT, Traits> Joiner; |
58 | |
59 | static_assert((std::is_copy_constructible<Joiner>::value == std::is_copy_constructible<typename std::decay<Delim>::type>::value), "" ); |
60 | static_assert((std::is_move_constructible<Joiner>::value == std::is_move_constructible<typename std::decay<Delim>::type>::value), "" ); |
61 | static_assert((std::is_copy_assignable<Joiner> ::value == std::is_copy_assignable<typename std::decay<Delim>::type> ::value), "" ); |
62 | static_assert((std::is_move_assignable<Joiner> ::value == std::is_move_assignable<typename std::decay<Delim>::type> ::value), "" ); |
63 | |
64 | std::basic_stringstream<CharT, Traits> sstream; |
65 | Joiner joiner(sstream, d); |
66 | while (first != last) |
67 | *joiner++ = *first++; |
68 | assert(sstream.str() == expected); |
69 | } |
70 | |
71 | int main(int, char**) { |
72 | { |
73 | const char chars[] = "0123456789" ; |
74 | const int ints [] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; |
75 | |
76 | test(d: 'X', first: chars, last: chars+10, expected: "0X1X2X3X4X5X6X7X8X9" ); |
77 | test(d: 'x', first: ints, last: ints+10, expected: "10x11x12x13x14x15x16x17x18x19" ); |
78 | test('X', cpp17_input_iterator<const char*>(chars), cpp17_input_iterator<const char*>(chars+10), "0X1X2X3X4X5X6X7X8X9" ); |
79 | test('x', cpp17_input_iterator<const int*>(ints), cpp17_input_iterator<const int*>(ints+10), "10x11x12x13x14x15x16x17x18x19" ); |
80 | test('X', forward_iterator<const char*>(chars), forward_iterator<const char*>(chars+10), "0X1X2X3X4X5X6X7X8X9" ); |
81 | test('x', forward_iterator<const int*>(ints), forward_iterator<const int*>(ints+10), "10x11x12x13x14x15x16x17x18x19" ); |
82 | test('X', random_access_iterator<const char*>(chars), random_access_iterator<const char*>(chars+10), "0X1X2X3X4X5X6X7X8X9" ); |
83 | test('x', random_access_iterator<const int*>(ints), random_access_iterator<const int*>(ints+10), "10x11x12x13x14x15x16x17x18x19" ); |
84 | |
85 | test(d: "Z" , first: chars, last: chars+10, expected: "0Z1Z2Z3Z4Z5Z6Z7Z8Z9" ); |
86 | test(d: "z" , first: ints, last: ints+10, expected: "10z11z12z13z14z15z16z17z18z19" ); |
87 | |
88 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
89 | test<char, const char *, wchar_t> (d: 'X', first: chars, last: chars+10, expected: L"0X1X2X3X4X5X6X7X8X9" ); |
90 | test<char, const int *, wchar_t> (d: 'x', first: ints, last: ints+10, expected: L"10x11x12x13x14x15x16x17x18x19" ); |
91 | #endif |
92 | // TODO(var-const): uncomment when it becomes possible to instantiate a `basic_ostream` object with a sized |
93 | // character type (see https://llvm.org/PR53119). |
94 | // test<char, const char *, char16_t>('X', chars, chars+10, u"0X1X2X3X4X5X6X7X8X9"); |
95 | // test<char, const int *, char16_t>('x', ints, ints+10, u"10x11x12x13x14x15x16x17x18x19"); |
96 | // test<char, const char *, char32_t>('X', chars, chars+10, U"0X1X2X3X4X5X6X7X8X9"); |
97 | // test<char, const int *, char32_t>('x', ints, ints+10, U"10x11x12x13x14x15x16x17x18x19"); |
98 | |
99 | test(d: mutating_delimiter(), first: chars, last: chars+10, expected: "0 1!2\"3#4$5%6&7'8(9" ); |
100 | test(d: mutating_delimiter2(), first: chars, last: chars+10, expected: "0 1!2\"3#4$5%6&7'8(9" ); |
101 | } |
102 | |
103 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
104 | { |
105 | const wchar_t chars[] = L"0123456789" ; |
106 | const int ints [] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; |
107 | test(d: L'X', first: chars, last: chars+10, expected: L"0X1X2X3X4X5X6X7X8X9" ); |
108 | test(d: L'x', first: ints, last: ints+10, expected: L"10x11x12x13x14x15x16x17x18x19" ); |
109 | test(L'X', cpp17_input_iterator<const wchar_t*>(chars), cpp17_input_iterator<const wchar_t*>(chars+10), L"0X1X2X3X4X5X6X7X8X9" ); |
110 | test(L'x', cpp17_input_iterator<const int*>(ints), cpp17_input_iterator<const int*>(ints+10), L"10x11x12x13x14x15x16x17x18x19" ); |
111 | test(L'X', forward_iterator<const wchar_t*>(chars), forward_iterator<const wchar_t*>(chars+10), L"0X1X2X3X4X5X6X7X8X9" ); |
112 | test(L'x', forward_iterator<const int*>(ints), forward_iterator<const int*>(ints+10), L"10x11x12x13x14x15x16x17x18x19" ); |
113 | test(L'X', random_access_iterator<const wchar_t*>(chars), random_access_iterator<const wchar_t*>(chars+10), L"0X1X2X3X4X5X6X7X8X9" ); |
114 | test(L'x', random_access_iterator<const int*>(ints), random_access_iterator<const int*>(ints+10), L"10x11x12x13x14x15x16x17x18x19" ); |
115 | |
116 | test(d: L"Z" , first: chars, last: chars+10, expected: L"0Z1Z2Z3Z4Z5Z6Z7Z8Z9" ); |
117 | test(d: L"z" , first: ints, last: ints+10, expected: L"10z11z12z13z14z15z16z17z18z19" ); |
118 | |
119 | test<char, const wchar_t *, wchar_t> (d: 'X', first: chars, last: chars+10, expected: L"0X1X2X3X4X5X6X7X8X9" ); |
120 | test<char, const int *, wchar_t> (d: 'x', first: ints, last: ints+10, expected: L"10x11x12x13x14x15x16x17x18x19" ); |
121 | |
122 | test(d: mutating_delimiter(), first: chars, last: chars+10, expected: L"0 1!2\"3#4$5%6&7'8(9" ); |
123 | } |
124 | #endif // TEST_HAS_NO_WIDE_CHARACTERS |
125 | |
126 | return 0; |
127 | } |
128 | |