Skip to content

Commit a8e720e

Browse files
committed
.keepAll buffering strategy added
1 parent a9b7a3d commit a8e720e

File tree

15 files changed

+262
-152
lines changed

15 files changed

+262
-152
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Foundation
22

33
/// Buffer used to stored previously read unicode scalars.
4-
internal final class Buffer: IteratorProtocol {
4+
internal final class ScalarBuffer: IteratorProtocol {
55
/// Unicode scalars read inferring configuration variables that were unknown.
66
///
77
/// This buffer is reversed to make it efficient to remove elements.

Sources/Active/Reader/Reader.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public final class CSVReader: IteratorProtocol, Sequence {
1313
/// The unicode scalar iterator providing all inputs.
1414
private let iterator: AnyIterator<Unicode.Scalar>
1515
/// Unicode scalar buffer to keep scalars that hasn't yet been analysed.
16-
private let buffer: Buffer
16+
private let buffer: ScalarBuffer
1717
/// Check whether the given unicode scalar is part of the field delimiter sequence.
1818
private let isFieldDelimiter: DelimiterChecker
1919
/// Check whether the given unicode scalar is par of the row delimiter sequence.
@@ -28,7 +28,7 @@ public final class CSVReader: IteratorProtocol, Sequence {
2828
self.headers = nil
2929
self.status = .reading
3030
self.iterator = AnyIterator(iterator)
31-
self.buffer = Buffer()
31+
self.buffer = ScalarBuffer()
3232
self.settings = try Settings(configuration: configuration, iterator: self.iterator, buffer: self.buffer)
3333

3434
self.isFieldDelimiter = CSVReader.makeMatcher(delimiter: self.settings.delimiters.field, buffer: self.buffer, iterator: self.iterator)
@@ -244,7 +244,7 @@ extension CSVReader {
244244
/// - parameter buffer: A unicode character buffer containing further characters to parse.
245245
/// - parameter iterator: A unicode character buffer containing further characters to parse.
246246
/// - returns: A closure which given the targeted unicode character and the buffer and iterrator, returns a Boolean indicating whether there is a delimiter.
247-
private static func makeMatcher(delimiter view: String.UnicodeScalarView, buffer: Buffer, iterator: AnyIterator<Unicode.Scalar>) -> DelimiterChecker {
247+
private static func makeMatcher(delimiter view: String.UnicodeScalarView, buffer: ScalarBuffer, iterator: AnyIterator<Unicode.Scalar>) -> DelimiterChecker {
248248
// This should never be triggered.
249249
precondition(!view.isEmpty, "Delimiters must include at least one unicode scalar.")
250250

Sources/Active/Reader/ReaderConfiguration.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ extension CSVReader {
4848
/// - parameter iterator: Source of the unicode scalar data. Note, that you can only iterate once through it.
4949
/// - parameter buffer: Buffer containing all read scalars used to infer not specified information.
5050
/// - throws: `CSVReader.Error` exclusively.
51-
init(configuration: Configuration, iterator: AnyIterator<Unicode.Scalar>, buffer: Buffer) throws {
51+
init(configuration: Configuration, iterator: AnyIterator<Unicode.Scalar>, buffer: ScalarBuffer) throws {
5252
switch configuration.trimStrategry {
5353
case .none: self.trimCharacters = nil
5454
case .whitespaces: self.trimCharacters = CharacterSet.whitespaces
@@ -95,21 +95,21 @@ extension CSVReader {
9595
extension CSVReader {
9696
/// Tries to infer the field delimiter given the row delimiter.
9797
/// - throws: `CSVReader.Error` exclusively.
98-
fileprivate static func inferFieldDelimiter(iterator: AnyIterator<Unicode.Scalar>, rowDelimiter: String.UnicodeScalarView, buffer: Buffer) throws -> Delimiter.RawPair {
98+
fileprivate static func inferFieldDelimiter(iterator: AnyIterator<Unicode.Scalar>, rowDelimiter: String.UnicodeScalarView, buffer: ScalarBuffer) throws -> Delimiter.RawPair {
9999
//#warning("TODO:")
100100
fatalError()
101101
}
102102

103103
/// Tries to infer the row delimiter given the field delimiter.
104104
/// - throws: `CSVReader.Error` exclusively.
105-
fileprivate static func inferRowDelimiter(iterator: AnyIterator<Unicode.Scalar>, fieldDelimiter: String.UnicodeScalarView, buffer: Buffer) throws -> Delimiter.RawPair {
105+
fileprivate static func inferRowDelimiter(iterator: AnyIterator<Unicode.Scalar>, fieldDelimiter: String.UnicodeScalarView, buffer: ScalarBuffer) throws -> Delimiter.RawPair {
106106
//#warning("TODO:")
107107
fatalError()
108108
}
109109

110110
/// Tries to infer both the field and row delimiter from the raw data.
111111
/// - throws: `CSVReader.Error` exclusively.
112-
fileprivate static func inferDelimiters(iterator: AnyIterator<Unicode.Scalar>, buffer: Buffer) throws -> Delimiter.RawPair {
112+
fileprivate static func inferDelimiters(iterator: AnyIterator<Unicode.Scalar>, buffer: ScalarBuffer) throws -> Delimiter.RawPair {
113113
//#warning("TODO:")
114114
fatalError()
115115
}
@@ -118,7 +118,7 @@ extension CSVReader {
118118
extension CSVReader {
119119
/// Tries to infer whether the CSV data has a header row or not.
120120
/// - throws: `CSVReader.Error` exclusively.
121-
fileprivate static func inferHeaderStatus(iterator: AnyIterator<Unicode.Scalar>, buffer: Buffer) throws -> Bool {
121+
fileprivate static func inferHeaderStatus(iterator: AnyIterator<Unicode.Scalar>, buffer: ScalarBuffer) throws -> Bool {
122122
//#warning("TODO:")
123123
fatalError()
124124
}

Sources/Active/Writer/Writer.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public final class CSVWriter {
77
/// Encoder used to transform unicode scalars into a bunch of bytes.
88
private let encoder: Unicode.Scalar.Encoder
99
/// Unicode scalar buffer to keep scalars that hasn't yet been analysed.
10-
private let buffer: Buffer
10+
private let buffer: ScalarBuffer
1111
/// Check whether the given unicode scalar is part of the field delimiter sequence.
1212
private let isFieldDelimiter: DelimiterChecker
1313
/// Check whether the given unicode scalar is par of the row delimiter sequence.
@@ -40,7 +40,7 @@ public final class CSVWriter {
4040
internal init(output: (stream: OutputStream, closeAtEnd: Bool), configuration: Configuration, encoder: @escaping Unicode.Scalar.Encoder) throws {
4141
self.settings = try Settings(configuration: configuration)
4242

43-
self.buffer = Buffer(reservingCapacity: max(self.settings.delimiters.field.count, self.settings.delimiters.row.count) + 1)
43+
self.buffer = ScalarBuffer(reservingCapacity: max(self.settings.delimiters.field.count, self.settings.delimiters.row.count) + 1)
4444
self.encoder = encoder
4545
self.isFieldDelimiter = CSVWriter.matchCreator(delimiter: self.settings.delimiters.field, buffer: self.buffer)
4646
self.isRowDelimiter = CSVWriter.matchCreator(delimiter: self.settings.delimiters.row, buffer: self.buffer)
@@ -362,7 +362,7 @@ extension CSVWriter {
362362
private typealias DelimiterChecker = (_ scalar: Unicode.Scalar, _ iterator: inout String.UnicodeScalarView.Iterator) -> Bool
363363

364364
/// Creates a delimiter identifier closure.
365-
private static func matchCreator(delimiter view: String.UnicodeScalarView, buffer: Buffer) -> DelimiterChecker {
365+
private static func matchCreator(delimiter view: String.UnicodeScalarView, buffer: ScalarBuffer) -> DelimiterChecker {
366366
// This should never be triggered.
367367
precondition(!view.isEmpty, "Delimiters must include at least one unicode scalar.")
368368

Sources/Codable/Decodable/DecoderConfiguration.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ extension CSVDecoder {
1717
public var dateStrategy: Strategy.DateDecoding = .deferredToDate
1818
/// The strategy to use when decoding binary data.
1919
public var dataStrategy: Strategy.DataDecoding = .base64
20+
/// The amount of CSV rows kept in memory after decoding to allow the random-order jumping exposed by keyed containers.
21+
public var bufferingStrategy: Strategy.Buffering = .keepAll
2022

2123
/// General configuration for CSV codecs and parsers.
2224
/// - parameter fieldDelimiter: The delimiter between CSV fields.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Foundation
2+
3+
extension ShadowDecoder.Source {
4+
/// The decoder buffer caching the decoded CSV rows.
5+
internal final class Buffer {
6+
/// The buffering strategy.
7+
let strategy: Strategy.Buffering
8+
/// The underlying storage.
9+
private var storage: [Int:[String]]
10+
/// The first index being stored.
11+
private var firstIndex: Int
12+
/// The last index being stored.
13+
private var lastIndex: Int
14+
15+
/// Designated initializer.
16+
init(strategy: Strategy.Buffering) {
17+
self.strategy = strategy
18+
self.storage = .init(minimumCapacity: 8)
19+
self.firstIndex = -1
20+
self.lastIndex = -1
21+
#warning("TODO: Buffering strategy")
22+
}
23+
24+
/// Stores the given row at the given position.
25+
func store(_ row: [String], at index: Int) {
26+
precondition(index >= 0)
27+
self.storage[index] = row
28+
}
29+
30+
/// Retrieves the row at the given position.
31+
func retrieve(at index: Int) -> [String]? {
32+
precondition(index >= 0)
33+
return self.storage[index]
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)