 # Sequence replacement operator?

Working on a little utility to generate 65C02 ROM images, I had this thought that it would be nice to be able to express a sub-array replacement as an array assignment, something like this:

``````var rom = [UInt8](repeating: 0xea, count: 32768)
rom[0x6000] <= [ 0x01, 0x02, 0x03 ]
``````

The result of the above code would be equivalent to:

``````rom[0x6000] = 0x01
rom[0x6001] = 0x02
rom[0x6002] = 0x03
``````

But I couldn't think of a way to implement this fictitious `<=` operator. I can see a way to do it like this:

``````rom <= (0x6000, [ 0x01, 0x02, 0x03 ])
``````

but that's not really any better than `replaceSubrange()`.

It may be silly to want to do this, it was just an idea I had, and made me wonder what was possible in Swift.

(I’m also not sure how to implement something like this for generics like Array).

It might make more sense to make this a labelled subscript, giving you something like:

``````rom[from: 0x6000] = [0x01, 0x02, 0x02]
``````

You'll have to decide some sensible behaviour for the subscript getter though (`rom[from: 0x6000] == ?`) and decide what to do at the bounds of the array, etc.

1 Like

That seems to be reasonable, but I wish I didn't have to define the getter.

``````extension
Data
{
subscript(at inIndex: Int)
-> [UInt8]
{
get
{
let b = [UInt8](self)
return Array(b[inIndex..<b.count])
}

set(inValue)
{
let r = inIndex ..< (inIndex + inValue.count)
self.replaceSubrange(r, with: inValue)
}
}
}

var d1 = Data(repeating: 0xea, count: 32768)
d1[at: 0x6000] = [UInt8]([0x1, 0x2, 0x3])
``````

Now I gotta figure out how to avoid the `[UInt8]()` cast when using it.

You sure you need `[UInt8]()`?

``````d1[at: 0x6000] = [0x1, 0x2, 0x3]
``````

This works fine for me.

If you really want to use the operator, it is possible

``````struct EditableArraySlice<T> {
var buffer: [T]
var range: Range<Int>
}

class ROM {
var buffer: [UInt8] = [UInt8](repeating: 0, count: 1024 * 1024)
subscript(index: Int) -> EditableArraySlice<UInt8> {
get {
return EditableArraySlice(buffer: buffer, range: index..<buffer.endIndex)
}
set {
precondition(newValue.buffer.count == buffer.count)
buffer = newValue.buffer
}
}
}

func <=<S: Sequence>(lhs: inout EditableArraySlice<S.Element>, rhs: S) {
var iter = rhs.makeIterator()
for index in lhs.range {
guard let next = iter.next() else { break }
lhs.buffer[index] = next
}
}
``````

Note: The above code causes the array to be copied each time you use the operator. If you're willing to use the not-yet-stable `_modify`, you can remove the array copy by replacing the `set` with this:

``````_modify {
var tmp = EditableArraySlice(buffer: buffer, range: index..<buffer.endIndex)
let oldCount = buffer.count
buffer = []
yield &tmp
precondition(tmp.buffer.count == oldCount)
buffer = tmp.buffer
}
``````
1 Like