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  }