Skip to content

Commit 54941cc

Browse files
committed
[stdlib] add loading and storing to and from raw buffer slices
1 parent 4d9d67a commit 54941cc

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed

stdlib/public/core/UnsafeBufferPointerSlice.swift

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

300419
extension Slice where Base == UnsafeRawBufferPointer {
@@ -401,6 +520,83 @@ extension Slice where Base == UnsafeRawBufferPointer {
401520
let buffer = Base(rebasing: self)
402521
return buffer.assumingMemoryBound(to: T.self)
403522
}
523+
524+
/// Returns a new instance of the given type, read from the
525+
/// specified offset into the buffer pointer slice's raw memory.
526+
///
527+
/// The memory at `offset` bytes into this buffer pointer slice
528+
/// must be properly aligned for accessing `T` and initialized to `T` or
529+
/// another type that is layout compatible with `T`.
530+
///
531+
/// You can use this method to create new values from the underlying
532+
/// buffer pointer's bytes. The following example creates two new `Int32`
533+
/// instances from the memory referenced by the buffer pointer `someBytes`.
534+
/// The bytes for `a` are copied from the first four bytes of `someBytes`,
535+
/// and the bytes for `b` are copied from the next four bytes.
536+
///
537+
/// let a = someBytes[0..<4].load(as: Int32.self)
538+
/// let b = someBytes[4..<8].load(as: Int32.self)
539+
///
540+
/// The memory to read for the new instance must not extend beyond the
541+
/// memory region represented by the buffer pointer slice---that is,
542+
/// `offset + MemoryLayout<T>.size` must be less than or equal
543+
/// to the slice's `count`.
544+
///
545+
/// - Parameters:
546+
/// - offset: The offset into the slice's memory, in bytes, at
547+
/// which to begin reading data for the new instance. The default is zero.
548+
/// - type: The type to use for the newly constructed instance. The memory
549+
/// must be initialized to a value of a type that is layout compatible
550+
/// with `type`.
551+
/// - Returns: A new instance of type `T`, copied from the buffer pointer
552+
/// slice's memory.
553+
@inlinable
554+
@_alwaysEmitIntoClient
555+
public func load<T>(fromByteOffset offset: Int = 0, as type: T.Type) -> T {
556+
let buffer = Base(rebasing: self)
557+
return buffer.load(fromByteOffset: offset, as: T.self)
558+
}
559+
560+
/// Returns a new instance of the given type, read from the
561+
/// specified offset into the buffer pointer slice's raw memory.
562+
///
563+
/// This function only supports loading trivial types.
564+
/// A trivial type does not contain any reference-counted property
565+
/// within its in-memory stored representation.
566+
/// The memory at `offset` bytes into the buffer slice must be laid out
567+
/// identically to the in-memory representation of `T`.
568+
///
569+
/// You can use this method to create new values from the buffer pointer's
570+
/// underlying bytes. The following example creates two new `Int32`
571+
/// instances from the memory referenced by the buffer pointer `someBytes`.
572+
/// The bytes for `a` are copied from the first four bytes of `someBytes`,
573+
/// and the bytes for `b` are copied from the fourth through seventh bytes.
574+
///
575+
/// let a = someBytes[..<4].loadUnaligned(as: Int32.self)
576+
/// let b = someBytes[3...].loadUnaligned(as: Int32.self)
577+
///
578+
/// The memory to read for the new instance must not extend beyond the
579+
/// memory region represented by the buffer pointer slice---that is,
580+
/// `offset + MemoryLayout<T>.size` must be less than or equal
581+
/// to the slice's `count`.
582+
///
583+
/// - Parameters:
584+
/// - offset: The offset into the slice's memory, in bytes, at
585+
/// which to begin reading data for the new instance. The default is zero.
586+
/// - type: The type to use for the newly constructed instance. The memory
587+
/// must be initialized to a value of a type that is layout compatible
588+
/// with `type`.
589+
/// - Returns: A new instance of type `T`, copied from the buffer pointer's
590+
/// memory.
591+
@inlinable
592+
@_alwaysEmitIntoClient
593+
public func loadUnaligned<T>(
594+
fromByteOffset offset: Int = 0,
595+
as type: T.Type
596+
) -> T {
597+
let buffer = Base(rebasing: self)
598+
return buffer.loadUnaligned(fromByteOffset: offset, as: T.self)
599+
}
404600
}
405601

406602
extension Slice {

0 commit comments

Comments
 (0)