[clang] [clang-tools-extra] [lldb] [llvm] Reland "[Support][JSON] Use std::unordered_map for object storage (#171230)" (PR #193628)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 22 16:46:18 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: Zixu Wang (zixu-w)
<details>
<summary>Changes</summary>
#<!-- -->171230 was reverted because of Buildbot failures with libstdc++.
libstdc++ eagerly instantiates `std::pair<const ObjectKey, Value>` with `std::unordered_map<ObjectKey, Value>`, requiring both types to be complete. This creates a circular dependency: `json::Object` needs `json::Value` complete, and `json::Value` needs `json::Object` complete (for `AlignedCharArrayUnion`).
The fix stores a `std::unique_ptr<json::Object>` in Value's union instead of inline, breaking the cycle. This allows reordering the type definitions as `ObjectKey -> Array -> Value -> Object`, so both key and value types are complete when the `unordered_map` is instantiated.
This also changes how `json::Value` is laid out in memory. With #<!-- -->171230, `sizeof(json::Object)` grows from the change to `std::unordered_map`, so `sizeof(json::Value::Union)` also increases. In this fix, the size of `Union` shrinks because we use `std::unique_ptr`, with the trade-off of an additional allocation outside of `AlignedCharArrayUnion`'s buffer to create `json::Object` (only occurring for object-typed values).
Benchmarked again and the performance is roughly the same as in #<!-- -->171230:
```
Running benchmarks/JSONParserBM
Run on (20 X 24 MHz CPU s)
CPU Caches:
L1 Data 64 KiB
L1 Instruction 128 KiB
L2 Unified 4096 KiB (x20)
Load Average: 5.58, 13.78, 10.19
-----------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
-----------------------------------------------------------------------------------------
BM_JSONParse/10 21614 ns 21608 ns 31732 AllocBytes=26.048k Allocs=640 ParseByteRate=142.822Mi/s
BM_JSONParse/1000 2307481 ns 2306885 ns 304 AllocBytes=2.55368M Allocs=63.016k ParseByteRate=137.234Mi/s
BM_JSONParse/100000 237053194 ns 236974667 ns 3 AllocBytes=257.189M Allocs=6.30002M ParseByteRate=137.611Mi/s
BM_JSONIterate/10 373 ns 372 ns 1881650 items_per_second=515.516M/s
BM_JSONIterate/1000 36334 ns 36330 ns 19185 items_per_second=523.046M/s
BM_JSONIterate/100000 7852453 ns 7851031 ns 159 items_per_second=242.007M/s
BM_JSONLookupSequential/10 1695 ns 1694 ns 414088 items_per_second=89.1237M/s
BM_JSONLookupSequential/1000 167926 ns 167893 ns 4156 items_per_second=89.3484M/s
BM_JSONLookupSequential/100000 17563538 ns 17554429 ns 35 items_per_second=85.4486M/s
BM_JSONLookupRandom/10 1777 ns 1776 ns 395003 items_per_second=85.0015M/s
BM_JSONLookupRandom/1000 189113 ns 189087 ns 3712 items_per_second=79.334M/s
BM_JSONLookupRandom/100000 22329233 ns 22325500 ns 36 items_per_second=67.1878M/s
```
Assisted-by: Claude Code (claude-opus-4-6)
---
Patch is 32.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/193628.diff
12 Files Affected:
- (modified) clang-tools-extra/clang-doc/JSONGenerator.cpp (+1-1)
- (modified) clang/include/clang/Basic/Sarif.h (+1)
- (modified) clang/lib/Basic/DarwinSDKInfo.cpp (+7-7)
- (modified) clang/tools/clang-installapi/Options.cpp (+2-2)
- (modified) clang/unittests/Basic/SarifTest.cpp (+1-1)
- (modified) lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h (+2)
- (modified) lldb/source/Plugins/Process/Linux/IntelPTThreadTraceCollection.h (+1)
- (modified) llvm/benchmarks/CMakeLists.txt (+1)
- (added) llvm/benchmarks/JSONParserBM.cpp (+299)
- (modified) llvm/include/llvm/Support/JSON.h (+140-121)
- (modified) llvm/lib/Support/JSON.cpp (+7-5)
- (modified) llvm/tools/llvm-mca/Views/InstructionInfoView.h (+1)
``````````diff
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index e895d641a6000..d4d12083197d5 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -155,7 +155,7 @@ static void insertComment(Object &Description, json::Value &Comment,
Description[Key] = std::move(CommentsArray);
Description["Has" + Key.str()] = true;
} else {
- DescriptionIt->getSecond().getAsArray()->push_back(Comment);
+ DescriptionIt->second.getAsArray()->push_back(Comment);
}
}
diff --git a/clang/include/clang/Basic/Sarif.h b/clang/include/clang/Basic/Sarif.h
index 7651d2ac7a768..a9099271ccc0c 100644
--- a/clang/include/clang/Basic/Sarif.h
+++ b/clang/include/clang/Basic/Sarif.h
@@ -34,6 +34,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Version.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index f7d02ef97f5a4..39d08387f8d1a 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -25,7 +25,7 @@ std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
return MaximumValue;
auto KV = Mapping.find(Key.normalize());
if (KV != Mapping.end())
- return KV->getSecond();
+ return KV->second;
// If no exact entry found, try just the major key version. Only do so when
// a minor version number is present, to avoid recursing indefinitely into
// the major-only check.
@@ -43,10 +43,10 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
VersionTuple MinValue = Min;
llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
for (const auto &KV : Obj) {
- if (auto Val = KV.getSecond().getAsString()) {
+ if (auto Val = KV.second.getAsString()) {
llvm::VersionTuple KeyVersion;
llvm::VersionTuple ValueVersion;
- if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
+ if (KeyVersion.tryParse(KV.first) || ValueVersion.tryParse(*Val))
return std::nullopt;
Mapping[KeyVersion.normalize()] = ValueVersion;
if (KeyVersion < Min)
@@ -119,7 +119,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
for (auto SupportedTargetPair : *SupportedTargets) {
llvm::json::Object *SupportedTarget =
- SupportedTargetPair.getSecond().getAsObject();
+ SupportedTargetPair.second.getAsObject();
auto Vendor = SupportedTarget->getString("LLVMTargetTripleVendor");
auto OS = SupportedTarget->getString("LLVMTargetTripleSys");
if (!Vendor || !OS)
@@ -136,7 +136,7 @@ static DarwinSDKInfo::PlatformInfoStorageType parsePlatformInfos(
// The key is either the Xcode platform, or a variant. The platform must be
// the first entry in the returned PlatformInfoStorageType.
- StringRef PlatformOrVariant = SupportedTargetPair.getFirst();
+ StringRef PlatformOrVariant = SupportedTargetPair.first;
StringRef EffectivePlatformPrefix;
// Ignore iosmac value if it exists.
@@ -202,12 +202,12 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(std::string FilePath,
// FIXME: Generalize this out beyond iOS-deriving targets.
// Look for ios_<targetos> version mapping for targets that derive from ios.
for (const auto &KV : *VM) {
- auto Pair = StringRef(KV.getFirst()).split("_");
+ auto Pair = StringRef(KV.first).split("_");
if (Pair.first.compare_insensitive("ios") == 0) {
llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
if (TT.getOS() != llvm::Triple::UnknownOS) {
auto Mapping = RelatedTargetVersionMapping::parseJSON(
- *KV.getSecond().getAsObject(), *MaximumDeploymentVersion);
+ *KV.second.getAsObject(), *MaximumDeploymentVersion);
if (Mapping)
VersionMappings[OSEnvPair(llvm::Triple::IOS,
llvm::Triple::UnknownEnvironment,
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index f484d6f33ad8f..1151f65af4dce 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -84,8 +84,8 @@ getArgListFromJSON(const StringRef Input, llvm::opt::OptTable *Table,
return llvm::opt::InputArgList();
for (const auto &KV : *Root) {
- const Array *ArgList = KV.getSecond().getAsArray();
- std::string Label = "-X" + KV.getFirst().str();
+ const Array *ArgList = KV.second.getAsArray();
+ std::string Label = "-X" + KV.first.str();
if (!ArgList)
return make_error<TextAPIError>(TextAPIErrorCode::InvalidInputFormat);
for (auto Arg : *ArgList) {
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index 42e85085d646e..cfae48a96c2a8 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -83,7 +83,7 @@ TEST_F(SarifDocumentWriterTest, canCreateEmptyDocument) {
const llvm::json::Object &EmptyDoc = Writer.createDocument();
std::vector<StringRef> Keys(EmptyDoc.size());
std::transform(EmptyDoc.begin(), EmptyDoc.end(), Keys.begin(),
- [](auto Item) { return Item.getFirst(); });
+ [](auto Item) { return Item.first; });
// THEN:
ASSERT_THAT(Keys, testing::UnorderedElementsAre("$schema", "version"));
diff --git a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
index eebb5117b30c5..603badf3330a7 100644
--- a/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
+++ b/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h
@@ -12,6 +12,8 @@
#include "lldb/Target/DynamicLoader.h"
#include "lldb/lldb-forward.h"
+#include "llvm/ADT/DenseMap.h"
+
namespace lldb_private {
class DynamicLoaderWindowsDYLD : public DynamicLoader {
diff --git a/lldb/source/Plugins/Process/Linux/IntelPTThreadTraceCollection.h b/lldb/source/Plugins/Process/Linux/IntelPTThreadTraceCollection.h
index 550cd46127ed9..31388d4b9be82 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTThreadTraceCollection.h
+++ b/lldb/source/Plugins/Process/Linux/IntelPTThreadTraceCollection.h
@@ -10,6 +10,7 @@
#define liblldb_IntelPTPerThreadTraceCollection_H_
#include "IntelPTSingleBufferTrace.h"
+#include "llvm/ADT/DenseMap.h"
#include <optional>
namespace lldb_private {
diff --git a/llvm/benchmarks/CMakeLists.txt b/llvm/benchmarks/CMakeLists.txt
index 69ebeaa78344b..bdd1ce40d2cb2 100644
--- a/llvm/benchmarks/CMakeLists.txt
+++ b/llvm/benchmarks/CMakeLists.txt
@@ -15,6 +15,7 @@ add_benchmark(MustacheBench Mustache.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(SpecialCaseListBM SpecialCaseListBM.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(DWARFVerifierBM DWARFVerifierBM.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(PointerUnionBM PointerUnionBM.cpp PARTIAL_SOURCES_INTENDED)
+add_benchmark(JSONParserBM JSONParserBM.cpp PARTIAL_SOURCES_INTENDED)
add_benchmark(RuntimeLibcallsBench RuntimeLibcalls.cpp PARTIAL_SOURCES_INTENDED)
diff --git a/llvm/benchmarks/JSONParserBM.cpp b/llvm/benchmarks/JSONParserBM.cpp
new file mode 100644
index 0000000000000..b5deb0bbf2f66
--- /dev/null
+++ b/llvm/benchmarks/JSONParserBM.cpp
@@ -0,0 +1,299 @@
+//===- JSONParserBM.cpp - JSON parser benchmarks --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// Benchmarks for LLVM's JSON parser.
+// Runs parsing, tree iteration, and object key lookup with generated inputs.
+// Measures time performance and memory consumption.
+//
+//===----------------------------------------------------------------------===//
+
+#include "benchmark/benchmark.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/JSON.h"
+#include <algorithm>
+#include <atomic>
+#include <random>
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Memory tracking via global operator new
+//
+// These are global overrides so the benchmark might be over-counting memory
+// allocations and usage. The data is still useful for comparisons with this
+// benchmark itself.
+//===----------------------------------------------------------------------===//
+
+static std::atomic_size_t TotalAllocatedBytes{0};
+static std::atomic_size_t NumAllocs{0};
+static bool TrackMemory = false;
+
+// Single-object new/delete.
+void *operator new(std::size_t Size) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new(std::size_t Size, std::align_val_t) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new(std::size_t Size, const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new(std::size_t Size, std::align_val_t,
+ const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void operator delete(void *Ptr) noexcept { std::free(Ptr); }
+void operator delete(void *Ptr, std::align_val_t) noexcept { std::free(Ptr); }
+void operator delete(void *Ptr, std::size_t) noexcept { std::free(Ptr); }
+void operator delete(void *Ptr, std::size_t, std::align_val_t) noexcept {
+ std::free(Ptr);
+}
+
+// Array new/delete.
+void *operator new[](std::size_t Size) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new[](std::size_t Size, std::align_val_t) {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new[](std::size_t Size, const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void *operator new[](std::size_t Size, std::align_val_t,
+ const std::nothrow_t &) noexcept {
+ if (TrackMemory) {
+ TotalAllocatedBytes += Size;
+ ++NumAllocs;
+ }
+ return std::malloc(Size);
+}
+
+void operator delete[](void *Ptr) noexcept { std::free(Ptr); }
+void operator delete[](void *Ptr, std::align_val_t) noexcept { std::free(Ptr); }
+void operator delete[](void *Ptr, std::size_t) noexcept { std::free(Ptr); }
+void operator delete[](void *Ptr, std::size_t, std::align_val_t) noexcept {
+ std::free(Ptr);
+}
+
+//===----------------------------------------------------------------------===//
+// Test data generation
+//===----------------------------------------------------------------------===//
+
+/// Generate a JSON string with \p N entries in an array. Each entry is a nested
+/// structure with objects and arrays to exercise parsing, iteration, and lookup
+/// at multiple depths.
+///
+/// Structure:
+/// {"items": [
+/// {
+/// "name": "item_I",
+/// "value": I,
+/// "tags": [
+/// {"label": "tag_0", "priority": 0},
+/// ...
+/// ],
+/// "details": {
+/// "description": "description text for item I",
+/// "active": true/false,
+/// "nested": { "x": I, "y": I*100 }
+/// }
+/// },
+/// ...
+/// ]}
+static std::string generateJSON(int N) {
+ std::string S;
+ raw_string_ostream OS(S);
+ OS << "{\"items\": [\n";
+ for (int I = 0; I < N; ++I) {
+ if (I > 0)
+ OS << ",\n";
+ OS << " {\n"
+ << " \"name\": \"item_" << I << "\",\n"
+ << " \"value\": " << I << ",\n"
+ << " \"tags\": [\n"
+ << " {\"label\": \"tag_0\", \"priority\": 0},\n"
+ << " {\"label\": \"tag_1\", \"priority\": 1},\n"
+ << " {\"label\": \"tag_2\", \"priority\": 2}\n"
+ << " ],\n"
+ << " \"details\": {\n"
+ << " \"description\": \"description text for item " << I << "\",\n"
+ << " \"active\": " << (I % 2 == 0 ? "true" : "false") << ",\n"
+ << " \"nested\": {\"x\": " << I << ", \"y\": " << I * 100 << "}\n"
+ << " }\n"
+ << " }";
+ }
+ OS << "\n]}";
+ return S;
+}
+
+//===----------------------------------------------------------------------===//
+// Tree traversal helpers
+//===----------------------------------------------------------------------===//
+
+/// Walk the JSON value tree, visiting every node. Returns the number of
+/// nodes visited.
+static size_t walkTree(const json::Value &V) {
+ size_t Count = 1;
+ if (const auto *Obj = V.getAsObject()) {
+ for (const auto &KV : *Obj)
+ Count += walkTree(KV.second);
+ } else if (const auto *Arr = V.getAsArray()) {
+ for (const auto &Elem : *Arr)
+ Count += walkTree(Elem);
+ }
+ return Count;
+}
+
+/// An Object paired with its own keys, for lookup benchmarks.
+struct ObjectWithKeys {
+ const json::Object *Obj;
+ SmallVector<std::string> Keys;
+};
+
+/// Collect every Object in the tree together with its own keys.
+static void collectObjectsWithKeys(const json::Value &V,
+ SmallVectorImpl<ObjectWithKeys> &Result) {
+ if (const auto *Obj = V.getAsObject()) {
+ ObjectWithKeys Entry;
+ Entry.Obj = Obj;
+ for (const auto &KV : *Obj) {
+ Entry.Keys.push_back(std::string(StringRef(KV.first)));
+ collectObjectsWithKeys(KV.second, Result);
+ }
+ Result.push_back(std::move(Entry));
+ } else if (const auto *Arr = V.getAsArray()) {
+ for (const auto &Elem : *Arr)
+ collectObjectsWithKeys(Elem, Result);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Benchmarks
+//===----------------------------------------------------------------------===//
+
+/// Benchmark json::parse(). Reports parse throughput and memory allocated.
+static void BM_JSONParse(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+
+ // Measure memory for a single parse before the timed loop.
+ TotalAllocatedBytes = 0;
+ NumAllocs = 0;
+ TrackMemory = true;
+ {
+ auto V = json::parse(JSON);
+ benchmark::DoNotOptimize(V);
+ }
+ TrackMemory = false;
+
+ State.counters["AllocBytes"] = TotalAllocatedBytes.load();
+ State.counters["Allocs"] = NumAllocs.load();
+
+ for (auto _ : State) {
+ auto V = json::parse(JSON);
+ benchmark::DoNotOptimize(V);
+ }
+ State.counters["ParseByteRate"] = benchmark::Counter(
+ State.iterations() * JSON.size(), benchmark::Counter::kIsRate,
+ benchmark::Counter::kIs1024);
+}
+BENCHMARK(BM_JSONParse)->Arg(10)->Arg(1000)->Arg(100000);
+
+/// Benchmark recursive tree iteration over a parsed JSON value.
+static void BM_JSONIterate(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+ json::Value Root = cantFail(json::parse(JSON));
+ size_t NodeCount = 0;
+ for (auto _ : State) {
+ NodeCount = walkTree(Root);
+ benchmark::DoNotOptimize(NodeCount);
+ }
+ State.SetItemsProcessed(State.iterations() * NodeCount);
+}
+BENCHMARK(BM_JSONIterate)->Arg(10)->Arg(1000)->Arg(100000);
+
+/// Benchmark Object::get() with each object's own keys in insertion order.
+static void BM_JSONLookupSequential(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+ json::Value Root = cantFail(json::parse(JSON));
+ SmallVector<ObjectWithKeys> ObjKeys;
+ collectObjectsWithKeys(Root, ObjKeys);
+
+ size_t TotalLookups = 0;
+ for (const auto &OK : ObjKeys)
+ TotalLookups += OK.Keys.size();
+
+ for (auto _ : State) {
+ for (const auto &OK : ObjKeys)
+ for (const auto &K : OK.Keys)
+ benchmark::DoNotOptimize(OK.Obj->get(K));
+ }
+ State.SetItemsProcessed(State.iterations() * TotalLookups);
+}
+BENCHMARK(BM_JSONLookupSequential)->Arg(10)->Arg(1000)->Arg(100000);
+
+/// Benchmark Object::get() with each object's own keys in random order.
+static void BM_JSONLookupRandom(benchmark::State &State) {
+ std::string JSON = generateJSON(State.range(0));
+ json::Value Root = cantFail(json::parse(JSON));
+ SmallVector<ObjectWithKeys> ObjKeys;
+ collectObjectsWithKeys(Root, ObjKeys);
+
+ std::mt19937 RNG(42);
+ size_t TotalLookups = 0;
+ for (auto &OK : ObjKeys) {
+ TotalLookups += OK.Keys.size();
+ std::shuffle(OK.Keys.begin(), OK.Keys.end(), RNG);
+ }
+
+ for (auto _ : State) {
+ for (const auto &OK : ObjKeys)
+ for (const auto &K : OK.Keys)
+ benchmark::DoNotOptimize(OK.Obj->get(K));
+ }
+ State.SetItemsProcessed(State.iterations() * TotalLookups);
+}
+BENCHMARK(BM_JSONLookupRandom)->Arg(10)->Arg(1000)->Arg(100000);
+
+BENCHMARK_MAIN();
diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h
index 27862eb7ab6bb..bd429f0106885 100644
--- a/llvm/include/llvm/Support/JSON.h
+++ b/llvm/include/llvm/Support/JSON.h
@@ -46,16 +46,18 @@
#ifndef LLVM_SUPPORT_JSON_H
#define LLVM_SUPPORT_JSON_H
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <cmath>
#include <map>
+#include <unordered_map>
namespace llvm {
namespace json {
@@ -75,10 +77,12 @@ namespace json {
// - When retrieving strings from Values (e.g. asString()), the result will
// always be valid UTF-8.
+template <typename T, bool = std::is_integral_v<T>>
+constexpr bool is_uint_64_bit_v = false;
+
template <typename T>
-constexpr bool is_uint_64_bit_v =
- std::is_integral_v<T> && std::is_unsigned_v<T> &&
- sizeof(T) == sizeof(uint64_t);
+constexpr bool is_uint_64_bit_v<T, true> =
+ std::is_unsigned_v<T> && sizeof(T) == sizeof(uint64_t);
/// Returns true if \p S is valid UTF-8, which is required for use as JSON.
/// If it returns false, \p Offset is set to a byte offset near the first error.
@@ -89,76 +93,65 @@ LLVM_ABI bool isUTF8(llvm::StringRef S, size_t *ErrOffset = nullptr);
LLVM_ABI std::string fixUTF8(llvm::StringRef S);
class Array;
-class ObjectKey;
class Value;
+class Object;
template <typename T> Value toJSON(const std::optional<T> &Opt);
-/// An Object is a JSON object, which maps strings to heterogenous JSON values.
-/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string.
-class Object {
- using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
- Storage M;
-
+/// ObjectKey is a used to capture keys in Object. Like Value but:
+/// - only strings are allowed
+/// - it's optimized for the string literal case (Owned == nullptr)
+/// Like Value, strings must be UTF-8. See isUTF8 documentation for details.
+class ObjectKey {
public:
- using key_type = ObjectKey;
- using mapped_type = Value;
- using value_type = Storage::value_type;
- using iterator = Storage::iterator;
- using const_iterator = Storage::const_iterator;
-
- Object() = default;
- // KV is a trivial key-value struct for list-initialization.
- // (using std::pair forces extra copies).
- struct KV;
- explicit Object(std::initializer_list<KV> Properties);
-
- iterator begin() { return M.begin(); }
- const_iterator begin() const { return M.begin(); }
- iterator end() { return M.end(); }
- const_iterator end() const { return M.end(); }
-
- bool empty() const { return M.empty(); }
- size_t size() const { return M.size(); }
-
- void clear() { M.clear(); }
- std::pair<iterator, bool> insert(KV E);
- template <typename... Ts>
- std::pair<iterator, bool> try_emplace(const ObjectKey &K, Ts &&... Args) {
- return M.try_emplace(K, std::forward<Ts>(Args)...);
+ ObjectKey(const char *S) : ObjectKey(StringRef(S)) {}
+ ObjectKey(std::string S) : Owned(new std::string(std::move...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/193628
More information about the llvm-commits
mailing list