-
Notifications
You must be signed in to change notification settings - Fork 320
/
Copy pathbdlma_managedallocator.h
376 lines (365 loc) · 15.3 KB
/
bdlma_managedallocator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
// bdlma_managedallocator.h -*-C++-*-
#ifndef INCLUDED_BDLMA_MANAGEDALLOCATOR
#define INCLUDED_BDLMA_MANAGEDALLOCATOR
#include <bsls_ident.h>
BSLS_IDENT("$Id: $")
//@PURPOSE: Provide a protocol for memory allocators that support 'release'.
//
//@CLASSES:
// bdlma::ManagedAllocator: protocol for allocators with 'release' capability
//
//@SEE_ALSO: bdlma_bufferedsequentialallocator
//
//@DESCRIPTION: This component provides a 'class', 'bdlma::ManagedAllocator',
// that extends the 'bslma::Allocator' protocol to allocators that support the
// ability to 'release' all memory currently allocated through the protocol
// back to the memory supplier of the derived concrete allocator object.
//..
// ,-----------------------.
// ( bdlma::ManagedAllocator )
// `-----------------------'
// | release
// |
// v
// ,----------------.
// ( bslma::Allocator )
// `----------------'
// allocate
// deallocate
//..
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Implementing the 'bdlma::ManagedAllocator' Protocol
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The 'bdlma::ManagedAllocator' interface is especially useful for allocators
// that are based on an underlying pooling mechanism (e.g., 'bdlma::Multipool'
// or 'bdlma::BufferedSequentialPool'). In particular, such an allocator that
// implements the 'bdlma::ManagedAllocator' interface can release, via the
// 'release' method, all outstanding (pooled) memory back to the underlying
// allocator making the memory available for subsequent reuse. Moreover, use
// of the 'release' method can also often render superfluous the running of
// destructors on the objects making use of a managed allocator. In this first
// usage example, we define the 'my_BufferAllocator' class, an allocator that
// implements the 'bdlma::ManagedAllocator' interface. 'my_BufferAllocator' is
// a considerably pared down version of 'bdlma::BufferedSequentialAllocator',
// and is intended for illustration purposes only. Please see the
// 'bdlma_bufferedsequentialallocator' component for full documentation of
// 'bdlma::BufferedSequentialAllocator', a managed allocator meant for
// production use.
//
// First, we define the interface of the 'my_BufferAllocator' class:
//..
// // my_bufferallocator.h
//
// class my_BufferAllocator : public bdlma::ManagedAllocator {
// // This 'class' provides a concrete buffer allocator that implements
// // the 'bdlma::ManagedAllocator' protocol.
//
// // DATA
// char *d_buffer_p; // external buffer (held, not
// // owned)
//
// bsls::Types::size_type d_bufferSize; // size (in bytes) of external
// // buffer
//
// bsls::Types::IntPtr d_cursor; // offset to next available byte
// // in buffer
//
// private:
// // NOT IMPLEMENTED
// my_BufferAllocator(const my_BufferAllocator&);
// my_BufferAllocator& operator=(const my_BufferAllocator&);
//
// public:
// // CREATORS
// my_BufferAllocator(char *buffer, bsls::Types::size_type bufferSize);
// // Create a buffer allocator for allocating maximally-aligned
// // memory blocks from the specified external 'buffer' having the
// // specified 'bufferSize' (in bytes).
//
// ~my_BufferAllocator();
// // Destroy this buffer allocator.
//
// // MANIPULATORS
// void *allocate(bsls::Types::size_type size);
// // Return the address of a maximally-aligned contiguous block of
// // memory of the specified 'size' (in bytes) on success, and 0 if
// // the allocation request exceeds the remaining free memory space
// // in the external buffer.
//
// void deallocate(void *address);
// // This method has no effect for this buffer allocator.
//
// void release();
// // Release all memory allocated through this object. This
// // allocator is reset to the state it was in immediately following
// // construction.
// };
//..
// Next, we define the 'inline' methods of 'my_BufferAllocator'. Note that the
// 'release' method resets the internal cursor to 0, effectively making the
// memory from the entire external buffer supplied at construction available
// for subsequent allocations, but has no effect on the contents of the buffer:
//..
// // CREATORS
// inline
// my_BufferAllocator::my_BufferAllocator(char *buffer,
// bsls::Types::size_type bufferSize)
// : d_buffer_p(buffer)
// , d_bufferSize(bufferSize)
// , d_cursor(0)
// {
// }
//
// // MANIPULATORS
// inline
// void my_BufferAllocator::deallocate(void *)
// {
// }
//
// inline
// void my_BufferAllocator::release()
// {
// d_cursor = 0;
// }
//..
// Finally, we provide the implementation of the 'my_BufferAllocator' methods
// that are defined in the '.cpp' file. A 'static' helper function,
// 'allocateFromBufferImp', provides the bulk of the implementation of the
// 'allocate' method:
//..
// // my_bufferallocator.cpp
//
// // STATIC HELPER FUNCTIONS
// static
// void *allocateFromBufferImp(bsls::Types::IntPtr *cursor,
// char *buffer,
// bsls::Types::size_type bufferSize,
// bsls::Types::size_type size)
// // Allocate a maximally-aligned memory block of the specified 'size'
// // (in bytes) from the specified 'buffer' having the specified
// // 'bufferSize' (in bytes) at the specified 'cursor' position. Return
// // the address of the allocated memory block if 'buffer' contains
// // sufficient available memory, and 0 otherwise. The 'cursor' is set
// // to the first byte position immediately after the allocated memory if
// // there is sufficient memory, and not modified otherwise. The
// // behavior is undefined unless '0 < size', '0 <= *cursor', and
// // '*cursor <= bufferSize'.
//
// {
// const int offset = bsls::AlignmentUtil::calculateAlignmentOffset(
// buffer + *cursor,
// bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT);
//
// if (*cursor + offset + size > bufferSize) { // insufficient space
// return 0; // RETURN
// }
//
// void *result = &buffer[*cursor + offset];
// *cursor += offset + size;
//
// return result;
// }
//
// // CREATORS
// my_BufferAllocator::~my_BufferAllocator()
// {
// }
//
// // MANIPULATORS
// void *my_BufferAllocator::allocate(bsls::Types::size_type size)
// {
// return 0 == size ? 0 : allocateFromBufferImp(&d_cursor,
// d_buffer_p,
// d_bufferSize,
// static_cast<int>(size));
// }
//..
//
///Example 2: Using the 'bdlma::ManagedAllocator' Protocol
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this second usage example, we illustrate how the managed allocator that
// was defined in Example 1, 'my_BufferAllocator', may be used. Note that
// substantial portions of the sample implementation are elided as they would
// only add unnecessary complications to the usage example. The portions shown
// are sufficient to illustrate the use of 'bdlma::ManagedAllocator'.
//
// The domain of our example is financial markets. Suppose that we are given a
// list of market indices (e.g., Dow Jones Industrial Average, S&P 500, etc.),
// and we want to perform some computation on each index, in turn. In this
// example, the essential attributes of an index are held in a 'bsl::pair'
// consisting of the name of the index (e.g., "DJIA") and the number of
// securities that comprise the index (e.g., 30 in the case of the DJIA). The
// collection of market indices that we wish to process is given by a vector of
// such pairs. Thus, we make use of these types related to indices:
//..
// typedef bsl::pair<const char *, int> IndexAttributes;
// typedef bsl::vector<IndexAttributes> IndexCollection;
//..
// In our example, a security is defined by the unconstrained attribute type
// 'my_SecurityAttributes', the interface and implementation of which is elided
// except we note that it uses 'bslma' allocators:
//..
// class my_SecurityAttributes {
// // ...
//
// public:
// // TRAITS
// BSLMF_NESTED_TRAIT_DECLARATION(my_SecurityAttributes,
// bslma::UsesBslmaAllocator);
//
// // ...
// };
//..
// For the collection of securities comprising an index we use a vector of
// 'my_SecurityAttributes':
//..
// typedef bsl::vector<my_SecurityAttributes> SecurityCollection;
//..
// Since some indices are quite large (e.g., Russell 3000, Wilshire 5000), for
// performance reasons it is advantageous for a 'SecurityCollection' to use an
// efficient memory allocation strategy. This is where 'my_BufferAllocator'
// comes into play, which we will see shortly.
//
// The top-level function in our example takes a 'bdlma::ManagedAllocator *'
// and the collection of market indices that we wish to process:
//..
// static
// void processIndices(bdlma::ManagedAllocator *managedAllocator,
// const IndexCollection& indices);
// // Process the specified market 'indices' using the specified
// // 'managedAllocator' to supply memory.
//..
// 'processIndices' makes use of two helper functions to process each index:
//..
// static
// void loadIndex(SecurityCollection *securities,
// bdlma::ManagedAllocator *managedAllocator,
// const IndexAttributes& index);
// // Load into the specified collection of 'securities' the attributes of
// // the securities comprising the specified market 'index' using the
// // specified 'managedAllocator' to supply memory.
//
// static
// void processIndex(const SecurityCollection& securities,
// const IndexAttributes& index);
// // Process the specified collection of 'securities' that comprise the
// // specified market 'index'.
//..
// Since we plan to use 'my_BufferAllocator' as our managed allocator, we need
// to supply it with an external buffer. The 'calculateMaxBufferSize' function
// computes the size of the buffer required to store the 'SecurityCollection'
// corresponding to the largest index to be processed by a given call to
// 'processIndices':
//..
// int calculateMaxBufferSize(const IndexCollection& indices);
// // Return the maximum buffer size (in bytes) required to process the
// // specified collection of market 'indices'.
//..
// Before showing the implementation of 'processIndices', where the most
// interesting use of our managed allocator takes place, we show the site of
// the call to 'processIndices'.
//
// First, assume that we have been given an 'IndexCollection' that has been
// populated with one or more 'IndexAttributes':
//..
// IndexCollection indices; // assume populated
//..
// Next, we calculate the size of the buffer that is needed, allocate the
// memory for the buffer from the default allocator, create our concrete
// managed allocator (namely, an instance of 'my_BufferAllocator'), and call
// 'processIndices':
//..
// const int bufferSize = calculateMaxBufferSize(indices);
//
// bslma::Allocator *allocator = bslma::Default::defaultAllocator();
// char *buffer = static_cast<char *>(allocator->allocate(bufferSize));
//
// my_BufferAllocator bufferAllocator(buffer, bufferSize);
//
// processIndices(&bufferAllocator, indices);
//..
// Next, we show the implementation of 'processIndices', within which we
// iterate over the market 'indices' that are passed to it:
//..
// static
// void processIndices(bdlma::ManagedAllocator *managedAllocator,
// const IndexCollection& indices)
// // Process the specified market 'indices' using the specified
// // 'managedAllocator' to supply memory.
// {
// for (IndexCollection::const_iterator citer = indices.begin();
// citer != indices.end(); ++citer) {
//
//..
// For each index, the 'SecurityCollection' comprising that index is created.
// All of the memory needs of the 'SecurityCollection' are provided by the
// 'managedAllocator'. Note that even the memory for the footprint of the
// collection comes from the 'managedAllocator':
//..
// SecurityCollection *securities =
// new (managedAllocator->allocate(sizeof(SecurityCollection)))
// SecurityCollection(managedAllocator);
//
//..
// Next, we call 'loadIndex' to populate 'securities', followed by the call to
// 'processIndex'. 'loadIndex' also uses the 'managedAllocator', the details
// of which are not shown here:
//..
// loadIndex(securities, managedAllocator, *citer);
//
// processIndex(*securities, *citer);
//..
// After the index is processed, 'release' is called on the managed allocator
// making all of the buffer supplied to the allocator at construction available
// for reuse:
//..
// managedAllocator->release();
// }
//..
// Finally, we let the 'SecurityCollection' used to process the index go out of
// scope intentionally without deleting 'securities'. The call to 'release'
// renders superfluous the need to call the 'SecurityCollection' destructor as
// well as the destructor of the contained 'my_SecurityAttributes' elements.
//..
// }
//..
#include <bdlscm_version.h>
#include <bslma_allocator.h>
namespace BloombergLP {
namespace bdlma {
// ======================
// class ManagedAllocator
// ======================
class ManagedAllocator : public bslma::Allocator {
// This protocol class extends 'bslma::Allocator' for allocators with the
// ability to 'release' all memory currently allocated through the protocol
// back to the memory supplier of the derived concrete allocator object.
public:
// MANIPULATORS
virtual void release() = 0;
// Release all memory currently allocated through this allocator. The
// effect of using a pointer after this call that was obtained from
// this allocator before this call is undefined.
};
} // close package namespace
} // close enterprise namespace
#endif
// ----------------------------------------------------------------------------
// Copyright 2016 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------