codec_cache.go raw

   1  // Copyright (C) MongoDB, Inc. 2017-present.
   2  //
   3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
   4  // not use this file except in compliance with the License. You may obtain
   5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
   6  
   7  package bsoncodec
   8  
   9  import (
  10  	"reflect"
  11  	"sync"
  12  	"sync/atomic"
  13  )
  14  
  15  // Runtime check that the kind encoder and decoder caches can store any valid
  16  // reflect.Kind constant.
  17  func init() {
  18  	if s := reflect.Kind(len(kindEncoderCache{}.entries)).String(); s != "kind27" {
  19  		panic("The capacity of kindEncoderCache is too small.\n" +
  20  			"This is due to a new type being added to reflect.Kind.")
  21  	}
  22  }
  23  
  24  // statically assert array size
  25  var _ = (kindEncoderCache{}).entries[reflect.UnsafePointer]
  26  var _ = (kindDecoderCache{}).entries[reflect.UnsafePointer]
  27  
  28  type typeEncoderCache struct {
  29  	cache sync.Map // map[reflect.Type]ValueEncoder
  30  }
  31  
  32  func (c *typeEncoderCache) Store(rt reflect.Type, enc ValueEncoder) {
  33  	c.cache.Store(rt, enc)
  34  }
  35  
  36  func (c *typeEncoderCache) Load(rt reflect.Type) (ValueEncoder, bool) {
  37  	if v, _ := c.cache.Load(rt); v != nil {
  38  		return v.(ValueEncoder), true
  39  	}
  40  	return nil, false
  41  }
  42  
  43  func (c *typeEncoderCache) LoadOrStore(rt reflect.Type, enc ValueEncoder) ValueEncoder {
  44  	if v, loaded := c.cache.LoadOrStore(rt, enc); loaded {
  45  		enc = v.(ValueEncoder)
  46  	}
  47  	return enc
  48  }
  49  
  50  func (c *typeEncoderCache) Clone() *typeEncoderCache {
  51  	cc := new(typeEncoderCache)
  52  	c.cache.Range(func(k, v interface{}) bool {
  53  		if k != nil && v != nil {
  54  			cc.cache.Store(k, v)
  55  		}
  56  		return true
  57  	})
  58  	return cc
  59  }
  60  
  61  type typeDecoderCache struct {
  62  	cache sync.Map // map[reflect.Type]ValueDecoder
  63  }
  64  
  65  func (c *typeDecoderCache) Store(rt reflect.Type, dec ValueDecoder) {
  66  	c.cache.Store(rt, dec)
  67  }
  68  
  69  func (c *typeDecoderCache) Load(rt reflect.Type) (ValueDecoder, bool) {
  70  	if v, _ := c.cache.Load(rt); v != nil {
  71  		return v.(ValueDecoder), true
  72  	}
  73  	return nil, false
  74  }
  75  
  76  func (c *typeDecoderCache) LoadOrStore(rt reflect.Type, dec ValueDecoder) ValueDecoder {
  77  	if v, loaded := c.cache.LoadOrStore(rt, dec); loaded {
  78  		dec = v.(ValueDecoder)
  79  	}
  80  	return dec
  81  }
  82  
  83  func (c *typeDecoderCache) Clone() *typeDecoderCache {
  84  	cc := new(typeDecoderCache)
  85  	c.cache.Range(func(k, v interface{}) bool {
  86  		if k != nil && v != nil {
  87  			cc.cache.Store(k, v)
  88  		}
  89  		return true
  90  	})
  91  	return cc
  92  }
  93  
  94  // atomic.Value requires that all calls to Store() have the same concrete type
  95  // so we wrap the ValueEncoder with a kindEncoderCacheEntry to ensure the type
  96  // is always the same (since different concrete types may implement the
  97  // ValueEncoder interface).
  98  type kindEncoderCacheEntry struct {
  99  	enc ValueEncoder
 100  }
 101  
 102  type kindEncoderCache struct {
 103  	entries [reflect.UnsafePointer + 1]atomic.Value // *kindEncoderCacheEntry
 104  }
 105  
 106  func (c *kindEncoderCache) Store(rt reflect.Kind, enc ValueEncoder) {
 107  	if enc != nil && rt < reflect.Kind(len(c.entries)) {
 108  		c.entries[rt].Store(&kindEncoderCacheEntry{enc: enc})
 109  	}
 110  }
 111  
 112  func (c *kindEncoderCache) Load(rt reflect.Kind) (ValueEncoder, bool) {
 113  	if rt < reflect.Kind(len(c.entries)) {
 114  		if ent, ok := c.entries[rt].Load().(*kindEncoderCacheEntry); ok {
 115  			return ent.enc, ent.enc != nil
 116  		}
 117  	}
 118  	return nil, false
 119  }
 120  
 121  func (c *kindEncoderCache) Clone() *kindEncoderCache {
 122  	cc := new(kindEncoderCache)
 123  	for i, v := range c.entries {
 124  		if val := v.Load(); val != nil {
 125  			cc.entries[i].Store(val)
 126  		}
 127  	}
 128  	return cc
 129  }
 130  
 131  // atomic.Value requires that all calls to Store() have the same concrete type
 132  // so we wrap the ValueDecoder with a kindDecoderCacheEntry to ensure the type
 133  // is always the same (since different concrete types may implement the
 134  // ValueDecoder interface).
 135  type kindDecoderCacheEntry struct {
 136  	dec ValueDecoder
 137  }
 138  
 139  type kindDecoderCache struct {
 140  	entries [reflect.UnsafePointer + 1]atomic.Value // *kindDecoderCacheEntry
 141  }
 142  
 143  func (c *kindDecoderCache) Store(rt reflect.Kind, dec ValueDecoder) {
 144  	if rt < reflect.Kind(len(c.entries)) {
 145  		c.entries[rt].Store(&kindDecoderCacheEntry{dec: dec})
 146  	}
 147  }
 148  
 149  func (c *kindDecoderCache) Load(rt reflect.Kind) (ValueDecoder, bool) {
 150  	if rt < reflect.Kind(len(c.entries)) {
 151  		if ent, ok := c.entries[rt].Load().(*kindDecoderCacheEntry); ok {
 152  			return ent.dec, ent.dec != nil
 153  		}
 154  	}
 155  	return nil, false
 156  }
 157  
 158  func (c *kindDecoderCache) Clone() *kindDecoderCache {
 159  	cc := new(kindDecoderCache)
 160  	for i, v := range c.entries {
 161  		if val := v.Load(); val != nil {
 162  			cc.entries[i].Store(val)
 163  		}
 164  	}
 165  	return cc
 166  }
 167