Skip to content

Commit 8b0ee8f

Browse files
committed
[stdlib] add loading and storing to and from raw buffer slices
1 parent 8fa10b2 commit 8b0ee8f

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed

stdlib/public/core/UnsafeBufferPointerSlice.swift

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,112 @@ extension Slice where Base == UnsafeMutableRawBufferPointer {
295295
let buffer = Base(rebasing: self)
296296
return buffer.assumingMemoryBound(to: T.self)
297297
}
298+
299+
/// Returns a new instance of the given type, read from the
300+
/// buffer pointer slice's raw memory.
301+
///
302+
/// The memory at the beginning of this buffer pointer slice
303+
/// must be properly aligned for accessing `T` and initialized to `T` or
304+
/// another type that is layout compatible with `T`.
305+
///
306+
/// You can use this method to create new values from the underlying
307+
/// buffer pointer's bytes. The following example creates two new `Int32`
308+
/// instances from the memory referenced by the buffer pointer `someBytes`.
309+
/// The bytes for `a` are copied from the first four bytes of `someBytes`,
310+
/// and the bytes for `b` are copied from the next four bytes.
311+
///
312+
/// let a = someBytes[0..<4].load(as: Int32.self)
313+
/// let b = someBytes[4..<8].load(as: Int32.self)
314+
///
315+
/// The memory to read for the new instance must not extend beyond the
316+
/// memory region represented by the buffer pointer slice---that is,
317+
/// `MemoryLayout<T>.size` must be less than or equal to the slice's `count`.
318+
///
319+
/// - Parameters:
320+
/// - type: The type to use for the newly constructed instance. The memory
321+
/// must be initialized to a value of a type that is layout compatible
322+
/// with `type`.
323+
/// - Returns: A new instance of type `T`, copied from the buffer pointer
324+
/// slice's memory.
325+
@inlinable
326+
@_alwaysEmitIntoClient
327+
public func load<T>(as type: T.Type) -> T {
328+
let buffer = Base(rebasing: self)
329+
return buffer.load(fromByteOffset: 0, as: T.self)
330+
}
331+
332+
/// Returns a new instance of the given type, read from the
333+
/// buffer pointer slice's raw memory.
334+
///
335+
/// This function only supports loading trivial types.
336+
/// A trivial type does not contain any reference-counted property
337+
/// within its in-memory stored representation.
338+
/// The memory at `offset` bytes into the buffer must be laid out
339+
/// identically to the in-memory representation of `T`.
340+
///
341+
/// You can use this method to create new values from the buffer pointer's
342+
/// underlying bytes. The following example creates two new `Int32`
343+
/// instances from the memory referenced by the buffer pointer `someBytes`.
344+
/// The bytes for `a` are copied from the first four bytes of `someBytes`,
345+
/// and the bytes for `b` are copied from the fourth through seventh bytes.
346+
///
347+
/// let a = someBytes[..<4].loadUnaligned(as: Int32.self)
348+
/// let b = someBytes[3...].loadUnaligned(as: Int32.self)
349+
///
350+
/// The memory to read for the new instance must not extend beyond the
351+
/// memory region represented by the buffer pointer slice---that is,
352+
/// `MemoryLayout<T>.size` must be less than or equal to the slice's `count`.
353+
///
354+
/// - Parameters:
355+
/// - type: The type to use for the newly constructed instance. The memory
356+
/// must be initialized to a value of a type that is layout compatible
357+
/// with `type`.
358+
/// - Returns: A new instance of type `T`, copied from the buffer pointer's
359+
/// memory.
360+
@inlinable
361+
@_alwaysEmitIntoClient
362+
public func loadUnaligned<T>(as type: T.Type) -> T {
363+
let buffer = Base(rebasing: self)
364+
return buffer.loadUnaligned(fromByteOffset: 0, as: T.self)
365+
}
366+
367+
/// Stores a value's bytes into the buffer pointer slice's raw memory.
368+
///
369+
/// The type `T` to be stored must be a trivial type. The memory must also be
370+
/// uninitialized, initialized to `T`, or initialized to another trivial
371+
/// type that is layout compatible with `T`.
372+
///
373+
/// The memory written to must not extend beyond
374+
/// the memory region represented by the buffer pointer slice---that is,
375+
/// `MemoryLayout<T>.size` must be less than or equal to the slice's `count`.
376+
///
377+
/// After calling `storeBytes(of:as:)`, the memory is
378+
/// initialized to the raw bytes of `value`. If the memory is bound to a
379+
/// type `U` that is layout compatible with `T`, then it contains a value of
380+
/// type `U`. Calling `storeBytes(of:toByteOffset:as:)` does not change the
381+
/// bound type of the memory.
382+
///
383+
/// - Note: A trivial type can be copied with just a bit-for-bit copy without
384+
/// any indirection or reference-counting operations. Generally, native
385+
/// Swift types that do not contain strong or weak references or other
386+
/// forms of indirection are trivial, as are imported C structs and enums.
387+
///
388+
/// If you need to store into memory a copy of a value of a type that isn't
389+
/// trivial, you cannot use the `storeBytes(of:as:)` method.
390+
/// Instead, you must know either initialize the memory or,
391+
/// if you know the memory was already bound to `type`, assign to the memory.
392+
///
393+
/// - Parameters:
394+
/// - value: The value to store as raw bytes.
395+
/// - type: The type to use for the newly constructed instance. The memory
396+
/// must be initialized to a value of a type that is layout compatible
397+
/// with `type`.
398+
@inlinable
399+
@_alwaysEmitIntoClient
400+
public func storeBytes<T>(of value: T, as type: T.Type) {
401+
let buffer = Base(rebasing: self)
402+
buffer.storeBytes(of: value, toByteOffset: 0, as: T.self)
403+
}
298404
}
299405

