This is not an API-breaking change, because it reduces the API that the leveldb embedder must implement. The project will build just fine against ports that still implement InitOnce. C++11 guarantees thread-safe initialization of static variables inside functions. This is a more restricted form of std::call_once or pthread_once_t (e.g., single call site), so the compiler might be able to generate better code [1]. Equally important, having less code in port_example.h makes it easier to port to other platforms. Due to the change above, this CL introduces a new approach for storing the singleton BytewiseComparatorImpl instance returned by BytewiseComparator(). The new approach avoids a dynamic memory allocation, which eliminates the false positive from LeakSanitizer reported in https://github.com/google/leveldb/issues/200 [1] https://stackoverflow.com/a/27206650/ ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=212348004baseline
@ -0,0 +1,47 @@ | |||||
// Copyright (c) 2018 The LevelDB Authors. All rights reserved. | |||||
// Use of this source code is governed by a BSD-style license that can be | |||||
// found in the LICENSE file. See the AUTHORS file for names of contributors. | |||||
#ifndef STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_ | |||||
#define STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_ | |||||
#include <type_traits> | |||||
#include <utility> | |||||
namespace leveldb { | |||||
// Wraps an instance whose destructor is never called. | |||||
// | |||||
// This is intended for use with function-level static variables. | |||||
template<typename InstanceType> | |||||
class NoDestructor { | |||||
public: | |||||
template <typename... ConstructorArgTypes> | |||||
explicit NoDestructor(ConstructorArgTypes&&... constructor_args) { | |||||
static_assert(sizeof(instance_storage_) >= sizeof(InstanceType), | |||||
"instance_storage_ is not large enough to hold the instance"); | |||||
static_assert( | |||||
alignof(decltype(instance_storage_)) >= alignof(InstanceType), | |||||
"instance_storage_ does not meet the instance's alignment requirement"); | |||||
new (&instance_storage_) InstanceType( | |||||
std::forward<ConstructorArgTypes>(constructor_args)...); | |||||
} | |||||
~NoDestructor() = default; | |||||
NoDestructor(const NoDestructor&) = delete; | |||||
NoDestructor& operator=(const NoDestructor&) = delete; | |||||
InstanceType* get() { | |||||
return reinterpret_cast<InstanceType*>(&instance_storage_); | |||||
} | |||||
private: | |||||
typename | |||||
std::aligned_storage<sizeof(InstanceType), alignof(InstanceType)>::type | |||||
instance_storage_; | |||||
}; | |||||
} // namespace leveldb | |||||
#endif // STORAGE_LEVELDB_UTIL_NO_DESTRUCTOR_H_ |
@ -0,0 +1,49 @@ | |||||
// Copyright (c) 2018 The LevelDB Authors. All rights reserved. | |||||
// Use of this source code is governed by a BSD-style license that can be | |||||
// found in the LICENSE file. See the AUTHORS file for names of contributors. | |||||
#include <cstdint> | |||||
#include <cstdlib> | |||||
#include <utility> | |||||
#include "util/no_destructor.h" | |||||
#include "util/testharness.h" | |||||
namespace leveldb { | |||||
namespace { | |||||
struct DoNotDestruct { | |||||
public: | |||||
DoNotDestruct(uint32_t a, uint64_t b) : a(a), b(b) {} | |||||
~DoNotDestruct() { std::abort(); } | |||||
// Used to check constructor argument forwarding. | |||||
uint32_t a; | |||||
uint64_t b; | |||||
}; | |||||
constexpr const uint32_t kGoldenA = 0xdeadbeef; | |||||
constexpr const uint64_t kGoldenB = 0xaabbccddeeffaabb; | |||||
} // namespace | |||||
class NoDestructorTest { }; | |||||
TEST(NoDestructorTest, StackInstance) { | |||||
NoDestructor<DoNotDestruct> instance(kGoldenA, kGoldenB); | |||||
ASSERT_EQ(kGoldenA, instance.get()->a); | |||||
ASSERT_EQ(kGoldenB, instance.get()->b); | |||||
} | |||||
TEST(NoDestructorTest, StaticInstance) { | |||||
static NoDestructor<DoNotDestruct> instance(kGoldenA, kGoldenB); | |||||
ASSERT_EQ(kGoldenA, instance.get()->a); | |||||
ASSERT_EQ(kGoldenB, instance.get()->b); | |||||
} | |||||
} // namespace leveldb | |||||
int main(int argc, char** argv) { | |||||
return leveldb::test::RunAllTests(); | |||||
} |