> On Mar 30, 2017, at 1:20 PM, Joshua Alvarado via swift-evolution
> <[email protected]> wrote:
>
> I think think the gain of functionality isn't there for the addition of this
> functionality to be added. There are other ways to implement what you are
> desiring to do without adding it to Swift language.
For instance, wrap your type in something like this:
struct Recorded<Base: RangeReplaceableCollection> {
init(_ base: Base) {
self.base = base
changes = [ Change(newElements: base) ]
}
fileprivate(set) var base: Base
fileprivate(set) var changes: [Change]
}
extension Recorded {
final class Change: Hashable, CustomStringConvertible {
let subrange: Range<Recorded.Index>?
let newElements: [Recorded.Iterator.Element]
init<C: Collection>(subrange: Range<Index>? = nil, newElements: C)
where C.Iterator.Element == Recorded.Iterator.Element
{
self.subrange = subrange
self.newElements = Array(newElements)
}
static func == (lhs: Change, rhs: Change) -> Bool {
return lhs === rhs
}
var hashValue: Int {
return ObjectIdentifier(self).hashValue
}
var description: String {
if let subrange = subrange {
return "base[\(subrange.description)] =
\(newElements.description)"
}
else {
return "base = \(newElements.description)"
}
}
func apply(to c: inout Recorded) {
let subrange = self.subrange ?? c.startIndex ..< c.endIndex
c.base.replaceSubrange(subrange, with: newElements)
c.changes.append(self)
}
}
mutating func apply(_ changes: [Change]) {
for change in changes {
change.apply(to: &self)
}
}
func newChanges(since older: Recorded) -> [Change] {
var changes = self.changes
guard let lastChange = older.changes.last,
let i = changes.index(of: lastChange) else {
return changes
}
let overlapRange = 0 ... i
precondition(
older.changes.suffix(overlapRange.count) == changes[overlapRange],
"self includes old changes not present in older"
)
changes.removeSubrange(0 ... i)
return changes
}
}
extension Recorded: RangeReplaceableCollection {
subscript(_ i: Base.Index) -> Base.Iterator.Element {
get {
return base[i]
}
set {
replaceSubrange(i ..< index(after: i), with: [newValue])
}
}
func index(after i: Base.Index) -> Base.Index {
return base.index(after: i)
}
var startIndex: Base.Index {
return base.startIndex
}
var endIndex: Base.Index {
return base.endIndex
}
init() {
self.init(Base())
}
mutating func replaceSubrange<C>(_ subrange: Range<Base.Index>, with
newElements: C)
where C : Collection,
C.Iterator.Element == Base.Iterator.Element
{
let change = Change(subrange: subrange, newElements: newElements)
change.apply(to: &self)
}
}
(This is begging for Swift 4's conditional conformance feature, which would
allow `Recorded` to conform to `RandomAccessCollection` et.al. if the
underlying type did.)
Now you have a ready-made change list, and all you need to do is write a
`didSet` that runs `newChanges(since: oldValue)` on the new value and figures
out what to do with it. That ought to be faster than a full difference
calculation from scratch on every `didSet`.
--
Brent Royal-Gordon
Architechies
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution