| //===----------------------------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2018 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| //===--- DataProtocol -----------------------------------------------------===// |
| |
| public protocol DataProtocol : RandomAccessCollection where Element == UInt8, SubSequence : DataProtocol { |
| // FIXME: Remove in favor of opaque type on `regions`. |
| associatedtype Regions: BidirectionalCollection where Regions.Element : DataProtocol & ContiguousBytes, Regions.Element.SubSequence : ContiguousBytes |
| |
| /// A `BidirectionalCollection` of `DataProtocol` elements which compose a |
| /// discontiguous buffer of memory. Each region is a contiguous buffer of |
| /// bytes. |
| /// |
| /// The sum of the lengths of the associated regions must equal `self.count` |
| /// (such that iterating `regions` and iterating `self` produces the same |
| /// sequence of indices in the same number of index advancements). |
| var regions: Regions { get } |
| |
| /// Returns the first found range of the given data buffer. |
| /// |
| /// A default implementation is given in terms of `self.regions`. |
| func firstRange<D: DataProtocol, R: RangeExpression>(of: D, in: R) -> Range<Index>? where R.Bound == Index |
| |
| /// Returns the last found range of the given data buffer. |
| /// |
| /// A default implementation is given in terms of `self.regions`. |
| func lastRange<D: DataProtocol, R: RangeExpression>(of: D, in: R) -> Range<Index>? where R.Bound == Index |
| |
| /// Copies `count` bytes from the start of the buffer to the destination |
| /// buffer. |
| /// |
| /// A default implementation is given in terms of `copyBytes(to:from:)`. |
| @discardableResult |
| func copyBytes(to: UnsafeMutableRawBufferPointer, count: Int) -> Int |
| |
| /// Copies `count` bytes from the start of the buffer to the destination |
| /// buffer. |
| /// |
| /// A default implementation is given in terms of `copyBytes(to:from:)`. |
| @discardableResult |
| func copyBytes<DestinationType>(to: UnsafeMutableBufferPointer<DestinationType>, count: Int) -> Int |
| |
| /// Copies the bytes from the given range to the destination buffer. |
| /// |
| /// A default implementation is given in terms of `self.regions`. |
| @discardableResult |
| func copyBytes<R: RangeExpression>(to: UnsafeMutableRawBufferPointer, from: R) -> Int where R.Bound == Index |
| |
| /// Copies the bytes from the given range to the destination buffer. |
| /// |
| /// A default implementation is given in terms of `self.regions`. |
| @discardableResult |
| func copyBytes<DestinationType, R: RangeExpression>(to: UnsafeMutableBufferPointer<DestinationType>, from: R) -> Int where R.Bound == Index |
| } |
| |
| //===--- MutableDataProtocol ----------------------------------------------===// |
| |
| public protocol MutableDataProtocol : DataProtocol, MutableCollection, RangeReplaceableCollection { |
| /// Replaces the contents of the buffer at the given range with zeroes. |
| /// |
| /// A default implementation is given in terms of |
| /// `replaceSubrange(_:with:)`. |
| mutating func resetBytes<R: RangeExpression>(in range: R) where R.Bound == Index |
| } |
| |
| //===--- DataProtocol Extensions ------------------------------------------===// |
| |
| extension DataProtocol { |
| public func firstRange<D: DataProtocol>(of data: D) -> Range<Index>? { |
| return self.firstRange(of: data, in: self.startIndex ..< self.endIndex) |
| } |
| |
| public func lastRange<D: DataProtocol>(of data: D) -> Range<Index>? { |
| return self.lastRange(of: data, in: self.startIndex ..< self.endIndex) |
| } |
| |
| @discardableResult |
| public func copyBytes(to ptr: UnsafeMutableRawBufferPointer) -> Int { |
| return copyBytes(to: ptr, from: self.startIndex ..< self.endIndex) |
| } |
| |
| @discardableResult |
| public func copyBytes<DestinationType>(to ptr: UnsafeMutableBufferPointer<DestinationType>) -> Int { |
| return copyBytes(to: ptr, from: self.startIndex ..< self.endIndex) |
| } |
| |
| @discardableResult |
| public func copyBytes(to ptr: UnsafeMutableRawBufferPointer, count: Int) -> Int { |
| return copyBytes(to: ptr, from: self.startIndex ..< self.index(self.startIndex, offsetBy: count)) |
| } |
| |
| @discardableResult |
| public func copyBytes<DestinationType>(to ptr: UnsafeMutableBufferPointer<DestinationType>, count: Int) -> Int { |
| return copyBytes(to: ptr, from: self.startIndex ..< self.index(self.startIndex, offsetBy: count)) |
| } |
| |
| @discardableResult |
| public func copyBytes<R: RangeExpression>(to ptr: UnsafeMutableRawBufferPointer, from range: R) -> Int where R.Bound == Index { |
| precondition(ptr.baseAddress != nil) |
| |
| let concreteRange = range.relative(to: self) |
| let slice = self[concreteRange] |
| |
| // The type isn't contiguous, so we need to copy one region at a time. |
| var offset = 0 |
| let rangeCount = distance(from: concreteRange.lowerBound, to: concreteRange.upperBound) |
| var amountToCopy = Swift.min(ptr.count, rangeCount) |
| for region in slice.regions { |
| guard amountToCopy > 0 else { |
| break |
| } |
| |
| region.withUnsafeBytes { buffer in |
| let offsetPtr = UnsafeMutableRawBufferPointer(rebasing: ptr[offset...]) |
| let buf = UnsafeRawBufferPointer(start: buffer.baseAddress, count: Swift.min(buffer.count, amountToCopy)) |
| offsetPtr.copyMemory(from: buf) |
| offset += buf.count |
| amountToCopy -= buf.count |
| } |
| } |
| |
| return offset |
| } |
| |
| @discardableResult |
| public func copyBytes<DestinationType, R: RangeExpression>(to ptr: UnsafeMutableBufferPointer<DestinationType>, from range: R) -> Int where R.Bound == Index { |
| return self.copyBytes(to: UnsafeMutableRawBufferPointer(start: ptr.baseAddress, count: ptr.count * MemoryLayout<DestinationType>.stride), from: range) |
| } |
| |
| public func firstRange<D: DataProtocol, R: RangeExpression>(of data: D, in range: R) -> Range<Index>? where R.Bound == Index { |
| let r = range.relative(to: self) |
| let rangeCount = distance(from: r.lowerBound, to: r.upperBound) |
| if rangeCount < data.count { |
| return nil |
| } |
| var haystackIndex = r.lowerBound |
| let haystackEnd = index(r.upperBound, offsetBy: -data.count) |
| while haystackIndex < haystackEnd { |
| var compareIndex = haystackIndex |
| var needleIndex = data.startIndex |
| let needleEnd = data.endIndex |
| var matched = true |
| while compareIndex < haystackEnd && needleIndex < needleEnd { |
| if self[compareIndex] != data[needleIndex] { |
| matched = false |
| break |
| } |
| needleIndex = data.index(after: needleIndex) |
| compareIndex = index(after: compareIndex) |
| } |
| if matched { |
| return haystackIndex..<compareIndex |
| } |
| haystackIndex = index(after: haystackIndex) |
| } |
| return nil |
| } |
| |
| public func lastRange<D: DataProtocol, R: RangeExpression>(of data: D, in range: R) -> Range<Index>? where R.Bound == Index { |
| let r = range.relative(to: self) |
| let rangeCount = distance(from: r.lowerBound, to: r.upperBound) |
| if rangeCount < data.count { |
| return nil |
| } |
| var haystackIndex = r.upperBound |
| let haystackStart = index(r.lowerBound, offsetBy: data.count) |
| while haystackIndex > haystackStart { |
| var compareIndex = haystackIndex |
| var needleIndex = data.endIndex |
| let needleStart = data.startIndex |
| var matched = true |
| while compareIndex > haystackStart && needleIndex > needleStart { |
| if self[compareIndex] != data[needleIndex] { |
| matched = false |
| break |
| } |
| needleIndex = data.index(before: needleIndex) |
| compareIndex = index(before: compareIndex) |
| } |
| if matched { |
| return compareIndex..<haystackIndex |
| } |
| haystackIndex = index(before: haystackIndex) |
| } |
| return nil |
| } |
| } |
| |
| extension DataProtocol where Self : ContiguousBytes { |
| public func copyBytes<DestinationType, R: RangeExpression>(to ptr: UnsafeMutableBufferPointer<DestinationType>, from range: R) where R.Bound == Index { |
| precondition(ptr.baseAddress != nil) |
| |
| let concreteRange = range.relative(to: self) |
| withUnsafeBytes { fullBuffer in |
| let adv = distance(from: startIndex, to: concreteRange.lowerBound) |
| let delta = distance(from: concreteRange.lowerBound, to: concreteRange.upperBound) |
| memcpy(ptr.baseAddress!, fullBuffer.baseAddress!.advanced(by: adv), delta) |
| } |
| } |
| } |
| |
| //===--- MutableDataProtocol Extensions -----------------------------------===// |
| |
| extension MutableDataProtocol { |
| public mutating func resetBytes<R: RangeExpression>(in range: R) where R.Bound == Index { |
| let r = range.relative(to: self) |
| let count = distance(from: r.lowerBound, to: r.upperBound) |
| replaceSubrange(r, with: repeatElement(UInt8(0), count: count)) |
| } |
| } |
| |
| //===--- DataProtocol Conditional Conformances ----------------------------===// |
| |
| extension Slice : DataProtocol where Base : DataProtocol { |
| public typealias Regions = [Base.Regions.Element.SubSequence] |
| |
| public var regions: [Base.Regions.Element.SubSequence] { |
| let sliceLowerBound = startIndex |
| let sliceUpperBound = endIndex |
| var regionUpperBound = base.startIndex |
| |
| return base.regions.compactMap { (region) -> Base.Regions.Element.SubSequence? in |
| let regionLowerBound = regionUpperBound |
| regionUpperBound = base.index(regionUpperBound, offsetBy: region.count) |
| |
| /* |
| [------ Region ------] |
| [--- Slice ---] => |
| |
| OR |
| |
| [------ Region ------] |
| <= [--- Slice ---] |
| */ |
| if sliceLowerBound >= regionLowerBound && sliceUpperBound <= regionUpperBound { |
| let regionRelativeSliceLowerBound = region.index(region.startIndex, offsetBy: base.distance(from: regionLowerBound, to: sliceLowerBound)) |
| let regionRelativeSliceUpperBound = region.index(region.startIndex, offsetBy: base.distance(from: regionLowerBound, to: sliceUpperBound)) |
| return region[regionRelativeSliceLowerBound..<regionRelativeSliceUpperBound] |
| } |
| |
| /* |
| [--- Region ---] => |
| [------ Slice ------] |
| |
| OR |
| |
| <= [--- Region ---] |
| [------ Slice ------] |
| */ |
| if regionLowerBound >= sliceLowerBound && regionUpperBound <= sliceUpperBound { |
| return region[region.startIndex..<region.endIndex] |
| } |
| |
| /* |
| [------ Region ------] |
| [------ Slice ------] |
| */ |
| if sliceLowerBound >= regionLowerBound && sliceLowerBound <= regionUpperBound { |
| let regionRelativeSliceLowerBound = region.index(region.startIndex, offsetBy: base.distance(from: regionLowerBound, to: sliceLowerBound)) |
| return region[regionRelativeSliceLowerBound..<region.endIndex] |
| } |
| |
| /* |
| [------ Region ------] |
| [------ Slice ------] |
| */ |
| if regionLowerBound >= sliceLowerBound && regionLowerBound <= sliceUpperBound { |
| let regionRelativeSliceUpperBound = region.index(region.startIndex, offsetBy: base.distance(from: regionLowerBound, to: sliceUpperBound)) |
| return region[region.startIndex..<regionRelativeSliceUpperBound] |
| } |
| |
| /* |
| [--- Region ---] |
| [--- Slice ---] |
| |
| OR |
| |
| [--- Region ---] |
| [--- Slice ---] |
| */ |
| return nil |
| } |
| } |
| } |