mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Another feed experiment
This commit is contained in:
181
submodules/Utils/RangeSet/Sources/RangeSetStorage.swift
Normal file
181
submodules/Utils/RangeSet/Sources/RangeSetStorage.swift
Normal file
@@ -0,0 +1,181 @@
|
||||
//===----------------------------------------------------------*- swift -*-===//
|
||||
//
|
||||
// This source file is part of the Swift open source project
|
||||
//
|
||||
// Copyright (c) 2020 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct _RangeSetStorage<T: Comparable> {
|
||||
fileprivate enum _Storage {
|
||||
case empty
|
||||
case singleRange(high: Int, low: Int32)
|
||||
case variadic([Range<T>])
|
||||
}
|
||||
|
||||
fileprivate var _storage: _Storage
|
||||
|
||||
init() {
|
||||
_storage = .empty
|
||||
}
|
||||
|
||||
init(_ range: Range<T>) {
|
||||
if let intRange = range as? Range<Int>,
|
||||
let lowerBound = Int32(exactly: intRange.lowerBound)
|
||||
{
|
||||
_storage = .singleRange(high: intRange.upperBound, low: lowerBound)
|
||||
} else {
|
||||
_storage = .variadic([range])
|
||||
}
|
||||
}
|
||||
|
||||
init(_ ranges: [Range<T>]) {
|
||||
_storage = .variadic(ranges)
|
||||
}
|
||||
|
||||
func unsafeRange(low: Int32, high: Int) -> Range<T> {
|
||||
unsafeBitCast(Int(low)..<high, to: Range<T>.self)
|
||||
}
|
||||
}
|
||||
|
||||
// _RangeSetStorage has custom Equatable (and therefore Hashable)
|
||||
// conformance, since the same "value" can be represented by different
|
||||
// storage structures. For example, `.empty` and `.variadic([])` are
|
||||
// equivalent, but the synthesized conformance treats them as distinct.
|
||||
// The same holds with the `singleRange` representation and `variadic`
|
||||
// with a single-element array.
|
||||
|
||||
extension _RangeSetStorage: Equatable {
|
||||
static func == (lhs: _RangeSetStorage, rhs: _RangeSetStorage) -> Bool {
|
||||
switch (lhs._storage, rhs._storage) {
|
||||
case (.empty, .empty):
|
||||
return true
|
||||
case (.empty, .singleRange), (.singleRange, .empty):
|
||||
return false
|
||||
case let (.empty, .variadic(ranges)),
|
||||
let (.variadic(ranges), .empty):
|
||||
return ranges.isEmpty
|
||||
|
||||
case let (.singleRange(lhsHigh, lhsLow), .singleRange(rhsHigh, rhsLow)):
|
||||
return (lhsLow, lhsHigh) == (rhsLow, rhsHigh)
|
||||
|
||||
case let (.singleRange(high, low), .variadic(ranges)),
|
||||
let (.variadic(ranges), .singleRange(high, low)):
|
||||
return ranges.count == 1 &&
|
||||
(ranges[0] as! Range<Int>) == Int(low)..<high
|
||||
|
||||
case let (.variadic(lhsRanges), .variadic(rhsRanges)):
|
||||
return lhsRanges == rhsRanges
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _RangeSetStorage: Hashable where T: Hashable {
|
||||
func hash(into hasher: inout Hasher) {
|
||||
for range in self {
|
||||
hasher.combine(range)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _RangeSetStorage: RandomAccessCollection, MutableCollection {
|
||||
var startIndex: Int { 0 }
|
||||
|
||||
var endIndex: Int {
|
||||
switch _storage {
|
||||
case .empty: return 0
|
||||
case .singleRange: return 1
|
||||
case let .variadic(ranges): return ranges.count
|
||||
}
|
||||
}
|
||||
|
||||
subscript(i: Int) -> Range<T> {
|
||||
get {
|
||||
switch _storage {
|
||||
case .empty: fatalError("Can't access elements of empty storage")
|
||||
case let .singleRange(high, low):
|
||||
assert(T.self == Int.self)
|
||||
return unsafeRange(low: low, high: high)
|
||||
case let .variadic(ranges):
|
||||
return ranges[i]
|
||||
}
|
||||
}
|
||||
set {
|
||||
switch _storage {
|
||||
case .empty: fatalError("Can't access elements of empty storage")
|
||||
case .singleRange:
|
||||
assert(T.self == Int.self)
|
||||
let intRange = newValue as! Range<Int>
|
||||
if let lowerBound = Int32(exactly: intRange.lowerBound) {
|
||||
_storage = .singleRange(high: intRange.upperBound, low: lowerBound)
|
||||
} else {
|
||||
_storage = .variadic([newValue])
|
||||
}
|
||||
case .variadic(var ranges):
|
||||
// Temporarily set `_storage` to empty so that `ranges`
|
||||
// remains uniquely referenced while mutating.
|
||||
_storage = .empty
|
||||
ranges[i] = newValue
|
||||
_storage = .variadic(ranges)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var count: Int {
|
||||
switch _storage {
|
||||
case .empty: return 0
|
||||
case .singleRange: return 1
|
||||
case let .variadic(ranges): return ranges.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension _RangeSetStorage: RangeReplaceableCollection {
|
||||
mutating func replaceSubrange<C>(_ subrange: Range<Int>, with newElements: C) where C : Collection, C.Element == Element {
|
||||
switch _storage {
|
||||
case .empty:
|
||||
if !newElements.isEmpty {
|
||||
_storage = .variadic(Array(newElements))
|
||||
}
|
||||
|
||||
case .singleRange(high: let high, low: let low):
|
||||
switch (subrange.isEmpty, newElements.isEmpty) {
|
||||
case (false, true):
|
||||
// Replacing the single range with an empty collection.
|
||||
_storage = .empty
|
||||
|
||||
case (false, false):
|
||||
// Replacing the single range with a non-empty collection;
|
||||
// promote to a variadic container.
|
||||
_storage = .variadic(Array(newElements))
|
||||
|
||||
case (true, true):
|
||||
// Inserting an empty collection; no-op.
|
||||
break
|
||||
|
||||
case (true, false):
|
||||
// Inserting a non-empty collection either before or after
|
||||
// the existing single element.
|
||||
var ranges: [Range<T>]
|
||||
if subrange.lowerBound == 0 {
|
||||
ranges = Array(newElements)
|
||||
ranges.append(unsafeRange(low: low, high: high))
|
||||
} else {
|
||||
ranges = [unsafeRange(low: low, high: high)]
|
||||
ranges.append(contentsOf: newElements)
|
||||
}
|
||||
_storage = .variadic(ranges)
|
||||
}
|
||||
|
||||
case .variadic(var ranges):
|
||||
// Temporarily set `_storage` to empty so that `ranges`
|
||||
// remains uniquely referenced while mutating.
|
||||
_storage = .empty
|
||||
ranges.replaceSubrange(subrange, with: newElements)
|
||||
_storage = .variadic(ranges)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user