From da4c98f3d0f0b01be380439a15e6b841b38de116 Mon Sep 17 00:00:00 2001 From: Kenta Kubo <601636+kkebo@users.noreply.github.com> Date: Tue, 13 Aug 2024 05:12:15 +0900 Subject: [PATCH] feat!: define `Str` as a wrapper type --- Sources/Str/Str.swift | 97 ++++++++++++++++++++++++++++--- Sources/Tokenizer/Tokenizer.swift | 8 +-- 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/Sources/Str/Str.swift b/Sources/Str/Str.swift index b7b87a0..6c4453b 100644 --- a/Sources/Str/Str.swift +++ b/Sources/Str/Str.swift @@ -1,30 +1,113 @@ -public typealias Str = [Char] public typealias StrSlice = ArraySlice public typealias Char = Unicode.Scalar -extension Str: @retroactive ExpressibleByStringLiteral { +public struct Str: Hashable, Sendable { + @usableFromInline + var storage: ContiguousArray + + @inlinable + public init() { + self.storage = [] + } + + @inlinable + public init(_ char: Char) { + self.storage = [char] + } + + @inlinable + public init(_ chars: ContiguousArray) { + self.storage = chars + } + + @inlinable + public init(_ sequence: some Sequence) { + self.storage = .init(sequence) + } + + @inlinable + public mutating func removeAll(keepingCapacity keepCapacity: Bool = false) { + self.storage.removeAll(keepingCapacity: keepCapacity) + } + + @inlinable + public mutating func append(_ newElement: Self.Element) { + self.storage.append(newElement) + } + + @inlinable + public static func += (lhs: inout Self, rhs: Self) { + lhs.storage += rhs.storage + } + + @inlinable + public static func += (lhs: inout Self, rhs: some Sequence) { + lhs.storage += rhs + } +} + +extension Str: Sequence { + public typealias Iterator = ContiguousArray.Iterator + public typealias Element = Char + + @inlinable + public func makeIterator() -> Self.Iterator { self.storage.makeIterator() } +} + +extension Str: BidirectionalCollection { + public typealias Index = ContiguousArray.Index + public typealias Indices = ContiguousArray.Indices + public typealias SubSequence = ContiguousArray.SubSequence + + @inlinable + public var startIndex: Self.Index { self.storage.startIndex } + @inlinable + public var endIndex: Self.Index { self.storage.endIndex } + @inlinable + public var indices: Self.Indices { self.storage.indices } + @inlinable + public func index(before i: Self.Index) -> Self.Index { self.storage.index(before: i) } + @inlinable + public func index(after i: Self.Index) -> Self.Index { self.storage.index(after: i) } + + @inlinable + public var count: Int { self.storage.count } + @inlinable + public var isEmpty: Bool { self.storage.isEmpty } + + @inlinable + public subscript(position: Self.Index) -> Self.Element { + self.storage[position] + } + @inlinable + public subscript(bounds: Range) -> Self.SubSequence { + self.storage[bounds] + } +} + +extension Str: ExpressibleByStringLiteral { @inlinable public init(stringLiteral value: consuming String) { guard !value.isEmpty else { - self = [] + self.init() return } self.init(value.unicodeScalars) } } -extension Str: @retroactive ExpressibleByUnicodeScalarLiteral { +extension Str: ExpressibleByUnicodeScalarLiteral { @inlinable public init(unicodeScalarLiteral value: consuming Unicode.Scalar) { - self = [value] + self.storage = [value] } } -extension Str: @retroactive ExpressibleByExtendedGraphemeClusterLiteral { +extension Str: ExpressibleByExtendedGraphemeClusterLiteral { @inlinable public init(extendedGraphemeClusterLiteral value: consuming Character) { self.init(value.unicodeScalars) } } -extension Str: @retroactive ExpressibleByStringInterpolation {} +extension Str: ExpressibleByStringInterpolation {} extension StrSlice: @retroactive ExpressibleByStringLiteral { @inlinable public init(stringLiteral value: consuming String) { diff --git a/Sources/Tokenizer/Tokenizer.swift b/Sources/Tokenizer/Tokenizer.swift index ea7a817..22235da 100644 --- a/Sources/Tokenizer/Tokenizer.swift +++ b/Sources/Tokenizer/Tokenizer.swift @@ -1486,14 +1486,14 @@ public struct Tokenizer: ~Copyable { @inline(__always) private mutating func createDOCTYPE(with c: consuming Char) { - self.currentDOCTYPE = .init(name: [c]) + self.currentDOCTYPE = .init(name: .init(c)) } @inline(__always) private mutating func appendDOCTYPEName(_ c: consuming Char) { switch self.currentDOCTYPE.name { case .some: self.currentDOCTYPE.name?.append(c) - case .none: self.currentDOCTYPE.name = [c] + case .none: self.currentDOCTYPE.name = .init(c) } } @@ -1501,7 +1501,7 @@ public struct Tokenizer: ~Copyable { private mutating func appendPublicID(_ c: consuming Char) { switch self.currentDOCTYPE.publicID { case .some: self.currentDOCTYPE.publicID?.append(c) - case .none: self.currentDOCTYPE.publicID = [c] + case .none: self.currentDOCTYPE.publicID = .init(c) } } @@ -1517,7 +1517,7 @@ public struct Tokenizer: ~Copyable { private mutating func appendSystemID(_ c: consuming Char) { switch self.currentDOCTYPE.systemID { case .some: self.currentDOCTYPE.systemID?.append(c) - case .none: self.currentDOCTYPE.systemID = [c] + case .none: self.currentDOCTYPE.systemID = .init(c) } }