Skip to content

Instantly share code, notes, and snippets.

@cooler333
Last active July 7, 2022 19:47
Show Gist options
  • Save cooler333/029db0c43fb6e36a49f0aa043ee54a7e to your computer and use it in GitHub Desktop.
Save cooler333/029db0c43fb6e36a49f0aa043ee54a7e to your computer and use it in GitHub Desktop.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
// 1
struct User: Equatable {
// 2
struct Address: Equatable {
var street: String
}
struct Phone: Equatable {
var number: String = "+7"
}
// 3
enum Role {
// 4
enum Permission {
case create
case read
case update
case delete
}
case admin
case member
case guest
var permissions: [Permission] {
switch self {
case .admin:
return [.create, .read, .update, .delete]
case .member:
return [.create, .read]
case .guest:
return [.read]
}
}
}
var name: String
let email: String
var address: Address?
var phone: Phone = .init()
let role: Role
}
struct Reducer<State, Action> {
let reduce: (State, Action) -> State
}
final class Store<State: Equatable, Action> {
private var stateGetter: (() -> State)!
private var stateSetter: ((State) -> Void)!
var state: State {
get { stateGetter() }
set { stateSetter(newValue) }
}
var _state: State! {
didSet {
listners.forEach { listner in
listner()
}
}
}
let reducer: Reducer<State, Action>
var listners: [() -> Void] = []
func addListener(_ listener: @escaping () -> Void) {
listners.append(listener)
}
init(
state: State,
reducer: Reducer<State, Action>
) {
self.reducer = reducer
self._state = state
self.stateGetter = { [unowned self] in
return self._state
}
self.stateSetter = { [unowned self] state in
self._state = state
}
}
private init(
stateSetter: @escaping (State) -> Void,
stateGetter: @escaping () -> State,
reducer: Reducer<State, Action>
) {
self.stateSetter = stateSetter
self.stateGetter = stateGetter
self.reducer = reducer
}
func dispatch(_ action: Action) {
state = reducer.reduce(state, action)
}
func createChildStore<ChildState, ChildAction>(
keyPath: WritableKeyPath<State, ChildState>,
reducer: Reducer<ChildState, ChildAction>
) -> Store<ChildState, ChildAction> {
let s = Store<ChildState, ChildAction>(
stateSetter: { self.state[keyPath: keyPath] = $0 },
stateGetter: { self.state[keyPath: keyPath] },
reducer: reducer
)
addListener({ [weak s] in
guard let s = s else { return }
s.listners.forEach { listner in
listner()
}
})
return s
}
}
let subReducer = Reducer<Optional<User.Address>, String>(reduce: { state, action in
if var state = state {
state.street += ", " + action + "sub"
return state
} else {
return .init(street: "initial " + action)
}
})
let reducer: Reducer<User, Int> = Reducer(
reduce: { state, action in
var state = state
state.name += "\(action)"
return state
}
)
let store = Store<User, Int>(
state: User(
name: "",
email: "",
address: nil,
role: .guest
),
reducer: reducer
)
var aaa = Date().timeIntervalSince1970
let initialAAA = aaa
print(Date().timeIntervalSince1970 - aaa, "Baseline")
aaa = Date().timeIntervalSince1970
let stores = Array(0...1000).map { _ -> Store<Optional<User.Address>, String> in
let subStore = store.createChildStore(keyPath: \.address, reducer: subReducer)
return subStore
}
print(Date().timeIntervalSince1970 - aaa, "createChildStore")
aaa = Date().timeIntervalSince1970
var updateCount = 0
stores.first?.listners.append {
updateCount += 1
}
print(Date().timeIntervalSince1970 - aaa, "updateCount")
aaa = Date().timeIntervalSince1970
Array(0...2).forEach { index in
stores.first!.dispatch("\(index)")
}
print(Date().timeIntervalSince1970 - aaa, "stores.first dispatch 3")
aaa = Date().timeIntervalSince1970
Array(0...100).forEach { index in
stores.last!.dispatch("\(index)")
}
print(Date().timeIntervalSince1970 - aaa, "stores.last dispatch 101 (* 1000)")
if Date().timeIntervalSince1970 - aaa > 1 {
print("TOO MUCH")
}
aaa = Date().timeIntervalSince1970
stores.last!.dispatch("final")
print(Date().timeIntervalSince1970 - aaa, "stores.last dispatch final")
aaa = Date().timeIntervalSince1970
store.dispatch(1)
store.dispatch(2)
store.dispatch(3)
store.dispatch(4)
print(Date().timeIntervalSince1970 - aaa, "rootStore dispatch 1,2,3,4")
aaa = Date().timeIntervalSince1970
stores.last!.dispatch("123")
print(Date().timeIntervalSince1970 - aaa, "stores.last dispatch 123")
aaa = Date().timeIntervalSince1970
print(store.state.name)
print(store.state.address?.street ?? "null")
print("IS SUBSTORES EQUAL: ", stores.first!.state?.street ?? "null" == stores.last!.state?.street ?? "null")
print("IS SUB & STORE EQUAL: ", stores.last!.state?.street ?? "null" == store.state.address?.street ?? "null")
print(Date().timeIntervalSince1970 - initialAAA, "final")
print("Update count:", updateCount)
print("IS UPDATE COUNT 110?", updateCount == 110 ? "TRUE" : "FALSE")
// 0.0002391338348388672 Baseline
// 1.5412371158599854 createChildStore
// 0.000701904296875 updateCount
// 0.027843952178955078 stores.first dispatch 3
// 0.9228630065917969 stores.last dispatch 101 (* 1000)
// 0.009496927261352539 stores.last dispatch final
// 0.04581594467163086 rootStore dispatch 1,2,3,4
// 0.009209156036376953 stores.last dispatch 123
// 1234
// initial 0, 1sub, 2sub, 0sub, 1sub, 2sub, 3sub, 4sub, 5sub, 6sub, 7sub, 8sub, 9sub, 10sub, 11sub, 12sub, 13sub, 14sub, 15sub, 16sub, 17sub, 18sub, 19sub, 20sub, 21sub, 22sub, 23sub, 24sub, 25sub, 26sub, 27sub, 28sub, 29sub, 30sub, 31sub, 32sub, 33sub, 34sub, 35sub, 36sub, 37sub, 38sub, 39sub, 40sub, 41sub, 42sub, 43sub, 44sub, 45sub, 46sub, 47sub, 48sub, 49sub, 50sub, 51sub, 52sub, 53sub, 54sub, 55sub, 56sub, 57sub, 58sub, 59sub, 60sub, 61sub, 62sub, 63sub, 64sub, 65sub, 66sub, 67sub, 68sub, 69sub, 70sub, 71sub, 72sub, 73sub, 74sub, 75sub, 76sub, 77sub, 78sub, 79sub, 80sub, 81sub, 82sub, 83sub, 84sub, 85sub, 86sub, 87sub, 88sub, 89sub, 90sub, 91sub, 92sub, 93sub, 94sub, 95sub, 96sub, 97sub, 98sub, 99sub, 100sub, finalsub, 123sub
// IS SUBSTORES EQUAL: true
// IS SUB & STORE EQUAL: true
// 2.5582311153411865 final
// Update count: 110
// IS UPDATE COUNT 110? TRUE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment