Commit eeaef4a2 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

make the template part of the unique-instance key

Summary: So that it is possible to have both `Foo<K0, K1, X, Y>` and `Bar<K0, K1, A, B>` where both `Foo` and `Bar` use `UniqueInstance`.

Differential Revision: D27600228

fbshipit-source-id: a5d58726ea0009d7a45c0234f9cff723662a4604
parent 2a80218d
...@@ -219,7 +219,7 @@ class SingletonThreadLocal { ...@@ -219,7 +219,7 @@ class SingletonThreadLocal {
template <typename T, typename Tag, typename Make, typename TLTag> template <typename T, typename Tag, typename Make, typename TLTag>
detail::UniqueInstance SingletonThreadLocal<T, Tag, Make, TLTag>::unique{ detail::UniqueInstance SingletonThreadLocal<T, Tag, Make, TLTag>::unique{
"folly::SingletonThreadLocal", tag_t<T, Tag>{}, tag_t<Make, TLTag>{}}; tag<SingletonThreadLocal>, tag<T, Tag>, tag<Make, TLTag>};
} // namespace folly } // namespace folly
......
...@@ -64,19 +64,27 @@ std::string join(PtrRange types) { ...@@ -64,19 +64,27 @@ std::string join(PtrRange types) {
return ret.str(); return ret.str();
} }
template <typename Value>
fbstring render_tmpl(Value value) {
auto const str = demangle(value.tmpl->name());
auto const off = str.find('<');
return str.substr(off + 1, str.size() - off - 2);
}
template <typename Value> template <typename Value>
std::string render(Value value) { std::string render(Value value) {
auto const tmpl_s = render_tmpl(value);
auto const key_s = join(ptr_range_key(value)); auto const key_s = join(ptr_range_key(value));
auto const mapped_s = join(ptr_range_mapped(value)); auto const mapped_s = join(ptr_range_mapped(value));
std::ostringstream ret; std::ostringstream ret;
ret << value.tmpl << "<" << key_s << ", " << mapped_s << ">"; ret << tmpl_s << "<" << key_s << ", " << mapped_s << ">";
return ret.str(); return ret.str();
} }
} // namespace } // namespace
void UniqueInstance::enforce( void UniqueInstance::enforce(
char const* tmpl, Ptr tmpl,
Ptr const* ptrs, Ptr const* ptrs,
std::uint32_t key_size, std::uint32_t key_size,
std::uint32_t mapped_size, std::uint32_t mapped_size,
...@@ -87,11 +95,13 @@ void UniqueInstance::enforce( ...@@ -87,11 +95,13 @@ void UniqueInstance::enforce(
global = local; global = local;
return; return;
} }
if (*global.tmpl != *local.tmpl) {
throw_exception<std::logic_error>("mismatched unique instance");
}
if (!equal(ptr_range_key(global), ptr_range_key(local))) { if (!equal(ptr_range_key(global), ptr_range_key(local))) {
throw_exception<std::logic_error>("mismatched unique instance"); throw_exception<std::logic_error>("mismatched unique instance");
} }
if (std::strcmp(global.tmpl, local.tmpl) == 0 && if (equal(ptr_range_mapped(global), ptr_range_mapped(local))) {
equal(ptr_range_mapped(global), ptr_range_mapped(local))) {
return; return;
} }
......
...@@ -26,11 +26,12 @@ namespace detail { ...@@ -26,11 +26,12 @@ namespace detail {
class UniqueInstance { class UniqueInstance {
public: public:
template <typename... Key, typename... Mapped> template <template <typename...> class Z, typename... Key, typename... Mapped>
FOLLY_EXPORT explicit UniqueInstance( FOLLY_EXPORT explicit UniqueInstance(
char const* tmpl, tag_t<Key...>, tag_t<Mapped...>) noexcept { tag_t<Z<Key..., Mapped...>>, tag_t<Key...>, tag_t<Mapped...>) noexcept {
Ptr const tmpl = &typeid(key_t<Z>);
static Ptr const ptrs[] = {&typeid(Key)..., &typeid(Mapped)...}; static Ptr const ptrs[] = {&typeid(Key)..., &typeid(Mapped)...};
auto& global = createGlobal<Value, tag_t<Tag, Key...>>(); auto& global = createGlobal<Value, key_t<Z, Key...>>();
enforce(tmpl, ptrs, sizeof...(Key), sizeof...(Mapped), global); enforce(tmpl, ptrs, sizeof...(Key), sizeof...(Mapped), global);
} }
...@@ -40,7 +41,8 @@ class UniqueInstance { ...@@ -40,7 +41,8 @@ class UniqueInstance {
UniqueInstance& operator=(UniqueInstance&&) = delete; UniqueInstance& operator=(UniqueInstance&&) = delete;
private: private:
struct Tag {}; template <template <typename...> class Z, typename... Key>
struct key_t {};
using Ptr = std::type_info const*; using Ptr = std::type_info const*;
struct PtrRange { struct PtrRange {
...@@ -48,7 +50,7 @@ class UniqueInstance { ...@@ -48,7 +50,7 @@ class UniqueInstance {
Ptr const* e; Ptr const* e;
}; };
struct Value { struct Value {
char const* tmpl; Ptr tmpl;
Ptr const* ptrs; Ptr const* ptrs;
std::uint32_t key_size; std::uint32_t key_size;
std::uint32_t mapped_size; std::uint32_t mapped_size;
...@@ -57,7 +59,7 @@ class UniqueInstance { ...@@ -57,7 +59,7 @@ class UniqueInstance {
// Under Clang, this call signature shrinks the aligned and padded size of // Under Clang, this call signature shrinks the aligned and padded size of
// call-sites, as compared to a call signature taking Value or Value const&. // call-sites, as compared to a call signature taking Value or Value const&.
static void enforce( static void enforce(
char const* tmpl, Ptr tmpl,
Ptr const* ptrs, Ptr const* ptrs,
std::uint32_t key_size, std::uint32_t key_size,
std::uint32_t mapped_size, std::uint32_t mapped_size,
......
...@@ -27,35 +27,32 @@ struct Key2 {}; ...@@ -27,35 +27,32 @@ struct Key2 {};
struct TagA {}; struct TagA {};
struct TagB {}; struct TagB {};
template <typename...>
struct Template0 {};
template <typename...>
struct Template1 {};
namespace folly { namespace folly {
namespace detail { namespace detail {
class UniqueInstanceDeathTest : public testing::Test {}; class UniqueInstanceDeathTest : public testing::Test {};
template <typename... Key, typename... Mapped> template <template <typename...> class Z, typename... Key, typename... Mapped>
static void make(char const* tmpl, tag_t<Key...> key, tag_t<Mapped...> mapped) { static void make(tag_t<Key...> key, tag_t<Mapped...> mapped) {
UniqueInstance _(tmpl, key, mapped); std::ignore = UniqueInstance{tag<Z<Key..., Mapped...>>, key, mapped};
std::ignore = _;
} }
TEST_F(UniqueInstanceDeathTest, basic) { TEST_F(UniqueInstanceDeathTest, basic) {
constexpr auto const tname = "tname"; make<Template0>(tag<Key1, Key2>, tag<TagA, TagB>);
make(tname, tag_t<Key1, Key2>{}, tag_t<TagA, TagB>{}); make<Template0>(tag<Key1, Key2>, tag<TagA, TagB>); // same everything
make(tname, tag_t<Key1, Key2>{}, tag_t<TagA, TagB>{}); // same everything make<Template1>(tag<Key1, Key2>, tag<TagA, TagB>); // different name
make(tname, tag_t<Key2, Key1>{}, tag_t<TagA, TagB>{}); // different key make<Template0>(tag<Key2, Key1>, tag<TagA, TagB>); // different key
EXPECT_DEATH( // different name
make("wrong", tag_t<Key1, Key2>{}, tag_t<TagA, TagB>{}),
stripLeftMargin(R"MESSAGE(
Overloaded unique instance over <Key1, Key2, ...> with differing trailing arguments:
tname<Key1, Key2, TagA, TagB>
wrong<Key1, Key2, TagA, TagB>
)MESSAGE"));
EXPECT_DEATH( // different mapped EXPECT_DEATH( // different mapped
make(tname, tag_t<Key1, Key2>{}, tag_t<TagB, TagA>{}), make<Template0>(tag<Key1, Key2>, tag<TagB, TagA>),
stripLeftMargin(R"MESSAGE( stripLeftMargin(R"MESSAGE(
Overloaded unique instance over <Key1, Key2, ...> with differing trailing arguments: Overloaded unique instance over <Key1, Key2, ...> with differing trailing arguments:
tname<Key1, Key2, TagA, TagB> Template0<Key1, Key2, TagA, TagB>
tname<Key1, Key2, TagB, TagA> Template0<Key1, Key2, TagB, TagA>
)MESSAGE")); )MESSAGE"));
} }
......
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