Add Inner method and support for wrapped Customizable (#8373)
Summary: Inner method added for classes to override to return has-a relationship. CheckedCast expanded to use Inner to return has-a relationship. Future Customizable classes (Env, FileSystem, Statistics, etc) will use this feature Pull Request resolved: https://github.com/facebook/rocksdb/pull/8373 Reviewed By: pdillinger Differential Revision: D29176369 Pulled By: mrambacher fbshipit-source-id: cfb6d7702fa365ca4e40c4a50a19e3a534e5ac43
This commit is contained in:
parent
ecccc63179
commit
d81c2d1e3d
@ -81,6 +81,9 @@ class Customizable : public Configurable {
|
||||
// potential names (e.g. "PosixEnv", "DefaultEnv") may also wish to override
|
||||
// this method.
|
||||
//
|
||||
// Note that IsInstanceOf only uses the "is-a" relationship and not "has-a".
|
||||
// Wrapped classes that have an Inner "has-a" should not be returned.
|
||||
//
|
||||
// @param name The name of the instance to find.
|
||||
// Returns true if the class is an instance of the input name.
|
||||
virtual bool IsInstanceOf(const std::string& name) const {
|
||||
@ -88,14 +91,19 @@ class Customizable : public Configurable {
|
||||
}
|
||||
|
||||
// Returns the named instance of the Customizable as a T*, or nullptr if not
|
||||
// found. This method uses IsInstanceOf to find the appropriate class instance
|
||||
// and then casts it to the expected return type.
|
||||
// found. This method uses IsInstanceOf/Inner to find the appropriate class
|
||||
// instance and then casts it to the expected return type.
|
||||
template <typename T>
|
||||
const T* CheckedCast() const {
|
||||
if (IsInstanceOf(T::kClassName())) {
|
||||
return static_cast<const T*>(this);
|
||||
} else {
|
||||
return nullptr;
|
||||
const auto inner = Inner();
|
||||
if (inner != nullptr) {
|
||||
return inner->CheckedCast<T>();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +112,12 @@ class Customizable : public Configurable {
|
||||
if (IsInstanceOf(T::kClassName())) {
|
||||
return static_cast<T*>(this);
|
||||
} else {
|
||||
return nullptr;
|
||||
auto inner = const_cast<Customizable*>(Inner());
|
||||
if (inner != nullptr) {
|
||||
return inner->CheckedCast<T>();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,8 +137,13 @@ class Customizable : public Configurable {
|
||||
// @see Configurable::GetOption for more details
|
||||
Status GetOption(const ConfigOptions& config_options, const std::string& name,
|
||||
std::string* value) const override;
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
// Returns the inner class when a Customizable implements a has-a (wrapped)
|
||||
// relationship. Derived classes that implement a has-a must override this
|
||||
// method in order to get CheckedCast to function properly.
|
||||
virtual const Customizable* Inner() const { return nullptr; }
|
||||
|
||||
protected:
|
||||
// Given a name (e.g. rocksdb.my.type.opt), returns the short name (opt)
|
||||
std::string GetOptionName(const std::string& long_name) const override;
|
||||
|
@ -505,6 +505,70 @@ static std::unordered_map<std::string, OptionTypeInfo> inner_option_info = {
|
||||
#endif // ROCKSDB_LITE
|
||||
};
|
||||
|
||||
class InnerCustomizable : public Customizable {
|
||||
public:
|
||||
explicit InnerCustomizable(const std::shared_ptr<Customizable>& w)
|
||||
: inner_(w) {}
|
||||
static const char* kClassName() { return "Inner"; }
|
||||
bool IsInstanceOf(const std::string& name) const override {
|
||||
if (name == kClassName()) {
|
||||
return true;
|
||||
} else {
|
||||
return Customizable::IsInstanceOf(name);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
const Customizable* Inner() const override { return inner_.get(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Customizable> inner_;
|
||||
};
|
||||
|
||||
class WrappedCustomizable1 : public InnerCustomizable {
|
||||
public:
|
||||
explicit WrappedCustomizable1(const std::shared_ptr<Customizable>& w)
|
||||
: InnerCustomizable(w) {}
|
||||
const char* Name() const override { return kClassName(); }
|
||||
static const char* kClassName() { return "Wrapped1"; }
|
||||
};
|
||||
|
||||
class WrappedCustomizable2 : public InnerCustomizable {
|
||||
public:
|
||||
explicit WrappedCustomizable2(const std::shared_ptr<Customizable>& w)
|
||||
: InnerCustomizable(w) {}
|
||||
const char* Name() const override { return kClassName(); }
|
||||
static const char* kClassName() { return "Wrapped2"; }
|
||||
};
|
||||
|
||||
TEST_F(CustomizableTest, WrappedInnerTest) {
|
||||
std::shared_ptr<TestCustomizable> ac =
|
||||
std::make_shared<TestCustomizable>("A");
|
||||
|
||||
ASSERT_TRUE(ac->IsInstanceOf("A"));
|
||||
ASSERT_TRUE(ac->IsInstanceOf("TestCustomizable"));
|
||||
ASSERT_EQ(ac->CheckedCast<TestCustomizable>(), ac.get());
|
||||
ASSERT_EQ(ac->CheckedCast<InnerCustomizable>(), nullptr);
|
||||
ASSERT_EQ(ac->CheckedCast<WrappedCustomizable1>(), nullptr);
|
||||
ASSERT_EQ(ac->CheckedCast<WrappedCustomizable2>(), nullptr);
|
||||
std::shared_ptr<Customizable> wc1 =
|
||||
std::make_shared<WrappedCustomizable1>(ac);
|
||||
|
||||
ASSERT_TRUE(wc1->IsInstanceOf(WrappedCustomizable1::kClassName()));
|
||||
ASSERT_EQ(wc1->CheckedCast<WrappedCustomizable1>(), wc1.get());
|
||||
ASSERT_EQ(wc1->CheckedCast<WrappedCustomizable2>(), nullptr);
|
||||
ASSERT_EQ(wc1->CheckedCast<InnerCustomizable>(), wc1.get());
|
||||
ASSERT_EQ(wc1->CheckedCast<TestCustomizable>(), ac.get());
|
||||
|
||||
std::shared_ptr<Customizable> wc2 =
|
||||
std::make_shared<WrappedCustomizable2>(wc1);
|
||||
ASSERT_TRUE(wc2->IsInstanceOf(WrappedCustomizable2::kClassName()));
|
||||
ASSERT_EQ(wc2->CheckedCast<WrappedCustomizable2>(), wc2.get());
|
||||
ASSERT_EQ(wc2->CheckedCast<WrappedCustomizable1>(), wc1.get());
|
||||
ASSERT_EQ(wc2->CheckedCast<InnerCustomizable>(), wc2.get());
|
||||
ASSERT_EQ(wc2->CheckedCast<TestCustomizable>(), ac.get());
|
||||
}
|
||||
|
||||
class ShallowCustomizable : public Customizable {
|
||||
public:
|
||||
ShallowCustomizable() {
|
||||
|
Loading…
Reference in New Issue
Block a user