300406
extension Slice where Base == UnsafeRawBufferPointer {
@@ -401,6 +507,74 @@ extension Slice where Base == UnsafeRawBufferPointer {
401507
let buffer = Base(rebasing: self)
402508
return buffer.assumingMemoryBound(to: T.self)
403509
}
510+
511+
/// Returns a new instance of the given type, read from the
512+
/// buffer pointer slice's raw memory.
513+
///
514+
/// The memory at the beginning of this buffer pointer slice
515+
/// must be properly aligned for accessing `T` and initialized to `T` or
516+
/// another type that is layout compatible with `T`.
517+
///
518+
/// You can use this method to create new values from the underlying
519+
/// buffer pointer's bytes. The following example creates two new `Int32`
520+
/// instances from the memory referenced by the buffer pointer `someBytes`.
521+
/// The bytes for `a` are copied from the first four bytes of `someBytes`,
522+
/// and the bytes for `b` are copied from the next four bytes.
523+
///
524+
/// let a = someBytes[0..<4].load(as: Int32.self)
525+
/// let b = someBytes[4..<8].load(as: Int32.self)
526+
///
527+
/// The memory to read for the new instance must not extend beyond the
528+
/// memory region represented by the buffer pointer slice---that is,
529+
/// `MemoryLayout<T>.size` must be less than or equal to the slice's `count`.
530+
///
531+
/// - Parameters:
532+
/// - type: The type to use for the newly constructed instance. The memory
533+
/// must be initialized to a value of a type that is layout compatible
534+
/// with `type`.
535+
/// - Returns: A new instance of type `T`, copied from the buffer pointer
536+
/// slice's memory.
537+
@inlinable
538+
@_alwaysEmitIntoClient
539+
public func load<T>(as type: T.Type) -> T {
540+
let buffer = Base(rebasing: self)
541+
return buffer.load(fromByteOffset: 0, as: T.self)
542+
}
543+
544+
/// Returns a new instance of the given type, read from the
545+
/// buffer pointer slice's raw memory.
546+
///
547+
/// This function only supports loading trivial types.
548+
/// A trivial type does not contain any reference-counted property
549+
/// within its in-memory stored representation.
550+
/// The memory at `offset` bytes into the buffer must be laid out
551+
/// identically to the in-memory representation of `T`.
552+
///
553+
/// You can use this method to create new values from the buffer pointer's
554+
/// underlying bytes. The following example creates two new `Int32`
555+
/// instances from the memory referenced by the buffer pointer `someBytes`.
556+
/// The bytes for `a` are copied from the first four bytes of `someBytes`,
557+
/// and the bytes for `b` are copied from the fourth through seventh bytes.
558+
///
559+
/// let a = someBytes[..<4].loadUnaligned(as: Int32.self)
560+
/// let b = someBytes[3...].loadUnaligned(as: Int32.self)
561+
///
562+
/// The memory to read for the new instance must not extend beyond the
563+
/// memory region represented by the buffer pointer slice---that is,
564+
/// `MemoryLayout<T>.size` must be less than or equal to the slice's `count`.
565+
///
566+
/// - Parameters:
567+
/// - type: The type to use for the newly constructed instance. The memory
568+
/// must be initialized to a value of a type that is layout compatible
569+
/// with `type`.
570+
/// - Returns: A new instance of type `T`, copied from the buffer pointer's
571+
/// memory.
572+
@inlinable
573+
@_alwaysEmitIntoClient
574+
public func loadUnaligned<T>(as type: T.Type) -> T {
575+
let buffer = Base(rebasing: self)
576+
return buffer.loadUnaligned(fromByteOffset: 0, as: T.self)
577+
}
404578
}
405579

406580
extension Slice {

0 commit comments

Comments
 (0)