michael@0: /* michael@0: * Copyright 2013 Google, Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkRTConf_DEFINED michael@0: #define SkRTConf_DEFINED michael@0: michael@0: #include "SkString.h" michael@0: #include "SkStream.h" michael@0: michael@0: #include "SkTDict.h" michael@0: #include "SkTArray.h" michael@0: michael@0: /** \class SkRTConfBase michael@0: Non-templated base class for the runtime configs michael@0: */ michael@0: michael@0: class SkRTConfBase { michael@0: public: michael@0: SkRTConfBase(const char *name) : fName(name) {} michael@0: virtual ~SkRTConfBase() {} michael@0: virtual const char *getName() const { return fName.c_str(); } michael@0: virtual bool isDefault() const = 0; michael@0: virtual void print(SkWStream *o) const = 0; michael@0: virtual bool equals(const SkRTConfBase *conf) const = 0; michael@0: protected: michael@0: SkString fName; michael@0: }; michael@0: michael@0: /** \class SkRTConf michael@0: A class to provide runtime configurability. michael@0: */ michael@0: template class SkRTConf: public SkRTConfBase { michael@0: public: michael@0: SkRTConf(const char *name, const T &defaultValue, const char *description); michael@0: operator const T&() const { return fValue; } michael@0: void print(SkWStream *o) const; michael@0: bool equals(const SkRTConfBase *conf) const; michael@0: bool isDefault() const { return fDefault == fValue; } michael@0: void set(const T& value) { fValue = value; } michael@0: protected: michael@0: void doPrint(char *s) const; michael@0: michael@0: T fValue; michael@0: T fDefault; michael@0: SkString fDescription; michael@0: }; michael@0: michael@0: #ifdef SK_DEVELOPER michael@0: #define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf varName(confName, defaultValue, description) michael@0: #define SK_CONF_SET(confname, value) \ michael@0: skRTConfRegistry().set(confname, value, true) michael@0: /* SK_CONF_TRY_SET() is like SK_CONF_SET(), but doesn't complain if michael@0: confname can't be found. This is useful if the SK_CONF_DECLARE is michael@0: inside a source file whose linkage is dependent on the system. */ michael@0: #define SK_CONF_TRY_SET(confname, value) \ michael@0: skRTConfRegistry().set(confname, value, false) michael@0: #else michael@0: #define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static confType varName = defaultValue michael@0: #define SK_CONF_SET(confname, value) (void) confname, (void) value michael@0: #define SK_CONF_TRY_SET(confname, value) (void) confname, (void) value michael@0: #endif michael@0: michael@0: /** \class SkRTConfRegistry michael@0: A class that maintains a systemwide registry of all runtime configuration michael@0: parameters. Mainly used for printing them out and handling multiply-defined michael@0: knobs. michael@0: */ michael@0: michael@0: class SkRTConfRegistry { michael@0: public: michael@0: SkRTConfRegistry(); michael@0: ~SkRTConfRegistry(); michael@0: void printAll(const char *fname = NULL) const; michael@0: bool hasNonDefault() const; michael@0: void printNonDefault(const char *fname = NULL) const; michael@0: const char *configFileLocation() const; michael@0: void possiblyDumpFile() const; michael@0: void validate() const; michael@0: template void set(const char *confname, michael@0: T value, michael@0: bool warnIfNotFound = true); michael@0: #ifdef SK_SUPPORT_UNITTEST michael@0: static void UnitTest(); michael@0: #endif michael@0: private: michael@0: template friend class SkRTConf; michael@0: michael@0: void registerConf(SkRTConfBase *conf); michael@0: template bool parse(const char *name, T* value); michael@0: michael@0: SkTDArray fConfigFileKeys, fConfigFileValues; michael@0: typedef SkTDict< SkTDArray * > ConfMap; michael@0: ConfMap fConfs; michael@0: #ifdef SK_SUPPORT_UNITTEST michael@0: SkRTConfRegistry(bool); michael@0: #endif michael@0: }; michael@0: michael@0: // our singleton registry michael@0: michael@0: SkRTConfRegistry &skRTConfRegistry(); michael@0: michael@0: template michael@0: SkRTConf::SkRTConf(const char *name, const T &defaultValue, const char *description) michael@0: : SkRTConfBase(name) michael@0: , fValue(defaultValue) michael@0: , fDefault(defaultValue) michael@0: , fDescription(description) { michael@0: michael@0: T value; michael@0: if (skRTConfRegistry().parse(fName.c_str(), &value)) { michael@0: fValue = value; michael@0: } michael@0: skRTConfRegistry().registerConf(this); michael@0: } michael@0: michael@0: template michael@0: void SkRTConf::print(SkWStream *o) const { michael@0: char outline[200]; // should be ok because we specify a max. width for everything here. michael@0: char *outptr; michael@0: if (strlen(getName()) >= 30) { michael@0: o->writeText(getName()); michael@0: o->writeText(" "); michael@0: outptr = &(outline[0]); michael@0: } else { michael@0: sprintf(outline, "%-30.30s", getName()); michael@0: outptr = &(outline[30]); michael@0: } michael@0: michael@0: doPrint(outptr); michael@0: sprintf(outptr+30, " %.128s", fDescription.c_str()); michael@0: for (size_t i = strlen(outline); i --> 0 && ' ' == outline[i];) { michael@0: outline[i] = '\0'; michael@0: } michael@0: o->writeText(outline); michael@0: } michael@0: michael@0: template michael@0: void SkRTConf::doPrint(char *s) const { michael@0: sprintf(s, "%-30.30s", "How do I print myself??"); michael@0: } michael@0: michael@0: template<> inline void SkRTConf::doPrint(char *s) const { michael@0: char tmp[30]; michael@0: sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false"); michael@0: sprintf(s, "%-30.30s", tmp); michael@0: } michael@0: michael@0: template<> inline void SkRTConf::doPrint(char *s) const { michael@0: char tmp[30]; michael@0: sprintf(tmp, "%d # [%d]", fValue, fDefault); michael@0: sprintf(s, "%-30.30s", tmp); michael@0: } michael@0: michael@0: template<> inline void SkRTConf::doPrint(char *s) const { michael@0: char tmp[30]; michael@0: sprintf(tmp, "%u # [%u]", fValue, fDefault); michael@0: sprintf(s, "%-30.30s", tmp); michael@0: } michael@0: michael@0: template<> inline void SkRTConf::doPrint(char *s) const { michael@0: char tmp[30]; michael@0: sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault); michael@0: sprintf(s, "%-30.30s", tmp); michael@0: } michael@0: michael@0: template<> inline void SkRTConf::doPrint(char *s) const { michael@0: char tmp[30]; michael@0: sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault); michael@0: sprintf(s, "%-30.30s", tmp); michael@0: } michael@0: michael@0: template<> inline void SkRTConf::doPrint(char *s) const { michael@0: char tmp[30]; michael@0: sprintf(tmp, "%s # [%s]", fValue, fDefault); michael@0: sprintf(s, "%-30.30s", tmp); michael@0: } michael@0: michael@0: template michael@0: bool SkRTConf::equals(const SkRTConfBase *conf) const { michael@0: // static_cast here is okay because there's only one kind of child class. michael@0: const SkRTConf *child_pointer = static_cast *>(conf); michael@0: return child_pointer && michael@0: fName == child_pointer->fName && michael@0: fDescription == child_pointer->fDescription && michael@0: fValue == child_pointer->fValue && michael@0: fDefault == child_pointer->fDefault; michael@0: } michael@0: michael@0: #endif