Skip to content

Commit 69255f0

Browse files
authored
Merge pull request #3831 from kballard/data_iterator
Implement a custom Data.Iterator
2 parents b6955ec + 69c3d71 commit 69255f0

File tree

5 files changed

+103
-1
lines changed

5 files changed

+103
-1
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ set(SWIFT_BENCH_MODULES
3737
single-source/CaptureProp
3838
single-source/Chars
3939
single-source/ClassArrayGetter
40+
single-source/Data
4041
single-source/DeadArray
4142
single-source/DictionaryBridge
4243
single-source/DictionaryLiteral

benchmark/single-source/Data.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- Data.swift -------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import TestsUtils
14+
import Foundation
15+
16+
@inline(never)
17+
func generateData() -> Data {
18+
var data = Data(count: 16 * 1024)
19+
data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) -> () in
20+
for i in 0..<data.count {
21+
ptr[i] = UInt8(i % 23)
22+
}
23+
}
24+
return data
25+
}
26+
27+
@inline(never)
28+
public func run_IterateData(_ N: Int) {
29+
let data = generateData()
30+
31+
for _ in 0...10*N {
32+
_ = data.reduce(0, +)
33+
}
34+
}

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import Calculator
3838
import CaptureProp
3939
import Chars
4040
import ClassArrayGetter
41+
import Data
4142
import DeadArray
4243
import DictTest
4344
import DictTest2
@@ -141,6 +142,7 @@ precommitTests = [
141142
"HashTest": run_HashTest,
142143
"Histogram": run_Histogram,
143144
"Integrate": run_Integrate,
145+
"IterateData": run_IterateData,
144146
"Join": run_Join,
145147
"LinkedList": run_LinkedList,
146148
"MapReduce": run_MapReduce,

stdlib/public/SDK/Foundation/Data.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,40 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
647647
///
648648
/// The iterator will increment byte-by-byte.
649649
public func makeIterator() -> Data.Iterator {
650-
return IndexingIterator(_elements: self)
650+
return Iterator(_data: self)
651+
}
652+
653+
public struct Iterator : IteratorProtocol {
654+
private let _data: Data
655+
private var _buffer: (
656+
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
657+
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
658+
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
659+
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
660+
private var _idx: Data.Index
661+
private let _endIdx: Data.Index
662+
663+
private init(_data: Data) {
664+
self._data = _data
665+
_buffer = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
666+
_idx = 0
667+
_endIdx = _data.endIndex
668+
}
669+
670+
public mutating func next() -> UInt8? {
671+
guard _idx < _endIdx else { return nil }
672+
defer { _idx += 1 }
673+
let bufferSize = sizeofValue(_buffer)
674+
return withUnsafeMutablePointer(to: &_buffer) { ptr_ in
675+
let ptr = UnsafeMutableRawPointer(ptr_).assumingMemoryBound(to: UInt8.self)
676+
let bufferIdx = _idx % bufferSize
677+
if bufferIdx == 0 {
678+
// populate the buffer
679+
_data.copyBytes(to: ptr, from: _idx..<(_endIdx - _idx > bufferSize ? _idx + bufferSize : _endIdx))
680+
}
681+
return ptr[bufferIdx]
682+
}
683+
}
651684
}
652685

653686
// MARK: -

validation-test/stdlib/Data.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
// REQUIRES: objc_interop
4+
5+
import StdlibUnittest
6+
import StdlibCollectionUnittest
7+
import Foundation
8+
9+
var DataTestSuite = TestSuite("Data")
10+
DataTestSuite.test("Data.Iterator semantics") {
11+
// Empty data
12+
checkSequence([], Data())
13+
14+
// Small data
15+
checkSequence([1,2,4,8,16], Data(bytes: [1,2,4,8,16]))
16+
17+
// Boundary conditions
18+
checkSequence([5], Data(bytes: [5]))
19+
checkSequence(1...31, Data(bytes: Array(1...31)))
20+
checkSequence(1...32, Data(bytes: Array(1...32)))
21+
checkSequence(1...33, Data(bytes: Array(1...33)))
22+
23+
// Large data
24+
var data = Data(count: 65535)
25+
data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) -> () in
26+
for i in 0..<data.count {
27+
ptr[i] = UInt8(i % 23)
28+
}
29+
}
30+
checkSequence((0..<65535).lazy.map({ UInt8($0 % 23) }), data)
31+
}
32+
runAllTests()

0 commit comments

Comments
 (0)