1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifndef WEBRTC_COMMON_H_
12#define WEBRTC_COMMON_H_
13
14#include <map>
15
16#include "webrtc/base/basictypes.h"
17
18namespace webrtc {
19
20// Only add new values to the end of the enumeration and never remove (only
21// deprecate) to maintain binary compatibility.
22enum class ConfigOptionID {
23  kMyExperimentForTest,
24  kAlgo1CostFunctionForTest,
25  kTemporalLayersFactory,
26  kNetEqCapacityConfig,
27  kNetEqFastAccelerate,
28  kVoicePacing,
29  kExtendedFilter,
30  kDelayAgnostic,
31  kExperimentalAgc,
32  kExperimentalNs,
33  kBeamforming,
34  kIntelligibility
35};
36
37// Class Config is designed to ease passing a set of options across webrtc code.
38// Options are identified by typename in order to avoid incorrect casts.
39//
40// Usage:
41// * declaring an option:
42//    struct Algo1_CostFunction {
43//      virtual float cost(int x) const { return x; }
44//      virtual ~Algo1_CostFunction() {}
45//    };
46//
47// * accessing an option:
48//    config.Get<Algo1_CostFunction>().cost(value);
49//
50// * setting an option:
51//    struct SqrCost : Algo1_CostFunction {
52//      virtual float cost(int x) const { return x*x; }
53//    };
54//    config.Set<Algo1_CostFunction>(new SqrCost());
55//
56// Note: This class is thread-compatible (like STL containers).
57class Config {
58 public:
59  // Returns the option if set or a default constructed one.
60  // Callers that access options too often are encouraged to cache the result.
61  // Returned references are owned by this.
62  //
63  // Requires std::is_default_constructible<T>
64  template<typename T> const T& Get() const;
65
66  // Set the option, deleting any previous instance of the same.
67  // This instance gets ownership of the newly set value.
68  template<typename T> void Set(T* value);
69
70  Config() {}
71  ~Config() {
72    // Note: this method is inline so webrtc public API depends only
73    // on the headers.
74    for (OptionMap::iterator it = options_.begin();
75         it != options_.end(); ++it) {
76      delete it->second;
77    }
78  }
79
80 private:
81  struct BaseOption {
82    virtual ~BaseOption() {}
83  };
84
85  template<typename T>
86  struct Option : BaseOption {
87    explicit Option(T* v): value(v) {}
88    ~Option() {
89      delete value;
90    }
91    T* value;
92  };
93
94  template<typename T>
95  static ConfigOptionID identifier() {
96    return T::identifier;
97  }
98
99  // Used to instantiate a default constructed object that doesn't needs to be
100  // owned. This allows Get<T> to be implemented without requiring explicitly
101  // locks.
102  template<typename T>
103  static const T& default_value() {
104    RTC_DEFINE_STATIC_LOCAL(const T, def, ());
105    return def;
106  }
107
108  typedef std::map<ConfigOptionID, BaseOption*> OptionMap;
109  OptionMap options_;
110
111  // RTC_DISALLOW_COPY_AND_ASSIGN
112  Config(const Config&);
113  void operator=(const Config&);
114};
115
116template<typename T>
117const T& Config::Get() const {
118  OptionMap::const_iterator it = options_.find(identifier<T>());
119  if (it != options_.end()) {
120    const T* t = static_cast<Option<T>*>(it->second)->value;
121    if (t) {
122      return *t;
123    }
124  }
125  return default_value<T>();
126}
127
128template<typename T>
129void Config::Set(T* value) {
130  BaseOption*& it = options_[identifier<T>()];
131  delete it;
132  it = new Option<T>(value);
133}
134
135}  // namespace webrtc
136
137#endif  // WEBRTC_COMMON_H_
138