Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Allocator.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
45 #include <string>
46 #include <vector>
47 
48 namespace { // (anonymous)
49 
50 
51 TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( Allocator, Test1, T )
52 {
55  using std::endl;
56 
57  Teuchos::OSTab tab0 (out);
58  out << "Test Teuchos::Details::Allocator for T = "
59  << TypeNameTraits<T>::name () << endl;
60  AllocationLogger::resetAllocationCounts ();
61 
62  typedef Teuchos::Details::Allocator<T> alloc_type;
63  alloc_type alloc;
64 
65  typedef typename alloc_type::size_type size_type;
66 
67  // At this point, we haven't allocated anything yet. The allocator
68  // does not track whatever memory it uses in its implementation.
69  TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
70 
71  // We'll use this below.
72  size_type oldMaxAlloc = 0;
73 
74  // Put the test in an inner scope, so that the std::vector gets
75  // deallocated before this test finishes. This lets us print
76  // whether deallocation succeeded.
77  {
78  const size_type numEntries = 10;
79 
80  typedef std::vector<T, alloc_type> vec_type;
81  // C++14 defines a two-argument std::vector constructor (count,
82  // alloc), but C++11 only has a three-argument constructor that
83  // takes a count and the allocator. Thus, we need some default
84  // value T. I choose 22 because it is one plus the sum of
85  // integers from 1 to 10, inclusive. It's not a default value,
86  // like zero, and it's positive, so it works if T is unsigned.
87  // It also fits exactly in float and double.
88  T val = static_cast<T> (22);
89  vec_type vec (numEntries, val, alloc);
90 
91  TEST_EQUALITY( vec.size (), numEntries );
92  TEST_EQUALITY_CONST( vec.capacity () >= vec.size (), true );
93 
94  oldMaxAlloc = alloc.maxAllocInBytes ();
95  const size_type curAlloc = alloc.curAllocInBytes ();
96  const size_type expectedCurAlloc = numEntries * sizeof (T);
97 
98  // We don't need strict equality, because the allocator may choose
99  // to allocate more memory than necessary (e.g., to stash
100  // additional information in each allocation).
101  TEST_EQUALITY_CONST( curAlloc >= expectedCurAlloc, true );
102  TEST_EQUALITY_CONST( oldMaxAlloc >= expectedCurAlloc, true );
103 
104  // Make sure that the std::vector's constructor correctly filled
105  // it using val. We have to test this because std::vector defers
106  // to alloc_type::construct for this.
107  for (size_type k = 0; k < numEntries; ++k) {
108  TEST_EQUALITY( vec[k], val );
109  }
110  }
111 
112  // At this point, alloc.curAlloc() should be zero, and
113  // alloc.maxAlloc() should not have changed.
114  const size_type newMaxAlloc = alloc.maxAllocInBytes ();
115  TEST_EQUALITY( oldMaxAlloc, newMaxAlloc );
116  TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
117 
118  out << "Done with test!" << endl;
119 }
120 
121 //
122 // Repeat Test1, but with verbose logging on.
123 //
124 TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( Allocator, Test2, T )
125 {
128  using std::endl;
129 
130  Teuchos::OSTab tab0 (out);
131  out << "Test Teuchos::Details::Allocator for T = "
132  << TypeNameTraits<T>::name () << ", with verbose logging on" << endl;
133  AllocationLogger::resetAllocationCounts ();
134 
135  typedef Teuchos::Details::Allocator<T> alloc_type;
136  // Tell the Allocator to track memory.
137  alloc_type alloc (true, true);
138 
139  typedef typename alloc_type::size_type size_type;
140 
141  // At this point, we haven't allocated anything yet. The allocator
142  // does not track whatever memory it uses in its implementation.
143  TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
144 
145  // We'll use this below.
146  size_type oldMaxAlloc = 0;
147 
148  // Put the test in an inner scope, so that the std::vector gets
149  // deallocated before this test finishes. This lets us print
150  // whether deallocation succeeded.
151  {
152  const size_type numEntries = 10;
153 
154  typedef std::vector<T, alloc_type> vec_type;
155  // C++14 defines a two-argument std::vector constructor (count,
156  // alloc), but C++11 only has a three-argument constructor that
157  // takes a count and the allocator. Thus, we need some default
158  // value T. I choose 22 because it is one plus the sum of
159  // integers from 1 to 10, inclusive. It's not a default value,
160  // like zero, and it's positive, so it works if T is unsigned.
161  // It also fits exactly in float and double.
162  T val = static_cast<T> (22);
163  vec_type vec (numEntries, val, alloc);
164 
165  TEST_EQUALITY( vec.size (), numEntries );
166  TEST_EQUALITY_CONST( vec.capacity () >= vec.size (), true );
167 
168  oldMaxAlloc = alloc.maxAllocInBytes ();
169  const size_type curAlloc = alloc.curAllocInBytes ();
170  const size_type expectedCurAlloc = numEntries * sizeof (T);
171 
172  // We don't need strict equality, because the allocator may choose
173  // to allocate more memory than necessary (e.g., to stash
174  // additional information in each allocation).
175  TEST_EQUALITY_CONST( curAlloc >= expectedCurAlloc, true );
176  TEST_EQUALITY_CONST( oldMaxAlloc >= expectedCurAlloc, true );
177 
178  // Make sure that the std::vector's constructor correctly filled
179  // it using val. We have to test this because std::vector defers
180  // to alloc_type::construct for this.
181  for (size_type k = 0; k < numEntries; ++k) {
182  TEST_EQUALITY( vec[k], val );
183  }
184  }
185 
186  // At this point, alloc.curAlloc() should be zero, and
187  // alloc.maxAlloc() should not have changed.
188  const size_type newMaxAlloc = alloc.maxAllocInBytes ();
189  TEST_EQUALITY( oldMaxAlloc, newMaxAlloc );
190  TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
191 
192  out << "Done with test!" << endl;
193 }
194 
195 //
196 // Make sure that mixing std::vector<T> instances for different T
197 // still gives the right current and max allocation numbers.
198 //
199 TEUCHOS_UNIT_TEST( Allocator, TestMixedTypes )
200 {
202  using std::endl;
203 
204  Teuchos::OSTab tab0 (out);
205  out << "Test Teuchos::Details::Allocator<T> for mixed T" << endl;
206  AllocationLogger::resetAllocationCounts ();
207 
208  typedef Teuchos::Details::Allocator<int> int_alloc_type;
209  typedef int_alloc_type::size_type size_type;
210  const size_type numEntries = 10;
211  const size_type expectedMaxAlloc = numEntries * sizeof (int) + numEntries * sizeof (double);
212 
213  // At this point, we haven't allocated anything yet.
214  TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
215 
216  {
217  std::vector<int, int_alloc_type> intVec (numEntries);
218 
219  typedef Teuchos::Details::Allocator<double> double_alloc_type;
220  std::vector<double, double_alloc_type> dblVec (numEntries);
221 
222  // Both std::vector types must report the same current and max total
223  // allocation sizes, since they share the same allocation mechanism.
224  TEST_EQUALITY( intVec.get_allocator ().curAllocInBytes (), dblVec.get_allocator ().curAllocInBytes () );
225  TEST_EQUALITY( intVec.get_allocator ().maxAllocInBytes (), dblVec.get_allocator ().maxAllocInBytes () );
226 
227 
228  TEST_EQUALITY_CONST( intVec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
229  TEST_EQUALITY_CONST( intVec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
230  }
231 
232  TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
233  TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
234 
235  out << "Done with test!" << endl;
236 }
237 
238 //
239 // Make sure that the Allocator works for types T that do run-time
240 // allocation. std::string is a good example.
241 //
242 // This is the test that shows why you CANNOT use "return new T[n]" to
243 // implement allocate(), and "delete [] p" to implement deallocate().
244 // (Try it on a Mac and watch your debug malloc complain that you're
245 // trying to free something it never malloc'd.)
246 //
247 TEUCHOS_UNIT_TEST( Allocator, TestString )
248 {
250  using std::endl;
251 
252  Teuchos::OSTab tab0 (out);
253  out << "Test Teuchos::Details::Allocator<std::string>" << endl;
254  AllocationLogger::resetAllocationCounts ();
255 
256  typedef Teuchos::Details::Allocator<std::string> string_alloc_type;
257  typedef string_alloc_type::size_type size_type;
258  const size_type numEntries = 10;
259  // Even though std::string itself does run-time allocation inside,
260  // this is still the correct max allocation for an array of
261  // std::string.
262  const size_type expectedMaxAlloc = numEntries * sizeof (std::string);
263 
264  // At this point, we haven't allocated anything yet.
265  TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
266 
267  // First, try it without setting any of the strings.
268  {
269  std::vector<std::string, string_alloc_type> vec (numEntries);
270 
271  TEST_EQUALITY_CONST( vec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
272  TEST_EQUALITY_CONST( vec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
273  }
274 
275  TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
276  TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
277 
278  // Next, construct the std::vector, setting all entries to a string
279  // of nonzero length.
280  {
281  string_alloc_type alloc;
282  std::string val ("I'm a little teapot, short and stout.");
283  std::vector<std::string, string_alloc_type> vec (numEntries, val, alloc);
284 
285  TEST_EQUALITY_CONST( vec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
286  TEST_EQUALITY_CONST( vec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
287  }
288 
289  TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
290  TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
291 
292  // Next, construct the std::vector without setting any of the
293  // strings, then iterate through it and set the strings one by one
294  // to different values (that circumvents possible reference counting
295  // in std::string).
296  {
297  string_alloc_type alloc;
298  std::vector<std::string, string_alloc_type> vec (numEntries);
299 
300  for (size_type k = 0; k < numEntries; ++k) {
301  std::ostringstream os;
302  os << "Current index: " << k;
303  vec[k] = os.str ();
304  }
305 
306  TEST_EQUALITY_CONST( vec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
307  TEST_EQUALITY_CONST( vec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
308  }
309 
310  TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
311  TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
312 
313  out << "Done with test!" << endl;
314 }
315 
316 
317 TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( Allocator, Test1, int )
318 TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( Allocator, Test1, double )
319 
320 
321 } // namespace (anonymous)
#define TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL(TEST_GROUP, TEST_NAME, TYPE)
Macro for defining a templated unit test with one template parameter.
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
#define TEUCHOS_UNIT_TEST(TEST_GROUP, TEST_NAME)
Macro for defining a (non-templated) unit test.
Optional tracking allocator for Teuchos Memory Management classes.
Logging implementation used by Allocator (see below).
Tabbing class for helping to create formated, indented output for a basic_FancyOStream object...
Unit testing support.
#define TEST_EQUALITY_CONST(v1, v2)
Assert the equality of v1 and constant v2.
Default traits class that just returns typeid(T).name().
#define TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(TEST_GROUP, TEST_NAME, TYPE)
Instantiate a templated unit test with one template parameter.
Defines basic traits returning the name of a type in a portable and readable way. ...
Declaration of Teuchos::Details::Allocator, a tracking and logging implementation of the C++ Standard...