Skip to content

Commit 93de69a

Browse files
Merge branch 'main' into itembox
2 parents afc302e + b0688fa commit 93de69a

File tree

3 files changed

+104
-41
lines changed

3 files changed

+104
-41
lines changed

Sources/CodeEditSourceEditor/Enums/CaptureModifier.swift

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -90,44 +90,3 @@ public enum CaptureModifier: Int8, CaseIterable, Sendable {
9090
extension CaptureModifier: CustomDebugStringConvertible {
9191
public var debugDescription: String { stringValue }
9292
}
93-
94-
/// A set of capture modifiers, efficiently represented by a single integer.
95-
public struct CaptureModifierSet: OptionSet, Equatable, Hashable, Sendable {
96-
public var rawValue: UInt
97-
98-
public init(rawValue: UInt) {
99-
self.rawValue = rawValue
100-
}
101-
102-
public static let declaration = CaptureModifierSet(rawValue: 1 << CaptureModifier.declaration.rawValue)
103-
public static let definition = CaptureModifierSet(rawValue: 1 << CaptureModifier.definition.rawValue)
104-
public static let readonly = CaptureModifierSet(rawValue: 1 << CaptureModifier.readonly.rawValue)
105-
public static let `static` = CaptureModifierSet(rawValue: 1 << CaptureModifier.static.rawValue)
106-
public static let deprecated = CaptureModifierSet(rawValue: 1 << CaptureModifier.deprecated.rawValue)
107-
public static let abstract = CaptureModifierSet(rawValue: 1 << CaptureModifier.abstract.rawValue)
108-
public static let async = CaptureModifierSet(rawValue: 1 << CaptureModifier.async.rawValue)
109-
public static let modification = CaptureModifierSet(rawValue: 1 << CaptureModifier.modification.rawValue)
110-
public static let documentation = CaptureModifierSet(rawValue: 1 << CaptureModifier.documentation.rawValue)
111-
public static let defaultLibrary = CaptureModifierSet(rawValue: 1 << CaptureModifier.defaultLibrary.rawValue)
112-
113-
/// All values in the set.
114-
public var values: [CaptureModifier] {
115-
var rawValue = self.rawValue
116-
117-
// This set is represented by an integer, where each `1` in the binary number represents a value.
118-
// We can interpret the index of the `1` as the raw value of a ``CaptureModifier`` (the index in 0b0100 would
119-
// be 2). This loops through each `1` in the `rawValue`, finds the represented modifier, and 0's out the `1` so
120-
// we can get the next one using the binary & operator (0b0110 -> 0b0100 -> 0b0000 -> finish).
121-
var values: [Int8] = []
122-
while rawValue > 0 {
123-
values.append(Int8(rawValue.trailingZeroBitCount))
124-
// Clears the bit at the desired index (eg: 0b110 if clearing index 0)
125-
rawValue &= ~UInt(1 << rawValue.trailingZeroBitCount)
126-
}
127-
return values.compactMap({ CaptureModifier(rawValue: $0) })
128-
}
129-
130-
public mutating func insert(_ value: CaptureModifier) {
131-
rawValue &= 1 << value.rawValue
132-
}
133-
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//
2+
// CaptureModifierSet.swift
3+
// CodeEditSourceEditor
4+
//
5+
// Created by Khan Winter on 12/16/24.
6+
//
7+
8+
/// A set of capture modifiers, efficiently represented by a single integer.
9+
public struct CaptureModifierSet: OptionSet, Equatable, Hashable, Sendable {
10+
public var rawValue: UInt
11+
12+
public init(rawValue: UInt) {
13+
self.rawValue = rawValue
14+
}
15+
16+
public static let declaration = CaptureModifierSet(rawValue: 1 << CaptureModifier.declaration.rawValue)
17+
public static let definition = CaptureModifierSet(rawValue: 1 << CaptureModifier.definition.rawValue)
18+
public static let readonly = CaptureModifierSet(rawValue: 1 << CaptureModifier.readonly.rawValue)
19+
public static let `static` = CaptureModifierSet(rawValue: 1 << CaptureModifier.static.rawValue)
20+
public static let deprecated = CaptureModifierSet(rawValue: 1 << CaptureModifier.deprecated.rawValue)
21+
public static let abstract = CaptureModifierSet(rawValue: 1 << CaptureModifier.abstract.rawValue)
22+
public static let async = CaptureModifierSet(rawValue: 1 << CaptureModifier.async.rawValue)
23+
public static let modification = CaptureModifierSet(rawValue: 1 << CaptureModifier.modification.rawValue)
24+
public static let documentation = CaptureModifierSet(rawValue: 1 << CaptureModifier.documentation.rawValue)
25+
public static let defaultLibrary = CaptureModifierSet(rawValue: 1 << CaptureModifier.defaultLibrary.rawValue)
26+
27+
/// All values in the set.
28+
///
29+
/// Results will be returned in order of ``CaptureModifier``'s raw value.
30+
/// This variable ignores garbage values in the ``rawValue`` property.
31+
public var values: [CaptureModifier] {
32+
var rawValue = self.rawValue
33+
34+
// This set is represented by an integer, where each `1` in the binary number represents a value.
35+
// We can interpret the index of the `1` as the raw value of a ``CaptureModifier`` (the index in 0b0100 would
36+
// be 2). This loops through each `1` in the `rawValue`, finds the represented modifier, and 0's out the `1` so
37+
// we can get the next one using the binary & operator (0b0110 -> 0b0100 -> 0b0000 -> finish).
38+
var values: [Int8] = []
39+
while rawValue > 0 {
40+
values.append(Int8(rawValue.trailingZeroBitCount))
41+
// Clears the bit at the desired index (eg: 0b110 if clearing index 0)
42+
rawValue &= ~UInt(1 << rawValue.trailingZeroBitCount)
43+
}
44+
return values.compactMap({ CaptureModifier(rawValue: $0) })
45+
}
46+
47+
/// Inserts the modifier into the set.
48+
public mutating func insert(_ value: CaptureModifier) {
49+
rawValue |= 1 << value.rawValue
50+
}
51+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import XCTest
2+
@testable import CodeEditSourceEditor
3+
4+
final class CaptureModifierSetTests: XCTestCase {
5+
func test_init() {
6+
// Init empty
7+
let set1 = CaptureModifierSet(rawValue: 0)
8+
XCTAssertEqual(set1, [])
9+
XCTAssertEqual(set1.values, [])
10+
11+
// Init with multiple values
12+
let set2 = CaptureModifierSet(rawValue: 0b1101)
13+
XCTAssertEqual(set2, [.declaration, .readonly, .static])
14+
XCTAssertEqual(set2.values, [.declaration, .readonly, .static])
15+
}
16+
17+
func test_insert() {
18+
var set = CaptureModifierSet(rawValue: 0)
19+
XCTAssertEqual(set, [])
20+
21+
// Insert one item
22+
set.insert(.declaration)
23+
XCTAssertEqual(set, [.declaration])
24+
25+
// Inserting again does nothing
26+
set.insert(.declaration)
27+
XCTAssertEqual(set, [.declaration])
28+
29+
// Insert more items
30+
set.insert(.declaration)
31+
set.insert(.async)
32+
set.insert(.documentation)
33+
XCTAssertEqual(set, [.declaration, .async, .documentation])
34+
35+
// Order doesn't matter
36+
XCTAssertEqual(set, [.async, .declaration, .documentation])
37+
}
38+
39+
func test_values() {
40+
// Invalid rawValue returns non-garbage results
41+
var set = CaptureModifierSet([.declaration, .readonly, .static])
42+
set.rawValue |= 1 << 48 // No real modifier with raw value 48, but we still have all the other values
43+
44+
XCTAssertEqual(set.values, [.declaration, .readonly, .static])
45+
46+
set = CaptureModifierSet()
47+
set.insert(.declaration)
48+
set.insert(.async)
49+
set.insert(.documentation)
50+
XCTAssertEqual(set.values, [.declaration, .async, .documentation])
51+
XCTAssertNotEqual(set.values, [.declaration, .documentation, .async]) // Order matters
52+
}
53+
}

0 commit comments

Comments
 (0)