Commit dd2f2ef7 authored by Anton Likhtarov's avatar Anton Likhtarov Committed by Facebook Github Bot

folly::settings: simplify; define/declare split; Metadata

Summary:
- Let's enforce a single definition. Also makes the implementation much simpler.
- Collect all static info about a setting in a Metadata struct

Differential Revision: D7544210

fbshipit-source-id: d3f2ef617bd817d355a37e11fa9425b6a4259384
parent f09d03aa
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "Settings.h" #include <folly/experimental/settings/Settings.h>
#include <map> #include <map>
...@@ -23,74 +23,29 @@ namespace folly { ...@@ -23,74 +23,29 @@ namespace folly {
namespace settings { namespace settings {
namespace detail { namespace detail {
namespace { namespace {
class Signature { using SettingsMap = std::map<std::string, SettingCoreBase*>;
public:
Signature(
const std::type_info& type,
std::string defaultString,
std::string desc,
bool unique)
: type_(type),
defaultString_(std::move(defaultString)),
desc_(std::move(desc)),
unique_(unique) {}
bool operator==(const Signature& other) const {
/* unique_ field is ignored on purpose */
return type_ == other.type_ && defaultString_ == other.defaultString_ &&
desc_ == other.desc_;
}
bool unique() const {
return unique_;
}
private:
std::type_index type_;
std::string defaultString_;
std::string desc_;
bool unique_;
};
using SettingsMap = std::
map<std::string, std::pair<Signature, std::shared_ptr<SettingCoreBase>>>;
Synchronized<SettingsMap>& settingsMap() { Synchronized<SettingsMap>& settingsMap() {
static Indestructible<Synchronized<SettingsMap>> map; static Indestructible<Synchronized<SettingsMap>> map;
return *map; return *map;
} }
} // namespace } // namespace
std::shared_ptr<SettingCoreBase> registerImpl( void registerSetting(SettingCoreBase& core) {
StringPiece project, if (core.meta().project.empty() ||
StringPiece name, core.meta().project.find('_') != std::string::npos) {
const std::type_info& type,
StringPiece defaultString,
StringPiece desc,
bool unique,
std::shared_ptr<SettingCoreBase> base) {
if (project.empty() || project.find('_') != std::string::npos) {
throw std::logic_error( throw std::logic_error(
"Setting project must be nonempty and cannot contain underscores: " + "Setting project must be nonempty and cannot contain underscores: " +
project.str()); core.meta().project.str());
} }
auto fullname = project.str() + "_" + name.str(); auto fullname = core.meta().project.str() + "_" + core.meta().name.str();
Signature sig(type, defaultString.str(), desc.str(), unique);
auto mapPtr = settingsMap().wlock(); auto mapPtr = settingsMap().wlock();
auto it = mapPtr->find(fullname); auto it = mapPtr->find(fullname);
if (it != mapPtr->end()) { if (it != mapPtr->end()) {
if (it->second.first == sig) { throw std::logic_error("FOLLY_SETTING already exists: " + fullname);
if (unique || it->second.first.unique()) {
throw std::logic_error("FOLLY_SETTING not unique: " + fullname);
}
/* Identical SHARED setting in a different translation unit,
reuse it */
return it->second.second;
}
throw std::logic_error("Setting collision detected: " + fullname);
} }
mapPtr->emplace(std::move(fullname), std::make_pair(std::move(sig), base)); mapPtr->emplace(std::move(fullname), &core);
return base;
} }
} // namespace detail } // namespace detail
...@@ -104,7 +59,7 @@ bool setFromString( ...@@ -104,7 +59,7 @@ bool setFromString(
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return false; return false;
} }
it->second.second->setFromString(newValue, reason); it->second->setFromString(newValue, reason);
return true; return true;
} }
...@@ -115,7 +70,7 @@ Optional<std::pair<std::string, std::string>> getAsString( ...@@ -115,7 +70,7 @@ Optional<std::pair<std::string, std::string>> getAsString(
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return folly::none; return folly::none;
} }
return it->second.second->getAsString(); return it->second->getAsString();
} }
bool resetToDefault(StringPiece settingName) { bool resetToDefault(StringPiece settingName) {
...@@ -124,21 +79,20 @@ bool resetToDefault(StringPiece settingName) { ...@@ -124,21 +79,20 @@ bool resetToDefault(StringPiece settingName) {
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return false; return false;
} }
it->second.second->resetToDefault(); it->second->resetToDefault();
return true; return true;
} }
void forEachSetting( void forEachSetting(
const std::function< const std::function<void(const SettingMetadata&, StringPiece, StringPiece)>&
void(StringPiece, StringPiece, StringPiece, const std::type_info&)>&
func) { func) {
detail::SettingsMap map; detail::SettingsMap map;
/* Note that this won't hold the lock over the callback, which is /* Note that this won't hold the lock over the callback, which is
what we want since the user might call other settings:: APIs */ what we want since the user might call other settings:: APIs */
map = *detail::settingsMap().rlock(); map = *detail::settingsMap().rlock();
for (const auto& kv : map) { for (const auto& kv : map) {
auto value = kv.second.second->getAsString(); auto value = kv.second->getAsString();
func(kv.first, value.first, value.second, kv.second.second->typeId()); func(kv.second->meta(), value.first, value.second);
} }
} }
......
...@@ -18,128 +18,141 @@ ...@@ -18,128 +18,141 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include <folly/Indestructible.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/experimental/settings/detail/SettingsImpl.h> #include <folly/experimental/settings/detail/SettingsImpl.h>
namespace folly { namespace folly {
namespace settings { namespace settings {
namespace detail {
template <class SettingMeta> /**
class SettingHandle { * Static information about the setting definition
public: */
struct SettingMetadata {
/**
* Project string.
*/
folly::StringPiece project;
/**
* Setting name within the project.
*/
folly::StringPiece name;
/** /**
* Setting type * String representation of the type.
*/ */
using Type = typename SettingMeta::Type; folly::StringPiece typeStr;
/** /**
* Returns the setting's current value. * typeid() of the type.
* Note that the returned reference is not guaranteed to be long-lived */
* and should not be saved anywhere. const std::type_info& typeId;
/**
* String representation of the default value.
* (note: string literal default values will be stringified with quotes)
*/
folly::StringPiece defaultStr;
/**
* Setting description field.
*/
folly::StringPiece description;
};
namespace detail {
template <class Type>
class Setting {
public:
/**
* Returns the setting's current value. Note that the returned
* reference is not guaranteed to be long-lived and should not be
* saved anywhere. In particular, a set() call might invalidate a
* reference obtained here after some amount of time (on the order
* of minutes).
*/ */
const Type& operator*() const { const Type& operator*() const {
return core().get(); return core_.get();
} }
const Type* operator->() const { const Type* operator->() const {
return &core().get(); return &core_.get();
} }
/** /**
* Atomically updates the setting's current value. * Atomically updates the setting's current value. Will invalidate
* any previous calls to operator*() after some amount of time (on
* the order of minutes).
*
* @param reason Will be stored with the current value, useful for debugging. * @param reason Will be stored with the current value, useful for debugging.
*/ */
static void set(const Type& t, folly::StringPiece reason = "api") { void set(const Type& t, StringPiece reason = "api") {
core().set(t, reason); core_.set(t, reason);
} }
SettingHandle() { Setting(SettingMetadata meta, Type defaultValue)
/* Ensure setting is registered */ : meta_(std::move(meta)), core_(meta_, std::move(defaultValue)) {}
core();
}
private: private:
static SettingCore<SettingMeta>& core() { SettingMetadata meta_;
static /* library-local */ SettingCore<Type> core_;
Indestructible<std::shared_ptr<SettingCoreBase>>
core = registerImpl(
SettingMeta::project(),
SettingMeta::name(),
typeid(typename SettingMeta::Type),
SettingMeta::defaultString(),
SettingMeta::desc(),
SettingMeta::unique(),
std::make_shared<SettingCore<SettingMeta>>());
return static_cast<SettingCore<SettingMeta>&>(**core);
}
}; };
} // namespace detail } // namespace detail
#define FOLLY_SETTING_IMPL(_project, _Type, _name, _def, _desc, _unique) \
namespace { \
struct FOLLY_SETTINGS_META__##_project##_##_name { \
using Type = _Type; \
static folly::StringPiece project() { \
return #_project; \
} \
static folly::StringPiece name() { \
return #_name; \
} \
static Type def() { \
return _def; \
} \
static folly::StringPiece defaultString() { \
return #_def; \
} \
static folly::StringPiece desc() { \
return _desc; \
} \
static bool unique() { \
return _unique; \
} \
}; \
folly::settings::detail::SettingHandle< \
FOLLY_SETTINGS_META__##_project##_##_name> \
SETTING_##_project##_##_name; \
} \
/* hack to require a trailing semicolon */ \
int FOLLY_SETTINGS_IGNORE__##_project##_##_name()
/** /**
* Defines a setting. * Defines a setting.
* *
* FOLLY_SETTING_SHARED(): syntactically, think of it like a class * FOLLY_SETTING_DEFINE() can only be placed in a single translation unit
* definition. You can place the identical setting definitions in
* distinct translation units, but not in the same translation unit.
* In particular, you can place a setting definition in a header file
* and include it from multiple .cpp files - all of these definitions
* will refer to a single setting.
*
* FOLLY_SETTING() variant can only be placed in a single translation unit
* and will be checked against accidental collisions. * and will be checked against accidental collisions.
* *
* The setting API can be accessed via SETTING_project_name::<api_func>() and * The setting API can be accessed via FOLLY_SETTING(project, name).<api_func>()
* is documented in the SettingHandle class. * and is documented in the Setting class.
* *
* While the specific SETTING_project_name classes are declared * All settings for a common namespace; (project, name) must be unique
* inplace and are namespace local, all settings for a given project * for the whole program. Collisions are verified at runtime on
* share a common namespace and collisions are verified at runtime on
* program startup. * program startup.
* *
* @param _project Project identifier, can only contain [a-zA-Z0-9] * @param _project Project identifier, can only contain [a-zA-Z0-9]
* @param _Type setting value type
* @param _name setting name within the project, can only contain [_a-zA-Z0-9]. * @param _name setting name within the project, can only contain [_a-zA-Z0-9].
* The string "<project>_<name>" must be unique for the whole program. * The string "<project>_<name>" must be unique for the whole program.
* @param _Type setting value type
* @param _def default value for the setting * @param _def default value for the setting
* @param _desc setting documentation * @param _desc setting documentation
*/ */
#define FOLLY_SETTING(_project, _Type, _name, _def, _desc) \ #define FOLLY_SETTING_DEFINE(_project, _name, _Type, _def, _desc) \
FOLLY_SETTING_IMPL(_project, _Type, _name, _def, _desc, /* unique */ true) /* Meyers singleton to avoid SIOF */ \
#define FOLLY_SETTING_SHARED(_project, _Type, _name, _def, _desc) \ inline folly::settings::detail::Setting<_Type>& \
FOLLY_SETTING_IMPL(_project, _Type, _name, _def, _desc, /* unique */ false) FOLLY_SETTINGS_FUNC__##_project##_##_name() { \
static folly::Indestructible<folly::settings::detail::Setting<_Type>> \
setting( \
folly::settings::SettingMetadata{ \
#_project, #_name, #_Type, typeid(_Type), #_def, _desc}, \
_def); \
return *setting; \
} \
/* Ensure the setting is registered even if not used in program */ \
auto& FOLLY_SETTINGS_INIT__##_project##_##_name = \
FOLLY_SETTINGS_FUNC__##_project##_##_name()
/**
* Declares a setting that's defined elsewhere.
*/
#define FOLLY_SETTING_DECLARE(_project, _name, _Type) \
folly::settings::detail::Setting<_Type>& \
FOLLY_SETTINGS_FUNC__##_project##_##_name()
/**
* Accesses a defined setting.
* Rationale for the macro:
* 1) Searchability, all settings access is done via FOLLY_SETTING(...)
* 2) Prevents omitting trailing () by accident, which could
* lead to bugs like `auto value = *FOLLY_SETTING_project_name;`,
* which compiles but dereferences the function pointer instead of
* the setting itself.
*/
#define FOLLY_SETTING(_project, _name) \
FOLLY_SETTINGS_FUNC__##_project##_##_name()
/** /**
* Look up a setting by name, and update the value from a string representation. * Look up a setting by name, and update the value from a string representation.
...@@ -170,13 +183,12 @@ bool resetToDefault(folly::StringPiece settingName); ...@@ -170,13 +183,12 @@ bool resetToDefault(folly::StringPiece settingName);
/** /**
* Iterates over all known settings and calls * Iterates over all known settings and calls
* func(name, to<string>(value), reason, typeid(Type)) for each. * func(meta, to<string>(value), reason) for each.
*/ */
void forEachSetting(const std::function<void( void forEachSetting(
folly::StringPiece, const std::function<
folly::StringPiece, void(const SettingMetadata&, folly::StringPiece, folly::StringPiece)>&
folly::StringPiece, func);
const std::type_info&)>& func);
} // namespace settings } // namespace settings
} // namespace folly } // namespace folly
...@@ -24,9 +24,13 @@ ...@@ -24,9 +24,13 @@
#include <folly/Conv.h> #include <folly/Conv.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/SharedMutex.h> #include <folly/SharedMutex.h>
#include <folly/ThreadLocal.h>
namespace folly { namespace folly {
namespace settings { namespace settings {
struct SettingMetadata;
namespace detail { namespace detail {
template <class Type> template <class Type>
...@@ -44,23 +48,15 @@ class SettingCoreBase { ...@@ -44,23 +48,15 @@ class SettingCoreBase {
virtual void setFromString(StringPiece newValue, StringPiece reason) = 0; virtual void setFromString(StringPiece newValue, StringPiece reason) = 0;
virtual std::pair<std::string, std::string> getAsString() const = 0; virtual std::pair<std::string, std::string> getAsString() const = 0;
virtual void resetToDefault() = 0; virtual void resetToDefault() = 0;
virtual const std::type_info& typeId() const = 0; virtual const SettingMetadata& meta() const = 0;
virtual ~SettingCoreBase() {} virtual ~SettingCoreBase() {}
}; };
std::shared_ptr<SettingCoreBase> registerImpl( void registerSetting(SettingCoreBase& core);
StringPiece project,
StringPiece name,
const std::type_info& type,
StringPiece defaultString,
StringPiece desc,
bool unique,
std::shared_ptr<SettingCoreBase> base);
template <class SettingMeta> template <class Type>
class SettingCore : public SettingCoreBase { class SettingCore : public SettingCoreBase {
public: public:
using Type = typename SettingMeta::Type;
using Contents = SettingContents<Type>; using Contents = SettingContents<Type>;
void setFromString(StringPiece newValue, StringPiece reason) override { void setFromString(StringPiece newValue, StringPiece reason) override {
...@@ -72,10 +68,10 @@ class SettingCore : public SettingCoreBase { ...@@ -72,10 +68,10 @@ class SettingCore : public SettingCoreBase {
to<std::string>(contents.value), contents.updateReason); to<std::string>(contents.value), contents.updateReason);
} }
void resetToDefault() override { void resetToDefault() override {
set(SettingMeta::def(), "default"); set(defaultValue_, "default");
} }
const std::type_info& typeId() const override { const SettingMetadata& meta() const override {
return typeid(Type); return meta_;
} }
const Type& get() const { const Type& get() const {
...@@ -87,24 +83,34 @@ class SettingCore : public SettingCoreBase { ...@@ -87,24 +83,34 @@ class SettingCore : public SettingCoreBase {
++(*globalVersion_); ++(*globalVersion_);
} }
SettingCore() SettingCore(const SettingMetadata& meta, Type defaultValue)
: globalValue_( : meta_(meta),
std::make_shared<Contents>("default", SettingMeta::def())) {} defaultValue_(std::move(defaultValue)),
globalValue_(std::make_shared<Contents>("default", defaultValue_)),
~SettingCore() {} localValue_([]() {
return new CachelinePadded<
Indestructible<std::pair<size_t, std::shared_ptr<Contents>>>>(
0, nullptr);
}) {
registerSetting(*this);
}
private: private:
const SettingMetadata& meta_;
const Type defaultValue_;
SharedMutex globalLock_; SharedMutex globalLock_;
std::shared_ptr<Contents> globalValue_; std::shared_ptr<Contents> globalValue_;
/* Local versions start at 0, this will force a read on first local access. */ /* Local versions start at 0, this will force a read on first local access. */
CachelinePadded<std::atomic<size_t>> globalVersion_{1}; CachelinePadded<std::atomic<size_t>> globalVersion_{1};
ThreadLocal<CachelinePadded<
Indestructible<std::pair<size_t, std::shared_ptr<Contents>>>>>
localValue_;
std::shared_ptr<Contents>& tlValue() { std::shared_ptr<Contents>& tlValue() {
thread_local CachelinePadded< auto& value = ***localValue_;
Indestructible<std::pair<size_t, std::shared_ptr<Contents>>>>
localValue;
auto& value = **localValue;
while (value.first < *globalVersion_) { while (value.first < *globalVersion_) {
/* If this destroys the old value, do it without holding the lock */ /* If this destroys the old value, do it without holding the lock */
value.second.reset(); value.second.reset();
......
...@@ -26,11 +26,11 @@ settings_get_bench 1.73ns 577.36M ...@@ -26,11 +26,11 @@ settings_get_bench 1.73ns 577.36M
============================================================================ ============================================================================
*/ */
FOLLY_SETTING(follytest, int, benchmarked, 100, "desc"); FOLLY_SETTING_DEFINE(follytest, benchmarked, int, 100, "desc");
BENCHMARK(settings_get_bench, iters) { BENCHMARK(settings_get_bench, iters) {
for (unsigned int i = 0; i < iters; ++i) { for (unsigned int i = 0; i < iters; ++i) {
auto value = *SETTING_follytest_benchmarked; auto value = *FOLLY_SETTING(follytest, benchmarked);
folly::doNotOptimizeAway(value); folly::doNotOptimizeAway(value);
} }
} }
......
...@@ -21,55 +21,37 @@ ...@@ -21,55 +21,37 @@
#include "b.h" #include "b.h"
namespace some_ns { namespace some_ns {
FOLLY_SETTING(follytest, std::string, some_flag, "default", "Description"); FOLLY_SETTING_DEFINE(
FOLLY_SETTING(
follytest, follytest,
some_flag,
std::string, std::string,
"default",
"Description");
FOLLY_SETTING_DEFINE(
follytest,
unused, unused,
std::string,
"unused_default", "unused_default",
"Not used, but should still be in the list"); "Not used, but should still be in the list");
// Enable to test runtime collision checking logic // Enable to test runtime collision checking logic
#if 0 #if 0
FOLLY_SETTING(follytest, std::string, internal_flag_to_a, "collision_with_a", FOLLY_SETTING_DEFINE(follytest, internal_flag_to_a, std::string,
"Collision_with_a"); "collision_with_a",
"Collision_with_a");
#endif #endif
} // namespace some_ns } // namespace some_ns
TEST(Settings, basic) { TEST(Settings, basic) {
std::string allFlags;
folly::settings::forEachSetting([&allFlags](
folly::StringPiece name,
folly::StringPiece value,
folly::StringPiece reason,
const std::type_info& type) {
std::string typeName;
if (type == typeid(int)) {
typeName = "int";
} else if (type == typeid(std::string)) {
typeName = "std::string";
} else {
ASSERT_FALSE(true);
}
allFlags += folly::sformat("{} {} {} {}\n", name, value, reason, typeName);
});
EXPECT_EQ(
allFlags,
"follytest_internal_flag_to_a 789 default int\n"
"follytest_internal_flag_to_b test default std::string\n"
"follytest_public_flag_to_a 456 default int\n"
"follytest_public_flag_to_b basdf default std::string\n"
"follytest_some_flag default default std::string\n"
"follytest_unused unused_default default std::string\n");
EXPECT_EQ(a_ns::a_func(), 1245); EXPECT_EQ(a_ns::a_func(), 1245);
EXPECT_EQ(b_ns::b_func(), "testbasdf"); EXPECT_EQ(b_ns::b_func(), "testbasdf");
EXPECT_EQ(*some_ns::SETTING_follytest_some_flag, "default"); EXPECT_EQ(*some_ns::FOLLY_SETTING(follytest, some_flag), "default");
EXPECT_EQ( // Test -> API
std::string(some_ns::SETTING_follytest_some_flag->c_str()), "default"); EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, some_flag)->size(), 7);
a_ns::SETTING_follytest_public_flag_to_a.set(100); a_ns::FOLLY_SETTING(follytest, public_flag_to_a).set(100);
EXPECT_EQ(*a_ns::SETTING_follytest_public_flag_to_a, 100); EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 100);
EXPECT_EQ(a_ns::getRemote(), 100); EXPECT_EQ(a_ns::getRemote(), 100);
a_ns::setRemote(200); a_ns::setRemote(200);
EXPECT_EQ(*a_ns::SETTING_follytest_public_flag_to_a, 200); EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 200);
EXPECT_EQ(a_ns::getRemote(), 200); EXPECT_EQ(a_ns::getRemote(), 200);
auto res = folly::settings::getAsString("follytest_public_flag_to_a"); auto res = folly::settings::getAsString("follytest_public_flag_to_a");
...@@ -82,7 +64,7 @@ TEST(Settings, basic) { ...@@ -82,7 +64,7 @@ TEST(Settings, basic) {
EXPECT_TRUE(folly::settings::setFromString( EXPECT_TRUE(folly::settings::setFromString(
"follytest_public_flag_to_a", "300", "from_string")); "follytest_public_flag_to_a", "300", "from_string"));
EXPECT_EQ(*a_ns::SETTING_follytest_public_flag_to_a, 300); EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 300);
EXPECT_EQ(a_ns::getRemote(), 300); EXPECT_EQ(a_ns::getRemote(), 300);
res = folly::settings::getAsString("follytest_public_flag_to_a"); res = folly::settings::getAsString("follytest_public_flag_to_a");
EXPECT_TRUE(res.hasValue()); EXPECT_TRUE(res.hasValue());
...@@ -92,8 +74,40 @@ TEST(Settings, basic) { ...@@ -92,8 +74,40 @@ TEST(Settings, basic) {
EXPECT_FALSE(folly::settings::setFromString( EXPECT_FALSE(folly::settings::setFromString(
"follytest_nonexisting", "300", "from_string")); "follytest_nonexisting", "300", "from_string"));
std::string allFlags;
folly::settings::forEachSetting(
[&allFlags](
const folly::settings::SettingMetadata& meta,
folly::StringPiece value,
folly::StringPiece reason) {
if (meta.typeId == typeid(int)) {
EXPECT_EQ(meta.typeStr, "int");
} else if (meta.typeId == typeid(std::string)) {
EXPECT_EQ(meta.typeStr, "std::string");
} else {
ASSERT_FALSE(true);
}
allFlags += folly::sformat(
"{}/{}/{}/{}/{}/{}/{}\n",
meta.project,
meta.name,
meta.typeStr,
meta.defaultStr,
meta.description,
value,
reason);
});
EXPECT_EQ(
allFlags,
"follytest/internal_flag_to_a/int/789/Desc of int/789/default\n"
"follytest/internal_flag_to_b/std::string/\"test\"/Desc of str/test/default\n"
"follytest/public_flag_to_a/int/456/Public flag to a/300/from_string\n"
"follytest/public_flag_to_b/std::string/\"basdf\"/Public flag to b/basdf/default\n"
"follytest/some_flag/std::string/\"default\"/Description/default/default\n"
"follytest/unused/std::string/\"unused_default\"/Not used, but should still be in the list/unused_default/default\n");
EXPECT_TRUE(folly::settings::resetToDefault("follytest_public_flag_to_a")); EXPECT_TRUE(folly::settings::resetToDefault("follytest_public_flag_to_a"));
EXPECT_EQ(*a_ns::SETTING_follytest_public_flag_to_a, 456); EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 456);
EXPECT_EQ(a_ns::getRemote(), 456); EXPECT_EQ(a_ns::getRemote(), 456);
EXPECT_FALSE(folly::settings::resetToDefault("follytest_nonexisting")); EXPECT_FALSE(folly::settings::resetToDefault("follytest_nonexisting"));
......
...@@ -18,21 +18,22 @@ ...@@ -18,21 +18,22 @@
#include <folly/experimental/settings/Settings.h> #include <folly/experimental/settings/Settings.h>
namespace a_ns { namespace a_ns {
FOLLY_SETTING_DEFINE(follytest, public_flag_to_a, int, 456, "Public flag to a");
namespace { namespace {
FOLLY_SETTING(follytest, int, internal_flag_to_a, 789, "Desc of int"); FOLLY_SETTING_DEFINE(follytest, internal_flag_to_a, int, 789, "Desc of int");
} }
int a_func() { int a_func() {
return *SETTING_follytest_public_flag_to_a + return *FOLLY_SETTING(follytest, public_flag_to_a) +
*SETTING_follytest_internal_flag_to_a; *FOLLY_SETTING(follytest, internal_flag_to_a);
} }
void setRemote(int value) { void setRemote(int value) {
SETTING_follytest_public_flag_to_a.set(value, "remote_set"); FOLLY_SETTING(follytest, public_flag_to_a).set(value, "remote_set");
} }
int getRemote() { int getRemote() {
return *SETTING_follytest_public_flag_to_a; return *FOLLY_SETTING(follytest, public_flag_to_a);
} }
} // namespace a_ns } // namespace a_ns
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
namespace a_ns { namespace a_ns {
FOLLY_SETTING_SHARED(follytest, int, public_flag_to_a, 456, "Public flag to a"); FOLLY_SETTING_DECLARE(follytest, public_flag_to_a, int);
int a_func(); int a_func();
void setRemote(int value); void setRemote(int value);
......
...@@ -18,18 +18,26 @@ ...@@ -18,18 +18,26 @@
#include <folly/experimental/settings/Settings.h> #include <folly/experimental/settings/Settings.h>
namespace b_ns { namespace b_ns {
namespace {
FOLLY_SETTING( FOLLY_SETTING_DEFINE(
follytest, follytest,
public_flag_to_b,
std::string, std::string,
"basdf",
"Public flag to b");
namespace {
FOLLY_SETTING_DEFINE(
follytest,
internal_flag_to_b, internal_flag_to_b,
std::string,
"test", "test",
"Desc of str"); "Desc of str");
} }
std::string b_func() { std::string b_func() {
return *SETTING_follytest_internal_flag_to_b + return *FOLLY_SETTING(follytest, internal_flag_to_b) +
*SETTING_follytest_public_flag_to_b; *FOLLY_SETTING(follytest, public_flag_to_b);
} }
} // namespace b_ns } // namespace b_ns
...@@ -19,12 +19,7 @@ ...@@ -19,12 +19,7 @@
namespace b_ns { namespace b_ns {
FOLLY_SETTING_SHARED( FOLLY_SETTING_DECLARE(follytest, public_flag_to_b, std::string);
follytest,
std::string,
public_flag_to_b,
"basdf",
"Public flag to b");
std::string b_func(); std::string b_func();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment