1/*
2 * Copyright 2013 Google, Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#ifndef SkRTConf_DEFINED
10#define SkRTConf_DEFINED
11
12#include "SkString.h"
13#include "SkStream.h"
14
15#include "SkTDict.h"
16#include "SkTArray.h"
17
18/** \class SkRTConfBase
19    Non-templated base class for the runtime configs
20*/
21
22class SkRTConfBase {
23public:
24    SkRTConfBase(const char *name) : fName(name) {}
25    virtual ~SkRTConfBase() {}
26    virtual const char *getName() const { return fName.c_str(); }
27    virtual bool isDefault() const = 0;
28    virtual void print(SkWStream *o) const = 0;
29    virtual bool equals(const SkRTConfBase *conf) const = 0;
30protected:
31    SkString fName;
32};
33
34/** \class SkRTConf
35    A class to provide runtime configurability.
36*/
37template<typename T> class SkRTConf: public SkRTConfBase {
38public:
39    SkRTConf(const char *name, const T &defaultValue, const char *description);
40    operator const T&() const { return fValue; }
41    void print(SkWStream *o) const;
42    bool equals(const SkRTConfBase *conf) const;
43    bool isDefault() const { return fDefault == fValue; }
44    void set(const T& value) { fValue = value; }
45protected:
46    void doPrint(char *s) const;
47
48    T        fValue;
49    T        fDefault;
50    SkString fDescription;
51};
52
53#ifdef SK_DEVELOPER
54#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf<confType> varName(confName, defaultValue, description)
55#define SK_CONF_SET(confname, value) \
56    skRTConfRegistry().set(confname, value, true)
57/* SK_CONF_TRY_SET() is like SK_CONF_SET(), but doesn't complain if
58   confname can't be found.  This is useful if the SK_CONF_DECLARE is
59   inside a source file whose linkage is dependent on the system. */
60#define SK_CONF_TRY_SET(confname, value) \
61    skRTConfRegistry().set(confname, value, false)
62#else
63#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static confType varName = defaultValue
64#define SK_CONF_SET(confname, value) (void) confname, (void) value
65#define SK_CONF_TRY_SET(confname, value) (void) confname, (void) value
66#endif
67
68/** \class SkRTConfRegistry
69    A class that maintains a systemwide registry of all runtime configuration
70    parameters.  Mainly used for printing them out and handling multiply-defined
71    knobs.
72*/
73
74class SkRTConfRegistry {
75public:
76    SkRTConfRegistry();
77    void printAll(const char *fname = NULL) const;
78    void printNonDefault(const char *fname = NULL) const;
79    const char *configFileLocation() const;
80    void possiblyDumpFile() const;
81    void validate() const;
82    template <typename T> void set(const char *confname,
83                                   T value,
84                                   bool warnIfNotFound = true);
85#ifdef SK_SUPPORT_UNITTEST
86    static void UnitTest();
87#endif
88private:
89    template<typename T> friend class SkRTConf;
90
91    void registerConf(SkRTConfBase *conf);
92    template <typename T> bool parse(const char *name, T* value);
93
94    SkTDArray<SkString *> fConfigFileKeys, fConfigFileValues;
95    typedef SkTDict< SkTDArray<SkRTConfBase *> * > ConfMap;
96    ConfMap fConfs;
97#ifdef SK_SUPPORT_UNITTEST
98    SkRTConfRegistry(bool);
99#endif
100};
101
102// our singleton registry
103
104SkRTConfRegistry &skRTConfRegistry();
105
106template<typename T>
107SkRTConf<T>::SkRTConf(const char *name, const T &defaultValue, const char *description)
108    : SkRTConfBase(name)
109    , fValue(defaultValue)
110    , fDefault(defaultValue)
111    , fDescription(description) {
112
113    T value;
114    if (skRTConfRegistry().parse(fName.c_str(), &value)) {
115        fValue = value;
116    }
117    skRTConfRegistry().registerConf(this);
118}
119
120template<typename T>
121void SkRTConf<T>::print(SkWStream *o) const {
122    char outline[200]; // should be ok because we specify a max. width for everything here.
123    char *outptr;
124    if (strlen(getName()) >= 30) {
125        o->writeText(getName());
126        o->writeText(" ");
127        outptr = &(outline[0]);
128    } else {
129        sprintf(outline, "%-30.30s", getName());
130        outptr = &(outline[30]);
131    }
132
133    doPrint(outptr);
134    sprintf(outptr+30, " %.128s", fDescription.c_str());
135    for (size_t i = strlen(outline); i --> 0 && ' ' == outline[i];) {
136        outline[i] = '\0';
137    }
138    o->writeText(outline);
139}
140
141template<typename T>
142void SkRTConf<T>::doPrint(char *s) const {
143    sprintf(s, "%-30.30s", "How do I print myself??");
144}
145
146template<> inline void SkRTConf<bool>::doPrint(char *s) const {
147    char tmp[30];
148    sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false");
149    sprintf(s, "%-30.30s", tmp);
150}
151
152template<> inline void SkRTConf<int>::doPrint(char *s) const {
153    char tmp[30];
154    sprintf(tmp, "%d # [%d]", fValue, fDefault);
155    sprintf(s, "%-30.30s", tmp);
156}
157
158template<> inline void SkRTConf<unsigned int>::doPrint(char *s) const {
159    char tmp[30];
160    sprintf(tmp, "%u # [%u]", fValue, fDefault);
161    sprintf(s, "%-30.30s", tmp);
162}
163
164template<> inline void SkRTConf<float>::doPrint(char *s) const {
165    char tmp[30];
166    sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
167    sprintf(s, "%-30.30s", tmp);
168}
169
170template<> inline void SkRTConf<double>::doPrint(char *s) const {
171    char tmp[30];
172    sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
173    sprintf(s, "%-30.30s", tmp);
174}
175
176template<> inline void SkRTConf<const char *>::doPrint(char *s) const {
177    char tmp[30];
178    sprintf(tmp, "%s # [%s]", fValue, fDefault);
179    sprintf(s, "%-30.30s", tmp);
180}
181
182template<typename T>
183bool SkRTConf<T>::equals(const SkRTConfBase *conf) const {
184    // static_cast here is okay because there's only one kind of child class.
185    const SkRTConf<T> *child_pointer = static_cast<const SkRTConf<T> *>(conf);
186    return child_pointer &&
187           fName == child_pointer->fName &&
188           fDescription == child_pointer->fDescription &&
189           fValue == child_pointer->fValue &&
190           fDefault == child_pointer->fDefault;
191}
192
193#endif
194