File: allocator_interface.h

package info (click to toggle)
seqan2 2.4.0%2Bdfsg-17
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 224,224 kB
  • sloc: cpp: 256,886; ansic: 91,672; python: 8,330; sh: 995; xml: 570; makefile: 255; awk: 51; javascript: 21
file content (416 lines) | stat: -rw-r--r-- 15,241 bytes parent folder | download | duplicates (6)
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
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
// ==========================================================================
//                 SeqAn - The Library for Sequence Analysis
// ==========================================================================
// Copyright (c) 2006-2018, Knut Reinert, FU Berlin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Knut Reinert or the FU Berlin nor the names of
//       its contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
// ==========================================================================
// Author: Andreas Gogol-Doering <andreas.doering@mdc-berlin.de>
// ==========================================================================
// Allocator class definition and generic interface.
// ==========================================================================

// TODO(holtgrew): Perform some benchmarks and use a better malloc, e.g. tcmalloc and see whether our allocator infrastructure is worth keeping around.
// TODO(holtgrew): Rename to allocator_base.h?

#ifndef SEQAN_INCLUDE_SEQAN_BASIC_ALLOCATOR_INTERFACE_H_
#define SEQAN_INCLUDE_SEQAN_BASIC_ALLOCATOR_INTERFACE_H_

