Add DeviceConfig and OncePer objects

Add DeviceConfig to store per-device configuration information.  Put a
OncePer object inside Config and DeviceConfig, which computes a value
once per key per object to allow build logic to store arbitrary
per-build or per-device computed values.

Change-Id: I1a38b426f29d223ef5e803e0d4d9604500de2fd2
diff --git a/android/onceper.go b/android/onceper.go
new file mode 100644
index 0000000..5f7a310
--- /dev/null
+++ b/android/onceper.go
@@ -0,0 +1,75 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"sync"
+	"sync/atomic"
+)
+
+type OncePer struct {
+	values     atomic.Value
+	valuesLock sync.Mutex
+}
+
+type valueMap map[interface{}]interface{}
+
+// Once computes a value the first time it is called with a given key per OncePer, and returns the
+// value without recomputing when called with the same key.  key must be hashable.
+func (once *OncePer) Once(key interface{}, value func() interface{}) interface{} {
+	// Atomically load the map without locking.  If this is the first call Load() will return nil
+	// and the type assertion will fail, leaving a nil map in m, but that's OK since m is only used
+	// for reads.
+	m, _ := once.values.Load().(valueMap)
+	if v, ok := m[key]; ok {
+		return v
+	}
+
+	once.valuesLock.Lock()
+	defer once.valuesLock.Unlock()
+
+	// Check again with the lock held
+	m, _ = once.values.Load().(valueMap)
+	if v, ok := m[key]; ok {
+		return v
+	}
+
+	// Copy the existing map
+	newMap := make(valueMap, len(m))
+	for k, v := range m {
+		newMap[k] = v
+	}
+
+	v := value()
+
+	newMap[key] = v
+	once.values.Store(newMap)
+
+	return v
+}
+
+func (once *OncePer) OnceStringSlice(key interface{}, value func() []string) []string {
+	return once.Once(key, func() interface{} { return value() }).([]string)
+}
+
+func (once *OncePer) Once2StringSlice(key interface{}, value func() ([]string, []string)) ([]string, []string) {
+	type twoStringSlice [2][]string
+	s := once.Once(key, func() interface{} {
+		var s twoStringSlice
+		s[0], s[1] = value()
+		return s
+	}).(twoStringSlice)
+	return s[0], s[1]
+}