@@ -44,7 +44,7 @@ public final class TextAttachmentManager {
4444 /// Finds attachments starting in the given line range, and returns them as an array.
4545 /// Returned attachment's ranges will be relative to the _document_, not the line.
4646 /// - Complexity: `O(n log(n))`, ideally `O(log(n))`
47- public func attachments ( startingIn range: NSRange ) -> [ TextAttachmentBox ] {
47+ public func get ( startingIn range: NSRange ) -> [ TextAttachmentBox ] {
4848 var results : [ TextAttachmentBox ] = [ ]
4949 var idx = findInsertionIndex ( for: range. location)
5050 while idx < orderedAttachments. count {
@@ -69,7 +69,7 @@ public final class TextAttachmentManager {
6969 ///
7070 /// - Parameter query: The `NSRange` to test for overlap.
7171 /// - Returns: An array of `TextAttachmentBox` instances whose ranges intersect `query`.
72- func attachments ( overlapping query: NSRange ) -> [ TextAttachmentBox ] {
72+ public func get ( overlapping query: NSRange ) -> [ TextAttachmentBox ] {
7373 // Find the first attachment whose end is beyond the start of the query.
7474 guard let startIdx = firstIndex ( where: { $0. range. upperBound > query. location } ) else {
7575 return [ ]
@@ -96,37 +96,44 @@ public final class TextAttachmentManager {
9696}
9797
9898private extension TextAttachmentManager {
99- /// Returns the index in `orderedAttachments` at which an attachment with
100- /// `range.location == location` should be inserted to keep the array sorted.
101- /// (Lower‐bound search.)
102- func findInsertionIndex( for location: Int ) -> Int {
99+ /// Binary-searches `orderedAttachments` and returns the smallest index
100+ /// at which `predicate(attachment)` is true (i.e. the lower-bound index).
101+ ///
102+ /// - Note: always returns a value in `0...orderedAttachments.count`.
103+ /// If it returns `orderedAttachments.count`, no element satisfied
104+ /// the predicate, but that’s still a valid insertion point.
105+ func lowerBoundIndex(
106+ where predicate: ( TextAttachmentBox ) -> Bool
107+ ) -> Int {
103108 var low = 0
104109 var high = orderedAttachments. count
105110 while low < high {
106111 let mid = ( low + high) / 2
107- if orderedAttachments [ mid] . range. location < location {
108- low = mid + 1
109- } else {
112+ if predicate ( orderedAttachments [ mid] ) {
110113 high = mid
114+ } else {
115+ low = mid + 1
111116 }
112117 }
113118 return low
114119 }
115120
116- /// Finds the first index that matches a callback.
117- /// - Parameter predicate: The query predicate.
118- /// - Returns: The first index that matches the given predicate.
121+ /// Returns the index in `orderedAttachments` at which an attachment whose
122+ /// `range.location == location` *could* be inserted, keeping the array sorted.
123+ ///
124+ /// - Parameter location: the attachment’s `range.location`
125+ /// - Returns: a valid insertion index in `0...orderedAttachments.count`
126+ func findInsertionIndex( for location: Int ) -> Int {
127+ lowerBoundIndex { $0. range. location >= location }
128+ }
129+
130+ /// Finds the first index whose attachment satisfies `predicate`.
131+ ///
132+ /// - Parameter predicate: the query predicate.
133+ /// - Returns: the first matching index, or `nil` if none of the
134+ /// attachments satisfy the predicate.
119135 func firstIndex( where predicate: ( TextAttachmentBox ) -> Bool ) -> Int ? {
120- var low = 0
121- var high = orderedAttachments. count
122- while low < high {
123- let mid = ( low + high) / 2
124- if predicate ( orderedAttachments [ mid] ) {
125- high = mid
126- } else {
127- low = mid + 1
128- }
129- }
130- return low < orderedAttachments. count ? low : nil
136+ let idx = lowerBoundIndex { predicate ( $0) }
137+ return idx < orderedAttachments. count ? idx : nil
131138 }
132139}
0 commit comments