BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bsls_alignmentutil.h
Go to the documentation of this file.
1/// @file bsls_alignmentutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_alignmentutil.h -*-C++-*-
8#ifndef INCLUDED_BSLS_ALIGNMENTUTIL
9#define INCLUDED_BSLS_ALIGNMENTUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_alignmentutil bsls_alignmentutil
15/// @brief Provide constants, types, and operations related to alignment.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_alignmentutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_alignmentutil-purpose"> Purpose</a>
25/// * <a href="#bsls_alignmentutil-classes"> Classes </a>
26/// * <a href="#bsls_alignmentutil-description"> Description </a>
27/// * <a href="#bsls_alignmentutil-assumptions"> Assumptions </a>
28/// * <a href="#bsls_alignmentutil-usage"> Usage </a>
29///
30/// # Purpose {#bsls_alignmentutil-purpose}
31/// Provide constants, types, and operations related to alignment.
32///
33/// # Classes {#bsls_alignmentutil-classes}
34///
35/// - bsls::AlignmentUtil: namespace for alignment functions, types, and constants
36///
37/// @see bslma_bufferimputil
38///
39/// # Description {#bsls_alignmentutil-description}
40/// This component defines a `struct`, `bsls::AlignmentUtil`, which
41/// serves as a namespace for compile-time constants, types, and operations
42/// associated with alignment on the current platform.
43///
44/// The `BSLS_MAX_ALIGNMENT` enumerator provides the minimal value that
45/// satisfies the alignment requirements for all types on the current platform.
46/// Additionally, the `MaxAlignedType` `typedef` specifies a primitive type that
47/// requires an alignment of `BSLS_MAX_ALIGNMENT`.
48///
49/// The `calculateAlignmentFromSize` function calculates a usable (but not
50/// necessarily minimal) alignment for any object with a memory footprint of the
51/// specified `size` (in bytes). The `calculateAlignmentOffset` function
52/// calculates the offset from a specified `address` where an object having a
53/// specified `alignment` requirement can be constructed safely. The
54/// `is2ByteAligned`, `is4ByteAligned`, and `is8ByteAligned` functions each
55/// return `true` if a specified `address` is, respectively, 2-, 4-, or 8-byte
56/// aligned. Finally, `roundUpToMaximalAlignment` returns the smallest whole
57/// multiple of `BSLS_MAX_ALIGNMENT` greater than or equal to its argument.
58///
59/// ## Assumptions {#bsls_alignmentutil-assumptions}
60///
61///
62/// The functionality in this component makes several assumptions:
63///
64/// * The alignment for any given type is an integral power of 2.
65/// * The required alignment for a type `T` evenly divides `sizeof(T)`, which
66/// implies that the required alignment for `T` is never larger than
67/// `sizeof(T)`.
68/// * The required alignment for a `struct`, `class`, or `union` is the same as
69/// the required alignment of its most restrictive non-static data member
70/// (including the implicit virtual table pointer in polymorphic classes and
71/// internal pointers in virtually-derived classes).
72///
73/// ## Usage {#bsls_alignmentutil-usage}
74///
75///
76/// A sequential memory allocator is used to return a sequence of memory blocks
77/// of varying requested sizes from a larger chunk of contiguous memory. Each
78/// block returned must also have an alignment that is sufficient for any
79/// conceivable object of that size. To achieve a fully factored
80/// implementation, we might choose to provide a low-level helper function
81/// `naturallyAlign` that, given the `address` of the next available byte in
82/// the larger chunk along with the requested block `size` (in bytes), returns
83/// the first appropriately (or *naturally*) aligned address for the requested
84/// block at or after `address`:
85/// @code
86/// void *naturallyAlign(void **currentAddress, int size);
87/// // Return the closest memory address at or after the specified
88/// // '*currentAddress' that is sufficiently aligned to accommodate any
89/// // object of the specified 'size', and update '*currentAddress' to
90/// // refer to the first available byte after the allocated object. The
91/// // behavior is undefined unless '1 <= size'.
92/// @endcode
93/// We can implement the `naturallyAlign` helper function easily using the
94/// methods defined in this class:
95/// @code
96/// void *naturallyAlign(void **currentAddress, std::size_t size)
97/// {
98/// int alignment = bsls::AlignmentUtil::calculateAlignmentFromSize(
99/// size);
100/// int offset = bsls::AlignmentUtil::calculateAlignmentOffset(
101/// *currentAddress,
102/// alignment);
103/// char *result = static_cast<char *>(*currentAddress) + offset;
104/// *currentAddress = result + size;
105/// return result;
106/// }
107/// @endcode
108/// We will then be able to use this `naturallyAlign` helper function to
109/// allocate, from a buffer of contiguous memory, efficiently (but not
110/// necessarily optimally) aligned memory for objects of varying sizes based
111/// solely on the size of each object (i.e., determined by its natural, not
112/// actual, alignment).
113///
114/// To illustrate the functionality provided in this component, we begin by
115/// assuming that we have some user-defined type, `MyType`, comprising several
116/// data members:
117/// @code
118/// struct MyType { // size 24; actual alignment 8; natural alignment 8
119/// int d_int;
120/// double d_double; // Assume 8-byte alignment.
121/// char *d_charPtr; // Assume size <= 8 bytes.
122/// };
123/// @endcode
124/// We then define a function, `f`, which starts off by creating a maximally
125/// aligned `buffer` on the program stack:
126/// @code
127/// void f()
128/// {
129/// // The remainder of the usage example is in the USAGE test case.
130/// }
131///
132/// union {
133/// bsls::AlignmentUtil::MaxAlignedType d_dummy; // force max. align.
134/// char d_buffer[BUFFER_SIZE];
135/// } buffer;
136/// @endcode
137/// Next we use the `bsls::AlignmentUtil` functions directly to confirm that
138/// `buffer` is sufficiently aligned to accommodate a `MaxAlignedType` object:
139/// @code
140/// int alignment = bsls::AlignmentFromType<
141/// bsls::AlignmentUtil::MaxAlignedType>::value;
142/// int offset =
143/// bsls::AlignmentUtil::calculateAlignmentOffset(
144/// buffer.d_buffer,
145/// alignment);
146/// assert(0 == offset); // sufficient alignment
147/// @endcode
148/// Below we perform various memory allocations using our `naturallyAlign`
149/// helper function:
150/// @code
151/// void *p = static_cast<void *>(buffer.d_buffer);
152///
153/// (void) naturallyAlign(&p, sizeof(char));
154///
155/// void *shortPtr5 = naturallyAlign(&p, 5 * sizeof(short));
156/// @endcode
157/// Note that the address held in `shortPtr` is numerically divisible by the
158/// alignment of a `short` on the current platform:
159/// @code
160/// assert(0 == ((static_cast<char *>(shortPtr5) - buffer.d_buffer) %
161/// bsls::AlignmentFromType<short>::value));
162///
163/// assert(bsls::AlignmentUtil::is2ByteAligned(shortPtr5));
164/// @endcode
165/// Next we use `naturallyAlign` to allocate a block of appropriate size and
166/// sufficient alignment to store a `MyType` object:
167/// @code
168/// void *objPtr = naturallyAlign(&p, sizeof(MyType));
169/// @endcode
170/// Note that the alignment of the address held in `objPtr` is numerically
171/// divisible by the actual alignment requirement:
172/// @code
173/// assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
174/// objPtr,
175/// bsls::AlignmentFromType<MyType>::value));
176/// @endcode
177/// Assuming `buffer` has sufficient capacity, and the alignments for `char`,
178/// `short`, and `MyType` are, respectively, 1, 2, and 8, we would expect this
179/// layout within `buffer.d_buffer`:
180/// @code
181/// charPtr shortPtr5 objPtr
182/// | | |
183/// V V V
184/// .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.-
185/// |ccc| |sssssss:sssssss:sssssss:sssssss:sssssss| : : : |oooooo...
186/// ^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^-
187/// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
188/// @endcode
189/// Note that on an atypical 32-bit platform where a `double` is 4-byte
190/// aligned, the actual alignment of `MyType` would be 4, but its natural
191/// alignment would still be 8 because its size would be 16; it is highly
192/// unlikely that `MyType` would have an actual (and therefore natural)
193/// alignment of 4 on a 64-bit platform when using default compiler settings.
194/// @}
195/** @} */
196/** @} */
197
198/** @addtogroup bsl
199 * @{
200 */
201/** @addtogroup bsls
202 * @{
203 */
204/** @addtogroup bsls_alignmentutil
205 * @{
206 */
207
208#include <bsls_alignmentfromtype.h>
209#include <bsls_alignmentimp.h>
210#include <bsls_alignmenttotype.h>
211#include <bsls_assert.h>
212#include <bsls_platform.h>
213#include <bsls_types.h>
214
215#include <limits> // 'std::numeric_limits'
216
217#include <cstddef> // 'std::size_t'
218
219
220
221namespace bsls {
222
223 // ====================
224 // struct AlignmentUtil
225 // ====================
226
227/// This `struct` provides a namespace for a suite of compile-time
228/// constants, types, and pure procedures that provide platform-dependent
229/// alignment information.
231
232 private:
233 // PRIVATE TYPES
234
235 /// Typedef used as an alias for a function pointer.
236 typedef void (*FuncPtr)();
237
238 union MaxAlignedUnion;
239 friend union MaxAlignedUnion;
240 // Afford 'MaxAlignedUnion' access to the (private) 'FuncPtr' type.
241
242 /// This `union` is guaranteed to be maximally aligned. However, this
243 /// union is *not* a good candidate for `MaxAlignedType` because it
244 /// might be larger than necessary.
245 union MaxAlignedUnion {
246
247 char d_char;
248 short d_short;
249 int d_int;
250 long d_long;
251 long long d_longLong;
252 bool d_bool;
253 wchar_t d_wchar_t;
254 void *d_pointer;
255 FuncPtr d_funcPointer;
256 float d_float;
257 double d_double;
258#if ! (defined(BSLS_PLATFORM_CPU_POWERPC) && defined(BSLS_PLATFORM_OS_LINUX))
259 long double d_longDouble;
260#endif
261#if defined(BSLS_PLATFORM_CPU_X86) \
262 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG)) \
263 && !defined(BSLS_PLATFORM_OS_SOLARIS)
264 AlignmentImp8ByteAlignedType
265 d_8bytesAlignedType;
266#endif
267 };
268
269 public:
270 // CONSTANTS
271 enum {
272 // Define the minimal value that satisfies the alignment requirements
273 // for all types.
274
276 };
277
278 // TYPES
279
280 /// Alias for a primitive type that has the most stringent alignment
281 /// requirement.
283
284 // CLASS METHODS
285
286 /// Return the *natural* alignment for a memory block of the specified
287 /// size -- i.e., the largest power of 2 that evenly divides `size`, up
288 /// to a maximum of `BSLS_MAX_ALIGNMENT`. It is guaranteed that this
289 /// alignment will be sufficient for any object having a footprint of
290 /// `size` bytes on the current platform. The behavior is undefined
291 /// unless `1 <= size` and `size <= INT_MAX`. Note that, depending on
292 /// the machine architecture and compiler setting, the returned
293 /// alignment value may be more restrictive than required for a
294 /// particular object for two reasons:
295 /// 1. The object may be composed entirely of elements, such as `char`,
296 /// that have minimal alignment restrictions, and
297 /// 2. The architecture and our compiler settings may result in
298 /// unexpectedly lenient alignment requirements.
299 /// Also note that aligning on a more restrictive boundary may improve
300 /// performance.
301 static int calculateAlignmentFromSize(std::size_t size);
302
303 /// Return the minimum non-negative integer that, when added to the
304 /// numerical value of the specified `address`, yields the specified
305 /// `alignment`. The behavior is undefined unless `alignment` is a
306 /// positive, integral power of 2.
307 static int calculateAlignmentOffset(const void *address, int alignment);
308
309 /// Return `true` if the specified `address` is aligned on a 2-byte
310 /// boundary (i.e., the numerical value of `address` is evenly divisible
311 /// by 2), and `false` otherwise.
312 static bool is2ByteAligned(const void *address);
313
314 /// Return `true` if the specified `address` is aligned on a 4-byte
315 /// boundary (i.e., the numerical value of `address` is evenly divisible
316 /// by 4), and `false` otherwise.
317 static bool is4ByteAligned(const void *address);
318
319 /// Return `true` if the specified `address` is aligned on an 8-byte
320 /// boundary (i.e., the numerical value of `address` is evenly divisible
321 /// by 8), and `false` otherwise.
322 static bool is8ByteAligned(const void *address);
323
324 /// Return the specified `size` (in bytes) rounded up to the smallest
325 /// integral multiple of the maximum alignment. The behavior is
326 /// undefined unless `0 <= size` and `size` satisfies:
327 /// @code
328 /// size <= std::numeric_limits<std::size_t>::max()
329 /// - BSLS_MAX_ALIGNMENT + 1
330 /// @endcode
331 static std::size_t roundUpToMaximalAlignment(std::size_t size);
332};
333
334// ============================================================================
335// INLINE FUNCTION DEFINITIONS
336// ============================================================================
337
338 // ----------------
339 // struct Alignment
340 // ----------------
341
342// CLASS METHODS
343inline
345{
346 ///IMPLEMENTATION NOTE
347 ///-------------------
348 // It is assumed that 'BSLS_MAX_ALIGNMENT' is a positive, integral power of
349 // 2 (see the checks to that effect in the '.cpp' file). For example,
350 // suppose that 'BSLS_MAX_ALIGNMENT' is 16:
351 //..
352 // negated
353 // modified modified intersect
354 // size size size size size returned
355 // ---- -------- -------- -------- -------- --------
356 // 0 00000000 00010000 11110000 00010000 16
357 // 1 00000001 00010001 11101111 00000001 1
358 // 2 00000010 00010010 11101110 00000010 2
359 // 3 00000011 00010011 11101101 00000001 1
360 //
361 // 4 00000100 00010100 11101100 00000100 4
362 // 5 00000101 00010101 11101011 00000001 1
363 // 6 00000110 00010110 11101010 00000010 2
364 // 7 00000110 00010111 11101001 00000001 1
365 //
366 // 8 00001000 00011000 11101000 00001000 8
367 // 9 00001001 00011001 11100111 00000001 1
368 // 10 00001010 00011010 11100110 00000010 2
369 // 11 00001011 00011011 11100101 00000001 1
370 //
371 // 12 00001100 00011100 11100100 00000100 4
372 // 13 00001101 00011101 11100011 00000001 1
373 // 14 00001110 00011110 11100010 00000010 2
374 // 15 00001110 00011111 11100001 00000001 1
375 //
376 // 16 00010000 00010000 11110000 00010000 16
377 // 17 00010001 00010001 11101111 00000001 1
378 // 18 00010010 00010010 11101110 00000010 2
379 // 19 00010011 00010011 11101101 00000001 1
380 //
381 // : : : : : :
382 //
383 // 32 00100000 00110000 11010000 00010000 16
384 // 33 00100001 00110001 11001111 00000001 1
385 // 34 00100010 00110010 11001110 00000010 2
386 // 35 00100011 00110011 11001101 00000001 1
387 //
388 // : : : : : :
389 //..
390
391 BSLS_ASSERT_SAFE(1 <= size);
392
393 // It is safe to cast our value from a 'size_t' to an int, because all
394 // bits that are higher order that 'BSLS_MAX_ALIGNMENT' are ignored by
395 // the arithmetic that is done.
396
397 int alignment = static_cast<int>(size | BSLS_MAX_ALIGNMENT);
398 alignment &= -alignment; // clear all but lowest order set bit
399
400 // Verify at most one bit is set (should be impossible to fail)
401
402 BSLS_ASSERT_SAFE(0 == (alignment & (alignment - 1)));
403
404 return alignment;
405}
406
407inline
409 int alignment)
410{
411 BSLS_ASSERT_SAFE(1 <= alignment);
412 BSLS_ASSERT_SAFE(0 == (alignment & (alignment - 1)));
413
414 // Note that if 'address' is null, this function will correctly return zero
415 // only if 'alignment' is a positive, integral power of 2. Also note that
416 // two other alternative implementations proved to be less efficient:
417 //..
418 // return static_cast<int>(alignment - 1 -
419 // (reinterpret_cast<std::size_t>(address - 1)) % alignment);
420 //..
421 // and:
422 //..
423 // const int mask = alignment - 1;
424 // return int(mask -
425 // ((reinterpret_cast<std::size_t>(address - 1)) & mask));
426 //..
427
428 return static_cast<int>(
429 (alignment - reinterpret_cast<std::size_t>(address))
430 & (alignment - 1));
431}
432
433inline
434bool AlignmentUtil::is2ByteAligned(const void *address)
435{
436 return 0 == (reinterpret_cast<std::size_t>(address) & 0x1);
437}
438
439inline
440bool AlignmentUtil::is4ByteAligned(const void *address)
441{
442 return 0 == (reinterpret_cast<std::size_t>(address) & 0x3);
443}
444
445inline
446bool AlignmentUtil::is8ByteAligned(const void *address)
447{
448 return 0 == (reinterpret_cast<std::size_t>(address) & 0x7);
449}
450
451inline
452std::size_t AlignmentUtil::roundUpToMaximalAlignment(std::size_t size)
453{
454 BSLS_ASSERT_SAFE(size <= std::numeric_limits<std::size_t>::max()
455 - BSLS_MAX_ALIGNMENT + 1);
456
457 return ((size + BSLS_MAX_ALIGNMENT - 1) / BSLS_MAX_ALIGNMENT)
459}
460
461} // close package namespace
462
463#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
464// ============================================================================
465// BACKWARD COMPATIBILITY
466// ============================================================================
467
468/// This alias is defined for backward compatibility.
470#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
471
472
473
474#endif
475
476// ----------------------------------------------------------------------------
477// Copyright 2013 Bloomberg Finance L.P.
478//
479// Licensed under the Apache License, Version 2.0 (the "License");
480// you may not use this file except in compliance with the License.
481// You may obtain a copy of the License at
482//
483// http://www.apache.org/licenses/LICENSE-2.0
484//
485// Unless required by applicable law or agreed to in writing, software
486// distributed under the License is distributed on an "AS IS" BASIS,
487// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
488// See the License for the specific language governing permissions and
489// limitations under the License.
490// ----------------------------- END-OF-FILE ----------------------------------
491
492/** @} */
493/** @} */
494/** @} */
bsls::AlignmentUtil bsls_AlignmentUtil
This alias is defined for backward compatibility.
Definition bsls_alignmentutil.h:469
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlt_iso8601util.h:691
Definition bsls_alignmentfromtype.h:376
AlignmentImpPriorityToType< PRIORITY >::Type Type
Definition bsls_alignmenttotype.h:394
Definition bsls_alignmentutil.h:230
static bool is2ByteAligned(const void *address)
Definition bsls_alignmentutil.h:434
static bool is4ByteAligned(const void *address)
Definition bsls_alignmentutil.h:440
friend union MaxAlignedUnion
Definition bsls_alignmentutil.h:239
static std::size_t roundUpToMaximalAlignment(std::size_t size)
Definition bsls_alignmentutil.h:452
AlignmentToType< BSLS_MAX_ALIGNMENT >::Type MaxAlignedType
Definition bsls_alignmentutil.h:282
static int calculateAlignmentOffset(const void *address, int alignment)
Definition bsls_alignmentutil.h:408
@ BSLS_MAX_ALIGNMENT
Definition bsls_alignmentutil.h:275
static bool is8ByteAligned(const void *address)
Definition bsls_alignmentutil.h:446
static int calculateAlignmentFromSize(std::size_t size)
Definition bsls_alignmentutil.h:344