From 6b68c28cb124c8fa45e3f1d19e93bb6e4b4529ec Mon Sep 17 00:00:00 2001 From: "andresp@webrtc.org" Date: Mon, 13 May 2013 08:06:36 +0000 Subject: [PATCH] Added a config class to ease passing a set of options across webrtc. Its main design reason is to expose control of experimental webrtc features. R=niklas.enbom@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1450009 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4004 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc.gyp | 17 ++++++ webrtc/common.h | 120 ++++++++++++++++++++++++++++++++++++++ webrtc/common_unittest.cc | 77 ++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 webrtc/common.h create mode 100644 webrtc/common_unittest.cc diff --git a/webrtc.gyp b/webrtc.gyp index 3c5742576d..6d2e04f09e 100644 --- a/webrtc.gyp +++ b/webrtc.gyp @@ -40,4 +40,21 @@ ], }, ], + 'conditions': [ + ['include_tests==1', { + 'targets': [ + { + 'target_name': 'common_unittests', + 'type': 'executable', + 'dependencies': [ + '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:test_support_main', + ], + 'sources': [ + 'webrtc/common_unittest.cc', + ], + }, + ], # targets + }], # include_tests + ], } diff --git a/webrtc/common.h b/webrtc/common.h new file mode 100644 index 0000000000..766f5b55b9 --- /dev/null +++ b/webrtc/common.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_COMMON_H +#define WEBRTC_COMMON_H + +#include + +namespace webrtc { + +// Class Config is designed to ease passing a set of options across webrtc code. +// Options are identified by typename in order to avoid incorrect casts. +// +// Usage: +// * declaring an option: +// struct Algo1_CostFunction { +// virtual float cost(int x) const { return x; } +// virtual ~Algo1_CostFunction() {} +// }; +// +// * accessing an option: +// config.Get().cost(value); +// +// * setting an option: +// struct SqrCost : Algo1_CostFunction { +// virtual float cost(int x) const { return x*x; } +// }; +// config.Set(new SqrCost()); +// +// Note: This class is thread-compatible (like STL containers). +class Config { + public: + // Returns the option if set or a default constructed one. + // Callers that access options to often are encouraged to cache the result. + // Returned references are owned by this. + // + // Requires std::is_default_constructible + template const T& Get() const; + + // Set the option, deleting any previous instance of the same. + // This instance gets ownership of the newly setted value. + template void Set(T* value); + + Config() {} + ~Config() { + // Note: this method is inline so webrtc public API depends only + // on the headers. + for (OptionMap::iterator it = options_.begin(); + it != options_.end(); ++it) { + delete it->second; + } + } + + private: + typedef void* OptionIdentifier; + + struct BaseOption { + virtual ~BaseOption() {} + }; + + template + struct Option : BaseOption { + explicit Option(T* v): value(v) {} + ~Option() { + delete value; + } + T* value; + }; + + // Own implementation of rtti-subset to avoid depending on rtti and its costs. + template + static OptionIdentifier identifier() { + static char id_placeholder; + return &id_placeholder; + } + + // Used to instantiate a default constructed object that doesn't needs to be + // owned. This allows Get to be implemented without requiring explicitly + // locks. + template + static const T& default_value() { + static const T def; + return def; + } + + typedef std::map OptionMap; + OptionMap options_; + + // DISALLOW_COPY_AND_ASSIGN + Config(const Config&); + void operator=(const Config&); +}; + +template +const T& Config::Get() const { + OptionMap::const_iterator it = options_.find(identifier()); + if (it != options_.end()) { + const T* t = static_cast*>(it->second)->value; + if (t) { + return *t; + } + } + return default_value(); +} + +template +void Config::Set(T* value) { + BaseOption*& it = options_[identifier()]; + delete it; + it = new Option(value); +} +} // namespace webrtc +#endif // WEBRTC_COMMON_H diff --git a/webrtc/common_unittest.cc b/webrtc/common_unittest.cc new file mode 100644 index 0000000000..e672f1da47 --- /dev/null +++ b/webrtc/common_unittest.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "common.h" // NOLINT + +#include "gtest/gtest.h" + +namespace webrtc { +namespace { + +struct MyExperiment { + enum { kDefaultFactor = 1 }; + enum { kDefaultOffset = 2 }; + + MyExperiment() + : factor(kDefaultFactor), offset(kDefaultOffset) {} + + MyExperiment(int factor, int offset) + : factor(factor), offset(offset) {} + + int factor; + int offset; +}; + +TEST(Config, ReturnsDefaultInstanceIfNotConfigured) { + Config config; + const MyExperiment& my_exp = config.Get(); + EXPECT_EQ(MyExperiment::kDefaultFactor, my_exp.factor); + EXPECT_EQ(MyExperiment::kDefaultOffset, my_exp.offset); +} + +TEST(Config, ReturnOptionWhenSet) { + Config config; + config.Set(new MyExperiment(5, 1)); + const MyExperiment& my_exp = config.Get(); + EXPECT_EQ(5, my_exp.factor); + EXPECT_EQ(1, my_exp.offset); +} + +TEST(Config, SetNullSetsTheOptionBackToDefault) { + Config config; + config.Set(new MyExperiment(5, 1)); + config.Set(NULL); + const MyExperiment& my_exp = config.Get(); + EXPECT_EQ(MyExperiment::kDefaultFactor, my_exp.factor); + EXPECT_EQ(MyExperiment::kDefaultOffset, my_exp.offset); +} + +struct Algo1_CostFunction { + Algo1_CostFunction() {} + + virtual int cost(int x) const { + return x; + } + + virtual ~Algo1_CostFunction() {} +}; + +struct SqrCost : Algo1_CostFunction { + virtual int cost(int x) const { + return x*x; + } +}; + +TEST(Config, SupportsPolimorphism) { + Config config; + config.Set(new SqrCost()); + EXPECT_EQ(25, config.Get().cost(5)); +} +} // namespace +} // namespace webrtc