@@ -68,13 +68,11 @@ using cpp::optional;
68
68
// / The blocks store their offsets to the previous and next blocks. The latter
69
69
// / is also the block's size.
70
70
// /
71
- // / The `ALIGNMENT` constant provided by the derived block is typically the
72
- // / minimum value of `alignof(OffsetType)`. Blocks will always be aligned to a
73
- // / `ALIGNMENT` boundary. Block sizes will always be rounded up to a multiple of
74
- // / `ALIGNMENT`.
71
+ // / Blocks will always be aligned to a `ALIGNMENT` boundary. Block sizes will
72
+ // / always be rounded up to a multiple of `ALIGNMENT`.
75
73
// /
76
- // / As an example, the diagram below represents two contiguous
77
- // / `Block<uint32_t, 8>`s. The indices indicate byte offsets:
74
+ // / As an example, the diagram below represents two contiguous `Block`s. The
75
+ // / indices indicate byte offsets:
78
76
// /
79
77
// / @code{.unparsed}
80
78
// / Block 1:
@@ -117,30 +115,15 @@ using cpp::optional;
117
115
// /
118
116
// / The next offset of a block matches the previous offset of its next block.
119
117
// / The first block in a list is denoted by having a previous offset of `0`.
120
- // /
121
- // / @tparam OffsetType Unsigned integral type used to encode offsets. Larger
122
- // / types can address more memory, but consume greater
123
- // / overhead.
124
- // / @tparam kAlign Sets the overall alignment for blocks. Minimum is
125
- // / `alignof(OffsetType)`, but the default is max_align_t,
126
- // / since the usable space will then already be
127
- // / aligned to max_align_t if the size of OffsetType is no
128
- // / less than half of max_align_t. Larger values cause
129
- // / greater overhead.
130
- template <typename OffsetType = uintptr_t , size_t kAlign = alignof (max_align_t )>
131
118
class Block {
132
119
// Masks for the contents of the next_ field.
133
120
static constexpr size_t PREV_FREE_MASK = 1 << 0 ;
134
121
static constexpr size_t LAST_MASK = 1 << 1 ;
135
122
static constexpr size_t SIZE_MASK = ~(PREV_FREE_MASK | LAST_MASK);
136
123
137
124
public:
138
- using offset_type = OffsetType;
139
- static_assert (cpp::is_unsigned_v<offset_type>,
140
- " offset type must be unsigned" );
141
- static constexpr size_t ALIGNMENT =
142
- cpp::max (cpp::max(kAlign , alignof (offset_type)), size_t {4 });
143
- static constexpr size_t BLOCK_OVERHEAD = align_up(sizeof (Block), ALIGNMENT);
125
+ static constexpr size_t ALIGNMENT = cpp::max(alignof (max_align_t ), size_t {4 });
126
+ static const size_t BLOCK_OVERHEAD;
144
127
145
128
// No copy or move.
146
129
Block (const Block &other) = delete ;
@@ -157,61 +140,61 @@ class Block {
157
140
// /
158
141
// / @warning This method does not do any checking; passing a random
159
142
// / pointer will return a non-null pointer.
160
- static Block *from_usable_space (void *usable_space) {
143
+ LIBC_INLINE static Block *from_usable_space (void *usable_space) {
161
144
auto *bytes = reinterpret_cast <cpp::byte *>(usable_space);
162
145
return reinterpret_cast <Block *>(bytes - BLOCK_OVERHEAD);
163
146
}
164
- static const Block *from_usable_space (const void *usable_space) {
147
+ LIBC_INLINE static const Block *from_usable_space (const void *usable_space) {
165
148
const auto *bytes = reinterpret_cast <const cpp::byte *>(usable_space);
166
149
return reinterpret_cast <const Block *>(bytes - BLOCK_OVERHEAD);
167
150
}
168
151
169
152
// / @returns The total size of the block in bytes, including the header.
170
- size_t outer_size () const { return next_ & SIZE_MASK; }
153
+ LIBC_INLINE size_t outer_size () const { return next_ & SIZE_MASK; }
171
154
172
- static size_t outer_size (size_t inner_size) {
155
+ LIBC_INLINE static size_t outer_size (size_t inner_size) {
173
156
// The usable region includes the prev_ field of the next block.
174
157
return inner_size - sizeof (prev_) + BLOCK_OVERHEAD;
175
158
}
176
159
177
160
// / @returns The number of usable bytes inside the block were it to be
178
161
// / allocated.
179
- size_t inner_size () const {
162
+ LIBC_INLINE size_t inner_size () const {
180
163
if (!next ())
181
164
return 0 ;
182
165
return inner_size (outer_size ());
183
166
}
184
167
185
168
// / @returns The number of usable bytes inside a block with the given outer
186
169
// / size were it to be allocated.
187
- static size_t inner_size (size_t outer_size) {
170
+ LIBC_INLINE static size_t inner_size (size_t outer_size) {
188
171
// The usable region includes the prev_ field of the next block.
189
172
return inner_size_free (outer_size) + sizeof (prev_);
190
173
}
191
174
192
175
// / @returns The number of usable bytes inside the block if it remains free.
193
- size_t inner_size_free () const {
176
+ LIBC_INLINE size_t inner_size_free () const {
194
177
if (!next ())
195
178
return 0 ;
196
179
return inner_size_free (outer_size ());
197
180
}
198
181
199
182
// / @returns The number of usable bytes inside a block with the given outer
200
183
// / size if it remains free.
201
- static size_t inner_size_free (size_t outer_size) {
184
+ LIBC_INLINE static size_t inner_size_free (size_t outer_size) {
202
185
return outer_size - BLOCK_OVERHEAD;
203
186
}
204
187
205
188
// / @returns A pointer to the usable space inside this block.
206
- cpp::byte *usable_space () {
189
+ LIBC_INLINE cpp::byte *usable_space () {
207
190
return reinterpret_cast <cpp::byte *>(this ) + BLOCK_OVERHEAD;
208
191
}
209
- const cpp::byte *usable_space () const {
192
+ LIBC_INLINE const cpp::byte *usable_space () const {
210
193
return reinterpret_cast <const cpp::byte *>(this ) + BLOCK_OVERHEAD;
211
194
}
212
195
213
196
// @returns The region of memory the block manages, including the header.
214
- ByteSpan region () {
197
+ LIBC_INLINE ByteSpan region () {
215
198
return {reinterpret_cast <cpp::byte *>(this ), outer_size ()};
216
199
}
217
200
@@ -229,42 +212,53 @@ class Block {
229
212
230
213
// / @returns The block immediately after this one, or a null pointer if this
231
214
// / is the last block.
232
- Block *next () const ;
215
+ LIBC_INLINE Block *next () const {
216
+ if (next_ & LAST_MASK)
217
+ return nullptr ;
218
+ return reinterpret_cast <Block *>(reinterpret_cast <uintptr_t >(this ) +
219
+ outer_size ());
220
+ }
233
221
234
222
// / @returns The free block immediately before this one, otherwise nullptr.
235
- Block *prev_free () const ;
223
+ LIBC_INLINE Block *prev_free () const {
224
+ if (!(next_ & PREV_FREE_MASK))
225
+ return nullptr ;
226
+ return reinterpret_cast <Block *>(reinterpret_cast <uintptr_t >(this ) - prev_);
227
+ }
236
228
237
229
// / @returns Whether the block is unavailable for allocation.
238
- bool used () const { return !next () || !next ()->prev_free (); }
230
+ LIBC_INLINE bool used () const { return !next () || !next ()->prev_free (); }
239
231
240
232
// / Marks this block as in use.
241
- void mark_used () {
233
+ LIBC_INLINE void mark_used () {
242
234
LIBC_ASSERT (next () && " last block is always considered used" );
243
235
next ()->next_ &= ~PREV_FREE_MASK;
244
236
}
245
237
246
238
// / Marks this block as free.
247
- void mark_free () {
239
+ LIBC_INLINE void mark_free () {
248
240
LIBC_ASSERT (next () && " last block is always considered used" );
249
241
next ()->next_ |= PREV_FREE_MASK;
250
242
// The next block's prev_ field becomes alive, as it is no longer part of
251
243
// this block's used space.
252
- *new (&next ()->prev_ ) offset_type = outer_size ();
244
+ *new (&next ()->prev_ ) size_t = outer_size ();
253
245
}
254
246
255
247
// / Marks this block as the last one in the chain. Makes next() return
256
248
// / nullptr.
257
- void mark_last () { next_ |= LAST_MASK; }
249
+ LIBC_INLINE void mark_last () { next_ |= LAST_MASK; }
258
250
259
- constexpr Block (size_t outer_size);
251
+ LIBC_INLINE constexpr Block (size_t outer_size) : next_(outer_size) {
252
+ LIBC_ASSERT (outer_size % ALIGNMENT == 0 && " block sizes must be aligned" );
253
+ }
260
254
261
- bool is_usable_space_aligned (size_t alignment) const {
255
+ LIBC_INLINE bool is_usable_space_aligned (size_t alignment) const {
262
256
return reinterpret_cast <uintptr_t >(usable_space ()) % alignment == 0 ;
263
257
}
264
258
265
259
// / @returns The new inner size of this block that would give the usable
266
260
// / space of the next block the given alignment.
267
- size_t padding_for_alignment (size_t alignment) const {
261
+ LIBC_INLINE size_t padding_for_alignment (size_t alignment) const {
268
262
if (is_usable_space_aligned (alignment))
269
263
return 0 ;
270
264
@@ -322,7 +316,9 @@ class Block {
322
316
private:
323
317
// / Construct a block to represent a span of bytes. Overwrites only enough
324
318
// / memory for the block header; the rest of the span is left alone.
325
- static Block *as_block (ByteSpan bytes);
319
+ LIBC_INLINE static Block *as_block (ByteSpan bytes) {
320
+ return ::new (bytes.data ()) Block (bytes.size ());
321
+ }
326
322
327
323
// / Like `split`, but assumes the caller has already checked to parameters to
328
324
// / ensure the split will succeed.
@@ -332,11 +328,11 @@ class Block {
332
328
// / block. This field is only alive when the previous block is free;
333
329
// / otherwise, its memory is reused as part of the previous block's usable
334
330
// / space.
335
- offset_type prev_ = 0 ;
331
+ size_t prev_ = 0 ;
336
332
337
333
// / Offset from this block to the next block. Valid even if this is the last
338
334
// / block, since it equals the size of the block.
339
- offset_type next_ = 0 ;
335
+ size_t next_ = 0 ;
340
336
341
337
// / Information about the current state of the block is stored in the two low
342
338
// / order bits of the next_ value. These are guaranteed free by a minimum
@@ -347,9 +343,10 @@ class Block {
347
343
// / previous block is free.
348
344
// / * If the `last` flag is set, the block is the sentinel last block. It is
349
345
// / summarily considered used and has no next block.
350
- } __attribute__((packed, aligned(cpp::max(kAlign , size_t {4 }))));
346
+ } __attribute__((packed, aligned(cpp::max(alignof ( max_align_t ) , size_t {4 }))));
351
347
352
- // Public template method implementations.
348
+ inline constexpr size_t Block::BLOCK_OVERHEAD =
349
+ align_up (sizeof (Block), ALIGNMENT);
353
350
354
351
LIBC_INLINE ByteSpan get_aligned_subspan (ByteSpan bytes, size_t alignment) {
355
352
if (bytes.data () == nullptr )
@@ -367,9 +364,8 @@ LIBC_INLINE ByteSpan get_aligned_subspan(ByteSpan bytes, size_t alignment) {
367
364
aligned_end - aligned_start);
368
365
}
369
366
370
- template <typename OffsetType, size_t kAlign >
371
- optional<Block<OffsetType, kAlign > *>
372
- Block<OffsetType, kAlign >::init(ByteSpan region) {
367
+ LIBC_INLINE
368
+ optional<Block *> Block::init (ByteSpan region) {
373
369
optional<ByteSpan> result = get_aligned_subspan (region, ALIGNMENT);
374
370
if (!result)
375
371
return {};
@@ -379,7 +375,7 @@ Block<OffsetType, kAlign>::init(ByteSpan region) {
379
375
if (region.size () < 2 * BLOCK_OVERHEAD)
380
376
return {};
381
377
382
- if (cpp::numeric_limits<OffsetType >::max () < region.size ())
378
+ if (cpp::numeric_limits<size_t >::max () < region.size ())
383
379
return {};
384
380
385
381
Block *block = as_block (region.first (region.size () - BLOCK_OVERHEAD));
@@ -389,9 +385,8 @@ Block<OffsetType, kAlign>::init(ByteSpan region) {
389
385
return block;
390
386
}
391
387
392
- template <typename OffsetType, size_t kAlign >
393
- bool Block<OffsetType, kAlign >::can_allocate(size_t alignment,
394
- size_t size) const {
388
+ LIBC_INLINE
389
+ bool Block::can_allocate (size_t alignment, size_t size) const {
395
390
if (inner_size () < size)
396
391
return false ;
397
392
if (is_usable_space_aligned (alignment))
@@ -406,10 +401,8 @@ bool Block<OffsetType, kAlign>::can_allocate(size_t alignment,
406
401
return size <= aligned_inner_size;
407
402
}
408
403
409
- template <typename OffsetType, size_t kAlign >
410
- typename Block<OffsetType, kAlign >::BlockInfo
411
- Block<OffsetType, kAlign >::allocate(Block *block, size_t alignment,
412
- size_t size) {
404
+ LIBC_INLINE
405
+ Block::BlockInfo Block::allocate (Block *block, size_t alignment, size_t size) {
413
406
LIBC_ASSERT (
414
407
block->can_allocate (alignment, size) &&
415
408
" Calls to this function for a given alignment and size should only be "
@@ -447,9 +440,8 @@ Block<OffsetType, kAlign>::allocate(Block *block, size_t alignment,
447
440
return info;
448
441
}
449
442
450
- template <typename OffsetType, size_t kAlign >
451
- optional<Block<OffsetType, kAlign > *>
452
- Block<OffsetType, kAlign >::split(size_t new_inner_size) {
443
+ LIBC_INLINE
444
+ optional<Block *> Block::split (size_t new_inner_size) {
453
445
if (used ())
454
446
return {};
455
447
// The prev_ field of the next block is always available, so there is a
@@ -469,9 +461,8 @@ Block<OffsetType, kAlign>::split(size_t new_inner_size) {
469
461
return split_impl (new_inner_size);
470
462
}
471
463
472
- template <typename OffsetType, size_t kAlign >
473
- Block<OffsetType, kAlign > *
474
- Block<OffsetType, kAlign >::split_impl(size_t new_inner_size) {
464
+ LIBC_INLINE
465
+ Block *Block::split_impl (size_t new_inner_size) {
475
466
size_t outer_size1 = outer_size (new_inner_size);
476
467
LIBC_ASSERT (outer_size1 % ALIGNMENT == 0 && " new size must be aligned" );
477
468
ByteSpan new_region = region ().subspan (outer_size1);
@@ -484,8 +475,8 @@ Block<OffsetType, kAlign>::split_impl(size_t new_inner_size) {
484
475
return new_block;
485
476
}
486
477
487
- template < typename OffsetType, size_t kAlign >
488
- bool Block<OffsetType, kAlign > ::merge_next() {
478
+ LIBC_INLINE
479
+ bool Block::merge_next () {
489
480
if (used () || next ()->used ())
490
481
return false ;
491
482
size_t new_size = outer_size () + next ()->outer_size ();
@@ -495,34 +486,6 @@ bool Block<OffsetType, kAlign>::merge_next() {
495
486
return true ;
496
487
}
497
488
498
- template <typename OffsetType, size_t kAlign >
499
- Block<OffsetType, kAlign > *Block<OffsetType, kAlign >::next() const {
500
- if (next_ & LAST_MASK)
501
- return nullptr ;
502
- return reinterpret_cast <Block *>(reinterpret_cast <uintptr_t >(this ) +
503
- outer_size ());
504
- }
505
-
506
- template <typename OffsetType, size_t kAlign >
507
- Block<OffsetType, kAlign > *Block<OffsetType, kAlign >::prev_free() const {
508
- if (!(next_ & PREV_FREE_MASK))
509
- return nullptr ;
510
- return reinterpret_cast <Block *>(reinterpret_cast <uintptr_t >(this ) - prev_);
511
- }
512
-
513
- // Private template method implementations.
514
-
515
- template <typename OffsetType, size_t kAlign >
516
- constexpr Block<OffsetType, kAlign >::Block(size_t outer_size)
517
- : next_(outer_size) {
518
- LIBC_ASSERT (outer_size % ALIGNMENT == 0 && " block sizes must be aligned" );
519
- }
520
-
521
- template <typename OffsetType, size_t kAlign >
522
- Block<OffsetType, kAlign > *Block<OffsetType, kAlign >::as_block(ByteSpan bytes) {
523
- return ::new (bytes.data ()) Block (bytes.size ());
524
- }
525
-
526
489
} // namespace LIBC_NAMESPACE_DECL
527
490
528
491
#endif // LLVM_LIBC_SRC___SUPPORT_BLOCK_H
0 commit comments