|
1 |
| -// Copyright (c) 2021-2023 Dr. Colin Hirsch and Daniel Frey |
| 1 | +// Copyright (c) 2021-2025 Daniel Frey and Dr. Colin Hirsch |
2 | 2 | // Distributed under the Boost Software License, Version 1.0.
|
3 | 3 | // (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
|
4 | 4 |
|
|
7 | 7 |
|
8 | 8 | #include <cstddef>
|
9 | 9 | #include <string>
|
10 |
| - |
11 |
| -#include "../config.hpp" |
| 10 | +#include <vector> |
12 | 11 |
|
13 | 12 | namespace TAO_PEGTL_NAMESPACE::internal
|
14 | 13 | {
|
15 |
| - // the below uses a hack to call private member functions of a class, described here: |
| 14 | + // This uses a hack to call private member functions of a class, described here: |
16 | 15 | // https://github.com/facebook/folly/blob/master/folly/memory/UninitializedMemoryHacks.h
|
17 | 16 |
|
18 | 17 | namespace // NOLINT(google-build-namespaces)
|
19 | 18 | {
|
20 |
| - // declare some functions... |
21 |
| - void resize_uninitialized_proxy( std::string& v, const std::size_t n ); |
22 |
| - void resize_uninitialized_proxy( std::basic_string< unsigned char >& v, const std::size_t n ); |
23 |
| - void resize_uninitialized_proxy( std::basic_string< std::byte >& v, const std::size_t n ); |
| 19 | + struct odr_helper; |
| 20 | + |
| 21 | + void resize_uninitialized_proxy( std::string& v, const std::size_t n ) noexcept; |
24 | 22 |
|
25 | 23 | #if defined( _LIBCPP_STRING )
|
26 | 24 |
|
27 |
| - // ...create a proxy to generate the actual implementation of the above function... |
28 |
| - template< typename T, void ( T::*F )( std::size_t ) > |
29 |
| - struct proxy |
| 25 | + // Create a proxy to generate the actual implementation of the above function... |
| 26 | + |
| 27 | + template< typename T, auto F > |
| 28 | + struct string_proxy |
30 | 29 | {
|
31 | 30 | // ...define the function declared above...
|
32 |
| - friend void resize_uninitialized_proxy( T& v, const std::size_t n ) |
| 31 | + friend void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept |
33 | 32 | {
|
34 | 33 | ( v.*F )( n ); // v.__set_size( n );
|
35 | 34 | v[ v.size() ] = typename T::value_type( 0 );
|
36 | 35 | }
|
37 | 36 | };
|
38 | 37 |
|
39 |
| - // ...and here's the actual "trick": an explicit template instantiation skips the access checks, |
| 38 | + // ...the actual "trick": an explicit template instantiation skips the access checks, |
40 | 39 | // so you can reference private members and forward them to the above proxy!
|
41 |
| - template struct proxy< std::string, &std::string::__set_size >; |
42 |
| - template struct proxy< std::basic_string< unsigned char >, &std::basic_string< unsigned char >::__set_size >; |
43 |
| - template struct proxy< std::basic_string< std::byte >, &std::basic_string< std::byte >::__set_size >; |
44 | 40 |
|
45 |
| -#elif defined( _GLIBCXX_STRING ) && _GLIBCXX_USE_CXX11_ABI |
| 41 | + template struct string_proxy< std::string, &std::string::__set_size >; |
46 | 42 |
|
47 |
| - template< typename T, void ( T::*F )( std::size_t ) > |
48 |
| - struct proxy |
| 43 | +#elif defined( _GLIBCXX_STRING ) && _GLIBCXX_USE_CXX11_ABI // NOLINT(misc-include-cleaner) |
| 44 | + |
| 45 | + template< typename T, auto F > |
| 46 | + struct string_proxy |
49 | 47 | {
|
50 |
| - friend void resize_uninitialized_proxy( T& v, const std::size_t n ) |
| 48 | + friend void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept |
51 | 49 | {
|
52 | 50 | ( v.*F )( n ); // v._M_set_length( n );
|
53 | 51 | }
|
54 | 52 | };
|
55 | 53 |
|
56 |
| - template struct proxy< std::string, &std::string::_M_set_length >; |
57 |
| - template struct proxy< std::basic_string< unsigned char >, &std::basic_string< unsigned char >::_M_set_length >; |
58 |
| - template struct proxy< std::basic_string< std::byte >, &std::basic_string< std::byte >::_M_set_length >; |
| 54 | + template struct string_proxy< std::string, &std::string::_M_set_length >; |
59 | 55 |
|
60 | 56 | #elif defined( _GLIBCXX_STRING )
|
61 | 57 |
|
62 |
| - template< typename T, |
63 |
| - typename R, |
64 |
| - R* ( T::*F )() const > |
65 |
| - struct proxy |
| 58 | + template< typename T, auto F > |
| 59 | + struct string_proxy |
66 | 60 | {
|
67 |
| - friend void resize_uninitialized_proxy( T& v, const std::size_t n ) |
| 61 | + friend void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept |
68 | 62 | {
|
69 | 63 | // v._M_rep()->_M_set_length_and_sharable( n );
|
70 | 64 | ( v.*F )()->_M_set_length_and_sharable( n );
|
71 | 65 | }
|
72 | 66 | };
|
73 | 67 |
|
74 |
| - template struct proxy< std::string, |
75 |
| - std::string::_Rep, |
76 |
| - &std::string::_M_rep >; |
| 68 | + template struct string_proxy< std::string, &std::string::_M_rep >; |
| 69 | + |
| 70 | +#elif defined( _MSC_VER ) |
| 71 | + |
| 72 | + template< typename T, auto F > |
| 73 | + struct string_proxy |
| 74 | + { |
| 75 | + friend void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept |
| 76 | + { |
| 77 | + ( v.*F )( n ); // v._Eos( n ); |
| 78 | + } |
| 79 | + }; |
77 | 80 |
|
78 |
| - template struct proxy< std::basic_string< unsigned char >, |
79 |
| - std::basic_string< unsigned char >::_Rep, |
80 |
| - &std::basic_string< unsigned char >::_M_rep >; |
| 81 | + template struct string_proxy< std::string, &std::string::_Eos >; |
| 82 | + |
| 83 | +#else |
| 84 | +#error "No implementation for resize_uninitialized for std::string available on this platform." |
| 85 | +#endif |
| 86 | + |
| 87 | +#if defined( _LIBCPP_VECTOR ) |
| 88 | + |
| 89 | + void resize_uninitialized_proxy( std::vector< std::byte >& v, const std::size_t n ) noexcept; |
| 90 | + |
| 91 | + template< typename T, auto M > |
| 92 | + struct vector_proxy |
| 93 | + { |
| 94 | + friend void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept |
| 95 | + { |
| 96 | + // v.__end_ = v.data() + n; |
| 97 | + v.*M = v.data() + n; |
| 98 | + |
| 99 | +#ifndef _LIBCPP_HAS_NO_ASAN |
| 100 | + __sanitizer_annotate_contiguous_container( v.data(), |
| 101 | + v.data() + v.capacity(), |
| 102 | + v.data() + v.size(), |
| 103 | + v.data() + n ); |
| 104 | +#endif |
| 105 | + } |
| 106 | + }; |
81 | 107 |
|
82 |
| - template struct proxy< std::basic_string< std::byte >, |
83 |
| - std::basic_string< std::byte >::_Rep, |
84 |
| - &std::basic_string< std::byte >::_M_rep >; |
| 108 | + template struct vector_proxy< std::vector< std::byte >, &std::vector< std::byte >::__end_ >; |
85 | 109 |
|
86 | 110 | #elif defined( _MSC_VER )
|
87 | 111 |
|
88 |
| - template< typename T, void ( T::*F )( std::size_t ) > |
89 |
| - struct proxy |
| 112 | + void resize_uninitialized_proxy( std::vector< std::byte >& v, const std::size_t n ) noexcept; |
| 113 | + |
| 114 | + template< typename T, auto Mypair, auto Myval2, auto Mylast > |
| 115 | + struct vector_proxy |
90 | 116 | {
|
91 |
| - friend void resize_uninitialized_proxy( T& v, const std::size_t n ) |
| 117 | + friend void resize_uninitialized_proxy( T& v, const std::size_t n ) noexcept |
92 | 118 | {
|
93 |
| - ( v.*F )( n ); // v._Eos( n ); |
| 119 | + // v._Mypair._Myval2._Mylast = v.data() + n; |
| 120 | + v.*Mypair.*Myval2.*Mylast = v.data() + n; |
94 | 121 | }
|
95 | 122 | };
|
96 | 123 |
|
97 |
| - template struct proxy< std::string, &std::string::_Eos >; |
98 |
| - template struct proxy< std::basic_string< unsigned char >, &std::basic_string< unsigned char >::_Eos >; |
99 |
| - template struct proxy< std::basic_string< std::byte >, &std::basic_string< std::byte >::_Eos >; |
| 124 | + template struct vector_proxy< std::vector< std::byte >, |
| 125 | + &std::vector< std::byte >::_Mypair, |
| 126 | + &decltype( std::declval< std::vector< std::byte > >()._Mypair )::_Myval2, |
| 127 | + &decltype( std::declval< std::vector< std::byte > >()._Mypair._Myval2 )::_Mylast >; |
100 | 128 |
|
101 | 129 | #else
|
102 |
| -#error "No implementation for resize_uninitialized available." |
| 130 | + |
| 131 | + // generic version |
| 132 | + |
| 133 | + struct no_init_byte |
| 134 | + { |
| 135 | + std::byte b; |
| 136 | + no_init_byte() noexcept {} // NOLINT(modernize-use-equals-default) |
| 137 | + }; |
| 138 | + |
| 139 | + static_assert( sizeof( std::vector< std::byte > ) == sizeof( std::vector< no_init_byte > ) ); |
| 140 | + static_assert( alignof( std::vector< std::byte > ) == alignof( std::vector< no_init_byte > ) ); |
| 141 | + |
| 142 | + inline void resize_uninitialized_proxy( std::vector< std::byte >& v, const std::size_t n ) noexcept |
| 143 | + { |
| 144 | + // undefined behaviour? |
| 145 | + reinterpret_cast< std::vector< no_init_byte >& >( v ).resize( n ); |
| 146 | + } |
| 147 | + |
103 | 148 | #endif
|
104 | 149 |
|
105 | 150 | } // namespace
|
106 | 151 |
|
107 |
| - template< typename T > |
108 |
| - void resize_uninitialized( std::basic_string< T >& v, const std::size_t n ) |
| 152 | + template< typename = odr_helper > |
| 153 | + void resize_uninitialized( std::string& v, const std::size_t n ) |
| 154 | + { |
| 155 | + if( n <= v.size() ) { |
| 156 | + v.resize( n ); |
| 157 | + } |
| 158 | + else { |
| 159 | + if( n > v.capacity() ) { |
| 160 | + v.reserve( n ); |
| 161 | + } |
| 162 | + internal::resize_uninitialized_proxy( v, n ); |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + template< typename = odr_helper > |
| 167 | + void resize_uninitialized( std::vector< std::byte >& v, const std::size_t n ) |
109 | 168 | {
|
110 | 169 | if( n <= v.size() ) {
|
111 | 170 | v.resize( n );
|
112 | 171 | }
|
113 | 172 | else {
|
114 |
| - // careful not to call reserve() unless necessary, as it causes shrink_to_fit() on many platforms |
115 | 173 | if( n > v.capacity() ) {
|
116 | 174 | v.reserve( n );
|
117 | 175 | }
|
|
0 commit comments