as i’m heavily dependent on _modify
across a lot of my code, i’ve been looking into just how robust of a tool this accessor (and _read
) is for preserving algorithmic complexity.
just what are we allowed to do with _modify
that won’t add a linear factor to an algorithm?
example 1: normal _modify
use
public
struct Tables
{
var core:[Int]
var colonies:[Int: [Int]]
subscript(index:Int) -> [Int]
{
_read
{
yield index == 0 ? self.core : self.colonies[index]!
}
_modify
{
if index == 0
{
yield &self.core
}
else
{
yield &self.colonies[index]!
}
}
}
public mutating
func insert(x:Int, y:Int)
{
self[x].append(y)
}
}
example 2: _modify
that wraps an inlinable get set
why are we allowed to do this?
public
struct Tables
{
var _core:[Int]
var _colonies:[Int: [Int]]
var core:[Int]
{
get
{
self._core
}
set(value)
{
self._core = value
}
}
var colonies:[Int: [Int]]
{
get
{
self._colonies
}
set(value)
{
self._colonies = value
}
}
subscript(index:Int) -> [Int]
{
_read
{
yield index == 0 ? self.core : self.colonies[index]!
}
_modify
{
if index == 0
{
yield &self.core
}
else
{
yield &self.colonies[index]!
}
}
}
public mutating
func insert(x:Int, y:Int)
{
self[x].append(y)
}
}
example 3: _modify
that wraps a resilient get set
(godbolt for people who are good at reading assembly)
public
struct Tables
{
var _core:[Int]
var _colonies:[Int: [Int]]
@inline(never)
var core:[Int]
{
get
{
self._core
}
set(value)
{
self._core = value
}
}
@inline(never)
var colonies:[Int: [Int]]
{
get
{
self._colonies
}
set(value)
{
self._colonies = value
}
}
subscript(index:Int) -> [Int]
{
_read
{
yield index == 0 ? self.core : self.colonies[index]!
}
_modify
{
if index == 0
{
yield &self.core
}
else
{
yield &self.colonies[index]!
}
}
}
public mutating
func insert(x:Int, y:Int)
{
self[x].append(y)
}
}