Skip to content

Commit

Permalink
[c++] Add a non-destructed type (grpc#30491)
Browse files Browse the repository at this point in the history
* [c++] Add a non-destructed type

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* comment

Co-authored-by: ctiller <[email protected]>
  • Loading branch information
ctiller and ctiller authored Aug 4, 2022
1 parent 3d2e503 commit 15a8113
Show file tree
Hide file tree
Showing 14 changed files with 365 additions and 2 deletions.
11 changes: 11 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,16 @@ grpc_cc_library(
],
)

grpc_cc_library(
name = "no_destruct",
language = "c++",
public_hdrs = ["src/core/lib/gprpp/no_destruct.h"],
deps = [
"construct_destruct",
"gpr_base",
],
)

grpc_cc_library(
name = "orphanable",
language = "c++",
Expand Down Expand Up @@ -7288,6 +7298,7 @@ grpc_cc_library(
"gpr_base",
"json",
"json_args",
"no_destruct",
"time",
],
)
Expand Down
90 changes: 90 additions & 0 deletions CMakeLists.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

94 changes: 94 additions & 0 deletions build_autogenerated.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions gRPC-C++.podspec

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions gRPC-Core.podspec

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions grpc.gemspec

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 88 additions & 0 deletions src/core/lib/gprpp/no_destruct.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef GRPC_CORE_LIB_GPRPP_NO_DESTRUCT_H
#define GRPC_CORE_LIB_GPRPP_NO_DESTRUCT_H

#include <grpc/support/port_platform.h>

#include <utility>

#include "src/core/lib/gprpp/construct_destruct.h"

namespace grpc_core {

// NoDestruct<T> is a wrapper around an object of type T that:
// - stores the value inline - no heap allocation
// - is non-copyable
// - is eagerly constructed (i.e. the constructor is called when NoDestruct is
// constructed)
// - *NEVER* calls ~T()
// It's useful in cases where no ordering can be assumed between destructors of
// objects that need to refer to each other - such as at program destruction
// time.
// Examples:
// // globally available object:
// static NoDestruct<Foo> g_foo(1, "foo", 2.0);
// // used as:
// g_foo->DoSomething();
// // singleton function:
// Bar* BarSingleton() {
// static NoDestruct<Bar> bar(1, "bar", 2.0);
// return &*bar;
// }
// The globally available version is constructed at program startup, and the
// singleton version is constructed at the first call to BarSingleton().
// Neither Foo nor Bar instance will be destructed.
template <typename T>
class NoDestruct {
public:
template <typename... Args>
explicit NoDestruct(Args&&... args) {
static_assert(std::is_trivially_destructible<NoDestruct<T>>::value,
"NoDestruct must be trivially destructible");
Construct(reinterpret_cast<T*>(&space_), std::forward<Args>(args)...);
}
NoDestruct(const NoDestruct&) = delete;
NoDestruct& operator=(const NoDestruct&) = delete;
~NoDestruct() = default;

T* operator->() { return reinterpret_cast<T*>(&space_); }
const T* operator->() const { return *reinterpret_cast<const T*>(&space_); }
T& operator*() { return *reinterpret_cast<T*>(&space_); }
const T& operator*() const { return *reinterpret_cast<const T*>(&space_); }

private:
typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
};

// Helper for when a program desires a single instance of a default constructed
// T to be always available.
// T is constructed eagerly at program startup, so it's essentially free to load
// the pointer to the instance.
template <typename T>
class NoDestructSingleton {
public:
static T* Get() { return &*value_; }

private:
static NoDestruct<T> value_;
};

template <typename T>
NoDestruct<T> NoDestructSingleton<T>::value_;

} // namespace grpc_core

#endif // GRPC_CORE_LIB_GPRPP_NO_DESTRUCT_H
4 changes: 2 additions & 2 deletions src/core/lib/json/json_object_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"

#include "src/core/lib/gprpp/no_destruct.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
Expand Down Expand Up @@ -354,8 +355,7 @@ class AutoLoader<absl::optional<T>> final : public LoaderInterface {
// Simply keeps a static AutoLoader<T> and returns a pointer to that.
template <typename T>
const LoaderInterface* LoaderForType() {
static const auto* loader = new AutoLoader<T>();
return loader;
return NoDestructSingleton<AutoLoader<T>>::Get();
}

// Element describes one typed field to be loaded from a JSON object.
Expand Down
Loading

0 comments on commit 15a8113

Please sign in to comment.