Switch some SFINAE based dispatch into `if constexpr`.

This cleans up C++14 logic.

PiperOrigin-RevId: 695400014
pull/19164/head
Protobuf Team Bot 3 weeks ago committed by Copybara-Service
parent 4b3a548d7f
commit 1271b32897
  1. 17
      csharp/src/Google.Protobuf/Reflection/FeatureSetDescriptor.g.cs
  2. 26
      src/google/protobuf/arena.h
  3. 129
      src/google/protobuf/map.h

@ -1,17 +0,0 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#endregion
namespace Google.Protobuf.Reflection;
internal sealed partial class FeatureSetDescriptor
{
// Canonical serialized form of the edition defaults, generated by embed_edition_defaults.
private const string DefaultsBase64 =
"ChMYhAciACoMCAEQAhgCIAMoATACChMY5wciACoMCAIQARgBIAIoATABChMY6AciDAgBEAEYASACKAEwASoAIOYHKOgH";
}

@ -581,32 +581,18 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
// which needs to declare Map as friend of generated message.
template <typename T, typename... Args>
static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) {
CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>(),
std::forward<Args>(args)...);
if (ABSL_PREDICT_TRUE(arena != nullptr)) {
RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>());
}
}
template <typename T, typename... Args>
static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
std::true_type, Args&&... args) {
if constexpr (is_arena_constructable<T>::value) {
InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
std::false_type, Args&&... args) {
} else {
new (ptr) T(std::forward<Args>(args)...);
}
template <typename T>
static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
std::true_type) {}
template <typename T>
static void RegisterDestructorInternal(T* ptr, Arena* arena,
std::false_type) {
if constexpr (!is_destructor_skippable<T>::value) {
if (ABSL_PREDICT_TRUE(arena != nullptr)) {
arena->OwnDestructor(ptr);
}
}
}
// Implementation for GetArena(). Only message objects with
// InternalArenaConstructable_ tags can be associated with an arena, and such

