github.com/aaabigfish/gopkg@v1.1.0/cloud/metainfo/kv.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package metainfo 16 17 import "context" 18 19 type ctxKeyType struct{} 20 21 var ctxKey ctxKeyType 22 23 type kv struct { 24 key string 25 val string 26 } 27 28 type node struct { 29 persistent []kv 30 transient []kv 31 stale []kv 32 } 33 34 func (n *node) size() int { 35 return len(n.persistent) + len(n.transient) + len(n.stale) 36 } 37 38 func (n *node) transferForward() (r *node) { 39 r = &node{ 40 persistent: n.persistent, 41 stale: n.transient, 42 } 43 return 44 } 45 46 func (n *node) addTransient(k, v string) *node { 47 if res, ok := remove(n.stale, k); ok { 48 return &node{ 49 persistent: n.persistent, 50 transient: appendEx(n.transient, kv{ 51 key: k, 52 val: v, 53 }), 54 stale: res, 55 } 56 } 57 58 if idx, ok := search(n.transient, k); ok { 59 if n.transient[idx].val == v { 60 return n 61 } 62 r := *n 63 r.transient = make([]kv, len(n.transient)) 64 copy(r.transient, n.transient) 65 r.transient[idx].val = v 66 return &r 67 } 68 69 r := *n 70 r.transient = appendEx(r.transient, kv{ 71 key: k, 72 val: v, 73 }) 74 return &r 75 } 76 77 func (n *node) addPersistent(k, v string) *node { 78 if idx, ok := search(n.persistent, k); ok { 79 if n.persistent[idx].val == v { 80 return n 81 } 82 r := *n 83 r.persistent = make([]kv, len(n.persistent)) 84 copy(r.persistent, n.persistent) 85 r.persistent[idx].val = v 86 return &r 87 } 88 r := *n 89 r.persistent = appendEx(r.persistent, kv{ 90 key: k, 91 val: v, 92 }) 93 return &r 94 } 95 96 func (n *node) delTransient(k string) (r *node) { 97 if res, ok := remove(n.stale, k); ok { 98 return &node{ 99 persistent: n.persistent, 100 transient: n.transient, 101 stale: res, 102 } 103 } 104 if res, ok := remove(n.transient, k); ok { 105 return &node{ 106 persistent: n.persistent, 107 transient: res, 108 stale: n.stale, 109 } 110 } 111 return n 112 } 113 114 func (n *node) delPersistent(k string) (r *node) { 115 if res, ok := remove(n.persistent, k); ok { 116 return &node{ 117 persistent: res, 118 transient: n.transient, 119 stale: n.stale, 120 } 121 } 122 return n 123 } 124 125 type mapView struct { 126 persistent map[string]string 127 transient map[string]string 128 stale map[string]string 129 } 130 131 func newMapView() *mapView { 132 return &mapView{ 133 persistent: make(map[string]string), 134 transient: make(map[string]string), 135 stale: make(map[string]string), 136 } 137 } 138 139 func (m *mapView) size() int { 140 return len(m.persistent) + len(m.transient) + len(m.stale) 141 } 142 143 func (m *mapView) toNode() *node { 144 return &node{ 145 persistent: mapToSlice(m.persistent), 146 transient: mapToSlice(m.transient), 147 stale: mapToSlice(m.stale), 148 } 149 } 150 151 func (n *node) mapView() *mapView { 152 return &mapView{ 153 persistent: sliceToMap(n.persistent), 154 transient: sliceToMap(n.transient), 155 stale: sliceToMap(n.stale), 156 } 157 } 158 159 func search(kvs []kv, key string) (idx int, ok bool) { 160 for i := range kvs { 161 if kvs[i].key == key { 162 return i, true 163 } 164 } 165 return 166 } 167 168 func remove(kvs []kv, key string) (res []kv, removed bool) { 169 if idx, ok := search(kvs, key); ok { 170 if cnt := len(kvs); cnt == 1 { 171 removed = true 172 return 173 } 174 res = make([]kv, len(kvs)-1) 175 copy(res, kvs[:idx]) 176 copy(res[idx:], kvs[idx+1:]) 177 return res, true 178 } 179 return kvs, false 180 } 181 182 func getNode(ctx context.Context) *node { 183 if ctx != nil { 184 if val, ok := ctx.Value(ctxKey).(*node); ok { 185 return val 186 } 187 } 188 return nil 189 } 190 191 func withNode(ctx context.Context, n *node) context.Context { 192 if ctx == nil { 193 return ctx 194 } 195 return context.WithValue(ctx, ctxKey, n) 196 } 197 198 func appendEx(arr []kv, x kv) (res []kv) { 199 res = make([]kv, len(arr)+1) 200 copy(res, arr) 201 res[len(arr)] = x 202 return res 203 }