core/alloc/
layout.rs

1// Seemingly inconsequential code changes to this file can lead to measurable
2// performance impact on compilation times, due at least in part to the fact
3// that the layout code gets called from many instantiations of the various
4// collections, resulting in having to optimize down excess IR multiple times.
5// Your performance intuition is useless. Run perf.
6
7use crate::error::Error;
8use crate::intrinsics::{unchecked_add, unchecked_mul, unchecked_sub};
9use crate::mem::SizedTypeProperties;
10use crate::ptr::{Alignment, NonNull};
11use crate::{assert_unsafe_precondition, fmt, mem};
12
13// While this function is used in one place and its implementation
14// could be inlined, the previous attempts to do so made rustc
15// slower:
16//
17// * https://github.com/rust-lang/rust/pull/72189
18// * https://github.com/rust-lang/rust/pull/79827
19const fn size_align<T>() -> (usize, usize) {
20    (size_of::<T>(), align_of::<T>())
21}
22
23/// Layout of a block of memory.
24///
25/// An instance of `Layout` describes a particular layout of memory.
26/// You build a `Layout` up as an input to give to an allocator.
27///
28/// All layouts have an associated size and a power-of-two alignment. The size, when rounded up to
29/// the nearest multiple of `align`, does not overflow `isize` (i.e., the rounded value will always be
30/// less than or equal to `isize::MAX`).
31///
32/// (Note that layouts are *not* required to have non-zero size,
33/// even though `GlobalAlloc` requires that all memory requests
34/// be non-zero in size. A caller must either ensure that conditions
35/// like this are met, use specific allocators with looser
36/// requirements, or use the more lenient `Allocator` interface.)
37#[stable(feature = "alloc_layout", since = "1.28.0")]
38#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
39#[lang = "alloc_layout"]
40pub struct Layout {
41    // size of the requested block of memory, measured in bytes.
42    size: usize,
43
44    // alignment of the requested block of memory, measured in bytes.
45    // we ensure that this is always a power-of-two, because API's
46    // like `posix_memalign` require it and it is a reasonable
47    // constraint to impose on Layout constructors.
48    //
49    // (However, we do not analogously require `align >= sizeof(void*)`,
50    //  even though that is *also* a requirement of `posix_memalign`.)
51    align: Alignment,
52}
53
54impl Layout {
55    /// Constructs a `Layout` from a given `size` and `align`,
56    /// or returns `LayoutError` if any of the following conditions
57    /// are not met:
58    ///
59    /// * `align` must not be zero,
60    ///
61    /// * `align` must be a power of two,
62    ///
63    /// * `size`, when rounded up to the nearest multiple of `align`,
64    ///   must not overflow `isize` (i.e., the rounded value must be
65    ///   less than or equal to `isize::MAX`).
66    #[stable(feature = "alloc_layout", since = "1.28.0")]
67    #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
68    #[inline]
69    pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
70        if Layout::is_size_align_valid(size, align) {
71            // SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
72            unsafe { Ok(Layout { size, align: mem::transmute(align) }) }
73        } else {
74            Err(LayoutError)
75        }
76    }
77
78    const fn is_size_align_valid(size: usize, align: usize) -> bool {
79        let Some(align) = Alignment::new(align) else { return false };
80        if size > Self::max_size_for_align(align) {
81            return false;
82        }
83        true
84    }
85
86    #[inline(always)]
87    const fn max_size_for_align(align: Alignment) -> usize {
88        // (power-of-two implies align != 0.)
89
90        // Rounded up size is:
91        //   size_rounded_up = (size + align - 1) & !(align - 1);
92        //
93        // We know from above that align != 0. If adding (align - 1)
94        // does not overflow, then rounding up will be fine.
95        //
96        // Conversely, &-masking with !(align - 1) will subtract off
97        // only low-order-bits. Thus if overflow occurs with the sum,
98        // the &-mask cannot subtract enough to undo that overflow.
99        //
100        // Above implies that checking for summation overflow is both
101        // necessary and sufficient.
102
103        // SAFETY: the maximum possible alignment is `isize::MAX + 1`,
104        // so the subtraction cannot overflow.
105        unsafe { unchecked_sub(isize::MAX as usize + 1, align.as_usize()) }
106    }
107
108    /// Internal helper constructor to skip revalidating alignment validity.
109    #[inline]
110    const fn from_size_alignment(size: usize, align: Alignment) -> Result<Self, LayoutError> {
111        if size > Self::max_size_for_align(align) {
112            return Err(LayoutError);
113        }
114
115        // SAFETY: Layout::size invariants checked above.
116        Ok(Layout { size, align })
117    }
118
119    /// Creates a layout, bypassing all checks.
120    ///
121    /// # Safety
122    ///
123    /// This function is unsafe as it does not verify the preconditions from
124    /// [`Layout::from_size_align`].
125    #[stable(feature = "alloc_layout", since = "1.28.0")]
126    #[rustc_const_stable(feature = "const_alloc_layout_unchecked", since = "1.36.0")]
127    #[must_use]
128    #[inline]
129    #[track_caller]
130    pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
131        assert_unsafe_precondition!(
132            check_library_ub,
133            "Layout::from_size_align_unchecked requires that align is a power of 2 \
134            and the rounded-up allocation size does not exceed isize::MAX",
135            (
136                size: usize = size,
137                align: usize = align,
138            ) => Layout::is_size_align_valid(size, align)
139        );
140        // SAFETY: the caller is required to uphold the preconditions.
141        unsafe { Layout { size, align: mem::transmute(align) } }
142    }
143
144    /// The minimum size in bytes for a memory block of this layout.
145    #[stable(feature = "alloc_layout", since = "1.28.0")]
146    #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
147    #[must_use]
148    #[inline]
149    pub const fn size(&self) -> usize {
150        self.size
151    }
152
153    /// The minimum byte alignment for a memory block of this layout.
154    ///
155    /// The returned alignment is guaranteed to be a power of two.
156    #[stable(feature = "alloc_layout", since = "1.28.0")]
157    #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
158    #[must_use = "this returns the minimum alignment, \
159                  without modifying the layout"]
160    #[inline]
161    pub const fn align(&self) -> usize {
162        self.align.as_usize()
163    }
164
165    /// Constructs a `Layout` suitable for holding a value of type `T`.
166    #[stable(feature = "alloc_layout", since = "1.28.0")]
167    #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
168    #[must_use]
169    #[inline]
170    pub const fn new<T>() -> Self {
171        let (size, align) = size_align::<T>();
172        // SAFETY: if the type is instantiated, rustc already ensures that its
173        // layout is valid. Use the unchecked constructor to avoid inserting a
174        // panicking codepath that needs to be optimized out.
175        unsafe { Layout::from_size_align_unchecked(size, align) }
176    }
177
178    /// Produces layout describing a record that could be used to
179    /// allocate backing structure for `T` (which could be a trait
180    /// or other unsized type like a slice).
181    #[stable(feature = "alloc_layout", since = "1.28.0")]
182    #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
183    #[must_use]
184    #[inline]
185    pub const fn for_value<T: ?Sized>(t: &T) -> Self {
186        let (size, align) = (size_of_val(t), align_of_val(t));
187        // SAFETY: see rationale in `new` for why this is using the unsafe variant
188        unsafe { Layout::from_size_align_unchecked(size, align) }
189    }
190
191    /// Produces layout describing a record that could be used to
192    /// allocate backing structure for `T` (which could be a trait
193    /// or other unsized type like a slice).
194    ///
195    /// # Safety
196    ///
197    /// This function is only safe to call if the following conditions hold:
198    ///
199    /// - If `T` is `Sized`, this function is always safe to call.
200    /// - If the unsized tail of `T` is:
201    ///     - a [slice], then the length of the slice tail must be an initialized
202    ///       integer, and the size of the *entire value*
203    ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
204    ///       For the special case where the dynamic tail length is 0, this function
205    ///       is safe to call.
206    ///     - a [trait object], then the vtable part of the pointer must point
207    ///       to a valid vtable for the type `T` acquired by an unsizing coercion,
208    ///       and the size of the *entire value*
209    ///       (dynamic tail length + statically sized prefix) must fit in `isize`.
210    ///     - an (unstable) [extern type], then this function is always safe to
211    ///       call, but may panic or otherwise return the wrong value, as the
212    ///       extern type's layout is not known. This is the same behavior as
213    ///       [`Layout::for_value`] on a reference to an extern type tail.
214    ///     - otherwise, it is conservatively not allowed to call this function.
215    ///
216    /// [trait object]: ../../book/ch17-02-trait-objects.html
217    /// [extern type]: ../../unstable-book/language-features/extern-types.html
218    #[unstable(feature = "layout_for_ptr", issue = "69835")]
219    #[must_use]
220    pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
221        // SAFETY: we pass along the prerequisites of these functions to the caller
222        let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
223        // SAFETY: see rationale in `new` for why this is using the unsafe variant
224        unsafe { Layout::from_size_align_unchecked(size, align) }
225    }
226
227    /// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
228    ///
229    /// Note that the pointer value may potentially represent a valid pointer,
230    /// which means this must not be used as a "not yet initialized"
231    /// sentinel value. Types that lazily allocate must track initialization by
232    /// some other means.
233    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
234    #[must_use]
235    #[inline]
236    pub const fn dangling(&self) -> NonNull<u8> {
237        NonNull::without_provenance(self.align.as_nonzero())
238    }
239
240    /// Creates a layout describing the record that can hold a value
241    /// of the same layout as `self`, but that also is aligned to
242    /// alignment `align` (measured in bytes).
243    ///
244    /// If `self` already meets the prescribed alignment, then returns
245    /// `self`.
246    ///
247    /// Note that this method does not add any padding to the overall
248    /// size, regardless of whether the returned layout has a different
249    /// alignment. In other words, if `K` has size 16, `K.align_to(32)`
250    /// will *still* have size 16.
251    ///
252    /// Returns an error if the combination of `self.size()` and the given
253    /// `align` violates the conditions listed in [`Layout::from_size_align`].
254    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
255    #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
256    #[inline]
257    pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
258        if let Some(align) = Alignment::new(align) {
259            Layout::from_size_alignment(self.size, Alignment::max(self.align, align))
260        } else {
261            Err(LayoutError)
262        }
263    }
264
265    /// Returns the amount of padding we must insert after `self`
266    /// to ensure that the following address will satisfy `align`
267    /// (measured in bytes).
268    ///
269    /// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
270    /// returns 3, because that is the minimum number of bytes of
271    /// padding required to get a 4-aligned address (assuming that the
272    /// corresponding memory block starts at a 4-aligned address).
273    ///
274    /// The return value of this function has no meaning if `align` is
275    /// not a power-of-two.
276    ///
277    /// Note that the utility of the returned value requires `align`
278    /// to be less than or equal to the alignment of the starting
279    /// address for the whole allocated block of memory. One way to
280    /// satisfy this constraint is to ensure `align <= self.align()`.
281    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
282    #[must_use = "this returns the padding needed, \
283                  without modifying the `Layout`"]
284    #[inline]
285    pub const fn padding_needed_for(&self, align: usize) -> usize {
286        // FIXME: Can we just change the type on this to `Alignment`?
287        let Some(align) = Alignment::new(align) else { return usize::MAX };
288        let len_rounded_up = self.size_rounded_up_to_custom_align(align);
289        // SAFETY: Cannot overflow because the rounded-up value is never less
290        unsafe { unchecked_sub(len_rounded_up, self.size) }
291    }
292
293    /// Returns the smallest multiple of `align` greater than or equal to `self.size()`.
294    ///
295    /// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`)
296    /// because the original size is at most `isize::MAX`.
297    #[inline]
298    const fn size_rounded_up_to_custom_align(&self, align: Alignment) -> usize {
299        // SAFETY:
300        // Rounded up value is:
301        //   size_rounded_up = (size + align - 1) & !(align - 1);
302        //
303        // The arithmetic we do here can never overflow:
304        //
305        // 1. align is guaranteed to be > 0, so align - 1 is always
306        //    valid.
307        //
308        // 2. size is at most `isize::MAX`, so adding `align - 1` (which is at
309        //    most `isize::MAX`) can never overflow a `usize`.
310        //
311        // 3. masking by the alignment can remove at most `align - 1`,
312        //    which is what we just added, thus the value we return is never
313        //    less than the original `size`.
314        //
315        // (Size 0 Align MAX is already aligned, so stays the same, but things like
316        // Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.)
317        unsafe {
318            let align_m1 = unchecked_sub(align.as_usize(), 1);
319            let size_rounded_up = unchecked_add(self.size, align_m1) & !align_m1;
320            size_rounded_up
321        }
322    }
323
324    /// Creates a layout by rounding the size of this layout up to a multiple
325    /// of the layout's alignment.
326    ///
327    /// This is equivalent to adding the result of `padding_needed_for`
328    /// to the layout's current size.
329    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
330    #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
331    #[must_use = "this returns a new `Layout`, \
332                  without modifying the original"]
333    #[inline]
334    pub const fn pad_to_align(&self) -> Layout {
335        // This cannot overflow. Quoting from the invariant of Layout:
336        // > `size`, when rounded up to the nearest multiple of `align`,
337        // > must not overflow isize (i.e., the rounded value must be
338        // > less than or equal to `isize::MAX`)
339        let new_size = self.size_rounded_up_to_custom_align(self.align);
340
341        // SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
342        unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
343    }
344
345    /// Creates a layout describing the record for `n` instances of
346    /// `self`, with a suitable amount of padding between each to
347    /// ensure that each instance is given its requested size and
348    /// alignment. On success, returns `(k, offs)` where `k` is the
349    /// layout of the array and `offs` is the distance between the start
350    /// of each element in the array.
351    ///
352    /// (That distance between elements is sometimes known as "stride".)
353    ///
354    /// On arithmetic overflow, returns `LayoutError`.
355    ///
356    /// # Examples
357    ///
358    /// ```
359    /// #![feature(alloc_layout_extra)]
360    /// use std::alloc::Layout;
361    ///
362    /// // All rust types have a size that's a multiple of their alignment.
363    /// let normal = Layout::from_size_align(12, 4).unwrap();
364    /// let repeated = normal.repeat(3).unwrap();
365    /// assert_eq!(repeated, (Layout::from_size_align(36, 4).unwrap(), 12));
366    ///
367    /// // But you can manually make layouts which don't meet that rule.
368    /// let padding_needed = Layout::from_size_align(6, 4).unwrap();
369    /// let repeated = padding_needed.repeat(3).unwrap();
370    /// assert_eq!(repeated, (Layout::from_size_align(24, 4).unwrap(), 8));
371    /// ```
372    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
373    #[inline]
374    pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
375        let padded = self.pad_to_align();
376        if let Ok(repeated) = padded.repeat_packed(n) {
377            Ok((repeated, padded.size()))
378        } else {
379            Err(LayoutError)
380        }
381    }
382
383    /// Creates a layout describing the record for `self` followed by
384    /// `next`, including any necessary padding to ensure that `next`
385    /// will be properly aligned, but *no trailing padding*.
386    ///
387    /// In order to match C representation layout `repr(C)`, you should
388    /// call `pad_to_align` after extending the layout with all fields.
389    /// (There is no way to match the default Rust representation
390    /// layout `repr(Rust)`, as it is unspecified.)
391    ///
392    /// Note that the alignment of the resulting layout will be the maximum of
393    /// those of `self` and `next`, in order to ensure alignment of both parts.
394    ///
395    /// Returns `Ok((k, offset))`, where `k` is layout of the concatenated
396    /// record and `offset` is the relative location, in bytes, of the
397    /// start of the `next` embedded within the concatenated record
398    /// (assuming that the record itself starts at offset 0).
399    ///
400    /// On arithmetic overflow, returns `LayoutError`.
401    ///
402    /// # Examples
403    ///
404    /// To calculate the layout of a `#[repr(C)]` structure and the offsets of
405    /// the fields from its fields' layouts:
406    ///
407    /// ```rust
408    /// # use std::alloc::{Layout, LayoutError};
409    /// pub fn repr_c(fields: &[Layout]) -> Result<(Layout, Vec<usize>), LayoutError> {
410    ///     let mut offsets = Vec::new();
411    ///     let mut layout = Layout::from_size_align(0, 1)?;
412    ///     for &field in fields {
413    ///         let (new_layout, offset) = layout.extend(field)?;
414    ///         layout = new_layout;
415    ///         offsets.push(offset);
416    ///     }
417    ///     // Remember to finalize with `pad_to_align`!
418    ///     Ok((layout.pad_to_align(), offsets))
419    /// }
420    /// # // test that it works
421    /// # #[repr(C)] struct S { a: u64, b: u32, c: u16, d: u32 }
422    /// # let s = Layout::new::<S>();
423    /// # let u16 = Layout::new::<u16>();
424    /// # let u32 = Layout::new::<u32>();
425    /// # let u64 = Layout::new::<u64>();
426    /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16])));
427    /// ```
428    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
429    #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
430    #[inline]
431    pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
432        let new_align = Alignment::max(self.align, next.align);
433        let offset = self.size_rounded_up_to_custom_align(next.align);
434
435        // SAFETY: `offset` is at most `isize::MAX + 1` (such as from aligning
436        // to `Alignment::MAX`) and `next.size` is at most `isize::MAX` (from the
437        // `Layout` type invariant).  Thus the largest possible `new_size` is
438        // `isize::MAX + 1 + isize::MAX`, which is `usize::MAX`, and cannot overflow.
439        let new_size = unsafe { unchecked_add(offset, next.size) };
440
441        if let Ok(layout) = Layout::from_size_alignment(new_size, new_align) {
442            Ok((layout, offset))
443        } else {
444            Err(LayoutError)
445        }
446    }
447
448    /// Creates a layout describing the record for `n` instances of
449    /// `self`, with no padding between each instance.
450    ///
451    /// Note that, unlike `repeat`, `repeat_packed` does not guarantee
452    /// that the repeated instances of `self` will be properly
453    /// aligned, even if a given instance of `self` is properly
454    /// aligned. In other words, if the layout returned by
455    /// `repeat_packed` is used to allocate an array, it is not
456    /// guaranteed that all elements in the array will be properly
457    /// aligned.
458    ///
459    /// On arithmetic overflow, returns `LayoutError`.
460    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
461    #[inline]
462    pub const fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
463        if let Some(size) = self.size.checked_mul(n) {
464            // The safe constructor is called here to enforce the isize size limit.
465            Layout::from_size_alignment(size, self.align)
466        } else {
467            Err(LayoutError)
468        }
469    }
470
471    /// Creates a layout describing the record for `self` followed by
472    /// `next` with no additional padding between the two. Since no
473    /// padding is inserted, the alignment of `next` is irrelevant,
474    /// and is not incorporated *at all* into the resulting layout.
475    ///
476    /// On arithmetic overflow, returns `LayoutError`.
477    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
478    #[inline]
479    pub const fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
480        // SAFETY: each `size` is at most `isize::MAX == usize::MAX/2`, so the
481        // sum is at most `usize::MAX/2*2 == usize::MAX - 1`, and cannot overflow.
482        let new_size = unsafe { unchecked_add(self.size, next.size) };
483        // The safe constructor enforces that the new size isn't too big for the alignment
484        Layout::from_size_alignment(new_size, self.align)
485    }
486
487    /// Creates a layout describing the record for a `[T; n]`.
488    ///
489    /// On arithmetic overflow or when the total size would exceed
490    /// `isize::MAX`, returns `LayoutError`.
491    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
492    #[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
493    #[inline]
494    pub const fn array<T>(n: usize) -> Result<Self, LayoutError> {
495        // Reduce the amount of code we need to monomorphize per `T`.
496        return inner(T::LAYOUT, n);
497
498        #[inline]
499        const fn inner(element_layout: Layout, n: usize) -> Result<Layout, LayoutError> {
500            let Layout { size: element_size, align } = element_layout;
501
502            // We need to check two things about the size:
503            //  - That the total size won't overflow a `usize`, and
504            //  - That the total size still fits in an `isize`.
505            // By using division we can check them both with a single threshold.
506            // That'd usually be a bad idea, but thankfully here the element size
507            // and alignment are constants, so the compiler will fold all of it.
508            if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
509                return Err(LayoutError);
510            }
511
512            // SAFETY: We just checked that we won't overflow `usize` when we multiply.
513            // This is a useless hint inside this function, but after inlining this helps
514            // deduplicate checks for whether the overall capacity is zero (e.g., in RawVec's
515            // allocation path) before/after this multiplication.
516            let array_size = unsafe { unchecked_mul(element_size, n) };
517
518            // SAFETY: We just checked above that the `array_size` will not
519            // exceed `isize::MAX` even when rounded up to the alignment.
520            // And `Alignment` guarantees it's a power of two.
521            unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
522        }
523    }
524
525    /// Perma-unstable access to `align` as `Alignment` type.
526    #[unstable(issue = "none", feature = "std_internals")]
527    #[doc(hidden)]
528    #[inline]
529    pub const fn alignment(&self) -> Alignment {
530        self.align
531    }
532}
533
534#[stable(feature = "alloc_layout", since = "1.28.0")]
535#[deprecated(
536    since = "1.52.0",
537    note = "Name does not follow std convention, use LayoutError",
538    suggestion = "LayoutError"
539)]
540pub type LayoutErr = LayoutError;
541
542/// The `LayoutError` is returned when the parameters given
543/// to `Layout::from_size_align`
544/// or some other `Layout` constructor
545/// do not satisfy its documented constraints.
546#[stable(feature = "alloc_layout_error", since = "1.50.0")]
547#[non_exhaustive]
548#[derive(Clone, PartialEq, Eq, Debug)]
549pub struct LayoutError;
550
551#[stable(feature = "alloc_layout", since = "1.28.0")]
552impl Error for LayoutError {}
553
554// (we need this for downstream impl of trait Error)
555#[stable(feature = "alloc_layout", since = "1.28.0")]
556impl fmt::Display for LayoutError {
557    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
558        f.write_str("invalid parameters to Layout::from_size_align")
559    }
560}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy