1// Copyright 2016 Google Inc. All rights reserved. 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 15package android 16 17import ( 18 "sync" 19 "sync/atomic" 20) 21 22type OncePer struct { 23 values atomic.Value 24 valuesLock sync.Mutex 25} 26 27type valueMap map[interface{}]interface{} 28 29// Once computes a value the first time it is called with a given key per OncePer, and returns the 30// value without recomputing when called with the same key. key must be hashable. 31func (once *OncePer) Once(key interface{}, value func() interface{}) interface{} { 32 // Atomically load the map without locking. If this is the first call Load() will return nil 33 // and the type assertion will fail, leaving a nil map in m, but that's OK since m is only used 34 // for reads. 35 m, _ := once.values.Load().(valueMap) 36 if v, ok := m[key]; ok { 37 return v 38 } 39 40 once.valuesLock.Lock() 41 defer once.valuesLock.Unlock() 42 43 // Check again with the lock held 44 m, _ = once.values.Load().(valueMap) 45 if v, ok := m[key]; ok { 46 return v 47 } 48 49 // Copy the existing map 50 newMap := make(valueMap, len(m)) 51 for k, v := range m { 52 newMap[k] = v 53 } 54 55 v := value() 56 57 newMap[key] = v 58 once.values.Store(newMap) 59 60 return v 61} 62 63func (once *OncePer) OnceStringSlice(key interface{}, value func() []string) []string { 64 return once.Once(key, func() interface{} { return value() }).([]string) 65} 66 67func (once *OncePer) Once2StringSlice(key interface{}, value func() ([]string, []string)) ([]string, []string) { 68 type twoStringSlice [2][]string 69 s := once.Once(key, func() interface{} { 70 var s twoStringSlice 71 s[0], s[1] = value() 72 return s 73 }).(twoStringSlice) 74 return s[0], s[1] 75} 76