Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/components/protobuf/src/google/protobuf/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 9 kB image not shown  

Quelle  map.cc

  Sprache: C
 

// 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

#include "google/protobuf/map.h"

#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <string>

#include "absl/base/no_destructor.h"
#include "absl/base/optimization.h"
#include "absl/functional/overload.h"
#include "absl/log/absl_check.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/field_with_arena.h"
#include "google/protobuf/message_lite.h"
#include "google/protobuf/port.h"


// Must be included last.
#include "google/protobuf/port_def.inc"

namespace google {
namespace protobuf {
namespace internal {

std::atomic<MapFieldBaseForParse::SyncFunc>
    MapFieldBaseForParse::sync_map_with_repeated{};

NodeBase* const kGlobalEmptyTable[kGlobalEmptyTableSize] = {};

void UntypedMapBase::UntypedMergeFrom(Arena* arena,
                                      const UntypedMapBase& other) {
  ABSL_DCHECK_EQ(arena, this->arena());
  if (other.empty()) return;

  // Do the merging in steps to avoid Key*Value number of instantiations and
  // reduce code duplication per instantation.
  NodeBase* nodes = nullptr;

  // First, allocate all the nodes without types.
  for (size_t i = 0; i < other.num_elements_; ++i) {
    NodeBase* new_node = AllocNode(arena);
    new_node->next = nodes;
    nodes = new_node;
  }

  // Then, copy the values.
  VisitValueType([&](auto value_type) {
    using Value = typename decltype(value_type)::type;
    NodeBase* out_node = nodes;

    // Get the ClassData once to avoid redundant virtual function calls.
    const internal::ClassData* class_data =
        std::is_same_v<MessageLite, Value>
            ? GetClassData(*other.GetValue<MessageLite>(other.begin().node_))
            : nullptr;

    for (auto it = other.begin(); !it.Equals(EndIterator()); it.PlusPlus()) {
      Value* out = GetValue<Value>(out_node);
      out_node = out_node->next;
      auto& in = *other.GetValue<Value>(it.node_);
      if constexpr (std::is_same_v<MessageLite, Value>) {
        class_data->PlacementNew(out, arena)->CheckTypeAndMergeFrom(in);
      } else {
        Arena::CreateInArenaStorage(out, arena, in);
      }
    }
  });

  // Finally, copy the keys and insert the nodes.
  VisitKeyType([&](auto key_type) {
    using Key = typename decltype(key_type)::type;
    for (auto it = other.begin(); !it.Equals(EndIterator()); it.PlusPlus()) {
      NodeBase* node = nodes;
      nodes = nodes->next;
      const Key& in = *other.GetKey<Key>(it.node_);
      Key* out = GetKey<Key>(node);
      if (!internal::InitializeMapKey(out, in, arena)) {
        Arena::CreateInArenaStorage(out, arena, in);
      }

      static_cast<KeyMapBase<Key>*>(this)->InsertOrReplaceNode(
          arena, static_cast<typename KeyMapBase<Key>::KeyNode*>(node));
    }
  });
}

void UntypedMapBase::UntypedSwap(Arena* arena, UntypedMapBase& other,
                                 Arena* other_arena) {
  ABSL_DCHECK_EQ(arena, this->arena());
  ABSL_DCHECK_EQ(other_arena, other.arena());

  if (arena == other_arena) {
    InternalSwap(&other);
  } else {
    // `FieldWithArena` checks that the arena pointer is null when destroying a
    // destructor-skippable type. Since `UntypedMapBase` is
    // destructor-skippable, we need to put it in an `absl::NoDestructor` and
    // manually destroy it if the arena pointer is null.
    absl::NoDestructor<FieldWithArena<UntypedMapBase>> tmp_container(
        arena, type_info_);
    UntypedMapBase& tmp = tmp_container->field();
    InternalSwap(&tmp);

    ABSL_DCHECK(empty());
    UntypedMergeFrom(arena, other);

    other.ClearTable(other_arena, /*reset=*/true);
    other.UntypedMergeFrom(other_arena, tmp);

    if (arena == nullptr) {
      tmp.ClearTable(arena, /*reset=*/false);
      tmp.~UntypedMapBase();
    }
  }
}

void UntypedMapBase::DeleteNode(NodeBase* node) {
  const auto destroy = absl::Overload{
      [](std::string* str) { str->~basic_string(); },
      [](MessageLite* msg) { msg->DestroyInstance(); }, [](void*) {}};
  VisitKey(node, destroy);
  VisitValue(node, destroy);
  DeallocNode(node);
}

void UntypedMapBase::DeleteList(NodeBase* list) {
  while (list != nullptr) {
    NodeBase* n = list;
    list = list->next;
    DeleteNode(n);
  }
}

void UntypedMapBase::ClearTableImpl(Arena* arena, bool reset) {
  ABSL_DCHECK_NE(num_buckets_, kGlobalEmptyTableSize);
  ABSL_DCHECK_EQ(arena, this->arena());

  if (arena == nullptr) {
    const auto loop = [this](auto destroy_node) {
      NodeBase** table = table_;
      for (map_index_t b = 0, end = num_buckets_; b < end; ++b) {
        for (NodeBase* node = table[b]; node != nullptr;) {
          NodeBase* next = node->next;
          absl::PrefetchToLocalCacheNta(next);
          destroy_node(node);
          SizedDelete(node, type_info_.node_size);
          node = next;
        }
      }
    };

    const auto dispatch_key = [&](auto value_handler) {
      if (type_info_.key_type_kind() < TypeKind::kString) {
        loop(value_handler);
      } else if (type_info_.key_type_kind() == TypeKind::kString) {
        loop([=](NodeBase* node) {
          static_cast<std::string*>(node->GetVoidKey())->~basic_string();
          value_handler(node);
        });
      } else {
        Unreachable();
      }
    };

    if (type_info_.value_type_kind() < TypeKind::kString) {
      dispatch_key([](NodeBase*) {});
    } else if (type_info_.value_type_kind() == TypeKind::kString) {
      dispatch_key([&](NodeBase* node) {
        GetValue<std::string>(node)->~basic_string();
      });
    } else if (type_info_.value_type_kind() == TypeKind::kMessage) {
      dispatch_key([&](NodeBase* node) {
        GetValue<MessageLite>(node)->DestroyInstance();
      });
    } else {
      Unreachable();
    }
  }

  if (reset) {
    std::fill(table_, table_ + num_buckets_, nullptr);
    num_elements_ = 0;
  } else {
    DeleteTable(arena, table_, num_buckets_);
  }
}

size_t UntypedMapBase::SpaceUsedExcludingSelfLong() const {
  size_t size = 0;
  // The size of the table.
  size += sizeof(void*) * num_buckets_;
  // All the nodes.
  size += type_info_.node_size * num_elements_;
  VisitAllNodes([&](auto* key, auto* value) {
    const auto space_used = absl::Overload{
        [](const std::string* str) -> size_t {
          return StringSpaceUsedExcludingSelfLong(*str);
        },
        [&](const MessageLite* msg) -> size_t {
          const auto* class_data = GetClassData(*msg);
          if (class_data->is_lite) return 0;
          return class_data->full().descriptor_methods()->space_used_long(
                     *msg) -
                 class_data->allocation_size();
        },
        [](const void*) -> size_t { return 0; }};
    size += space_used(key);
    size += space_used(value);
  });
  return size;
}

static size_t AlignTo(size_t v, size_t alignment, size_t& max_align) {
  max_align = std::max<size_t>(max_align, alignment);
  return (v + alignment - 1) / alignment * alignment;
}

struct Offsets {
  size_t start;
  size_t end;
};

template <typename T>
static Offsets AlignAndAddSize(size_t v, size_t& max_align) {
  v = AlignTo(v, alignof(T), max_align);
  return {v, v + sizeof(T)};
}

static Offsets AlignAndAddSizeDynamic(
    size_t v, UntypedMapBase::TypeKind kind,
    const MessageLite* value_prototype_if_message, size_t& max_align) {
  switch (kind) {
    case UntypedMapBase::TypeKind::kBool:
      return AlignAndAddSize<bool>(v, max_align);
    case UntypedMapBase::TypeKind::kU32:
      return AlignAndAddSize<int32_t>(v, max_align);
    case UntypedMapBase::TypeKind::kU64:
      return AlignAndAddSize<int64_t>(v, max_align);
    case UntypedMapBase::TypeKind::kFloat:
      return AlignAndAddSize<float>(v, max_align);
    case UntypedMapBase::TypeKind::kDouble:
      return AlignAndAddSize<double>(v, max_align);
    case UntypedMapBase::TypeKind::kString:
      return AlignAndAddSize<std::string>(v, max_align);
    case UntypedMapBase::TypeKind::kMessage: {
      auto* class_data = GetClassData(*value_prototype_if_message);
      v = AlignTo(v, class_data->alignment(), max_align);
      return {v, v + class_data->allocation_size()};
    }
    default:
      Unreachable();
  }
}

template <typename T, typename U>
T Narrow(U value) {
  ABSL_CHECK_EQ(value, static_cast<T>(value));
  return static_cast<T>(value);
}

UntypedMapBase::TypeInfo UntypedMapBase::GetTypeInfoDynamic(
    TypeKind key_type, TypeKind value_type,
    const MessageLite* value_prototype_if_message) {
  size_t max_align = alignof(NodeBase);
  const auto key_offsets =
      AlignAndAddSizeDynamic(sizeof(NodeBase), key_type, nullptr, max_align);
  const auto value_offsets = AlignAndAddSizeDynamic(
      key_offsets.end, value_type, value_prototype_if_message, max_align);
  return TypeInfo{
      Narrow<uint16_t>(AlignTo(value_offsets.end, max_align, max_align)),
      Narrow<uint8_t>(value_offsets.start), static_cast<uint8_t>(key_type),
      static_cast<uint8_t>(value_type)};
}

void UntypedMapBase::InsertOrReplaceNodes(Arena* arena, NodeBase* list,
                                          map_index_t count) {
  if (ABSL_PREDICT_FALSE(count == 0)) return;
  VisitKeyType([=](auto key_type) {
    using Key = typename decltype(key_type)::type;
    static_cast<KeyMapBase<Key>&>(*this).InsertOrReplaceNodes(
        arena, static_cast<typename KeyMapBase<Key>::KeyNode*>(list), count);
  });
}

}  // namespace internal
}  // namespace protobuf
}  // namespace google

#include "google/protobuf/port_undef.inc"

Messung V0.5 in Prozent
C=87 H=96 G=91

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.