summaryrefslogtreecommitdiffstats
path: root/runtime/base
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2015-01-26 10:55:53 -0800
committerIgor Murashkin <iam@google.com>2015-02-04 13:29:19 -0800
commitaaebaa0121be3b9d9f13630585304482cbcaeb4b (patch)
tree0f47257e497fdf920c8d703d2d00adab53934a76 /runtime/base
parentbabecc483276b46d84cb83d4f01e577228827305 (diff)
downloadart-aaebaa0121be3b9d9f13630585304482cbcaeb4b.tar.gz
art-aaebaa0121be3b9d9f13630585304482cbcaeb4b.tar.bz2
art-aaebaa0121be3b9d9f13630585304482cbcaeb4b.zip
art: Refactor RuntimeOptions/ParsedOptions
Refactor the RuntimeOptions to be a type-safe map (VariantMap, see runtime_options.h) and the ParsedOptions to delegate the parsing to CmdlineParser (see cmdline/cmdline_parser.h). This is the start of a command line parsing refactor, and may include more in the future (dex2oat, patchoat, etc). For more details of the command line parsing generator usage see cmdline/README.md Change-Id: Ic67c6bca5e1f33bf2ec60e2e3ff8c366bab91563
Diffstat (limited to 'runtime/base')
-rw-r--r--runtime/base/variant_map.h453
-rw-r--r--runtime/base/variant_map_test.cc168
2 files changed, 621 insertions, 0 deletions
diff --git a/runtime/base/variant_map.h b/runtime/base/variant_map.h
new file mode 100644
index 0000000000..cf7977edca
--- /dev/null
+++ b/runtime/base/variant_map.h
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_BASE_VARIANT_MAP_H_
+#define ART_RUNTIME_BASE_VARIANT_MAP_H_
+
+#include <memory.h>
+#include <map>
+#include <utility>
+
+namespace art {
+
+//
+// A variant map is a heterogenous, type safe key->value map. It allows
+// for multiple different value types to be stored dynamically in the same map.
+//
+// It provides the following interface in a nutshell:
+//
+// struct VariantMap {
+// template <typename TValue>
+// TValue* Get(Key<T> key); // nullptr if the value was never set, otherwise the value.
+//
+// template <typename TValue>
+// void Set(Key<T> key, TValue value);
+// };
+//
+// Since the key is strongly typed at compile-time, it is impossible to accidentally
+// read/write a value with a different type than the key at either compile-time or run-time.
+//
+// Do not use VariantMap/VariantMapKey directly. Instead subclass each of them and use
+// the subclass, for example:
+//
+// template <typename TValue>
+// struct FruitMapKey : VariantMapKey<TValue> {
+// FruitMapKey() {}
+// };
+//
+// struct FruitMap : VariantMap<FruitMap, FruitMapKey> {
+// // This 'using' line is necessary to inherit the variadic constructor.
+// using VariantMap<FruitMap, FruitMapKey>::VariantMap;
+//
+// // Make the next '4' usages of Key slightly shorter to type.
+// template <typename TValue>
+// using Key = FruitMapKey<TValue>;
+//
+// static const Key<int> Apple;
+// static const Key<double> Orange;
+// static const Key<std::string> Banana;
+// };
+//
+// const FruitMap::Key<int> FruitMap::Apple;
+// const FruitMap::Key<double> FruitMap::Orange;
+// const FruitMap::Key<std::string> Banana;
+//
+// See variant_map_test.cc for more examples.
+//
+
+// Implementation details for VariantMap.
+namespace detail {
+ // Allocate a unique counter value each time it's called.
+ struct VariantMapKeyCounterAllocator {
+ static size_t AllocateCounter() {
+ static size_t counter = 0;
+ counter++;
+
+ return counter;
+ }
+ };
+
+ // Type-erased version of VariantMapKey<T>
+ struct VariantMapKeyRaw {
+ // TODO: this may need to call a virtual function to support string comparisons
+ bool operator<(const VariantMapKeyRaw& other) const {
+ return key_counter_ < other.key_counter_;
+ }
+
+ // The following functions need to be virtual since we don't know the compile-time type anymore:
+
+ // Clone the key, creating a copy of the contents.
+ virtual VariantMapKeyRaw* Clone() const = 0;
+
+ // Delete a value whose runtime type is that of the non-erased key's TValue.
+ virtual void ValueDelete(void* value) const = 0;
+
+ // Clone a value whose runtime type is that of the non-erased key's TValue.
+ virtual void* ValueClone(void* value) const = 0;
+
+ // Compare one key to another (same as operator<).
+ virtual bool Compare(const VariantMapKeyRaw* other) const {
+ if (other == nullptr) {
+ return false;
+ }
+ return key_counter_ < other->key_counter_;
+ }
+
+ virtual ~VariantMapKeyRaw() {}
+
+ protected:
+ VariantMapKeyRaw()
+ : key_counter_(VariantMapKeyCounterAllocator::AllocateCounter()) {}
+ // explicit VariantMapKeyRaw(size_t counter)
+ // : key_counter_(counter) {}
+
+ size_t GetCounter() const {
+ return key_counter_;
+ }
+
+ protected:
+ // Avoid the object slicing problem; use Clone() instead.
+ VariantMapKeyRaw(const VariantMapKeyRaw& other) = default;
+ VariantMapKeyRaw(VariantMapKeyRaw&& other) = default;
+
+ private:
+ size_t key_counter_; // Runtime type ID. Unique each time a new type is reified.
+ };
+} // namespace detail
+
+// The base type for keys used by the VariantMap. Users must subclass this type.
+template <typename TValue>
+struct VariantMapKey : detail::VariantMapKeyRaw {
+ // Instantiate a default value for this key. If an explicit default value was provided
+ // then that is used. Otherwise, the default value for the type TValue{} is returned.
+ TValue CreateDefaultValue() const {
+ if (default_value_ == nullptr) {
+ return TValue{}; // NOLINT [readability/braces] [4]
+ } else {
+ return TValue(*default_value_);
+ }
+ }
+
+ protected:
+ // explicit VariantMapKey(size_t counter) : detail::VariantMapKeyRaw(counter) {}
+ explicit VariantMapKey(const TValue& default_value)
+ : default_value_(std::make_shared<TValue>(default_value)) {}
+ explicit VariantMapKey(TValue&& default_value)
+ : default_value_(std::make_shared<TValue>(default_value)) {}
+ VariantMapKey() {}
+ virtual ~VariantMapKey() {}
+
+ private:
+ virtual VariantMapKeyRaw* Clone() const {
+ return new VariantMapKey<TValue>(*this);
+ }
+
+ virtual void* ValueClone(void* value) const {
+ if (value == nullptr) {
+ return nullptr;
+ }
+
+ TValue* strong_value = reinterpret_cast<TValue*>(value);
+ return new TValue(*strong_value);
+ }
+
+ virtual void ValueDelete(void* value) const {
+ if (value == nullptr) {
+ return;
+ }
+
+ // Smartly invoke the proper delete/delete[]/etc
+ const std::default_delete<TValue> deleter = std::default_delete<TValue>();
+ deleter(reinterpret_cast<TValue*>(value));
+ }
+
+ VariantMapKey(const VariantMapKey& other) = default;
+ VariantMapKey(VariantMapKey&& other) = default;
+
+ template <typename Base, template <typename TV> class TKey> friend struct VariantMap;
+
+ // Store a prototype of the key's default value, for usage with VariantMap::GetOrDefault
+ std::shared_ptr<TValue> default_value_;
+};
+
+// Implementation details for a stringified VariantMapStringKey.
+namespace detail {
+ struct VariantMapStringKeyRegistry {
+ // TODO
+ };
+} // namespace detail
+
+// Alternative base type for all keys used by VariantMap, supports runtime strings as the name.
+template <typename TValue>
+struct VariantMapStringKey : VariantMapKey<TValue> {
+ explicit VariantMapStringKey(const char* name)
+ : // VariantMapKey(/*std::hash<std::string>()(name)*/),
+ name_(name) {
+ }
+
+ private:
+ const char* name_;
+};
+
+// A variant map allows type-safe heteregeneous key->value mappings.
+// All possible key types must be specified at compile-time. Values may be added/removed
+// at runtime.
+template <typename Base, template <typename TV> class TKey>
+struct VariantMap {
+ // Allow users of this static interface to use the key type.
+ template <typename TValue>
+ using Key = TKey<TValue>;
+
+ // Look up the value from the key. The pointer becomes invalid if this key is overwritten/removed.
+ // A null value is returned only when the key does not exist in this map.
+ template <typename TValue>
+ const TValue* Get(const TKey<TValue>& key) const {
+ return GetValuePtr(key);
+ }
+
+ // Look up the value from the key. The pointer becomes invalid if this key is overwritten/removed.
+ // A null value is returned only when the key does not exist in this map.
+ template <typename TValue>
+ TValue* Get(const TKey<TValue>& key) {
+ return GetValuePtr(key);
+ }
+
+ // Lookup the value from the key. If it was not set in the map, return the default value.
+ // The default value is either the key's default, or TValue{} if the key doesn't have a default.
+ template <typename TValue>
+ TValue GetOrDefault(const TKey<TValue>& key) const {
+ auto* ptr = Get(key);
+ return (ptr == nullptr) ? key.CreateDefaultValue() : *ptr;
+ }
+
+ private:
+ // TODO: move to detail, or make it more generic like a ScopeGuard(function)
+ template <typename TValue>
+ struct ScopedRemove {
+ ScopedRemove(VariantMap& map, const TKey<TValue>& key) : map_(map), key_(key) {}
+ ~ScopedRemove() {
+ map_.Remove(key_);
+ }
+
+ VariantMap& map_;
+ const TKey<TValue>& key_;
+ };
+
+ public:
+ // Release the value from the key. If it was not set in the map, returns the default value.
+ // If the key was set, it is removed as a side effect.
+ template <typename TValue>
+ TValue ReleaseOrDefault(const TKey<TValue>& key) {
+ ScopedRemove<TValue> remove_on_return(*this, key);
+
+ TValue* ptr = Get(key);
+ if (ptr != nullptr) {
+ return std::move(*ptr);
+ } else {
+ TValue default_value = key.CreateDefaultValue();
+ return std::move(default_value);
+ }
+ }
+
+ // See if a value is stored for this key.
+ template <typename TValue>
+ bool Exists(const TKey<TValue>& key) const {
+ return GetKeyValueIterator(key) != storage_map_.end();
+ }
+
+ // Set a value for a given key, overwriting the previous value if any.
+ template <typename TValue>
+ void Set(const TKey<TValue>& key, const TValue& value) {
+ Remove(key);
+ storage_map_.insert({{key.Clone(), new TValue(value)}});
+ }
+
+ // Set a value for a given key, only if there was no previous value before.
+ // Returns true if the value was set, false if a previous value existed.
+ template <typename TValue>
+ bool SetIfMissing(const TKey<TValue>& key, const TValue& value) {
+ TValue* ptr = Get(key);
+ if (ptr == nullptr) {
+ Set(key, value);
+ return true;
+ }
+ return false;
+ }
+
+ // Remove the value for a given key, or a no-op if there was no previously set value.
+ template <typename TValue>
+ void Remove(const TKey<TValue>& key) {
+ StaticAssertKeyType<TValue>();
+
+ auto&& it = GetKeyValueIterator(key);
+ if (it != storage_map_.end()) {
+ key.ValueDelete(it->second);
+ delete it->first;
+ storage_map_.erase(it);
+ }
+ }
+
+ // Remove all key/value pairs.
+ void Clear() {
+ DeleteStoredValues();
+ storage_map_.clear();
+ }
+
+ // How many key/value pairs are stored in this map.
+ size_t Size() const {
+ return storage_map_.size();
+ }
+
+ // Construct an empty map.
+ explicit VariantMap() {}
+
+ template <typename ... TKeyValue>
+ explicit VariantMap(const TKeyValue& ... key_value_list) {
+ static_assert(sizeof...(TKeyValue) % 2 == 0, "Must be an even number of key/value elements");
+ InitializeParameters(key_value_list...);
+ }
+
+ // Create a new map from an existing map, copying all the key/value pairs.
+ VariantMap(const VariantMap& other) {
+ operator=(other);
+ }
+
+ // Copy the key/value pairs from the other map into this one. Existing key/values are cleared.
+ VariantMap& operator=(const VariantMap& other) {
+ if (this == &other) {
+ return *this;
+ }
+
+ Clear();
+
+ for (auto&& kv_pair : other.storage_map_) {
+ const detail::VariantMapKeyRaw* raw_key_other = kv_pair.first;
+ void* value = kv_pair.second;
+
+ detail::VariantMapKeyRaw* cloned_raw_key = raw_key_other->Clone();
+ void* cloned_value = raw_key_other->ValueClone(value);
+
+ storage_map_.insert({{ cloned_raw_key, cloned_value }});
+ }
+
+ return *this;
+ }
+
+ // Create a new map by moving an existing map into this one. The other map becomes empty.
+ VariantMap(VariantMap&& other) {
+ operator=(std::forward<VariantMap>(other));
+ }
+
+ // Move the existing map's key/value pairs into this one. The other map becomes empty.
+ VariantMap& operator=(VariantMap&& other) {
+ if (this != &other) {
+ Clear();
+ storage_map_.swap(other.storage_map_);
+ other.storage_map_.clear();
+ }
+ return *this;
+ }
+
+ ~VariantMap() {
+ DeleteStoredValues();
+ }
+
+ private:
+ void InitializeParameters() {}
+
+ template <typename TK, typename TValue, typename ... Rest>
+ void InitializeParameters(const TK& key, const TValue& value, const Rest& ... rest) {
+ static_assert(
+ std::is_same<TK, TKey<TValue>>::value, "The 0th/2nd/4th/etc parameters must be a key");
+
+ const TKey<TValue>& key_refined = key;
+
+ Set(key_refined, value);
+ InitializeParameters(rest...);
+ }
+
+ // Custom key comparator for std::map, needed since we are storing raw pointers as the keys.
+ struct KeyComparator {
+ bool operator()(const detail::VariantMapKeyRaw* lhs,
+ const detail::VariantMapKeyRaw* rhs) const {
+ if (lhs == nullptr) {
+ return lhs != rhs;
+ }
+
+ return lhs->Compare(rhs);
+ }
+ };
+
+ // Map of key pointers to value pointers. Pointers are never null.
+ using StorageMap = std::map<const detail::VariantMapKeyRaw*, void*, KeyComparator>;
+
+ template <typename TValue>
+ typename StorageMap::iterator GetKeyValueIterator(const TKey<TValue>& key) {
+ StaticAssertKeyType<TValue>();
+
+ const TKey<TValue>* key_ptr = &key;
+ const detail::VariantMapKeyRaw* raw_ptr = key_ptr;
+ return storage_map_.find(raw_ptr);
+ }
+
+ template <typename TValue>
+ typename StorageMap::const_iterator GetKeyValueIterator(const TKey<TValue>& key) const {
+ StaticAssertKeyType<TValue>();
+
+ const TKey<TValue>* key_ptr = &key;
+ const detail::VariantMapKeyRaw* raw_ptr = key_ptr;
+ return storage_map_.find(raw_ptr);
+ }
+
+ template <typename TValue>
+ TValue* GetValuePtr(const TKey<TValue>& key) {
+ return const_cast<TValue*>(GetValueConstPtr(key));
+ }
+
+ template <typename TValue>
+ const TValue* GetValuePtr(const TKey<TValue>& key) const {
+ return GetValueConstPtr(key);
+ }
+
+ template <typename TValue>
+ const TValue* GetValueConstPtr(const TKey<TValue>& key) const {
+ auto&& it = GetKeyValueIterator(key);
+ if (it == storage_map_.end()) {
+ return nullptr;
+ }
+
+ return reinterpret_cast<const TValue*>(it->second);
+ }
+
+ template <typename TValue>
+ static void StaticAssertKeyType() {
+ static_assert(std::is_base_of<VariantMapKey<TValue>, TKey<TValue>>::value,
+ "The provided key type (TKey) must be a subclass of VariantMapKey");
+ }
+
+ void DeleteStoredValues() {
+ for (auto&& kv_pair : storage_map_) {
+ kv_pair.first->ValueDelete(kv_pair.second);
+ delete kv_pair.first;
+ }
+ }
+
+ StorageMap storage_map_;
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_VARIANT_MAP_H_
diff --git a/runtime/base/variant_map_test.cc b/runtime/base/variant_map_test.cc
new file mode 100644
index 0000000000..827de46249
--- /dev/null
+++ b/runtime/base/variant_map_test.cc
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "variant_map.h"
+#include "gtest/gtest.h"
+
+#define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
+ reinterpret_cast<void*>(NULL));
+
+namespace art {
+
+namespace {
+ template <typename TValue>
+ struct FruitMapKey : VariantMapKey<TValue> {
+ FruitMapKey() {}
+ };
+
+ struct FruitMap : VariantMap<FruitMap, FruitMapKey> {
+ // This 'using' line is necessary to inherit the variadic constructor.
+ using VariantMap<FruitMap, FruitMapKey>::VariantMap;
+
+ // Make the next '4' usages of Key slightly shorter to type.
+ template <typename TValue>
+ using Key = FruitMapKey<TValue>;
+
+ static const Key<int> Apple;
+ static const Key<double> Orange;
+ };
+
+ const FruitMap::Key<int> FruitMap::Apple;
+ const FruitMap::Key<double> FruitMap::Orange;
+} // namespace
+
+TEST(VariantMaps, BasicReadWrite) {
+ FruitMap fm;
+
+ EXPECT_NULL(fm.Get(FruitMap::Apple));
+ EXPECT_FALSE(fm.Exists(FruitMap::Apple));
+ EXPECT_NULL(fm.Get(FruitMap::Orange));
+ EXPECT_FALSE(fm.Exists(FruitMap::Orange));
+
+ fm.Set(FruitMap::Apple, 1);
+ EXPECT_NULL(fm.Get(FruitMap::Orange));
+ EXPECT_EQ(1, *fm.Get(FruitMap::Apple));
+ EXPECT_TRUE(fm.Exists(FruitMap::Apple));
+
+ fm.Set(FruitMap::Apple, 5);
+ EXPECT_NULL(fm.Get(FruitMap::Orange));
+ EXPECT_EQ(5, *fm.Get(FruitMap::Apple));
+ EXPECT_TRUE(fm.Exists(FruitMap::Apple));
+
+ fm.Set(FruitMap::Orange, 555.0);
+ EXPECT_EQ(5, *fm.Get(FruitMap::Apple));
+ EXPECT_DOUBLE_EQ(555.0, *fm.Get(FruitMap::Orange));
+ EXPECT_EQ(size_t(2), fm.Size());
+
+ fm.Remove(FruitMap::Apple);
+ EXPECT_FALSE(fm.Exists(FruitMap::Apple));
+
+ fm.Clear();
+ EXPECT_EQ(size_t(0), fm.Size());
+ EXPECT_FALSE(fm.Exists(FruitMap::Orange));
+}
+
+TEST(VariantMaps, RuleOfFive) {
+ // Test empty constructor
+ FruitMap fmEmpty;
+ EXPECT_EQ(size_t(0), fmEmpty.Size());
+
+ // Test empty constructor
+ FruitMap fmFilled;
+ fmFilled.Set(FruitMap::Apple, 1);
+ fmFilled.Set(FruitMap::Orange, 555.0);
+ EXPECT_EQ(size_t(2), fmFilled.Size());
+
+ // Test copy constructor
+ FruitMap fmEmptyCopy(fmEmpty);
+ EXPECT_EQ(size_t(0), fmEmptyCopy.Size());
+
+ // Test copy constructor
+ FruitMap fmFilledCopy(fmFilled);
+ EXPECT_EQ(size_t(2), fmFilledCopy.Size());
+ EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy.Get(FruitMap::Apple));
+ EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy.Get(FruitMap::Orange));
+
+ // Test operator=
+ FruitMap fmFilledCopy2;
+ fmFilledCopy2 = fmFilled;
+ EXPECT_EQ(size_t(2), fmFilledCopy2.Size());
+ EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmFilledCopy2.Get(FruitMap::Apple));
+ EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmFilledCopy2.Get(FruitMap::Orange));
+
+ // Test move constructor
+ FruitMap fmMoved(std::move(fmFilledCopy));
+ EXPECT_EQ(size_t(0), fmFilledCopy.Size());
+ EXPECT_EQ(size_t(2), fmMoved.Size());
+ EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved.Get(FruitMap::Apple));
+ EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved.Get(FruitMap::Orange));
+
+ // Test operator= move
+ FruitMap fmMoved2;
+ fmMoved2.Set(FruitMap::Apple, 12345); // This value will be clobbered after the move
+
+ fmMoved2 = std::move(fmFilledCopy2);
+ EXPECT_EQ(size_t(0), fmFilledCopy2.Size());
+ EXPECT_EQ(size_t(2), fmMoved2.Size());
+ EXPECT_EQ(*fmFilled.Get(FruitMap::Apple), *fmMoved2.Get(FruitMap::Apple));
+ EXPECT_DOUBLE_EQ(*fmFilled.Get(FruitMap::Orange), *fmMoved2.Get(FruitMap::Orange));
+}
+
+TEST(VariantMaps, VariadicConstructors) {
+ // Variadic constructor, 1 kv/pair
+ FruitMap fmApple(FruitMap::Apple, 12345);
+ EXPECT_EQ(size_t(1), fmApple.Size());
+ EXPECT_EQ(12345, *fmApple.Get(FruitMap::Apple));
+
+ // Variadic constructor, 2 kv/pair
+ FruitMap fmAppleAndOrange(FruitMap::Apple, 12345,
+ FruitMap::Orange, 100.0);
+ EXPECT_EQ(size_t(2), fmAppleAndOrange.Size());
+ EXPECT_EQ(12345, *fmAppleAndOrange.Get(FruitMap::Apple));
+ EXPECT_DOUBLE_EQ(100.0, *fmAppleAndOrange.Get(FruitMap::Orange));
+}
+
+TEST(VariantMaps, ReleaseOrDefault) {
+ FruitMap fmAppleAndOrange(FruitMap::Apple, 12345,
+ FruitMap::Orange, 100.0);
+
+ int apple = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple);
+ EXPECT_EQ(12345, apple);
+
+ // Releasing will also remove the Apple key.
+ EXPECT_EQ(size_t(1), fmAppleAndOrange.Size());
+
+ // Releasing again yields a default value.
+ int apple2 = fmAppleAndOrange.ReleaseOrDefault(FruitMap::Apple);
+ EXPECT_EQ(0, apple2);
+}
+
+TEST(VariantMaps, GetOrDefault) {
+ FruitMap fm(FruitMap::Apple, 12345);
+
+ // Apple gives the expected value we set.
+ int apple = fm.GetOrDefault(FruitMap::Apple);
+ EXPECT_EQ(12345, apple);
+
+ // Map is still 1.
+ EXPECT_EQ(size_t(1), fm.Size());
+
+ // Orange gives back a default value, since it's not in the map.
+ double orange = fm.GetOrDefault(FruitMap::Orange);
+ EXPECT_DOUBLE_EQ(0.0, orange);
+}
+
+} // namespace art