2 Copyright (c) 2005-2019 Intel Corporation
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 // Basic testing of an allocator
18 // Tests against requirements in 20.1.5 of ISO C++ Standard (1998).
19 // Does not check for thread safety or false sharing issues.
21 // Tests for compatibility with the host's STL are in
22 // test_Allocator_STL.h. Those tests are in a separate file
23 // because they bring in lots of STL headers, and the tests here
24 // are supposed to work in the abscense of STL.
27 #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
28 #include <utility> //for std::pair
32 struct is_zero_filling {
33 static const bool value = false;
38 template<typename T, size_t N>
42 zero_fill<T>(foo_array, N);
47 //Internal call of assignment
49 Foo& operator=( const Foo& x ) {
50 for (size_t i = 0; i < N; i++)
51 foo_array[i] = x.foo_array[i];
61 inline char PseudoRandomValue( size_t j, size_t k ) {
62 return char(j*3 ^ j>>4 ^ k);
69 // A RAII class to disable stderr in a certain scope. It's not thread-safe.
72 static void dupToStderrAndClose(int fd) {
73 int ret = dup2(fd, STDERR_FILENO); // close current stderr
74 ASSERT(ret != -1, NULL);
76 ASSERT(ret != -1, NULL);
80 int devNull = open("/dev/null", O_WRONLY);
81 ASSERT(devNull != -1, NULL);
82 stderrCopy = dup(STDERR_FILENO);
83 ASSERT(stderrCopy != -1, NULL);
84 dupToStderrAndClose(devNull);
87 dupToStderrAndClose(stderrCopy);
92 //! T is type and A is allocator for that type
93 template<typename T, typename A>
94 void TestBasic( A& a ) {
98 // See Table 32 in ISO ++ Standard
99 typename A::pointer px = &x;
100 typename A::const_pointer pcx = &cx;
102 typename A::reference rx = x;
103 ASSERT( &rx==&x, NULL );
105 typename A::const_reference rcx = cx;
106 ASSERT( &rcx==&cx, NULL );
108 typename A::value_type v = x;
110 typename A::size_type size;
113 ASSERT( size>0, "not an unsigned integral type?" );
115 typename A::difference_type difference;
118 ASSERT( difference<0, "not an signed integral type?" );
120 // "rebind" tested by our caller
122 ASSERT( a.address(rx)==px, NULL );
124 ASSERT( a.address(rcx)==pcx, NULL );
126 typename A::pointer array[100];
127 size_t sizeof_T = sizeof(T);
128 for( size_t k=0; k<100; ++k ) {
129 array[k] = k&1 ? a.allocate(k,array[0]) : a.allocate(k);
130 char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[k]));
131 for( size_t j=0; j<k*sizeof_T; ++j )
132 s[j] = PseudoRandomValue(j,k);
135 // Test hint argument. This can't be compiled when hint is void*, It should be const void*
136 typename A::pointer a_ptr;
137 const void * const_hint = NULL;
138 a_ptr = a.allocate (1, const_hint);
139 a.deallocate(a_ptr, 1);
141 // Test "a.deallocate(p,n)
142 for( size_t k=0; k<100; ++k ) {
143 char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[k]));
144 for( size_t j=0; j<k*sizeof_T; ++j )
145 ASSERT( s[j] == PseudoRandomValue(j,k), NULL );
146 a.deallocate(array[k],k);
149 // Test "a.max_size()"
150 AssertSameType( a.max_size(), typename A::size_type(0) );
151 // Following assertion catches case where max_size() is so large that computation of
152 // number of bytes for such an allocation would overflow size_type.
153 ASSERT( a.max_size()*typename A::size_type(sizeof(T))>=a.max_size(), "max_size larger than reasonable" );
155 // Test "a.construct(p,t)"
157 typename A::pointer p = a.allocate(1);
158 a.construct( p, cx );
159 ASSERT( NumberOfFoo==n+1, "constructor for Foo not called?" );
161 // Test "a.destroy(p)"
163 ASSERT( NumberOfFoo==n, "destructor for Foo not called?" );
166 #if TBB_USE_EXCEPTIONS
167 volatile size_t too_big = (~size_t(0) - 1024*1024)/sizeof(T);
168 bool exception_caught = false;
169 typename A::pointer p1 = NULL;
172 // On macOS*, failure to map memory results in messages to stderr;
174 DisableStderr disableStderr;
176 p1 = a.allocate(too_big);
177 } catch ( std::bad_alloc& ) {
178 exception_caught = true;
180 ASSERT( exception_caught, "allocate expected to throw bad_alloc" );
181 a.deallocate(p1, too_big);
182 #endif // TBB_USE_EXCEPTIONS
184 #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC
186 typedef typename A:: template rebind<std::pair<typename A::value_type, typename A::value_type> >::other pair_allocator_type;
187 pair_allocator_type pair_allocator(a);
188 int NumberOfFooBeforeConstruct= NumberOfFoo;
189 typename pair_allocator_type::pointer pair_pointer = pair_allocator.allocate(1);
190 pair_allocator.construct( pair_pointer, cx, cx);
191 ASSERT( NumberOfFoo==NumberOfFooBeforeConstruct+2, "constructor for Foo not called appropriate number of times?" );
193 pair_allocator.destroy( pair_pointer );
194 ASSERT( NumberOfFoo==NumberOfFooBeforeConstruct, "destructor for Foo not called appropriate number of times?" );
195 pair_allocator.deallocate(pair_pointer,1);
201 #include "tbb/blocked_range.h"
203 #if _MSC_VER && !defined(__INTEL_COMPILER)
204 // Workaround for erroneous "conditional expression is constant" warning in method check_allocate.
205 #pragma warning (disable: 4127)
208 // A is an allocator for some type
210 struct Body: NoAssign {
211 static const size_t max_k = 100000;
213 Body(A &a_) : a(a_) {}
214 void check_allocate( typename A::pointer array[], size_t i, size_t t ) const
216 ASSERT(array[i] == 0, NULL);
217 size_t size = i * (i&3);
218 array[i] = i&1 ? a.allocate(size, array[i>>3]) : a.allocate(size);
219 ASSERT(array[i] != 0, "allocator returned null");
220 char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[i]));
221 for( size_t j=0; j<size*sizeof(typename A::value_type); ++j ) {
222 if(is_zero_filling<typename A::template rebind<void>::other>::value)
223 ASSERT( !s[j], NULL);
224 s[j] = PseudoRandomValue(i, t);
228 void check_deallocate( typename A::pointer array[], size_t i, size_t t ) const
230 ASSERT(array[i] != 0, NULL);
231 size_t size = i * (i&3);
232 char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[i]));
233 for( size_t j=0; j<size*sizeof(typename A::value_type); ++j )
234 ASSERT( s[j] == PseudoRandomValue(i, t), "Thread safety test failed" );
235 a.deallocate(array[i], size);
239 void operator()( size_t thread_id ) const {
240 typename A::pointer array[256];
242 for( size_t k=0; k<256; ++k )
244 for( size_t k=0; k<max_k; ++k ) {
245 size_t i = static_cast<unsigned char>(PseudoRandomValue(k,thread_id));
246 if(!array[i]) check_allocate(array, i, thread_id);
247 else check_deallocate(array, i, thread_id);
249 for( size_t k=0; k<256; ++k )
251 check_deallocate(array, k, thread_id);
255 // A is an allocator for some type, and U is another type
256 template<typename U, typename A>
258 typename A::template rebind<U>::other b(a);
260 TestBasic<typename A::value_type>(a);
263 NativeParallelFor( 4, Body<A>(a) );
264 ASSERT( NumberOfFoo==0, "Allocate/deallocate count mismatched" );
266 ASSERT( a==b, NULL );
267 ASSERT( !(a!=b), NULL );
270 template<typename Allocator>
271 int TestMain(const Allocator &a = Allocator()) {
273 typename Allocator::template rebind<Foo<char,1> >::other a1(a);
274 typename Allocator::template rebind<Foo<double,1> >::other a2(a);
275 Test<Foo<int,17> >( a1 );
276 Test<Foo<float,23> >( a2 );