@@ -68,13 +68,11 @@ using cpp::optional;
6868// / The blocks store their offsets to the previous and next blocks. The latter
6969// / is also the block's size.
7070// /
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`.
7573// /
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:
7876// /
7977// / @code{.unparsed}
8078// / Block 1:
@@ -117,30 +115,15 @@ using cpp::optional;
117115// /
118116// / The next offset of a block matches the previous offset of its next block.
119117// / 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 )>
131118class Block {
132119 // Masks for the contents of the next_ field.
133120 static constexpr size_t PREV_FREE_MASK = 1 << 0 ;
134121 static constexpr size_t LAST_MASK = 1 << 1 ;
135122 static constexpr size_t SIZE_MASK = ~(PREV_FREE_MASK | LAST_MASK);
136123
137124public:
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;
144127
145128 // No copy or move.
146129 Block (const Block &other) = delete ;
@@ -157,61 +140,61 @@ class Block {
157140 // /
158141 // / @warning This method does not do any checking; passing a random
159142 // / 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) {
161144 auto *bytes = reinterpret_cast <cpp::byte *>(usable_space);
162145 return reinterpret_cast <Block *>(bytes - BLOCK_OVERHEAD);
163146 }
164- static const Block *from_usable_space (const void *usable_space) {
147+ LIBC_INLINE static const Block *from_usable_space (const void *usable_space) {
165148 const auto *bytes = reinterpret_cast <const cpp::byte *>(usable_space);
166149 return reinterpret_cast <const Block *>(bytes - BLOCK_OVERHEAD);
167150 }
168151
169152 // / @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; }
171154
172- static size_t outer_size (size_t inner_size) {
155+ LIBC_INLINE static size_t outer_size (size_t inner_size) {
173156 // The usable region includes the prev_ field of the next block.
174157 return inner_size - sizeof (prev_) + BLOCK_OVERHEAD;
175158 }
176159
177160 // / @returns The number of usable bytes inside the block were it to be
178161 // / allocated.
179- size_t inner_size () const {
162+ LIBC_INLINE size_t inner_size () const {
180163 if (!next ())
181164 return 0 ;
182165 return inner_size (outer_size ());
183166 }
184167
185168 // / @returns The number of usable bytes inside a block with the given outer
186169 // / 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) {
188171 // The usable region includes the prev_ field of the next block.
189172 return inner_size_free (outer_size) + sizeof (prev_);
190173 }
191174
192175 // / @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 {
194177 if (!next ())
195178 return 0 ;
196179 return inner_size_free (outer_size ());
197180 }
198181
199182 // / @returns The number of usable bytes inside a block with the given outer
200183 // / 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) {
202185 return outer_size - BLOCK_OVERHEAD;
203186 }
204187
205188 // / @returns A pointer to the usable space inside this block.
206- cpp::byte *usable_space () {
189+ LIBC_INLINE cpp::byte *usable_space () {
207190 return reinterpret_cast <cpp::byte *>(this ) + BLOCK_OVERHEAD;
208191 }
209- const cpp::byte *usable_space () const {
192+ LIBC_INLINE const cpp::byte *usable_space () const {
210193 return reinterpret_cast <const cpp::byte *>(this ) + BLOCK_OVERHEAD;
211194 }
212195
213196 // @returns The region of memory the block manages, including the header.
214- ByteSpan region () {
197+ LIBC_INLINE ByteSpan region () {
215198 return {reinterpret_cast <cpp::byte *>(this ), outer_size ()};
216199 }
217200
@@ -229,42 +212,53 @@ class Block {
229212
230213 // / @returns The block immediately after this one, or a null pointer if this
231214 // / 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+ }
233221
234222 // / @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+ }
236228
237229 // / @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 (); }
239231
240232 // / Marks this block as in use.
241- void mark_used () {
233+ LIBC_INLINE void mark_used () {
242234 LIBC_ASSERT (next () && " last block is always considered used" );
243235 next ()->next_ &= ~PREV_FREE_MASK;
244236 }
245237
246238 // / Marks this block as free.
247- void mark_free () {
239+ LIBC_INLINE void mark_free () {
248240 LIBC_ASSERT (next () && " last block is always considered used" );
249241 next ()->next_ |= PREV_FREE_MASK;
250242 // The next block's prev_ field becomes alive, as it is no longer part of
251243 // this block's used space.
252- *new (&next ()->prev_ ) offset_type = outer_size ();
244+ *new (&next ()->prev_ ) size_t = outer_size ();
253245 }
254246
255247 // / Marks this block as the last one in the chain. Makes next() return
256248 // / nullptr.
257- void mark_last () { next_ |= LAST_MASK; }
249+ LIBC_INLINE void mark_last () { next_ |= LAST_MASK; }
258250
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+ }
260254
261- bool is_usable_space_aligned (size_t alignment) const {
255+ LIBC_INLINE bool is_usable_space_aligned (size_t alignment) const {
262256 return reinterpret_cast <uintptr_t >(usable_space ()) % alignment == 0 ;
263257 }
264258
265259 // / @returns The new inner size of this block that would give the usable
266260 // / 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 {
268262 if (is_usable_space_aligned (alignment))
269263 return 0 ;
270264
@@ -322,7 +316,9 @@ class Block {
322316private:
323317 // / Construct a block to represent a span of bytes. Overwrites only enough
324318 // / 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+ }
326322
327323 // / Like `split`, but assumes the caller has already checked to parameters to
328324 // / ensure the split will succeed.
@@ -332,11 +328,11 @@ class Block {
332328 // / block. This field is only alive when the previous block is free;
333329 // / otherwise, its memory is reused as part of the previous block's usable
334330 // / space.
335- offset_type prev_ = 0 ;
331+ size_t prev_ = 0 ;
336332
337333 // / Offset from this block to the next block. Valid even if this is the last
338334 // / block, since it equals the size of the block.
339- offset_type next_ = 0 ;
335+ size_t next_ = 0 ;
340336
341337 // / Information about the current state of the block is stored in the two low
342338 // / order bits of the next_ value. These are guaranteed free by a minimum
@@ -347,9 +343,10 @@ class Block {
347343 // / previous block is free.
348344 // / * If the `last` flag is set, the block is the sentinel last block. It is
349345 // / 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 }))));
351347
352- // Public template method implementations.
348+ inline constexpr size_t Block::BLOCK_OVERHEAD =
349+ align_up (sizeof (Block), ALIGNMENT);
353350
354351LIBC_INLINE ByteSpan get_aligned_subspan (ByteSpan bytes, size_t alignment) {
355352 if (bytes.data () == nullptr )
@@ -367,9 +364,8 @@ LIBC_INLINE ByteSpan get_aligned_subspan(ByteSpan bytes, size_t alignment) {
367364 aligned_end - aligned_start);
368365}
369366
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) {
373369 optional<ByteSpan> result = get_aligned_subspan (region, ALIGNMENT);
374370 if (!result)
375371 return {};
@@ -379,7 +375,7 @@ Block<OffsetType, kAlign>::init(ByteSpan region) {
379375 if (region.size () < 2 * BLOCK_OVERHEAD)
380376 return {};
381377
382- if (cpp::numeric_limits<OffsetType >::max () < region.size ())
378+ if (cpp::numeric_limits<size_t >::max () < region.size ())
383379 return {};
384380
385381 Block *block = as_block (region.first (region.size () - BLOCK_OVERHEAD));
@@ -389,9 +385,8 @@ Block<OffsetType, kAlign>::init(ByteSpan region) {
389385 return block;
390386}
391387
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 {
395390 if (inner_size () < size)
396391 return false ;
397392 if (is_usable_space_aligned (alignment))
@@ -406,10 +401,8 @@ bool Block<OffsetType, kAlign>::can_allocate(size_t alignment,
406401 return size <= aligned_inner_size;
407402}
408403
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) {
413406 LIBC_ASSERT (
414407 block->can_allocate (alignment, size) &&
415408 " 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,
447440 return info;
448441}
449442
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) {
453445 if (used ())
454446 return {};
455447 // 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) {
469461 return split_impl (new_inner_size);
470462}
471463
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) {
475466 size_t outer_size1 = outer_size (new_inner_size);
476467 LIBC_ASSERT (outer_size1 % ALIGNMENT == 0 && " new size must be aligned" );
477468 ByteSpan new_region = region ().subspan (outer_size1);
@@ -484,8 +475,8 @@ Block<OffsetType, kAlign>::split_impl(size_t new_inner_size) {
484475 return new_block;
485476}
486477
487- template < typename OffsetType, size_t kAlign >
488- bool Block<OffsetType, kAlign > ::merge_next() {
478+ LIBC_INLINE
479+ bool Block::merge_next () {
489480 if (used () || next ()->used ())
490481 return false ;
491482 size_t new_size = outer_size () + next ()->outer_size ();
@@ -495,34 +486,6 @@ bool Block<OffsetType, kAlign>::merge_next() {
495486 return true ;
496487}
497488
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-
526489} // namespace LIBC_NAMESPACE_DECL
527490
528491#endif // LLVM_LIBC_SRC___SUPPORT_BLOCK_H
0 commit comments