17af56bee17764a0c118c8856a035bb3d27766969humper@google.com/*
27af56bee17764a0c118c8856a035bb3d27766969humper@google.com * Copyright 2013 Google, Inc.
37af56bee17764a0c118c8856a035bb3d27766969humper@google.com *
47af56bee17764a0c118c8856a035bb3d27766969humper@google.com * Use of this source code is governed by a BSD-style license that can be
57af56bee17764a0c118c8856a035bb3d27766969humper@google.com * found in the LICENSE file.
67af56bee17764a0c118c8856a035bb3d27766969humper@google.com */
77af56bee17764a0c118c8856a035bb3d27766969humper@google.com
87af56bee17764a0c118c8856a035bb3d27766969humper@google.com
97af56bee17764a0c118c8856a035bb3d27766969humper@google.com#ifndef SkRTConf_DEFINED
107af56bee17764a0c118c8856a035bb3d27766969humper@google.com#define SkRTConf_DEFINED
117af56bee17764a0c118c8856a035bb3d27766969humper@google.com
127af56bee17764a0c118c8856a035bb3d27766969humper@google.com#include "SkString.h"
137af56bee17764a0c118c8856a035bb3d27766969humper@google.com#include "SkStream.h"
147af56bee17764a0c118c8856a035bb3d27766969humper@google.com
157af56bee17764a0c118c8856a035bb3d27766969humper@google.com#include "SkTDict.h"
167af56bee17764a0c118c8856a035bb3d27766969humper@google.com#include "SkTArray.h"
177af56bee17764a0c118c8856a035bb3d27766969humper@google.com
187af56bee17764a0c118c8856a035bb3d27766969humper@google.com/** \class SkRTConfBase
197af56bee17764a0c118c8856a035bb3d27766969humper@google.com    Non-templated base class for the runtime configs
207af56bee17764a0c118c8856a035bb3d27766969humper@google.com*/
217af56bee17764a0c118c8856a035bb3d27766969humper@google.com
227af56bee17764a0c118c8856a035bb3d27766969humper@google.comclass SkRTConfBase {
237af56bee17764a0c118c8856a035bb3d27766969humper@google.compublic:
247af56bee17764a0c118c8856a035bb3d27766969humper@google.com    SkRTConfBase(const char *name) : fName(name) {}
257af56bee17764a0c118c8856a035bb3d27766969humper@google.com    virtual ~SkRTConfBase() {}
267af56bee17764a0c118c8856a035bb3d27766969humper@google.com    virtual const char *getName() const { return fName.c_str(); }
277af56bee17764a0c118c8856a035bb3d27766969humper@google.com    virtual bool isDefault() const = 0;
287af56bee17764a0c118c8856a035bb3d27766969humper@google.com    virtual void print(SkWStream *o) const = 0;
297af56bee17764a0c118c8856a035bb3d27766969humper@google.com    virtual bool equals(const SkRTConfBase *conf) const = 0;
307af56bee17764a0c118c8856a035bb3d27766969humper@google.comprotected:
317af56bee17764a0c118c8856a035bb3d27766969humper@google.com    SkString fName;
327af56bee17764a0c118c8856a035bb3d27766969humper@google.com};
337af56bee17764a0c118c8856a035bb3d27766969humper@google.com
347af56bee17764a0c118c8856a035bb3d27766969humper@google.com/** \class SkRTConf
357af56bee17764a0c118c8856a035bb3d27766969humper@google.com    A class to provide runtime configurability.
367af56bee17764a0c118c8856a035bb3d27766969humper@google.com*/
377af56bee17764a0c118c8856a035bb3d27766969humper@google.comtemplate<typename T> class SkRTConf: public SkRTConfBase {
387af56bee17764a0c118c8856a035bb3d27766969humper@google.compublic:
397af56bee17764a0c118c8856a035bb3d27766969humper@google.com    SkRTConf(const char *name, const T &defaultValue, const char *description);
407af56bee17764a0c118c8856a035bb3d27766969humper@google.com    operator const T&() const { return fValue; }
417af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void print(SkWStream *o) const;
427af56bee17764a0c118c8856a035bb3d27766969humper@google.com    bool equals(const SkRTConfBase *conf) const;
437af56bee17764a0c118c8856a035bb3d27766969humper@google.com    bool isDefault() const { return fDefault == fValue; }
447af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void set(const T& value) { fValue = value; }
457af56bee17764a0c118c8856a035bb3d27766969humper@google.comprotected:
467af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void doPrint(char *s) const;
47fb830981f2ec157674953650de6ddbf8723051a0skia.committer@gmail.com
48fb830981f2ec157674953650de6ddbf8723051a0skia.committer@gmail.com    T        fValue;
499b64cac7c8db2dce6759f551d3bab4192563d8c0humper@google.com    T        fDefault;
507af56bee17764a0c118c8856a035bb3d27766969humper@google.com    SkString fDescription;
517af56bee17764a0c118c8856a035bb3d27766969humper@google.com};
527af56bee17764a0c118c8856a035bb3d27766969humper@google.com
537af56bee17764a0c118c8856a035bb3d27766969humper@google.com#ifdef SK_DEVELOPER
547af56bee17764a0c118c8856a035bb3d27766969humper@google.com#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf<confType> varName(confName, defaultValue, description)
551f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com#define SK_CONF_SET(confname, value) \
561f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com    skRTConfRegistry().set(confname, value, true)
571f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com/* SK_CONF_TRY_SET() is like SK_CONF_SET(), but doesn't complain if
581f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com   confname can't be found.  This is useful if the SK_CONF_DECLARE is
591f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com   inside a source file whose linkage is dependent on the system. */
601f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com#define SK_CONF_TRY_SET(confname, value) \
611f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com    skRTConfRegistry().set(confname, value, false)
627af56bee17764a0c118c8856a035bb3d27766969humper@google.com#else
63807863839fd5fb9a3fac603241515863dc0790c0humper@google.com#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static confType varName = defaultValue
647af56bee17764a0c118c8856a035bb3d27766969humper@google.com#define SK_CONF_SET(confname, value) (void) confname, (void) value
651f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com#define SK_CONF_TRY_SET(confname, value) (void) confname, (void) value
667af56bee17764a0c118c8856a035bb3d27766969humper@google.com#endif
677af56bee17764a0c118c8856a035bb3d27766969humper@google.com
687af56bee17764a0c118c8856a035bb3d27766969humper@google.com/** \class SkRTConfRegistry
697af56bee17764a0c118c8856a035bb3d27766969humper@google.com    A class that maintains a systemwide registry of all runtime configuration
707af56bee17764a0c118c8856a035bb3d27766969humper@google.com    parameters.  Mainly used for printing them out and handling multiply-defined
717af56bee17764a0c118c8856a035bb3d27766969humper@google.com    knobs.
727af56bee17764a0c118c8856a035bb3d27766969humper@google.com*/
737af56bee17764a0c118c8856a035bb3d27766969humper@google.com
747af56bee17764a0c118c8856a035bb3d27766969humper@google.comclass SkRTConfRegistry {
757af56bee17764a0c118c8856a035bb3d27766969humper@google.compublic:
767af56bee17764a0c118c8856a035bb3d27766969humper@google.com    SkRTConfRegistry();
77bf6a6d45043393f8cd9c942d7f03b789fe2c94b3commit-bot@chromium.org    ~SkRTConfRegistry();
787af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void printAll(const char *fname = NULL) const;
792d1adf2322b026ec746dbdd931ca6aac7bb5d4cbhalcanary@google.com    bool hasNonDefault() const;
807af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void printNonDefault(const char *fname = NULL) const;
817af56bee17764a0c118c8856a035bb3d27766969humper@google.com    const char *configFileLocation() const;
827af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void possiblyDumpFile() const;
837af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void validate() const;
841f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com    template <typename T> void set(const char *confname,
851f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com                                   T value,
861f0121af495e5a70ecff2521729b7749c81a20b2halcanary@google.com                                   bool warnIfNotFound = true);
87c1bf2de83549406de305e174af2b88630fdc3098commit-bot@chromium.org#ifdef SK_SUPPORT_UNITTEST
88c1bf2de83549406de305e174af2b88630fdc3098commit-bot@chromium.org    static void UnitTest();
89c1bf2de83549406de305e174af2b88630fdc3098commit-bot@chromium.org#endif
907af56bee17764a0c118c8856a035bb3d27766969humper@google.comprivate:
917af56bee17764a0c118c8856a035bb3d27766969humper@google.com    template<typename T> friend class SkRTConf;
927fc0e0a75a99ac5ea2e5d03ab3a00cacabacfa09skia.committer@gmail.com
937af56bee17764a0c118c8856a035bb3d27766969humper@google.com    void registerConf(SkRTConfBase *conf);
947af56bee17764a0c118c8856a035bb3d27766969humper@google.com    template <typename T> bool parse(const char *name, T* value);
957fc0e0a75a99ac5ea2e5d03ab3a00cacabacfa09skia.committer@gmail.com
967af56bee17764a0c118c8856a035bb3d27766969humper@google.com    SkTDArray<SkString *> fConfigFileKeys, fConfigFileValues;
977af56bee17764a0c118c8856a035bb3d27766969humper@google.com    typedef SkTDict< SkTDArray<SkRTConfBase *> * > ConfMap;
987af56bee17764a0c118c8856a035bb3d27766969humper@google.com    ConfMap fConfs;
99c1bf2de83549406de305e174af2b88630fdc3098commit-bot@chromium.org#ifdef SK_SUPPORT_UNITTEST
100c1bf2de83549406de305e174af2b88630fdc3098commit-bot@chromium.org    SkRTConfRegistry(bool);
101c1bf2de83549406de305e174af2b88630fdc3098commit-bot@chromium.org#endif
1027af56bee17764a0c118c8856a035bb3d27766969humper@google.com};
1037af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1047af56bee17764a0c118c8856a035bb3d27766969humper@google.com// our singleton registry
1057af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1067af56bee17764a0c118c8856a035bb3d27766969humper@google.comSkRTConfRegistry &skRTConfRegistry();
1077af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1087af56bee17764a0c118c8856a035bb3d27766969humper@google.comtemplate<typename T>
1097af56bee17764a0c118c8856a035bb3d27766969humper@google.comSkRTConf<T>::SkRTConf(const char *name, const T &defaultValue, const char *description)
1107af56bee17764a0c118c8856a035bb3d27766969humper@google.com    : SkRTConfBase(name)
1117af56bee17764a0c118c8856a035bb3d27766969humper@google.com    , fValue(defaultValue)
1127af56bee17764a0c118c8856a035bb3d27766969humper@google.com    , fDefault(defaultValue)
1137af56bee17764a0c118c8856a035bb3d27766969humper@google.com    , fDescription(description) {
1147fc0e0a75a99ac5ea2e5d03ab3a00cacabacfa09skia.committer@gmail.com
1157af56bee17764a0c118c8856a035bb3d27766969humper@google.com    T value;
1167af56bee17764a0c118c8856a035bb3d27766969humper@google.com    if (skRTConfRegistry().parse(fName.c_str(), &value)) {
1177af56bee17764a0c118c8856a035bb3d27766969humper@google.com        fValue = value;
1187af56bee17764a0c118c8856a035bb3d27766969humper@google.com    }
1197af56bee17764a0c118c8856a035bb3d27766969humper@google.com    skRTConfRegistry().registerConf(this);
1207af56bee17764a0c118c8856a035bb3d27766969humper@google.com}
1217af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1227af56bee17764a0c118c8856a035bb3d27766969humper@google.comtemplate<typename T>
1237af56bee17764a0c118c8856a035bb3d27766969humper@google.comvoid SkRTConf<T>::print(SkWStream *o) const {
1247af56bee17764a0c118c8856a035bb3d27766969humper@google.com    char outline[200]; // should be ok because we specify a max. width for everything here.
125bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com    char *outptr;
126bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com    if (strlen(getName()) >= 30) {
127bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com        o->writeText(getName());
128bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com        o->writeText(" ");
129bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com        outptr = &(outline[0]);
130bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com    } else {
131bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com        sprintf(outline, "%-30.30s", getName());
132bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com        outptr = &(outline[30]);
133bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com    }
134fbc58a305518fe611113a51649bf557c991ac8cfskia.committer@gmail.com
135bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com    doPrint(outptr);
136bdecb68a2bc6e6a04cf446f1e75731bac2f8446bhumper@google.com    sprintf(outptr+30, " %.128s", fDescription.c_str());
137ffe95f541437f75bab0c4e3e656cf492e7ed29f0bungeman@google.com    for (size_t i = strlen(outline); i --> 0 && ' ' == outline[i];) {
138ffe95f541437f75bab0c4e3e656cf492e7ed29f0bungeman@google.com        outline[i] = '\0';
1397af56bee17764a0c118c8856a035bb3d27766969humper@google.com    }
1407af56bee17764a0c118c8856a035bb3d27766969humper@google.com    o->writeText(outline);
1417af56bee17764a0c118c8856a035bb3d27766969humper@google.com}
1427af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1437af56bee17764a0c118c8856a035bb3d27766969humper@google.comtemplate<typename T>
1447af56bee17764a0c118c8856a035bb3d27766969humper@google.comvoid SkRTConf<T>::doPrint(char *s) const {
1457af56bee17764a0c118c8856a035bb3d27766969humper@google.com    sprintf(s, "%-30.30s", "How do I print myself??");
1467af56bee17764a0c118c8856a035bb3d27766969humper@google.com}
1477af56bee17764a0c118c8856a035bb3d27766969humper@google.com
148810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.comtemplate<> inline void SkRTConf<bool>::doPrint(char *s) const {
149810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    char tmp[30];
150810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false");
151810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(s, "%-30.30s", tmp);
152810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com}
153810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com
154810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.comtemplate<> inline void SkRTConf<int>::doPrint(char *s) const {
155810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    char tmp[30];
156810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(tmp, "%d # [%d]", fValue, fDefault);
157810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(s, "%-30.30s", tmp);
158810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com}
159810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com
160810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.comtemplate<> inline void SkRTConf<unsigned int>::doPrint(char *s) const {
161810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    char tmp[30];
162810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(tmp, "%u # [%u]", fValue, fDefault);
163810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(s, "%-30.30s", tmp);
164810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com}
165810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com
166810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.comtemplate<> inline void SkRTConf<float>::doPrint(char *s) const {
167810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    char tmp[30];
168810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
169810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(s, "%-30.30s", tmp);
170810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com}
171810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com
172810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.comtemplate<> inline void SkRTConf<double>::doPrint(char *s) const {
173810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    char tmp[30];
174810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
175810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(s, "%-30.30s", tmp);
176810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com}
177810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com
178810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.comtemplate<> inline void SkRTConf<const char *>::doPrint(char *s) const {
179810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    char tmp[30];
180810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(tmp, "%s # [%s]", fValue, fDefault);
181810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com    sprintf(s, "%-30.30s", tmp);
182810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com}
183810ae48f82f82d6e7fc4cf78d7a5a69e3cf9f2edhumper@google.com
1847af56bee17764a0c118c8856a035bb3d27766969humper@google.comtemplate<typename T>
1857af56bee17764a0c118c8856a035bb3d27766969humper@google.combool SkRTConf<T>::equals(const SkRTConfBase *conf) const {
1866d29eda49129893d8f5e385bfbe8473af154b82bhumper@google.com    // static_cast here is okay because there's only one kind of child class.
1876d29eda49129893d8f5e385bfbe8473af154b82bhumper@google.com    const SkRTConf<T> *child_pointer = static_cast<const SkRTConf<T> *>(conf);
1887fc0e0a75a99ac5ea2e5d03ab3a00cacabacfa09skia.committer@gmail.com    return child_pointer &&
1897af56bee17764a0c118c8856a035bb3d27766969humper@google.com           fName == child_pointer->fName &&
1907af56bee17764a0c118c8856a035bb3d27766969humper@google.com           fDescription == child_pointer->fDescription &&
1917af56bee17764a0c118c8856a035bb3d27766969humper@google.com           fValue == child_pointer->fValue &&
1927af56bee17764a0c118c8856a035bb3d27766969humper@google.com           fDefault == child_pointer->fDefault;
1937af56bee17764a0c118c8856a035bb3d27766969humper@google.com}
1947af56bee17764a0c118c8856a035bb3d27766969humper@google.com
1957af56bee17764a0c118c8856a035bb3d27766969humper@google.com#endif
196