@ -246,30 +246,17 @@ struct TransparentSupport {
// that is convertible to absl::string_view.
template <>
struct TransparentSupport<std::string> {
// Use go/ranked-overloads for dispatching.
struct Rank0 {};
struct Rank1 : Rank0 {};
struct Rank2 : Rank1 {};
template <typename T, typename = std::enable_if_t<
std::is_convertible<T, absl::string_view>::value>>
static absl::string_view ImplicitConvertImpl(T&& str, Rank2) {
absl::string_view ref = str;
return ref;
}
template <typename T, typename = std::enable_if_t<
std::is_convertible<T, const std::string&>::value>>
static absl::string_view ImplicitConvertImpl(T&& str, Rank1) {
template <typename T>
static absl::string_view ImplicitConvert(T&& str) {
if constexpr (std::is_convertible<T, absl::string_view>::value) {
absl::string_view res = str;
return res;
} else if constexpr (std::is_convertible<T, const std::string&>::value) {
const std::string& ref = str;
return ref;
}
template <typename T>
static absl::string_view ImplicitConvertImpl(T&& str, Rank0) {
} else {
return {str.data(), str.size()};
}
template <typename T>
static absl::string_view ImplicitConvert(T&& str) {
return ImplicitConvertImpl(std::forward<T>(str), Rank2{});
}
struct hash : public absl::Hash<absl::string_view> {
@ -1576,17 +1563,34 @@ class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
template <typename K, typename... Args>
std::pair<iterator, bool> try_emplace(K&& k, Args&&... args)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// Inserts a new element into the container if there is no element with the
// key in the container.
// The new element is:
// (1) Constructed in-place with the given args, if mapped_type is not
// arena constructible.
// (2) Constructed in-place with the arena and then assigned with a
// mapped_type temporary constructed with the given args, otherwise.
return ArenaAwareTryEmplace(Arena::is_arena_constructable<mapped_type>(),
std::forward<K>(k),
// Case 1: `mapped_type` is arena constructible. A temporary object is
// created and then (if `Args` are not empty) assigned to a mapped value
// that was created with the arena.
if constexpr (Arena::is_arena_constructable<mapped_type>::value) {
if constexpr (sizeof...(Args) == 0) {
// case 1.1: "default" constructed (e.g. from arena only).
return TryEmplaceInternal(std::forward<K>(k));
} else {
// case 1.2: "default" constructed + copy/move assignment
auto p = TryEmplaceInternal(std::forward<K>(k));
if (p.second) {
if constexpr (std::is_same<void(typename std::decay<Args>::type...),
void(mapped_type)>::value) {
// Avoid the temporary when the input is the right type.
p.first->second = (std::forward<Args>(args), ...);
} else {
p.first->second = mapped_type(std::forward<Args>(args)...);
}
}
return p;
}
} else {
// Case 2: `mapped_type` is not arena constructible. Using in-place
// construction.
return TryEmplaceInternal(std::forward<K>(k),
std::forward<Args>(args)...);
}
}
std::pair<iterator, bool> insert(init_type&& value)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return try_emplace(std::move(value.first), std::move(value.second));
@ -1599,7 +1603,14 @@ class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
template <typename... Args>
std::pair<iterator, bool> emplace(Args&&... args)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return EmplaceInternal(Rank0{}, std::forward<Args>(args)...);
// We try to construct `init_type` from `Args` with a fall back to
// `value_type`. The latter is less desired as it unconditionally makes a
// copy of `value_type::first`.
if constexpr (std::is_constructible<init_type, Args...>::value) {
return insert(init_type(std::forward<Args>(args)...));
} else {
return insert(value_type(std::forward<Args>(args)...));
}
}
template <class InputIt>
void insert(InputIt first, InputIt last) {
@ -1687,9 +1698,6 @@ class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
}
private:
struct Rank1 {};
struct Rank0 : Rank1 {};
// Linked-list nodes, as one would expect for a chaining hash table.
struct Node : Base::KeyNode {
using key_type = Key;
@ -1724,20 +1732,6 @@ class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
return this->SpaceUsedInTable(sizeof(Node));
}
// We try to construct `init_type` from `Args` with a fall back to
// `value_type`. The latter is less desired as it unconditionally makes a copy
// of `value_type::first`.
template <typename... Args>
auto EmplaceInternal(Rank0, Args&&... args) ->
typename std::enable_if<std::is_constructible<init_type, Args...>::value,
std::pair<iterator, bool>>::type {
return insert(init_type(std::forward<Args>(args)...));
}
template <typename... Args>
std::pair<iterator, bool> EmplaceInternal(Rank1, Args&&... args) {
return insert(value_type(std::forward<Args>(args)...));
}
template <typename K, typename... Args>
std::pair<iterator, bool> TryEmplaceInternal(K&& k, Args&&... args) {
auto p = this->FindHelper(TS::ToView(k));
@ -1777,47 +1771,6 @@ class Map : private internal::KeyMapBase<internal::KeyForBase<Key>> {
true);
}
// A helper function to perform an assignment of `mapped_type`.
// If the first argument is true, then it is a regular assignment.
// Otherwise, we first create a temporary and then perform an assignment.
template <typename V>
static void AssignMapped(std::true_type, mapped_type& mapped, V&& v) {
mapped = std::forward<V>(v);
}
template <typename... Args>
static void AssignMapped(std::false_type, mapped_type& mapped,
Args&&... args) {
mapped = mapped_type(std::forward<Args>(args)...);
}
// Case 1: `mapped_type` is arena constructible. A temporary object is
// created and then (if `Args` are not empty) assigned to a mapped value
// that was created with the arena.
template <typename K>
std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k) {
// case 1.1: "default" constructed (e.g. from arena only).
return TryEmplaceInternal(std::forward<K>(k));
}
template <typename K, typename... Args>
std::pair<iterator, bool> ArenaAwareTryEmplace(std::true_type, K&& k,
Args&&... args) {
// case 1.2: "default" constructed + copy/move assignment
auto p = TryEmplaceInternal(std::forward<K>(k));
if (p.second) {
AssignMapped(std::is_same<void(typename std::decay<Args>::type...),
void(mapped_type)>(),
p.first->second, std::forward<Args>(args)...);
}
return p;
}
// Case 2: `mapped_type` is not arena constructible. Using in-place
// construction.
template <typename... Args>
std::pair<iterator, bool> ArenaAwareTryEmplace(std::false_type,
Args&&... args) {
return TryEmplaceInternal(std::forward<Args>(args)...);
}
using Base::arena;
friend class Arena;

Loading…
Cancel
Save