namespace seqan {

// ============================================================================
// Forwards
// ============================================================================

struct Tristate_;
typedef Tag<Tristate_> Tristate;
template <typename TValue, typename TSpec> struct Holder;

// ============================================================================
// Tags, Classes, Enums
// ============================================================================

/*!
 * @defgroup AllocatorUsageTags Allocator Usage Tags
 * @brief The purpose of an allocated memory block.
 *
 * @tag AllocatorUsageTags#TagAllocateUnspecified
 * @headerfile <seqan/basic.h>
 * @brief Not specified.
 *
 * @tag AllocatorUsageTags#TagAllocateTemp
 * @headerfile <seqan/basic.h>
 * @brief Temporary memory.
 *
 * @tag AllocatorUsageTags#TagAllocateStorage
 * @headerfile <seqan/basic.h>
 * @brief Memory for storing container content.
 */

// TODO(holtgrew): ANY use/difference?

struct AllocateUnspecified_;
typedef Tag<AllocateUnspecified_> TagAllocateUnspecified;

struct AllocateTemp_;
typedef Tag<AllocateTemp_> TagAllocateTemp;

struct AllocateStorage_;
typedef Tag<AllocateStorage_> TagAllocateStorage;

struct AllocateAlignedMalloc_;
typedef Tag<AllocateAlignedMalloc_> TagAllocateAlignedMalloc;

/*!
 * @class Allocator
 * @headerfile <seqan/basic.h>
 * @brief Manager for allocated memory.
 *
 * @signature template <typename TSpec>
 *            class Allocator;
 *
 * @tparam TSpec The specializing type.
 *
 * @section Remarks
 *
 * There are two reasons for using non-trivial allocators:
 *
 * <ol>
 *   <li>Allocators support the function @link Allocator#clear @endlink for a fast deallocation of all allocated
 *       memory blocks.</li>
 *   <li>Some allocators are faster in allocating an deallocating memory.  Pool allocators like e.g.
 *       @link SinglePoolAllocator @endlink or @link MultiPoolAllocator @endlink speed up
 *       @link Allocator#allocate @endlink, @link Allocator#deallocate * @endlink, and
 *       @link Allocator#clear @endlink for pooled memory blocks.</li>
 * </ol>
 */

template <typename TSpec>
struct Allocator;

// ============================================================================
// Metafunctions
// ============================================================================

//.Metafunction.Spec.param.T.type:Class.Allocator

template <typename TSpec>
struct Spec<Allocator<TSpec> >
{
    typedef TSpec Type;
};

// ============================================================================
// Functions
// ============================================================================

// ----------------------------------------------------------------------------
// Function allocate()
// ----------------------------------------------------------------------------

/*!
 * @fn Allocator#allocate
 * @headerfile <seqan/basic.h>
 * @brief Allocates memory from heap.
 *
 * @signature void allocate(allocator, data, count[, usageTag]);
 *
 * @param[in]     count     Number of items that could be stored in the allocated memory.  The type of the allocated
 *                          items is given by the type of <tt>data</tt>.
 * @param[in]     usageTag  A tag the specifies the purpose for the allocated memory.  Values:
 *                          @link AllocatorUsageTags @endlink.
 * @param[in,out] allocator Allocator object.  <tt>allocator</tt> is conceptually the "owner" of the allocated
 *                          memory.  Objects of all types can be used as allocators.  If no special behavior is
 *                          implemented,  default functions allocation/deallocation are applied that uses standard
 *                          <tt>new</tt> and <tt>delete</tt> operators. Types: Allocator
 *
 * @section Remarks
 *
 * The function allocates at least <tt>count*sizeof(data)</tt> bytes.  The allocated memory is large enough  to hold
 * <tt>count</tt> objects of type <tt>T</tt>, where <tt>T *</tt> is type of <tt>data</tt>.
 *
 * These objects are not constructed by <tt>allocate</tt>.
 *
 * Use e.g. one of the functions @link valueConstruct @endlink, @link arrayConstruct @endlink, @link arrayConstructCopy
 * @endlink or @link arrayFill @endlink to construct the objects. A <tt>new</tt> operator which is part of the C++
 * standard (defined in <tt>&lt;new&gt;</tt>)  can also be used to construct objects at a given memory address.
 *
 * @section Remarks
 *
 * All allocated memory blocks should be deallocated by the corresponding function @link Allocator#deallocate @endlink.
 */

template <typename T, typename TValue, typename TSize>
inline void
allocate(T const & me,
         TValue * & data,
         TSize count)
{
    allocate(me, data, count, TagAllocateUnspecified());
}

template <typename T, typename TValue, typename TSize>
inline void
allocate(T & me,
         TValue * & data,
         TSize count)
{
    allocate(me, data, count, TagAllocateUnspecified());
}

template <typename T, typename TValue, typename TSize, typename TUsage>
inline void
allocate(T const &,
         TValue * & data,
         TSize count,
         Tag<TUsage> const &)
{
//  data = (TValue *) operator new(count * sizeof(TValue));
#ifdef STDLIB_VS
    data = (TValue *) _aligned_malloc(count * sizeof(TValue), __alignof(TValue));
#else
/*#if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
    const size_t align = (__alignof__(TValue) < sizeof(void*)) ? sizeof(void*): __alignof__(TValue);
    if (posix_memalign(&(void* &)data, align, count * sizeof(TValue)))
        data = NULL;
#else
    data = (TValue *) malloc(count * sizeof(TValue));
#endif*/
// suppress -Walloc-size-larger-than= warning; a simple static_cast does not work
// a working solution would be to downcast std::size_t to unsigned, but this
// would loose information; thus disabling this for gcc 7 and upwards
    SEQAN_ASSERT_LEQ(static_cast<std::size_t>(count), std::numeric_limits<std::size_t>::max() / sizeof(TValue));
#   if defined(COMPILER_GCC) &&  __GNUC__ >= 7
#       pragma GCC diagnostic push
#       pragma GCC diagnostic ignored "-Walloc-size-larger-than="
#   endif //COMPILER_GCC
    data = (TValue *) operator new(count * sizeof(TValue));
#   if defined(COMPILER_GCC) &&  __GNUC__ >= 7
#       pragma GCC diagnostic pop
#   endif //COMPILER_GCC
#endif

#ifdef SEQAN_PROFILE
    if (data)
        SEQAN_PROADD(SEQAN_PROMEMORY, count * sizeof(TValue));
#endif
}

// NOTE(rrahn): Currently *new* does not support aligned memory, but we need it for dynamically
// allocated SimdVector class, so we overload the allocation to use mem_alloc for simd vector types.
// See following discussion: http://stackoverflow.com/questions/6973995/dynamic-aligned-memory-allocation-in-c11
template <typename T, typename TValue, typename TSize>
inline void
allocate(T const &,
         TValue * & data,
         TSize count,
         TagAllocateAlignedMalloc const &)
{
#ifdef PLATFORM_WINDOWS_VS
    data = (TValue *) _aligned_malloc(count * sizeof(TValue), __alignof(TValue));
#else
    #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
        const size_t align = (__alignof__(TValue) < sizeof(void*)) ? sizeof(void*): __alignof__(TValue);
        if (posix_memalign(&(void* &)data, align, count * sizeof(TValue)))
            data = NULL;
    #else
        data = (TValue *) malloc(count * sizeof(TValue));
    #endif
#endif
}

template <typename T, typename TValue, typename TSize>
inline void
allocate(T &,
         TValue * & data,
         TSize count,
         TagAllocateAlignedMalloc const &)
{
#ifdef PLATFORM_WINDOWS_VS
    data = (TValue *) _aligned_malloc(count * sizeof(TValue), __alignof(TValue));
#else
    #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
        const size_t align = (__alignof__(TValue) < sizeof(void*)) ? sizeof(void*) : __alignof__(TValue);
        if (posix_memalign(&(void* &)data, align, count * sizeof(TValue)))
        data = NULL;
    #else
        data = (TValue *) malloc(count * sizeof(TValue));
    #endif
#endif
}

// ----------------------------------------------------------------------------
// Function deallocate()
// ----------------------------------------------------------------------------

/*!
 * @fn Allocator#deallocate
 * @headerfile <seqan/basic.h>
 * @brief Deallocates memory.
 *
 * @signature void deallocate(object, data, count[, usageTag])
 *
 * @param[in,out] object Allocator object.<tt>object</tt> is conceptually the "owner" of the allocated memory.
 *                       Objects of all types can be used as allocators.  If no special behavior is implemented,
 *                       default functions allocation/deallocation are applied that uses standard  <tt>new</tt>
 *                       and <tt>delete</tt> operators.  Types: Allocator
 * @param[out]     data  Pointer to allocated memory that was allocated by <tt>allocate</tt>.
 * @param[in]     count    Number of items that could be stored in the allocated memory.
 * @param[in]     usageTag A tag the specifies the purpose for the allocated memory.
 *                         Values: @link AllocatorUsageTags @endlink.
 *
 * The values for <tt>object</tt>, <tt>count</tt> and <tt>usageTag</tt> should be the same that was used when
 * <tt>allocate</tt> was called. The value of <tt>data</tt> should be the same that was returned by <tt>allocate</tt>.
 *
 * <tt>deallocate</tt> does not destruct objects.
 *
 * Use e.g. one of the functions @link valueDestruct @endlink or @link arrayDestruct @endlink to destruct the objects.
 * <tt>delete</tt> and <tt>delete []</tt> operators which are part of the C++ standard (defined in <tt>&lt;new&gt;</tt>)
 * can also be used to destruct objects at a given memory address.
 */

template <typename T, typename TValue, typename TSize>
inline void
deallocate(T const & me,
           TValue * data,
           TSize const count)
{
    deallocate(me, data, count, TagAllocateUnspecified());
}

template <typename T, typename TValue, typename TSize>
inline void
deallocate(T & me,
           TValue * data,
           TSize const count)
{
    deallocate(me, data, count, TagAllocateUnspecified());
}

template <typename T, typename TValue, typename TSize, typename TUsage>
inline void
deallocate(
    T const & /*me*/,
    TValue * data,
#ifdef SEQAN_PROFILE
    TSize count,
#else
    TSize,
#endif
    Tag<TUsage> const)
{
#ifdef SEQAN_PROFILE
    if (data && count)  // .. to use count if SEQAN_PROFILE is not defined
        SEQAN_PROSUB(SEQAN_PROMEMORY, count * sizeof(TValue));
#endif
//  operator delete ((void *) data);
#ifdef STDLIB_VS
    _aligned_free((void *) data);
#else
//  free((void *) data);
    operator delete ((void *) data);
#endif
}

template <typename T, typename TValue, typename TSize, typename TUsage>
inline void
deallocate(
    T & /*me*/,
    TValue * data,
#ifdef SEQAN_PROFILE
    TSize count,
#else
    TSize,
#endif
    Tag<TUsage> const)
{
#ifdef SEQAN_PROFILE
    if (data && count)  // .. to use count if SEQAN_PROFILE is not defined
        SEQAN_PROSUB(SEQAN_PROMEMORY, count * sizeof(TValue));
#endif
//  operator delete ((void *) data);
#ifdef STDLIB_VS
    _aligned_free((void *) data);
#else
//  free((void *) data);
    operator delete ((void *) data);
#endif
}

// NOTE(rrahn): Currently *new* does not support aligned memory, but we need it for dynamically
// allocated SimdVector class, so we overload the allocation to use mem_alloc for simd vector types.
// See following discussion: http://stackoverflow.com/questions/6973995/dynamic-aligned-memory-allocation-in-c11
template <typename T, typename TValue, typename TSize>
inline void
deallocate(
           T const & /*me*/,
           TValue * data,
#ifdef SEQAN_PROFILE
           TSize count,
#else
           TSize,
#endif
           TagAllocateAlignedMalloc const)
{
#ifdef SEQAN_PROFILE
    if (data && count)  // .. to use count if SEQAN_PROFILE is not defined
        SEQAN_PROSUB(SEQAN_PROMEMORY, count * sizeof(TValue));
#endif
#ifdef PLATFORM_WINDOWS_VS
    _aligned_free((void *) data);
#else
    free((void *) data);
#endif
}

template <typename T, typename TValue, typename TSize>
inline void
deallocate(
           T & /*me*/,
           TValue * data,
#ifdef SEQAN_PROFILE
           TSize count,
#else
           TSize,
#endif
           TagAllocateAlignedMalloc const)
{
#ifdef SEQAN_PROFILE
    if (data && count)  // .. to use count if SEQAN_PROFILE is not defined
        SEQAN_PROSUB(SEQAN_PROMEMORY, count * sizeof(TValue));
#endif
    //  operator delete ((void *) data);
#ifdef PLATFORM_WINDOWS_VS
    _aligned_free((void *) data);
#else
    free((void *) data);
#endif
}

}  // namespace seqan

#endif  // #ifndef SEQAN_INCLUDE_SEQAN_BASIC_ALLOCATOR_INTERFACE_H_