This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new 6cb53a51d refactor(cpp): remove abseil dependency (#3634)
6cb53a51d is described below

commit 6cb53a51d231779ae1697961ef4e422d17792ad0
Author: Shawn Yang <[email protected]>
AuthorDate: Wed Apr 29 16:21:52 2026 +0800

    refactor(cpp): remove abseil dependency (#3634)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence of the final clean AI review results
    from both fresh reviewers on the current PR diff or current HEAD after
    the latest code changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 .github/workflows/ci.yml                           | 131 +++-
 BUILD                                              |   2 +-
 LICENSE                                            |   8 +-
 MODULE.bazel                                       |   5 +-
 benchmarks/cpp/CMakeLists.txt                      |   5 +-
 cpp/CMakeLists.txt                                 |  34 +-
 cpp/cmake/ForyConfig.cmake.in                      |   3 -
 cpp/fory/serialization/BUILD                       |   2 +-
 cpp/fory/serialization/CMakeLists.txt              |   1 -
 cpp/fory/serialization/context.cc                  |   6 +-
 cpp/fory/serialization/context.h                   |   5 +-
 cpp/fory/serialization/ref_resolver.h              |  10 +-
 cpp/fory/serialization/type_info.h                 |   4 +-
 cpp/fory/serialization/type_resolver.cc            |  42 +-
 cpp/fory/serialization/type_resolver.h             |  23 +-
 cpp/fory/thirdparty/BUILD                          |  17 +
 cpp/fory/thirdparty/CMakeLists.txt                 |   6 +
 cpp/fory/thirdparty/flat_hash_map.h                | 853 +++++++++++++++++++++
 cpp/fory/thirdparty/flat_hash_map_test.cc          | 125 +++
 cpp/fory/util/BUILD                                |   5 -
 cpp/fory/util/CMakeLists.txt                       |  12 -
 cpp/fory/util/logging.cc                           |  42 +-
 cpp/fory/util/logging_test.cc                      |  13 +-
 LICENSE => licenses/LICENSE-abseil-cpp.txt         | 107 +--
 licenses/LICENSE-cython-abseil-example.txt         |  21 -
 python/pyfory/context.pxi                          |  35 +-
 python/pyfory/includes/libabsl.pxd                 |  75 --
 .../pyfory/includes/libflat_hash_map.pxd           |  41 +-
 python/pyfory/serialization.pyx                    |  42 +-
 29 files changed, 1295 insertions(+), 380 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 36459f081..adfd5b080 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,8 +47,15 @@ jobs:
     runs-on: ubuntu-latest
     outputs:
       cpp: ${{ steps.filter.outputs.cpp }}
+      cpp_code: ${{ steps.filter.outputs.cpp_code }}
+      java_code: ${{ steps.filter.outputs.java_code }}
       python: ${{ steps.filter.outputs.python }}
       graalvm: ${{ steps.filter.outputs.graalvm }}
+      rust: ${{ steps.filter.outputs.rust }}
+      swift: ${{ steps.filter.outputs.swift }}
+      javascript: ${{ steps.filter.outputs.javascript }}
+      kotlin: ${{ steps.filter.outputs.kotlin }}
+      scala: ${{ steps.filter.outputs.scala }}
     steps:
       - uses: actions/checkout@v5
       - name: Detect changed paths
@@ -59,8 +66,15 @@ jobs:
         run: |
           if [[ "$GITHUB_EVENT_NAME" != "pull_request" ]]; then
             echo "cpp=true" >> "$GITHUB_OUTPUT"
+            echo "cpp_code=true" >> "$GITHUB_OUTPUT"
+            echo "java_code=true" >> "$GITHUB_OUTPUT"
             echo "python=true" >> "$GITHUB_OUTPUT"
             echo "graalvm=true" >> "$GITHUB_OUTPUT"
+            echo "rust=true" >> "$GITHUB_OUTPUT"
+            echo "swift=true" >> "$GITHUB_OUTPUT"
+            echo "javascript=true" >> "$GITHUB_OUTPUT"
+            echo "kotlin=true" >> "$GITHUB_OUTPUT"
+            echo "scala=true" >> "$GITHUB_OUTPUT"
             exit 0
           fi
 
@@ -73,7 +87,19 @@ jobs:
             echo "cpp=false" >> "$GITHUB_OUTPUT"
           fi
 
-          if grep -Eq 
'^(cpp/|python/|bazel/|BUILD$|WORKSPACE$|MODULE\.bazel$|\.bazelrc$)' <<< 
"$changed_files"; then
+          if grep -Eq '^(cpp/)' <<< "$changed_files"; then
+            echo "cpp_code=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "cpp_code=false" >> "$GITHUB_OUTPUT"
+          fi
+
+          if grep -Eq '^(java/)' <<< "$changed_files"; then
+            echo "java_code=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "java_code=false" >> "$GITHUB_OUTPUT"
+          fi
+
+          if grep -Eq '^(python/)' <<< "$changed_files"; then
             echo "python=true" >> "$GITHUB_OUTPUT"
           else
             echo "python=false" >> "$GITHUB_OUTPUT"
@@ -85,6 +111,36 @@ jobs:
             echo "graalvm=false" >> "$GITHUB_OUTPUT"
           fi
 
+          if grep -Eq '^(rust/)' <<< "$changed_files"; then
+            echo "rust=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "rust=false" >> "$GITHUB_OUTPUT"
+          fi
+
+          if grep -Eq '^(swift/)' <<< "$changed_files"; then
+            echo "swift=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "swift=false" >> "$GITHUB_OUTPUT"
+          fi
+
+          if grep -Eq '^(javascript/)' <<< "$changed_files"; then
+            echo "javascript=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "javascript=false" >> "$GITHUB_OUTPUT"
+          fi
+
+          if grep -Eq '^(java/|kotlin/)' <<< "$changed_files"; then
+            echo "kotlin=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "kotlin=false" >> "$GITHUB_OUTPUT"
+          fi
+
+          if grep -Eq '^(java/|scala/)' <<< "$changed_files"; then
+            echo "scala=true" >> "$GITHUB_OUTPUT"
+          else
+            echo "scala=false" >> "$GITHUB_OUTPUT"
+          fi
+
   compiler:
     name: Compiler CI
     runs-on: ubuntu-latest
@@ -104,12 +160,13 @@ jobs:
 
   java:
     name: Java CI
+    needs: changes
     runs-on: ubuntu-latest
     env:
       MY_VAR: "PATH"
     strategy:
       matrix:
-        java-version: ["8", "11", "17", "21", "25"]
+        java-version: ${{ fromJSON(needs.changes.outputs.java_code == 'true' 
&& '["8","11","17","21","25"]' || '["8"]') }}
     steps:
       - uses: actions/checkout@v5
       - name: Set up JDK ${{ matrix.java-version }}
@@ -142,6 +199,8 @@ jobs:
 
   openj9:
     name: Openj9 Java CI
+    needs: changes
+    if: needs.changes.outputs.java_code == 'true'
     runs-on: ubuntu-latest
     env:
       MY_VAR: "PATH"
@@ -173,6 +232,8 @@ jobs:
 
   java21_windows:
     name: Windows Java 21 CI
+    needs: changes
+    if: needs.changes.outputs.java_code == 'true'
     runs-on: windows-2022
     env:
       MY_VAR: "PATH"
@@ -281,6 +342,8 @@ jobs:
 
   swift:
     name: Swift CI
+    needs: changes
+    if: needs.changes.outputs.swift == 'true'
     runs-on: macos-latest
     steps:
       - uses: actions/checkout@v5
@@ -301,10 +364,6 @@ jobs:
     runs-on: macos-latest
     steps:
       - uses: actions/checkout@v5
-      - name: Set up Python 3.11
-        uses: actions/setup-python@v5
-        with:
-          python-version: 3.11
       - name: Set up JDK 21
         uses: actions/setup-java@v4
         with:
@@ -340,6 +399,28 @@ jobs:
           mvn -T16 --no-transfer-progress clean install -DskipTests 
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true
           cd fory-core
           mvn -T16 --no-transfer-progress test 
-Dtest=org.apache.fory.xlang.SwiftXlangTest
+
+  swift_idl:
+    name: Swift IDL Tests
+    runs-on: macos-latest
+    steps:
+      - uses: actions/checkout@v5
+      - name: Set up Python 3.11
+        uses: actions/setup-python@v5
+        with:
+          python-version: 3.11
+      - name: Set up JDK 21
+        uses: actions/setup-java@v4
+        with:
+          java-version: 21
+          distribution: "temurin"
+      - name: Cache Maven local repository
+        uses: actions/cache@v4
+        with:
+          path: ~/.m2/repository
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-
       - name: Generate Swift IDL test code
         run: python ./integration_tests/idl_tests/generate_idl.py --lang swift
       - name: Cache Swift IDL package build artifacts
@@ -361,6 +442,10 @@ jobs:
         run: |
           cd integration_tests/idl_tests/swift/idl_package
           swift test --disable-automatic-resolution --skip-build
+      - name: Install Java artifacts for IDL tests
+        run: |
+          cd java
+          mvn -T16 --no-transfer-progress clean install -DskipTests 
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true
       - name: Run Java IDL tests against Swift peer
         env:
           IDL_PEER_LANG: "swift"
@@ -399,6 +484,8 @@ jobs:
 
   kotlin:
     name: Kotlin CI
+    needs: changes
+    if: needs.changes.outputs.kotlin == 'true'
     runs-on: ubuntu-latest
     env:
       MY_VAR: "PATH"
@@ -430,6 +517,8 @@ jobs:
 
   scala:
     name: Scala CI
+    needs: changes
+    if: needs.changes.outputs.scala == 'true'
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v5
@@ -479,6 +568,8 @@ jobs:
 
   javascript:
     name: JavaScript CI
+    needs: changes
+    if: needs.changes.outputs.javascript == 'true'
     strategy:
       matrix:
         node-version: [18, 24]
@@ -553,9 +644,11 @@ jobs:
 
   rust:
     name: Rust CI
+    needs: changes
     strategy:
       matrix:
-        os: [ubuntu-latest, macos-14, macos-latest] # macos-14: arm64
+        # macos-14 is the arm64 runner; keep it for Rust code changes only.
+        os: ${{ fromJSON(needs.changes.outputs.rust == 'true' && 
'["ubuntu-latest","macos-14","macos-latest"]' || 
'["ubuntu-latest","macos-latest"]') }}
     runs-on: ${{ matrix.os }}
     timeout-minutes: 45
     steps:
@@ -724,6 +817,8 @@ jobs:
 
   cpp_sanitizers:
     name: C++ Sanitizer (${{ matrix.sanitizer }})
+    needs: changes
+    if: needs.changes.outputs.cpp_code == 'true'
     runs-on: ubuntu-latest
     strategy:
       matrix:
@@ -903,6 +998,8 @@ jobs:
 
   python:
     name: Python CI
+    needs: changes
+    if: needs.changes.outputs.python == 'true'
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
@@ -927,13 +1024,17 @@ jobs:
           echo "Cleaning Bazel cache to ensure fresh build..."
           bazel clean --expunge || true
       - name: Run Python CI
-        shell: bash
-        run: python ./ci/run_ci.py python
-      - name: Run Python CI (ENABLE_FORY_CYTHON_SERIALIZATION=1)
         shell: bash
         env:
           ENABLE_FORY_CYTHON_SERIALIZATION: "1"
         run: python ./ci/run_ci.py python
+      - name: Run Python tests (ENABLE_FORY_CYTHON_SERIALIZATION=0)
+        shell: bash
+        env:
+          ENABLE_FORY_CYTHON_SERIALIZATION: "0"
+        run: |
+          cd python
+          pytest -v -s --durations=60 pyfory/tests
 
   python_windows:
     name: Python CI (${{ matrix.python-version }}, windows-2022)
@@ -963,13 +1064,17 @@ jobs:
           echo "Cleaning Bazel cache to ensure fresh build..."
           bazel clean --expunge || true
       - name: Run Python CI
-        shell: bash
-        run: python ./ci/run_ci.py python
-      - name: Run Python CI (ENABLE_FORY_CYTHON_SERIALIZATION=1)
         shell: bash
         env:
           ENABLE_FORY_CYTHON_SERIALIZATION: "1"
         run: python ./ci/run_ci.py python
+      - name: Run Python tests (ENABLE_FORY_CYTHON_SERIALIZATION=0)
+        shell: bash
+        env:
+          ENABLE_FORY_CYTHON_SERIALIZATION: "0"
+        run: |
+          cd python
+          pytest -v -s --durations=60 pyfory/tests
 
   python_xlang:
     name: Python Xlang Test
diff --git a/BUILD b/BUILD
index 2485123fd..69350bd55 100644
--- a/BUILD
+++ b/BUILD
@@ -51,7 +51,7 @@ pyx_library(
         "//cpp/fory/util:fory_util",
         "//cpp/fory/type:fory_type",
         "//python/pyfory/cpp:_pyfory",
-        "@abseil-cpp//absl/container:flat_hash_map",
+        "//cpp/fory/thirdparty:flat_hash_map",
     ],
 )
 
diff --git a/LICENSE b/LICENSE
index 62e28df76..ec5b5a270 100644
--- a/LICENSE
+++ b/LICENSE
@@ -247,6 +247,10 @@ The text of each license is the standard Apache 2.0 
license.
     Files:
       bazel/cython_library.bzl
 
+* abseil-cpp (https://github.com/abseil/abseil-cpp)
+    Files:
+      cpp/fory/thirdparty/flat_hash_map.h
+
 
 ================================================================
 BSD-3-Clause licenses
@@ -282,10 +286,6 @@ The text of each license is also included in 
licenses/LICENSE-[project].txt
     Files:
       javascript/packages/fory/lib/murmurHash3.ts
 
-* cython-abseil-sample (https://github.com/messense/cython-abseil-sample)
-    Files:
-      python/pyfory/includes/libabsl.pxd
-
 
 ================================================================
 Public Domain
diff --git a/MODULE.bazel b/MODULE.bazel
index 5a6712054..40e986476 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -17,7 +17,7 @@
 
 module(
     name = "fory",
-    version = "0.14.0",
+    version = "0.18.0",
 )
 
 # Platforms (needed for platform-specific build configurations)
@@ -49,9 +49,6 @@ bazel_dep(name = "cython", version = "3.1.3")
 # Google Test
 bazel_dep(name = "googletest", version = "1.15.2")
 
-# Abseil C++
-bazel_dep(name = "abseil-cpp", version = "20240722.0")
-
 # Hedron's Compile Commands Extractor for Bazel
 bazel_dep(name = "hedron_compile_commands", dev_dependency = True)
 git_override(
diff --git a/benchmarks/cpp/CMakeLists.txt b/benchmarks/cpp/CMakeLists.txt
index 972f4d8ac..b1659c08b 100644
--- a/benchmarks/cpp/CMakeLists.txt
+++ b/benchmarks/cpp/CMakeLists.txt
@@ -42,15 +42,14 @@ endif()
 # =============================================================================
 include(FetchContent)
 
-# Fory C++ library (local source) - this will also fetch Abseil
+# Fory C++ library (local source)
 FetchContent_Declare(
     fory
     SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../cpp"
 )
 FetchContent_MakeAvailable(fory)
 
-# Protobuf - fetch to ensure Abseil version compatibility
-# Using v25.5 which is compatible with Abseil 20240722.0
+# Protobuf benchmark dependency may use Abseil; Fory targets must not depend 
on it.
 set(protobuf_BUILD_TESTS OFF CACHE BOOL "" FORCE)
 set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
 set(protobuf_ABSL_PROVIDER "package" CACHE STRING "" FORCE)
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index afb70641e..98accdba8 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -67,18 +67,23 @@ endif()
 # Set Fory root directory for include paths (important when used as 
subdirectory)
 set(FORY_CPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Fory C++ root 
directory")
 
-# Fetch Abseil (required for debugging support)
-message(STATUS "Fetching Abseil via FetchContent")
-include(FetchContent)
-set(ABSL_PROPAGATE_CXX_STD ON)
-set(ABSL_BUILD_TESTING OFF)
-set(ABSL_ENABLE_INSTALL ON)
-FetchContent_Declare(
-    abseil-cpp
-    GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
-    GIT_TAG 20240722.0
-)
-FetchContent_MakeAvailable(abseil-cpp)
+# Tests are declared inside runtime subdirectories, so GTest's CMake helpers 
must
+# be available before those subdirectories are configured.
+if(FORY_BUILD_TESTS)
+    enable_testing()
+    find_package(GTest QUIET)
+    if(NOT GTest_FOUND)
+        include(FetchContent)
+        set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
+        FetchContent_Declare(
+            googletest
+            GIT_REPOSITORY https://github.com/google/googletest.git
+            GIT_TAG v1.15.2
+        )
+        FetchContent_MakeAvailable(googletest)
+    endif()
+    include(GoogleTest)
+endif()
 
 # Add subdirectories
 add_subdirectory(fory/thirdparty)
@@ -105,10 +110,7 @@ target_link_libraries(fory_lib INTERFACE 
fory_serialization fory_row_format fory
 add_library(fory::fory ALIAS fory_lib)
 
 # Tests
-if(FORY_BUILD_TESTS)
-    enable_testing()
-    find_package(GTest REQUIRED)
-    include(GoogleTest)
+if(FORY_BUILD_TESTS AND EXISTS 
"${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt")
     add_subdirectory(tests)
 endif()
 
diff --git a/cpp/cmake/ForyConfig.cmake.in b/cpp/cmake/ForyConfig.cmake.in
index f14844247..1ddd407a3 100644
--- a/cpp/cmake/ForyConfig.cmake.in
+++ b/cpp/cmake/ForyConfig.cmake.in
@@ -19,9 +19,6 @@
 
 include(CMakeFindDependencyMacro)
 
-# Check for Abseil (optional)
-find_package(absl CONFIG QUIET)
-
 include("${CMAKE_CURRENT_LIST_DIR}/ForyTargets.cmake")
 
 # Provide convenient component targets
diff --git a/cpp/fory/serialization/BUILD b/cpp/fory/serialization/BUILD
index 77f15a5d1..2308a59bf 100644
--- a/cpp/fory/serialization/BUILD
+++ b/cpp/fory/serialization/BUILD
@@ -38,10 +38,10 @@ cc_library(
     strip_include_prefix = "/cpp",
     deps = [
         "//cpp/fory/meta:fory_meta",
+        "//cpp/fory/thirdparty:flat_hash_map",
         "//cpp/fory/thirdparty:libmmh3",
         "//cpp/fory/type:fory_type",
         "//cpp/fory/util:fory_util",
-        "@abseil-cpp//absl/container:flat_hash_map",
     ],
     visibility = ["//visibility:public"],
 )
diff --git a/cpp/fory/serialization/CMakeLists.txt 
b/cpp/fory/serialization/CMakeLists.txt
index 0582554c7..b65047b5c 100644
--- a/cpp/fory/serialization/CMakeLists.txt
+++ b/cpp/fory/serialization/CMakeLists.txt
@@ -64,7 +64,6 @@ target_link_libraries(fory_serialization
         fory_type
         fory_util
         fory_thirdparty
-        absl::flat_hash_map
 )
 
 set_target_properties(fory_serialization PROPERTIES
diff --git a/cpp/fory/serialization/context.cc 
b/cpp/fory/serialization/context.cc
index 28fbc6b1d..7967a3335 100644
--- a/cpp/fory/serialization/context.cc
+++ b/cpp/fory/serialization/context.cc
@@ -520,10 +520,10 @@ Result<const TypeInfo *, Error> 
ReadContext::read_type_meta() {
     return cached;
   }
 
-  auto cache_it = parsed_type_infos_.find(meta_header);
-  if (cache_it != parsed_type_infos_.end()) {
+  auto *cache_entry = parsed_type_infos_.find(meta_header);
+  if (cache_entry != nullptr) {
     // Found in cache - reuse and skip the bytes
-    const TypeInfo *cached = cache_it->second;
+    const TypeInfo *cached = cache_entry->second;
     reading_type_infos_.push_back(cached);
     has_last_meta_header_ = true;
     last_meta_header_ = meta_header;
diff --git a/cpp/fory/serialization/context.h b/cpp/fory/serialization/context.h
index 9b8063055..52d740ccf 100644
--- a/cpp/fory/serialization/context.h
+++ b/cpp/fory/serialization/context.h
@@ -23,14 +23,13 @@
 #include "fory/serialization/config.h"
 #include "fory/serialization/ref_resolver.h"
 #include "fory/serialization/type_info.h"
+#include "fory/thirdparty/flat_hash_map.h"
 #include "fory/type/type.h"
 #include "fory/util/buffer.h"
 #include "fory/util/error.h"
 #include "fory/util/flat_int_map.h"
 #include "fory/util/result.h"
 
-#include "absl/container/flat_hash_map.h"
-
 #include <cassert>
 #include <typeindex>
 
@@ -674,7 +673,7 @@ private:
   // Index-based access (pointers to owned_reading_type_infos_ or 
type_resolver)
   std::vector<const TypeInfo *> reading_type_infos_;
   // Cache by meta_header (pointers to cached_type_infos_)
-  absl::flat_hash_map<int64_t, const TypeInfo *> parsed_type_infos_;
+  fory::flat_hash_map<int64_t, const TypeInfo *> parsed_type_infos_;
   // Fast path for repeated type meta headers.
   int64_t last_meta_header_ = 0;
   const TypeInfo *last_meta_type_info_ = nullptr;
diff --git a/cpp/fory/serialization/ref_resolver.h 
b/cpp/fory/serialization/ref_resolver.h
index c22255283..01c2b8eec 100644
--- a/cpp/fory/serialization/ref_resolver.h
+++ b/cpp/fory/serialization/ref_resolver.h
@@ -22,7 +22,7 @@
 #include "fory/util/error.h"
 #include "fory/util/result.h"
 
-#include "absl/container/flat_hash_map.h"
+#include "fory/thirdparty/flat_hash_map.h"
 
 #include <any>
 #include <cstdint>
@@ -65,10 +65,10 @@ public:
     }
 
     auto address = reinterpret_cast<uintptr_t>(ptr.get());
-    auto it = ptr_to_id_.find(address);
-    if (it != ptr_to_id_.end()) {
+    auto *entry = ptr_to_id_.find(address);
+    if (entry != nullptr) {
       writer.write_int8(static_cast<int8_t>(RefFlag::Ref));
-      writer.write_var_uint32(it->second);
+      writer.write_var_uint32(entry->second);
       return true;
     }
 
@@ -91,7 +91,7 @@ public:
   }
 
 private:
-  absl::flat_hash_map<uintptr_t, uint32_t> ptr_to_id_;
+  fory::flat_hash_map<uintptr_t, uint32_t> ptr_to_id_;
   uint32_t next_id_;
 };
 
diff --git a/cpp/fory/serialization/type_info.h 
b/cpp/fory/serialization/type_info.h
index 1379727da..f31b14cc0 100644
--- a/cpp/fory/serialization/type_info.h
+++ b/cpp/fory/serialization/type_info.h
@@ -23,7 +23,7 @@
 #include "fory/util/error.h"
 #include "fory/util/result.h"
 
-#include "absl/container/flat_hash_map.h"
+#include "fory/thirdparty/flat_hash_map.h"
 
 #include <any>
 #include <cstdint>
@@ -125,7 +125,7 @@ struct TypeInfo {
   bool is_external = false;
   std::unique_ptr<TypeMeta> type_meta;
   std::vector<size_t> sorted_indices;
-  absl::flat_hash_map<std::string, size_t> name_to_index;
+  fory::flat_hash_map<std::string, size_t> name_to_index;
   std::vector<uint8_t> type_def;
   Harness harness;
   // Pre-encoded meta strings for efficient writing (avoids re-encoding on each
diff --git a/cpp/fory/serialization/type_resolver.cc 
b/cpp/fory/serialization/type_resolver.cc
index d5038ddd6..b17f959fb 100644
--- a/cpp/fory/serialization/type_resolver.cc
+++ b/cpp/fory/serialization/type_resolver.cc
@@ -1324,11 +1324,11 @@ encode_meta_string(const std::string &value, bool 
is_namespace) {
 Result<const TypeInfo *, Error>
 TypeResolver::get_type_info(const std::type_index &type_index) const {
   // For runtime polymorphic lookups (e.g., smart pointers with dynamic types)
-  auto it = type_info_by_runtime_type_.find(type_index);
-  if (it == type_info_by_runtime_type_.end()) {
+  auto *entry = type_info_by_runtime_type_.find(type_index);
+  if (entry == nullptr) {
     return Unexpected(Error::type_error("TypeInfo not found for type_index"));
   }
-  return it->second;
+  return entry->second;
 }
 
 Result<std::unique_ptr<TypeResolver>, Error>
@@ -1343,7 +1343,7 @@ TypeResolver::build_final_type_resolver() {
   final_resolver->finalized_ = true;
 
   // Build mapping from old pointers to new pointers for rebuilding lookup maps
-  absl::flat_hash_map<const TypeInfo *, TypeInfo *> ptr_map;
+  fory::flat_hash_map<const TypeInfo *, TypeInfo *> ptr_map;
 
   // Deep clone all existing TypeInfo objects
   for (const auto &info : type_infos_) {
@@ -1352,26 +1352,31 @@ TypeResolver::build_final_type_resolver() {
     ptr_map[info.get()] = new_ptr;
     final_resolver->type_infos_.push_back(std::move(cloned));
   }
+  auto remap_type_info = [&ptr_map](const TypeInfo *old_ptr) {
+    auto *entry = ptr_map.find(old_ptr);
+    FORY_CHECK(entry != nullptr);
+    return entry->second;
+  };
 
   // Rebuild lookup maps with new pointers
   for (const auto &[key, old_ptr] : type_info_by_ctid_) {
-    final_resolver->type_info_by_ctid_.put(key, ptr_map[old_ptr]);
+    final_resolver->type_info_by_ctid_.put(key, remap_type_info(old_ptr));
   }
   for (const auto &[key, old_ptr] : type_info_by_id_) {
-    final_resolver->type_info_by_id_.put(key, ptr_map[old_ptr]);
+    final_resolver->type_info_by_id_.put(key, remap_type_info(old_ptr));
   }
   for (const auto &[key, old_ptr] : user_type_info_by_id_) {
-    final_resolver->user_type_info_by_id_.put(key, ptr_map[old_ptr]);
+    final_resolver->user_type_info_by_id_.put(key, remap_type_info(old_ptr));
   }
   for (const auto &[key, old_ptr] : type_info_by_name_) {
-    final_resolver->type_info_by_name_[key] = ptr_map[old_ptr];
+    final_resolver->type_info_by_name_[key] = remap_type_info(old_ptr);
   }
   for (const auto &[key, old_ptr] : type_info_by_runtime_type_) {
-    final_resolver->type_info_by_runtime_type_[key] = ptr_map[old_ptr];
+    final_resolver->type_info_by_runtime_type_[key] = remap_type_info(old_ptr);
   }
 
   for (const auto &[key, old_ptr] : partial_type_infos_) {
-    final_resolver->partial_type_infos_.put(key, ptr_map[old_ptr]);
+    final_resolver->partial_type_infos_.put(key, remap_type_info(old_ptr));
   }
 
   // Process all partial type infos to build complete type metadata
@@ -1418,7 +1423,7 @@ std::unique_ptr<TypeResolver> TypeResolver::clone() const 
{
   cloned->finalized_ = finalized_;
 
   // Build mapping from old pointers to new pointers
-  absl::flat_hash_map<const TypeInfo *, TypeInfo *> ptr_map;
+  fory::flat_hash_map<const TypeInfo *, TypeInfo *> ptr_map;
 
   // Deep clone all TypeInfo objects
   for (const auto &info : type_infos_) {
@@ -1427,22 +1432,27 @@ std::unique_ptr<TypeResolver> TypeResolver::clone() 
const {
     ptr_map[info.get()] = new_ptr;
     cloned->type_infos_.push_back(std::move(cloned_info));
   }
+  auto remap_type_info = [&ptr_map](const TypeInfo *old_ptr) {
+    auto *entry = ptr_map.find(old_ptr);
+    FORY_CHECK(entry != nullptr);
+    return entry->second;
+  };
 
   // Rebuild lookup maps with new pointers
   for (const auto &[key, old_ptr] : type_info_by_ctid_) {
-    cloned->type_info_by_ctid_.put(key, ptr_map[old_ptr]);
+    cloned->type_info_by_ctid_.put(key, remap_type_info(old_ptr));
   }
   for (const auto &[key, old_ptr] : type_info_by_id_) {
-    cloned->type_info_by_id_.put(key, ptr_map[old_ptr]);
+    cloned->type_info_by_id_.put(key, remap_type_info(old_ptr));
   }
   for (const auto &[key, old_ptr] : user_type_info_by_id_) {
-    cloned->user_type_info_by_id_.put(key, ptr_map[old_ptr]);
+    cloned->user_type_info_by_id_.put(key, remap_type_info(old_ptr));
   }
   for (const auto &[key, old_ptr] : type_info_by_name_) {
-    cloned->type_info_by_name_[key] = ptr_map[old_ptr];
+    cloned->type_info_by_name_[key] = remap_type_info(old_ptr);
   }
   for (const auto &[key, old_ptr] : type_info_by_runtime_type_) {
-    cloned->type_info_by_runtime_type_[key] = ptr_map[old_ptr];
+    cloned->type_info_by_runtime_type_[key] = remap_type_info(old_ptr);
   }
   // Note: Don't copy partial_type_infos_ - clone should only be used on
   // finalized resolvers
diff --git a/cpp/fory/serialization/type_resolver.h 
b/cpp/fory/serialization/type_resolver.h
index d13157b5e..e5c746781 100644
--- a/cpp/fory/serialization/type_resolver.h
+++ b/cpp/fory/serialization/type_resolver.h
@@ -42,8 +42,6 @@
 #include <utility>
 #include <vector>
 
-#include "absl/container/flat_hash_map.h"
-
 #include "fory/meta/field.h"
 #include "fory/meta/field_info.h"
 #include "fory/meta/type_traits.h"
@@ -51,6 +49,7 @@
 #include "fory/serialization/serializer.h"
 #include "fory/serialization/serializer_traits.h"
 #include "fory/serialization/type_info.h"
+#include "fory/thirdparty/flat_hash_map.h"
 #include "fory/type/type.h"
 #include "fory/util/buffer.h"
 #include "fory/util/error.h"
@@ -1194,11 +1193,11 @@ private:
   util::U64PtrMap<TypeInfo> type_info_by_ctid_{256};
   util::U32PtrMap<TypeInfo> type_info_by_id_{256};
   util::U64PtrMap<TypeInfo> user_type_info_by_id_{256};
-  absl::flat_hash_map<std::string, TypeInfo *> type_info_by_name_;
+  fory::flat_hash_map<std::string, TypeInfo *> type_info_by_name_;
   util::U64PtrMap<TypeInfo> partial_type_infos_{256};
 
   // For runtime polymorphic lookups (smart pointers) - uses std::type_index
-  absl::flat_hash_map<std::type_index, TypeInfo *> type_info_by_runtime_type_;
+  fory::flat_hash_map<std::type_index, TypeInfo *> type_info_by_runtime_type_;
 };
 
 // Alias for backward compatibility (already defined above as top-level)
@@ -1579,11 +1578,11 @@ TypeResolver::build_struct_type_info(uint32_t type_id, 
uint32_t user_type_id,
   entry->sorted_indices.clear();
   entry->sorted_indices.reserve(field_count);
   for (const auto &sorted_field : sorted_fields) {
-    auto it = entry->name_to_index.find(sorted_field.field_name);
-    FORY_CHECK(it != entry->name_to_index.end())
+    auto *name_entry = entry->name_to_index.find(sorted_field.field_name);
+    FORY_CHECK(name_entry != nullptr)
         << "Sorted field name '" << sorted_field.field_name
         << "' not found in original struct definition";
-    entry->sorted_indices.push_back(it->second);
+    entry->sorted_indices.push_back(name_entry->second);
   }
 
   entry->harness = make_struct_harness<T>();
@@ -1889,8 +1888,8 @@ TypeResolver::register_type_internal(uint64_t ctid,
 
   if (raw_ptr->register_by_name) {
     name_key = make_name_key(raw_ptr->namespace_name, raw_ptr->type_name);
-    auto it = type_info_by_name_.find(name_key);
-    if (it != type_info_by_name_.end()) {
+    auto *entry = type_info_by_name_.find(name_key);
+    if (entry != nullptr) {
       return Unexpected(Error::invalid(
           "Type already registered for namespace '" + raw_ptr->namespace_name +
           "' and name '" + raw_ptr->type_name + "'"));
@@ -1949,9 +1948,9 @@ inline Result<const TypeInfo *, Error>
 TypeResolver::get_type_info_by_name(const std::string &ns,
                                     const std::string &type_name) const {
   auto key = make_name_key(ns, type_name);
-  auto it = type_info_by_name_.find(key);
-  if (it != type_info_by_name_.end()) {
-    return it->second;
+  auto *entry = type_info_by_name_.find(key);
+  if (entry != nullptr) {
+    return entry->second;
   }
   return Unexpected(Error::type_error("TypeInfo not found for type: " + ns +
                                       "." + type_name));
diff --git a/cpp/fory/thirdparty/BUILD b/cpp/fory/thirdparty/BUILD
index f54e00356..e951e391a 100644
--- a/cpp/fory/thirdparty/BUILD
+++ b/cpp/fory/thirdparty/BUILD
@@ -9,3 +9,20 @@ cc_library(
     linkstatic=True,
     visibility = ["//visibility:public"],
 )
+
+cc_library(
+    name = "flat_hash_map",
+    hdrs = ["flat_hash_map.h"],
+    strip_include_prefix = "/cpp",
+    visibility = ["//visibility:public"],
+)
+
+cc_test(
+    name = "flat_hash_map_test",
+    srcs = ["flat_hash_map_test.cc"],
+    deps = [
+        ":flat_hash_map",
+        "@googletest//:gtest",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/cpp/fory/thirdparty/CMakeLists.txt 
b/cpp/fory/thirdparty/CMakeLists.txt
index 048922fae..ec0800ef4 100644
--- a/cpp/fory/thirdparty/CMakeLists.txt
+++ b/cpp/fory/thirdparty/CMakeLists.txt
@@ -30,3 +30,9 @@ set_target_properties(fory_thirdparty PROPERTIES
     POSITION_INDEPENDENT_CODE ON
     OUTPUT_NAME fory_thirdparty
 )
+
+if(FORY_BUILD_TESTS)
+    add_executable(fory_thirdparty_flat_hash_map_test flat_hash_map_test.cc)
+    target_link_libraries(fory_thirdparty_flat_hash_map_test fory_thirdparty 
GTest::gtest GTest::gtest_main)
+    gtest_discover_tests(fory_thirdparty_flat_hash_map_test)
+endif()
diff --git a/cpp/fory/thirdparty/flat_hash_map.h 
b/cpp/fory/thirdparty/flat_hash_map.h
new file mode 100644
index 000000000..ae5439487
--- /dev/null
+++ b/cpp/fory/thirdparty/flat_hash_map.h
@@ -0,0 +1,853 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+// This file is a compact Fory-owned SwissTable flat hash map derived from
+// Abseil's flat_hash_map/raw_hash_set design. It keeps the 
performance-critical
+// pieces Fory relies on: separate control bytes, H1/H2 hash splitting,
+// triangular group probing, and SIMD group matching on SSE2/AArch64 NEON.
+
+#pragma once
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <new>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <typeindex>
+#include <utility>
+#include <vector>
+
+#if defined(_MSC_VER)
+#define FORY_FLAT_HASH_MAP_ALWAYS_INLINE __forceinline
+#else
+#define FORY_FLAT_HASH_MAP_ALWAYS_INLINE inline __attribute__((always_inline))
+#endif
+
+#if defined(__SSE2__) || defined(_M_X64) ||                                    
\
+    (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+#include <emmintrin.h>
+#define FORY_FLAT_HASH_MAP_HAVE_SSE2 1
+#endif
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+#if defined(__ARM_NEON) || defined(__ARM_NEON__)
+#include <arm_neon.h>
+#define FORY_FLAT_HASH_MAP_HAVE_NEON 1
+#endif
+
+namespace fory {
+namespace detail {
+namespace flat_hash_map_internal {
+
+using ctrl_t = int8_t;
+
+constexpr ctrl_t kEmpty = static_cast<ctrl_t>(-128);
+constexpr ctrl_t kDeleted = static_cast<ctrl_t>(-2);
+constexpr float kMaxLoadFactor = 0.875f;
+
+FORY_FLAT_HASH_MAP_ALWAYS_INLINE size_t mix_hash(size_t hash) {
+  uint64_t x = static_cast<uint64_t>(hash);
+  x ^= x >> 32;
+  x *= 0xd6e8feb86659fd93ULL;
+  x ^= x >> 32;
+  if constexpr (sizeof(size_t) < sizeof(uint64_t)) {
+    return static_cast<size_t>(x ^ (x >> 32));
+  } else {
+    return static_cast<size_t>(x);
+  }
+}
+
+FORY_FLAT_HASH_MAP_ALWAYS_INLINE uint8_t h2(size_t hash) {
+  return static_cast<uint8_t>(hash >> (sizeof(size_t) * 8 - 7));
+}
+
+FORY_FLAT_HASH_MAP_ALWAYS_INLINE bool is_full(ctrl_t ctrl) { return ctrl >= 0; 
}
+FORY_FLAT_HASH_MAP_ALWAYS_INLINE bool is_empty(ctrl_t ctrl) {
+  return ctrl == kEmpty;
+}
+FORY_FLAT_HASH_MAP_ALWAYS_INLINE bool is_deleted(ctrl_t ctrl) {
+  return ctrl == kDeleted;
+}
+
+inline size_t next_capacity(size_t requested) {
+  size_t capacity = 16;
+  while (capacity < requested) {
+    capacity <<= 1;
+  }
+  return capacity;
+}
+
+inline uint32_t trailing_zeros(uint32_t value) {
+#if defined(_MSC_VER)
+  unsigned long index = 0;
+  _BitScanForward(&index, value);
+  return static_cast<uint32_t>(index);
+#else
+  return static_cast<uint32_t>(__builtin_ctz(value));
+#endif
+}
+
+inline uint32_t trailing_zeros(uint64_t value) {
+#if defined(_MSC_VER) && defined(_M_X64)
+  unsigned long index = 0;
+  _BitScanForward64(&index, value);
+  return static_cast<uint32_t>(index);
+#elif defined(_MSC_VER)
+  uint32_t low = static_cast<uint32_t>(value);
+  if (low != 0) {
+    return trailing_zeros(low);
+  }
+  return 32 + trailing_zeros(static_cast<uint32_t>(value >> 32));
+#else
+  return static_cast<uint32_t>(__builtin_ctzll(value));
+#endif
+}
+
+inline uint32_t clear_lowest_bit(uint32_t mask) { return mask & (mask - 1); }
+
+inline uint64_t clear_lowest_bit(uint64_t mask) { return mask & (mask - 1); }
+
+template <typename T, typename = void> struct default_hash {
+  size_t operator()(const T &value) const { return std::hash<T>{}(value); }
+};
+
+template <typename A, typename B> struct default_hash<std::pair<A, B>> {
+  size_t operator()(const std::pair<A, B> &value) const {
+    size_t first = default_hash<A>{}(value.first);
+    size_t second = default_hash<B>{}(value.second);
+    return first ^
+           (second + 0x9e3779b97f4a7c15ULL + (first << 6) + (first >> 2));
+  }
+};
+
+template <size_t Width> class probe_seq {
+public:
+  probe_seq(size_t hash, size_t mask) : mask_(mask), offset_(hash & mask) {}
+
+  size_t offset() const { return offset_; }
+
+  void next() {
+    index_ += Width;
+    offset_ = (offset_ + index_) & mask_;
+  }
+
+  size_t index() const { return index_; }
+
+private:
+  size_t mask_;
+  size_t offset_;
+  size_t index_ = 0;
+};
+
+#if defined(FORY_FLAT_HASH_MAP_HAVE_SSE2)
+class group_sse2 {
+public:
+  static constexpr size_t kWidth = 16;
+  using mask_type = uint32_t;
+
+  explicit group_sse2(const ctrl_t *control)
+      : control_(_mm_loadu_si128(reinterpret_cast<const __m128i *>(control))) 
{}
+
+  uint32_t match(uint8_t tag) const {
+    const __m128i match = _mm_set1_epi8(static_cast<char>(tag));
+    return static_cast<uint32_t>(
+        _mm_movemask_epi8(_mm_cmpeq_epi8(match, control_)));
+  }
+
+  uint32_t mask_empty() const {
+    const __m128i match = _mm_set1_epi8(static_cast<char>(kEmpty));
+    return static_cast<uint32_t>(
+        _mm_movemask_epi8(_mm_cmpeq_epi8(match, control_)));
+  }
+
+  uint32_t mask_empty_or_deleted() const {
+    const __m128i sentinel = _mm_set1_epi8(static_cast<char>(-1));
+    return static_cast<uint32_t>(
+        _mm_movemask_epi8(_mm_cmpgt_epi8(sentinel, control_)));
+  }
+
+  static uint32_t lowest_bit(mask_type mask) { return trailing_zeros(mask); }
+
+  static mask_type clear_lowest_bit(mask_type mask) {
+    return flat_hash_map_internal::clear_lowest_bit(mask);
+  }
+
+private:
+  __m128i control_;
+};
+#endif
+
+#if defined(FORY_FLAT_HASH_MAP_HAVE_NEON)
+constexpr uint64_t kMsbs8Bytes = 0x8080808080808080ULL;
+
+class group_neon {
+public:
+  static constexpr size_t kWidth = 8;
+  using mask_type = uint64_t;
+
+  explicit group_neon(const ctrl_t *control)
+      : control_(vld1_u8(reinterpret_cast<const uint8_t *>(control))) {}
+
+  mask_type match(uint8_t tag) const {
+    const uint8x8_t result = vceq_u8(control_, vdup_n_u8(tag));
+    uint64_t raw = vget_lane_u64(vreinterpret_u64_u8(result), 0);
+    return raw & kMsbs8Bytes;
+  }
+
+  mask_type mask_empty() const {
+    const uint8x8_t result =
+        vceq_s8(vreinterpret_s8_u8(control_), vdup_n_s8(kEmpty));
+    uint64_t raw = vget_lane_u64(vreinterpret_u64_u8(result), 0);
+    return raw & kMsbs8Bytes;
+  }
+
+  mask_type mask_empty_or_deleted() const {
+    const uint8x8_t result = vcgt_s8(vdup_n_s8(static_cast<int8_t>(-1)),
+                                     vreinterpret_s8_u8(control_));
+    uint64_t raw = vget_lane_u64(vreinterpret_u64_u8(result), 0);
+    return raw & kMsbs8Bytes;
+  }
+
+  static uint32_t lowest_bit(mask_type mask) {
+    return trailing_zeros(mask) >> 3;
+  }
+
+  static mask_type clear_lowest_bit(mask_type mask) {
+    return flat_hash_map_internal::clear_lowest_bit(mask);
+  }
+
+private:
+  uint8x8_t control_;
+};
+#endif
+
+class group_portable {
+public:
+  static constexpr size_t kWidth = 8;
+  using mask_type = uint32_t;
+
+  explicit group_portable(const ctrl_t *control) : control_(control) {}
+
+  uint32_t match(uint8_t tag) const {
+    uint32_t mask = 0;
+    for (size_t i = 0; i < kWidth; ++i) {
+      mask |= static_cast<uint32_t>(control_[i] == static_cast<ctrl_t>(tag))
+              << i;
+    }
+    return mask;
+  }
+
+  uint32_t mask_empty() const {
+    uint32_t mask = 0;
+    for (size_t i = 0; i < kWidth; ++i) {
+      mask |= static_cast<uint32_t>(is_empty(control_[i])) << i;
+    }
+    return mask;
+  }
+
+  uint32_t mask_empty_or_deleted() const {
+    uint32_t mask = 0;
+    for (size_t i = 0; i < kWidth; ++i) {
+      mask |= static_cast<uint32_t>(control_[i] < static_cast<ctrl_t>(-1)) << 
i;
+    }
+    return mask;
+  }
+
+  static uint32_t lowest_bit(mask_type mask) { return trailing_zeros(mask); }
+
+  static mask_type clear_lowest_bit(mask_type mask) {
+    return flat_hash_map_internal::clear_lowest_bit(mask);
+  }
+
+private:
+  const ctrl_t *control_;
+};
+
+#if defined(FORY_FLAT_HASH_MAP_HAVE_SSE2)
+using group = group_sse2;
+#elif defined(FORY_FLAT_HASH_MAP_HAVE_NEON)
+using group = group_neon;
+#else
+using group = group_portable;
+#endif
+
+} // namespace flat_hash_map_internal
+} // namespace detail
+
+template <typename K, typename V,
+          typename Hash = detail::flat_hash_map_internal::default_hash<K>,
+          typename Eq = std::equal_to<K>,
+          typename Alloc = std::allocator<std::pair<K, V>>>
+class flat_hash_map {
+public:
+  using key_type = K;
+  using mapped_type = V;
+  using value_type = std::pair<K, V>;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using hasher = Hash;
+  using key_equal = Eq;
+  using allocator_type = Alloc;
+  using reference = value_type &;
+  using const_reference = const value_type &;
+  using pointer = value_type *;
+  using const_pointer = const value_type *;
+
+private:
+  using ctrl_t = detail::flat_hash_map_internal::ctrl_t;
+  using group = detail::flat_hash_map_internal::group;
+
+  struct slot_type {
+    alignas(value_type) unsigned char storage[sizeof(value_type)];
+
+    value_type *value() { return reinterpret_cast<value_type *>(storage); }
+
+    const value_type *value() const {
+      return reinterpret_cast<const value_type *>(storage);
+    }
+  };
+
+public:
+  // Iteration is retained for copy/rebuild/diagnostic paths. It scans control
+  // bytes and is not the optimized serialization fast path; hot lookup/insert
+  // code should use find()'s nullable pointer result and insert/emplace.
+  template <bool IsConst> class iterator_base {
+    using map_pointer =
+        std::conditional_t<IsConst, const flat_hash_map *, flat_hash_map *>;
+
+  public:
+    using iterator_category = std::forward_iterator_tag;
+    using value_type = flat_hash_map::value_type;
+    using difference_type = flat_hash_map::difference_type;
+    using reference =
+        std::conditional_t<IsConst, const value_type &, value_type &>;
+    using pointer =
+        std::conditional_t<IsConst, const value_type *, value_type *>;
+
+    iterator_base() : map_(nullptr), index_(0) {}
+
+    iterator_base(map_pointer map, size_t index) : map_(map), index_(index) {
+      skip_empty();
+    }
+
+    template <bool B = IsConst, typename = std::enable_if_t<B>>
+    iterator_base(const iterator_base<false> &other)
+        : map_(other.map_), index_(other.index_) {}
+
+    reference operator*() const { return *map_->slots_[index_].value(); }
+
+    pointer operator->() const { return map_->slots_[index_].value(); }
+
+    iterator_base &operator++() {
+      ++index_;
+      skip_empty();
+      return *this;
+    }
+
+    iterator_base operator++(int) {
+      iterator_base copy = *this;
+      ++(*this);
+      return copy;
+    }
+
+    iterator_base &operator--() = delete;
+
+    bool operator==(const iterator_base &other) const {
+      return map_ == other.map_ && index_ == other.index_;
+    }
+
+    bool operator!=(const iterator_base &other) const {
+      return !(*this == other);
+    }
+
+  private:
+    friend class flat_hash_map;
+    template <bool> friend class iterator_base;
+
+    void skip_empty() {
+      while (map_ != nullptr && index_ < map_->capacity_ &&
+             !detail::flat_hash_map_internal::is_full(map_->ctrl_[index_])) {
+        ++index_;
+      }
+    }
+
+    map_pointer map_;
+    size_t index_;
+  };
+
+  using iterator = iterator_base<false>;
+  using const_iterator = iterator_base<true>;
+
+  flat_hash_map() { initialize(0); }
+
+  explicit flat_hash_map(size_t bucket_count) { initialize(bucket_count); }
+
+  flat_hash_map(std::initializer_list<value_type> values) {
+    initialize(values.size());
+    for (const auto &value : values) {
+      emplace(value.first, value.second);
+    }
+  }
+
+  flat_hash_map(const flat_hash_map &other)
+      : hash_(other.hash_), eq_(other.eq_) {
+    initialize(other.size_);
+    for (const auto &value : other) {
+      emplace(value.first, value.second);
+    }
+  }
+
+  flat_hash_map(flat_hash_map &&other) noexcept
+      : ctrl_(std::move(other.ctrl_)), slots_(std::move(other.slots_)),
+        size_(other.size_), capacity_(other.capacity_),
+        growth_left_(other.growth_left_), hash_(std::move(other.hash_)),
+        eq_(std::move(other.eq_)) {
+    other.size_ = 0;
+    other.capacity_ = 0;
+    other.growth_left_ = 0;
+  }
+
+  flat_hash_map &operator=(const flat_hash_map &other) {
+    if (this == &other) {
+      return *this;
+    }
+    flat_hash_map copy(other);
+    swap(copy);
+    return *this;
+  }
+
+  flat_hash_map &operator=(flat_hash_map &&other) noexcept {
+    if (this == &other) {
+      return *this;
+    }
+    destroy_values();
+    ctrl_ = std::move(other.ctrl_);
+    slots_ = std::move(other.slots_);
+    size_ = other.size_;
+    capacity_ = other.capacity_;
+    growth_left_ = other.growth_left_;
+    hash_ = std::move(other.hash_);
+    eq_ = std::move(other.eq_);
+    other.size_ = 0;
+    other.capacity_ = 0;
+    other.growth_left_ = 0;
+    return *this;
+  }
+
+  ~flat_hash_map() { destroy_values(); }
+
+  iterator begin() { return iterator(this, 0); }
+
+  const_iterator begin() const { return const_iterator(this, 0); }
+
+  const_iterator cbegin() const { return begin(); }
+
+  iterator end() { return iterator(this, capacity_); }
+
+  const_iterator end() const { return const_iterator(this, capacity_); }
+
+  const_iterator cend() const { return end(); }
+
+  bool empty() const { return size_ == 0; }
+
+  size_t size() const { return size_; }
+
+  size_t bucket_count() const { return capacity_; }
+
+  size_t capacity() const { return capacity_; }
+
+  float max_load_factor() const {
+    return detail::flat_hash_map_internal::kMaxLoadFactor;
+  }
+
+  void max_load_factor(float) {}
+
+  void clear() {
+    destroy_values();
+    std::fill(ctrl_.begin(), ctrl_.end(),
+              detail::flat_hash_map_internal::kEmpty);
+    size_ = 0;
+    growth_left_ = max_load_for_capacity(capacity_);
+  }
+
+  void reserve(size_t count) {
+    size_t min_capacity = capacity_for_size(count);
+    if (min_capacity > capacity_) {
+      rehash(min_capacity);
+    }
+  }
+
+  void rehash(size_t count) {
+    size_t target = std::max(count, capacity_for_size(size_));
+    target = detail::flat_hash_map_internal::next_capacity(target);
+    if (target == capacity_) {
+      return;
+    }
+
+    flat_hash_map replacement(target);
+    replacement.hash_ = hash_;
+    replacement.eq_ = eq_;
+    for (size_t i = 0; i < capacity_; ++i) {
+      if (detail::flat_hash_map_internal::is_full(ctrl_[i])) {
+        replacement.insert_existing(std::move(*slots_[i].value()));
+        slots_[i].value()->~value_type();
+        set_ctrl(i, detail::flat_hash_map_internal::kEmpty);
+      }
+    }
+    size_ = 0;
+    swap(replacement);
+  }
+
+  // Hot-path lookup API: returns nullptr on miss and avoids iterator objects.
+  // Iterators remain available for maintenance paths that need range 
traversal.
+  value_type *find(const K &key) {
+    size_t index = find_index(key);
+    return index == npos() ? nullptr : slots_[index].value();
+  }
+
+  // Hot-path lookup API: returns nullptr on miss and avoids iterator objects.
+  const value_type *find(const K &key) const {
+    size_t index = find_index(key);
+    return index == npos() ? nullptr : slots_[index].value();
+  }
+
+  size_t count(const K &key) const { return find_index(key) == npos() ? 0 : 1; 
}
+
+  bool contains(const K &key) const { return count(key) != 0; }
+
+  V &at(const K &key) {
+    size_t index = find_index(key);
+    if (index == npos()) {
+      throw std::out_of_range("fory::flat_hash_map::at");
+    }
+    return slots_[index].value()->second;
+  }
+
+  const V &at(const K &key) const {
+    size_t index = find_index(key);
+    if (index == npos()) {
+      throw std::out_of_range("fory::flat_hash_map::at");
+    }
+    return slots_[index].value()->second;
+  }
+
+  V &operator[](const K &key) { return try_emplace_default(key); }
+
+  V &operator[](K &&key) { return try_emplace_default(std::move(key)); }
+
+  std::pair<value_type *, bool> insert(const value_type &value) {
+    return emplace(value.first, value.second);
+  }
+
+  std::pair<value_type *, bool> insert(value_type &&value) {
+    return emplace(std::move(value.first), std::move(value.second));
+  }
+
+  template <typename InputIt> void insert(InputIt first, InputIt last) {
+    for (; first != last; ++first) {
+      insert(*first);
+    }
+  }
+
+  template <typename... Args>
+  std::pair<value_type *, bool> emplace(Args &&...args) {
+    return emplace_value(value_type(std::forward<Args>(args)...));
+  }
+
+  template <
+      typename KeyArg, typename MappedArg,
+      typename = std::enable_if_t<std::is_same<std::decay_t<KeyArg>, 
K>::value>>
+  std::pair<value_type *, bool> emplace(KeyArg &&key, MappedArg &&mapped) {
+    return emplace_key_value(std::forward<KeyArg>(key),
+                             std::forward<MappedArg>(mapped));
+  }
+
+  void swap(flat_hash_map &other) noexcept {
+    ctrl_.swap(other.ctrl_);
+    slots_.swap(other.slots_);
+    std::swap(size_, other.size_);
+    std::swap(capacity_, other.capacity_);
+    std::swap(growth_left_, other.growth_left_);
+    std::swap(hash_, other.hash_);
+    std::swap(eq_, other.eq_);
+  }
+
+  size_t erase(const K &key) {
+    size_t index = find_index(key);
+    if (index == npos()) {
+      return 0;
+    }
+    erase_at(index);
+    return 1;
+  }
+
+private:
+  static constexpr size_t npos() { return std::numeric_limits<size_t>::max(); }
+
+  void initialize(size_t requested_capacity) {
+    capacity_ = detail::flat_hash_map_internal::next_capacity(
+        std::max<size_t>(requested_capacity, group::kWidth));
+    ctrl_.assign(capacity_ + group::kWidth,
+                 detail::flat_hash_map_internal::kEmpty);
+    slots_.clear();
+    slots_.resize(capacity_);
+    size_ = 0;
+    growth_left_ = max_load_for_capacity(capacity_);
+  }
+
+  void destroy_values() {
+    for (size_t i = 0; i < capacity_; ++i) {
+      if (detail::flat_hash_map_internal::is_full(ctrl_[i])) {
+        slots_[i].value()->~value_type();
+      }
+    }
+  }
+
+  static size_t max_load_for_capacity(size_t capacity) {
+    return std::max<size_t>(
+        1, static_cast<size_t>(capacity *
+                               
detail::flat_hash_map_internal::kMaxLoadFactor));
+  }
+
+  static size_t capacity_for_size(size_t size) {
+    size_t needed =
+        static_cast<size_t>(static_cast<double>(size) /
+                                detail::flat_hash_map_internal::kMaxLoadFactor 
+
+                            1);
+    return detail::flat_hash_map_internal::next_capacity(needed);
+  }
+
+  FORY_FLAT_HASH_MAP_ALWAYS_INLINE size_t hash_key(const K &key) const {
+    return detail::flat_hash_map_internal::mix_hash(hash_(key));
+  }
+
+  FORY_FLAT_HASH_MAP_ALWAYS_INLINE void set_ctrl(size_t index, ctrl_t value) {
+    ctrl_[index] = value;
+    if (index < group::kWidth) {
+      ctrl_[capacity_ + index] = value;
+    }
+  }
+
+  FORY_FLAT_HASH_MAP_ALWAYS_INLINE size_t slot_index(size_t group_offset,
+                                                     size_t group_index) const 
{
+    return (group_offset + group_index) & (capacity_ - 1);
+  }
+
+  FORY_FLAT_HASH_MAP_ALWAYS_INLINE size_t find_index(const K &key) const {
+    size_t hash = hash_key(key);
+    uint8_t tag = detail::flat_hash_map_internal::h2(hash);
+    detail::flat_hash_map_internal::probe_seq<group::kWidth> seq(hash,
+                                                                 capacity_ - 
1);
+
+    while (seq.index() < capacity_) {
+      group current(ctrl_.data() + seq.offset());
+      typename group::mask_type candidates = current.match(tag);
+      while (candidates != 0) {
+        uint32_t group_index = group::lowest_bit(candidates);
+        size_t index = slot_index(seq.offset(), group_index);
+        if (eq_(slots_[index].value()->first, key)) {
+          return index;
+        }
+        candidates = group::clear_lowest_bit(candidates);
+      }
+      if (current.mask_empty() != 0) {
+        return npos();
+      }
+      seq.next();
+    }
+    return npos();
+  }
+
+  FORY_FLAT_HASH_MAP_ALWAYS_INLINE size_t find_insert_index(const K &key,
+                                                            size_t hash,
+                                                            bool &found) const 
{
+    uint8_t tag = detail::flat_hash_map_internal::h2(hash);
+    detail::flat_hash_map_internal::probe_seq<group::kWidth> seq(hash,
+                                                                 capacity_ - 
1);
+    size_t first_deleted = npos();
+
+    while (seq.index() < capacity_) {
+      group current(ctrl_.data() + seq.offset());
+      typename group::mask_type candidates = current.match(tag);
+      while (candidates != 0) {
+        uint32_t group_index = group::lowest_bit(candidates);
+        size_t index = slot_index(seq.offset(), group_index);
+        if (eq_(slots_[index].value()->first, key)) {
+          found = true;
+          return index;
+        }
+        candidates = group::clear_lowest_bit(candidates);
+      }
+
+      typename group::mask_type non_full = current.mask_empty_or_deleted();
+      while (non_full != 0) {
+        uint32_t group_index = group::lowest_bit(non_full);
+        size_t index = slot_index(seq.offset(), group_index);
+        if (detail::flat_hash_map_internal::is_deleted(ctrl_[index])) {
+          if (first_deleted == npos()) {
+            first_deleted = index;
+          }
+        } else if (detail::flat_hash_map_internal::is_empty(ctrl_[index])) {
+          found = false;
+          return first_deleted == npos() ? index : first_deleted;
+        }
+        non_full = group::clear_lowest_bit(non_full);
+      }
+      seq.next();
+    }
+
+    found = false;
+    return first_deleted;
+  }
+
+  std::pair<value_type *, bool> emplace_value(value_type value) {
+    if (growth_left_ == 0) {
+      rehash(capacity_ * 2);
+    }
+    size_t hash = hash_key(value.first);
+    bool found = false;
+    size_t index = find_insert_index(value.first, hash, found);
+    if (found) {
+      return {slots_[index].value(), false};
+    }
+    if (index == npos()) {
+      rehash(capacity_ * 2);
+      hash = hash_key(value.first);
+      index = find_insert_index(value.first, hash, found);
+    }
+    ctrl_t previous = ctrl_[index];
+    new (slots_[index].value()) value_type(std::move(value));
+    set_ctrl(index,
+             static_cast<ctrl_t>(detail::flat_hash_map_internal::h2(hash)));
+    ++size_;
+    if (!detail::flat_hash_map_internal::is_deleted(previous)) {
+      --growth_left_;
+    }
+    return {slots_[index].value(), true};
+  }
+
+  template <typename KeyArg> V &try_emplace_default(KeyArg &&key) {
+    if (growth_left_ == 0) {
+      rehash(capacity_ * 2);
+    }
+    size_t hash = hash_key(key);
+    bool found = false;
+    size_t index = find_insert_index(key, hash, found);
+    if (found) {
+      return slots_[index].value()->second;
+    }
+    if (index == npos()) {
+      rehash(capacity_ * 2);
+      hash = hash_key(key);
+      index = find_insert_index(key, hash, found);
+      if (found) {
+        return slots_[index].value()->second;
+      }
+    }
+    ctrl_t previous = ctrl_[index];
+    new (slots_[index].value()) value_type(std::forward<KeyArg>(key), V{});
+    set_ctrl(index,
+             static_cast<ctrl_t>(detail::flat_hash_map_internal::h2(hash)));
+    ++size_;
+    if (!detail::flat_hash_map_internal::is_deleted(previous)) {
+      --growth_left_;
+    }
+    return slots_[index].value()->second;
+  }
+
+  template <typename KeyArg, typename MappedArg>
+  std::pair<value_type *, bool> emplace_key_value(KeyArg &&key,
+                                                  MappedArg &&mapped) {
+    if (growth_left_ == 0) {
+      rehash(capacity_ * 2);
+    }
+    size_t hash = hash_key(key);
+    bool found = false;
+    size_t index = find_insert_index(key, hash, found);
+    if (found) {
+      return {slots_[index].value(), false};
+    }
+    if (index == npos()) {
+      rehash(capacity_ * 2);
+      hash = hash_key(key);
+      index = find_insert_index(key, hash, found);
+      if (found) {
+        return {slots_[index].value(), false};
+      }
+    }
+    ctrl_t previous = ctrl_[index];
+    new (slots_[index].value())
+        value_type(std::forward<KeyArg>(key), std::forward<MappedArg>(mapped));
+    set_ctrl(index,
+             static_cast<ctrl_t>(detail::flat_hash_map_internal::h2(hash)));
+    ++size_;
+    if (!detail::flat_hash_map_internal::is_deleted(previous)) {
+      --growth_left_;
+    }
+    return {slots_[index].value(), true};
+  }
+
+  void insert_existing(value_type value) {
+    size_t hash = hash_key(value.first);
+    bool found = false;
+    size_t index = find_insert_index(value.first, hash, found);
+    new (slots_[index].value()) value_type(std::move(value));
+    set_ctrl(index,
+             static_cast<ctrl_t>(detail::flat_hash_map_internal::h2(hash)));
+    ++size_;
+    --growth_left_;
+  }
+
+  void erase_at(size_t index) {
+    slots_[index].value()->~value_type();
+    set_ctrl(index, detail::flat_hash_map_internal::kDeleted);
+    --size_;
+  }
+
+  std::vector<ctrl_t> ctrl_;
+  std::vector<slot_type> slots_;
+  size_t size_ = 0;
+  size_t capacity_ = 0;
+  size_t growth_left_ = 0;
+  Hash hash_;
+  Eq eq_;
+};
+
+template <typename K, typename V, typename Hash, typename Eq, typename Alloc>
+void swap(flat_hash_map<K, V, Hash, Eq, Alloc> &left,
+          flat_hash_map<K, V, Hash, Eq, Alloc> &right) noexcept {
+  left.swap(right);
+}
+
+} // namespace fory
+
+#undef FORY_FLAT_HASH_MAP_HAVE_SSE2
+#undef FORY_FLAT_HASH_MAP_HAVE_NEON
+#undef FORY_FLAT_HASH_MAP_ALWAYS_INLINE
diff --git a/cpp/fory/thirdparty/flat_hash_map_test.cc 
b/cpp/fory/thirdparty/flat_hash_map_test.cc
new file mode 100644
index 000000000..7fecb5b05
--- /dev/null
+++ b/cpp/fory/thirdparty/flat_hash_map_test.cc
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+#include "fory/thirdparty/flat_hash_map.h"
+
+#include <cstdint>
+#include <string>
+#include <typeindex>
+
+#include "gtest/gtest.h"
+
+namespace fory {
+
+TEST(FlatHashMapTest, RequiredApiCoverage) {
+  flat_hash_map<uint64_t, std::string> map;
+  EXPECT_TRUE(map.empty());
+
+  auto inserted = map.emplace(1, "one");
+  EXPECT_TRUE(inserted.second);
+  EXPECT_EQ(inserted.first->second, "one");
+  EXPECT_FALSE(map.emplace(1, "duplicate").second);
+  EXPECT_EQ(map[1], "one");
+
+  map[2] = "two";
+  EXPECT_EQ(map.size(), 2);
+  EXPECT_NE(map.find(1), nullptr);
+  EXPECT_EQ(map.find(42), nullptr);
+
+  size_t old_bucket_count = map.bucket_count();
+  map.reserve(256);
+  EXPECT_GE(map.bucket_count(), old_bucket_count);
+  map.rehash(512);
+  EXPECT_GE(map.bucket_count(), 512);
+
+  size_t visited = 0;
+  for (const auto &[key, value] : map) {
+    EXPECT_TRUE((key == 1 && value == "one") || (key == 2 && value == "two"));
+    ++visited;
+  }
+  EXPECT_EQ(visited, 2);
+
+  flat_hash_map<uint64_t, std::string> copied = map;
+  EXPECT_EQ(copied[1], "one");
+  EXPECT_EQ(copied[2], "two");
+
+  flat_hash_map<uint64_t, std::string> moved = std::move(copied);
+  EXPECT_EQ(moved[1], "one");
+  EXPECT_EQ(moved[2], "two");
+
+  moved.clear();
+  EXPECT_TRUE(moved.empty());
+  moved[3] = "three";
+  EXPECT_EQ(moved[3], "three");
+}
+
+TEST(FlatHashMapTest, SupportsRequiredKeyShapes) {
+  flat_hash_map<uint64_t, int> u64_map;
+  u64_map[123] = 1;
+  EXPECT_EQ(u64_map.find(123)->second, 1);
+
+  int target = 0;
+  flat_hash_map<uintptr_t, int> pointer_map;
+  pointer_map[reinterpret_cast<uintptr_t>(&target)] = 2;
+  EXPECT_EQ(pointer_map.find(reinterpret_cast<uintptr_t>(&target))->second, 2);
+
+  flat_hash_map<std::string, int> string_map;
+  string_map["abc"] = 3;
+  EXPECT_EQ(string_map.find("abc")->second, 3);
+
+  flat_hash_map<std::type_index, int> type_map;
+  type_map[std::type_index(typeid(int))] = 4;
+  EXPECT_EQ(type_map.find(std::type_index(typeid(int)))->second, 4);
+
+  flat_hash_map<std::pair<int64_t, int64_t>, int> pair_map;
+  pair_map[std::make_pair<int64_t, int64_t>(7, 9)] = 5;
+  EXPECT_EQ(pair_map.find(std::make_pair<int64_t, int64_t>(7, 9))->second, 5);
+}
+
+TEST(FlatHashMapTest, HandlesGroupProbingAndDeletedSlots) {
+  flat_hash_map<uint64_t, uint64_t> map;
+  for (uint64_t i = 0; i < 4096; ++i) {
+    map.emplace(i, i * 3);
+  }
+  EXPECT_EQ(map.size(), 4096);
+
+  for (uint64_t i = 0; i < 4096; i += 2) {
+    EXPECT_EQ(map.erase(i), 1);
+  }
+  EXPECT_EQ(map.size(), 2048);
+
+  for (uint64_t i = 1; i < 4096; i += 2) {
+    auto *entry = map.find(i);
+    ASSERT_NE(entry, nullptr);
+    EXPECT_EQ(entry->second, i * 3);
+  }
+
+  for (uint64_t i = 4096; i < 6144; ++i) {
+    map.emplace(i, i * 5);
+  }
+  EXPECT_EQ(map.size(), 4096);
+
+  for (uint64_t i = 4096; i < 6144; ++i) {
+    auto *entry = map.find(i);
+    ASSERT_NE(entry, nullptr);
+    EXPECT_EQ(entry->second, i * 5);
+  }
+}
+
+} // namespace fory
diff --git a/cpp/fory/util/BUILD b/cpp/fory/util/BUILD
index 881891378..ed38b341f 100644
--- a/cpp/fory/util/BUILD
+++ b/cpp/fory/util/BUILD
@@ -7,11 +7,6 @@ cc_library(
     strip_include_prefix = "/cpp",
     alwayslink=True,
     linkstatic=True,
-    deps = [
-        "@abseil-cpp//absl/debugging:failure_signal_handler",
-        "@abseil-cpp//absl/debugging:stacktrace",
-        "@abseil-cpp//absl/debugging:symbolize",
-    ],
     visibility = ["//visibility:public"],
 )
 
diff --git a/cpp/fory/util/CMakeLists.txt b/cpp/fory/util/CMakeLists.txt
index e6f4e52f1..a543154cd 100644
--- a/cpp/fory/util/CMakeLists.txt
+++ b/cpp/fory/util/CMakeLists.txt
@@ -50,14 +50,6 @@ target_include_directories(fory_util
         $<INSTALL_INTERFACE:include>
 )
 
-# Link Abseil for debugging support
-target_link_libraries(fory_util
-    PUBLIC
-        absl::failure_signal_handler
-        absl::stacktrace
-        absl::symbolize
-)
-
 set_target_properties(fory_util PROPERTIES
     POSITION_INDEPENDENT_CODE ON
     OUTPUT_NAME fory_util
@@ -93,10 +85,6 @@ if(FORY_BUILD_TESTS)
     target_link_libraries(fory_util_time_util_test fory_util GTest::gtest 
GTest::gtest_main)
     gtest_discover_tests(fory_util_time_util_test)
 
-    add_executable(fory_util_int_map_test int_map_test.cc)
-    target_link_libraries(fory_util_int_map_test fory_util GTest::gtest 
GTest::gtest_main)
-    gtest_discover_tests(fory_util_int_map_test)
-
     add_executable(fory_util_flat_int_map_test flat_int_map_test.cc)
     target_link_libraries(fory_util_flat_int_map_test fory_util GTest::gtest 
GTest::gtest_main)
     gtest_discover_tests(fory_util_flat_int_map_test)
diff --git a/cpp/fory/util/logging.cc b/cpp/fory/util/logging.cc
index 983e26166..24fe7e006 100644
--- a/cpp/fory/util/logging.cc
+++ b/cpp/fory/util/logging.cc
@@ -18,12 +18,18 @@
  */
 
 #include "fory/util/logging.h"
-#include "absl/debugging/failure_signal_handler.h"
-#include "absl/debugging/stacktrace.h"
-#include "absl/debugging/symbolize.h"
 #include "fory/util/time_util.h"
+
+#if !defined(_WIN32)
+#include <execinfo.h>
+#endif
+
+#include <algorithm>
+#include <array>
+#include <cctype>
+#include <cstdlib>
+#include <sstream>
 #include <unordered_map>
-#include <vector>
 
 namespace std {
 template <> struct hash<fory::ForyLogLevel> {
@@ -36,18 +42,30 @@ namespace fory {
 const ForyLogLevel fory_severity_threshold = ForyLog::get_log_level();
 
 std::string get_call_trace() {
-  std::vector<void *> local_stack;
-  local_stack.resize(100);
-  absl::GetStackTrace(local_stack.data(), 100, 0);
-  static constexpr size_t buf_size = 16 * 1024;
-  char buf[buf_size];
+#if !defined(_WIN32)
+  std::array<void *, 100> local_stack{};
+  int frames =
+      backtrace(local_stack.data(), static_cast<int>(local_stack.size()));
   std::string output;
-  for (auto &stack : local_stack) {
-    if (absl::Symbolize(stack, buf, buf_size)) {
-      output.append("    ").append(buf).append("\n");
+  char **symbols = backtrace_symbols(local_stack.data(), frames);
+  if (symbols != nullptr) {
+    for (int i = 0; i < frames; ++i) {
+      output.append("    ").append(symbols[i]).append("\n");
     }
+    std::free(symbols);
+    return output;
   }
+  for (int i = 0; i < frames; ++i) {
+    std::ostringstream stream;
+    stream << "    frame[" << i << "] " << local_stack[static_cast<size_t>(i)]
+           << "\n";
+    output.append(stream.str());
+  }
+  return output;
+#else
+  std::string output = "    Stack trace is not supported on this platform.\n";
   return output;
+#endif
 }
 
 std::unordered_map<ForyLogLevel, std::string> log_level_to_str = {
diff --git a/cpp/fory/util/logging_test.cc b/cpp/fory/util/logging_test.cc
index 6facd98ea..8525a9b9f 100644
--- a/cpp/fory/util/logging_test.cc
+++ b/cpp/fory/util/logging_test.cc
@@ -30,7 +30,8 @@ namespace fory {
 TEST(PrintLogTest, BasicLog) {
   FORY_LOG(FORY_INFO) << "test info";
   ASSERT_DEATH(FORY_LOG(FORY_FATAL) << "test fatal",
-               "\\[.*\\] FATAL cpp/fory/util/logging_test.cc:.*: test fatal");
+               "\\[.*\\] FATAL .*cpp/fory/util/logging_test.cc:.*: test "
+               "fatal");
 }
 
 TEST(PrintLogTest, TestCheckOp) {
@@ -71,12 +72,10 @@ std::string test_function_level2() { return 
test_function_level1(); }
 TEST(PrintLogTest, CallstackTraceTest) {
   auto ret = test_function_level2();
   FORY_LOG(FORY_INFO) << "stack trace:\n" << ret;
-  // work for linux
-  // EXPECT_TRUE(ret.find("test_function_level0") != std::string::npos);
-  // work for mac
-  // EXPECT_TRUE(ret.find("get_call_trace") != std::string::npos);
-  EXPECT_TRUE(ret.find("fory") != std::string::npos);
-  EXPECT_TRUE(ret.find("PrintLogTest") != std::string::npos);
+  EXPECT_FALSE(ret.empty());
+  EXPECT_TRUE(ret.find("0x") != std::string::npos ||
+              ret.find("test_function") != std::string::npos ||
+              ret.find("PrintLogTest") != std::string::npos);
 }
 #endif
 
diff --git a/LICENSE b/licenses/LICENSE-abseil-cpp.txt
similarity index 70%
copy from LICENSE
copy to licenses/LICENSE-abseil-cpp.txt
index 62e28df76..ccd61dcfe 100644
--- a/LICENSE
+++ b/licenses/LICENSE-abseil-cpp.txt
@@ -1,6 +1,7 @@
+
                                  Apache License
                            Version 2.0, January 2004
-                        http://www.apache.org/licenses/
+                        https://www.apache.org/licenses/
 
    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 
@@ -192,7 +193,7 @@
    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
+       https://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,
@@ -200,105 +201,3 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 
-================================================================
-
-This product includes a number of Dependencies with separate copyright notices
-and license terms. Your use of these submodules is subject to the terms and
-conditions of the following licenses.
-
-================================================================
-
-================================================================
-Apache-2.0 licenses
-================================================================
-The following components are provided under the Apache-2.0 License. See 
project link for details.
-The text of each license is the standard Apache 2.0 license.
-
-* guava (https://github.com/google/guava)
-    Files:
-      java/fory-core/src/main/java/org/apache/fory/util/Preconditions.java
-      java/fory-core/src/main/java/org/apache/fory/reflect/TypeParameter.java
-      java/fory-core/src/main/java/org/apache/fory/reflect/TypeRef.java
-      
java/fory-core/src/main/java/org/apache/fory/util/concurrency/DirectExecutorService.java
-
-* spark (https://github.com/apache/spark)
-    Files:
-      java/fory-core/src/main/java/org/apache/fory/codegen/Code.java
-      java/fory-core/src/main/java/org/apache/fory/memory/Platform.java
-      
java/fory-format/src/main/java/org/apache/fory/format/vectorized/ArrowWriter.java
-
-* commons-io (https://github.com/apache/commons-io)
-    Files:
-      
java/fory-core/src/main/java/org/apache/fory/io/ClassLoaderObjectInputStream.java
-
-* common-lang3 (https://github.com/apache/commons-lang)
-    Files:
-      java/fory-core/src/main/java/org/apache/fory/util/StringUtils.java
-
-* fast-serialization (https://github.com/RuedigerMoeller/fast-serialization)
-    Files:
-      
benchmarks/java/src/main/java/org/apache/fory/benchmark/Identity2IdMap.java
-
-* ray (https://github.com/ray-project/ray)
-    Files:
-      ci/format.sh
-
-* grpc (https://github.com/grpc/grpc)
-    Files:
-      bazel/cython_library.bzl
-
-
-================================================================
-BSD-3-Clause licenses
-================================================================
-The following components are provided under the BSD-3-Clause License. See 
project link for details.
-The text of each license is also included in licenses/LICENSE-[project].txt.
-
-* kryo (https://github.com/EsotericSoftware/kryo)
-    Files:
-      benchmarks/java/src/main/java/org/apache/fory/benchmark/data/Data.java
-      benchmarks/java/src/main/java/org/apache/fory/benchmark/data/Image.java
-      benchmarks/java/src/main/java/org/apache/fory/benchmark/data/Media.java
-      
benchmarks/java/src/main/java/org/apache/fory/benchmark/data/MediaContent.java
-      benchmarks/java/src/main/java/org/apache/fory/benchmark/data/Sample.java
-      
benchmarks/java/src/main/java/org/apache/fory/benchmark/state/BufferType.java
-      
benchmarks/java/src/main/java/org/apache/fory/benchmark/state/KryoState.java
-      
java/fory-core/src/main/java/org/apache/fory/collection/ForyObjectMap.java
-      java/fory-core/src/main/java/org/apache/fory/collection/IdentityMap.java
-      
java/fory-core/src/main/java/org/apache/fory/collection/IdentityObjectIntMap.java
-      java/fory-core/src/main/java/org/apache/fory/collection/LongMap.java
-      
java/fory-core/src/main/java/org/apache/fory/collection/LongLongByteMap.java
-      java/fory-core/src/main/java/org/apache/fory/collection/ObjectIntMap.java
-      java/fory-core/src/main/java/org/apache/fory/type/Generics.java
-      java/fory-core/src/test/java/org/apache/fory/type/GenericsTest.java
-
-================================================================
-MIT licenses
-================================================================
-The following components are provided under the MIT License. See project link 
for details.
-The text of each license is also included in licenses/LICENSE-[project].txt
-
-* murmurHash3.js (https://github.com/karanlyons/murmurHash3.js)
-    Files:
-      javascript/packages/fory/lib/murmurHash3.ts
-
-* cython-abseil-sample (https://github.com/messense/cython-abseil-sample)
-    Files:
-      python/pyfory/includes/libabsl.pxd
-
-
-================================================================
-Public Domain
-================================================================
-The following components are placed in the public domain.
-The author hereby disclaims copyright to this source code.
-See project link for details.
-
-* smhasher (https://github.com/aappleby/smhasher)
-    Files:
-      src/fory/thirdparty/MurmurHash3.cc
-      src/fory/thirdparty/MurmurHash3.h
-
-* java_util (https://github.com/yonik/java_util)
-    Files:
-      java/fory-core/src/main/java/org/apache/fory/util/MurmurHash3.java
diff --git a/licenses/LICENSE-cython-abseil-example.txt 
b/licenses/LICENSE-cython-abseil-example.txt
deleted file mode 100644
index 2e8b71311..000000000
--- a/licenses/LICENSE-cython-abseil-example.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 - present messense
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/python/pyfory/context.pxi b/python/pyfory/context.pxi
index 7aec0d11b..f3c94422a 100644
--- a/python/pyfory/context.pxi
+++ b/python/pyfory/context.pxi
@@ -68,7 +68,7 @@ cdef class RefWriter:
     cdef inline bint write_ref_or_null(self, CBuffer * c_buffer, obj):
         cdef uint64_t object_id
         cdef int32_t next_id
-        cdef flat_hash_map[uint64_t, int32_t].iterator it
+        cdef pair[uint64_t, int32_t] *entry
         if not self.track_ref:
             if obj is None:
                 deref(c_buffer).write_int8(NULL_FLAG)
@@ -79,8 +79,8 @@ cdef class RefWriter:
             deref(c_buffer).write_int8(NULL_FLAG)
             return True
         object_id = <uintptr_t> <PyObject *> obj
-        it = self.written_objects_id.find(object_id)
-        if it == self.written_objects_id.end():
+        entry = self.written_objects_id.find(object_id)
+        if entry == NULL:
             next_id = self.written_objects_id.size()
             self.written_objects_id[object_id] = next_id
             self.written_objects.push_back(<PyObject *> obj)
@@ -88,20 +88,20 @@ cdef class RefWriter:
             deref(c_buffer).write_int8(REF_VALUE_FLAG)
             return False
         deref(c_buffer).write_int8(REF_FLAG)
-        deref(c_buffer).write_var_uint32(<uint64_t> deref(it).second)
+        deref(c_buffer).write_var_uint32(<uint64_t> deref(entry).second)
         return True
 
     cdef inline bint write_ref_value_flag(self, CBuffer * c_buffer, obj):
         cdef uint64_t object_id
         cdef int32_t next_id
-        cdef flat_hash_map[uint64_t, int32_t].iterator it
+        cdef pair[uint64_t, int32_t] *entry
         assert obj is not None
         if not self.track_ref:
             deref(c_buffer).write_int8(NOT_NULL_VALUE_FLAG)
             return True
         object_id = <uintptr_t> <PyObject *> obj
-        it = self.written_objects_id.find(object_id)
-        if it == self.written_objects_id.end():
+        entry = self.written_objects_id.find(object_id)
+        if entry == NULL:
             next_id = self.written_objects_id.size()
             self.written_objects_id[object_id] = next_id
             self.written_objects.push_back(<PyObject *> obj)
@@ -109,7 +109,7 @@ cdef class RefWriter:
             deref(c_buffer).write_int8(REF_VALUE_FLAG)
             return True
         deref(c_buffer).write_int8(REF_FLAG)
-        deref(c_buffer).write_var_uint32(<uint64_t> deref(it).second)
+        deref(c_buffer).write_var_uint32(<uint64_t> deref(entry).second)
         return False
 
     cdef inline bint write_null_flag(self, CBuffer * c_buffer, obj):
@@ -281,8 +281,8 @@ cdef class MetaStringWriter:
         cdef uint64_t object_id = <uintptr_t> <PyObject *> encoded_meta_string
         cdef int32_t length = encoded_meta_string.length
         cdef int32_t dynamic_id
-        cdef flat_hash_map[uint64_t, int32_t].iterator it = 
self._written_encoded_meta_strings.find(object_id)
-        if it == self._written_encoded_meta_strings.end():
+        cdef pair[uint64_t, int32_t] *entry = 
self._written_encoded_meta_strings.find(object_id)
+        if entry == NULL:
             dynamic_id = self._written_encoded_meta_strings.size()
             self._written_encoded_meta_strings[object_id] = dynamic_id
             self._written_objects.push_back(<PyObject *> encoded_meta_string)
@@ -295,7 +295,7 @@ cdef class MetaStringWriter:
                 buffer.write_int64(encoded_meta_string.hashcode)
             buffer.write_bytes(encoded_meta_string.data)
             return
-        buffer.write_var_uint32(((deref(it).second + 1) << 1) | 1)
+        buffer.write_var_uint32(((deref(entry).second + 1) << 1) | 1)
 
     cpdef inline reset(self):
         cdef PyObject *item
@@ -326,6 +326,7 @@ cdef class MetaStringReader:
         cdef int8_t encoding = 0
         cdef bytes data
         cdef object encoded_meta_string
+        cdef pair[int64_t, PyObject *] *entry
         if header & 0b1:
             if length <= 0:
                 raise ValueError("Invalid dynamic metastring id 0")
@@ -344,8 +345,8 @@ cdef class MetaStringReader:
                 v1 = buffer.read_int64()
                 v2 = buffer.read_bytes_as_int64(length - 8)
             hashcode = _hash_small_metastring(v1, v2, length, <uint8_t> 
encoding)
-            encoded_meta_string_ptr = 
self._c_hash_to_small_encoded_meta_string[hashcode]
-            if encoded_meta_string_ptr == NULL:
+            entry = self._c_hash_to_small_encoded_meta_string.find(hashcode)
+            if entry == NULL or deref(entry).second == NULL:
                 reader_index = buffer.get_reader_index()
                 data = buffer.get_bytes(reader_index - length, length)
                 encoded_meta_string = 
self.shared_registry.get_or_create_encoded_meta_string(
@@ -354,13 +355,15 @@ cdef class MetaStringReader:
                 )
                 encoded_meta_string_ptr = <PyObject *> encoded_meta_string
                 self._c_hash_to_small_encoded_meta_string[hashcode] = 
encoded_meta_string_ptr
+            else:
+                encoded_meta_string_ptr = deref(entry).second
         else:
             hashcode = buffer.read_int64()
             reader_index = buffer.get_reader_index()
             buffer.check_bound(reader_index, length)
             buffer.set_reader_index(reader_index + length)
-            encoded_meta_string_ptr = 
self._c_hash_to_encoded_meta_string[hashcode]
-            if encoded_meta_string_ptr == NULL:
+            entry = self._c_hash_to_encoded_meta_string.find(hashcode)
+            if entry == NULL or deref(entry).second == NULL:
                 data = buffer.get_bytes(reader_index, length)
                 encoded_meta_string = 
self.shared_registry.get_or_create_encoded_meta_string(
                     data,
@@ -368,6 +371,8 @@ cdef class MetaStringReader:
                 )
                 encoded_meta_string_ptr = <PyObject *> encoded_meta_string
                 self._c_hash_to_encoded_meta_string[hashcode] = 
encoded_meta_string_ptr
+            else:
+                encoded_meta_string_ptr = deref(entry).second
         
self._c_dynamic_id_to_encoded_meta_string_vec.push_back(encoded_meta_string_ptr)
         return <object> encoded_meta_string_ptr
 
diff --git a/python/pyfory/includes/libabsl.pxd 
b/python/pyfory/includes/libabsl.pxd
deleted file mode 100644
index 906cc0b6b..000000000
--- a/python/pyfory/includes/libabsl.pxd
+++ /dev/null
@@ -1,75 +0,0 @@
-from libcpp.utility cimport pair
-
-# Copied from 
https://github.com/messense/cython-abseil-sample/blob/master/absl.pxd
-cdef extern from "absl/container/flat_hash_map.h" namespace "absl" nogil:
-    cdef cppclass flat_hash_map[T, U]:
-        ctypedef T key_type
-        ctypedef U mapped_type
-        ctypedef pair[const T, U] value_type
-        cppclass iterator:
-            pair[T, U]& operator*()
-            iterator operator++()
-            iterator operator--()
-            bint operator==(iterator)
-            bint operator!=(iterator)
-        cppclass reverse_iterator:
-            pair[T, U]& operator*()
-            iterator operator++()
-            iterator operator--()
-            bint operator==(reverse_iterator)
-            bint operator!=(reverse_iterator)
-        cppclass const_iterator(iterator):
-            pass
-        cppclass const_reverse_iterator(reverse_iterator):
-            pass
-        flat_hash_map() except +
-        flat_hash_map(flat_hash_map&) except +
-        # flat_hash_map(key_compare&)
-        U& operator[](T&)
-        # flat_hash_map& operator=(flat_hash_map&)
-        bint operator==(flat_hash_map&, flat_hash_map&)
-        bint operator!=(flat_hash_map&, flat_hash_map&)
-        bint operator<(flat_hash_map&, flat_hash_map&)
-        bint operator>(flat_hash_map&, flat_hash_map&)
-        bint operator<=(flat_hash_map&, flat_hash_map&)
-        bint operator>=(flat_hash_map&, flat_hash_map&)
-        U& at(const T&)
-        const U& const_at "at"(const T&)
-        iterator begin()
-        const_iterator const_begin "begin"()
-        void clear()
-        size_t count(T&)
-        bint empty()
-        iterator end()
-        const_iterator const_end "end"()
-        pair[iterator, iterator] equal_range(T&)
-        pair[const_iterator, const_iterator] const_equal_range 
"equal_range"(const T&)
-        void erase(iterator)
-        void erase(iterator, iterator)
-        size_t erase(T&)
-        iterator find(T&)
-        const_iterator const_find "find"(T&)
-        pair[iterator, bint] insert(pair[T, U])  # XXX pair[T,U]&
-        iterator insert(iterator, pair[T, U])  # XXX pair[T,U]&
-        iterator insert(iterator, iterator)
-        # key_compare key_comp()
-        iterator lower_bound(T&)
-        const_iterator const_lower_bound "lower_bound"(T&)
-        size_t max_size()
-        reverse_iterator rbegin()
-        const_reverse_iterator const_rbegin "rbegin"()
-        reverse_iterator rend()
-        const_reverse_iterator const_rend "rend"()
-        size_t size()
-        void swap(flat_hash_map&)
-        iterator upper_bound(T&)
-        const_iterator const_upper_bound "upper_bound"(T&)
-        # value_compare value_comp()
-        void max_load_factor(float)
-        float max_load_factor()
-        void rehash(size_t)
-        void reserve(size_t)
-        size_t bucket_count()
-        size_t max_bucket_count()
-        size_t bucket_size(size_t)
-        size_t bucket(const T&)
diff --git a/cpp/cmake/ForyConfig.cmake.in 
b/python/pyfory/includes/libflat_hash_map.pxd
similarity index 54%
copy from cpp/cmake/ForyConfig.cmake.in
copy to python/pyfory/includes/libflat_hash_map.pxd
index f14844247..5cc39d6d0 100644
--- a/cpp/cmake/ForyConfig.cmake.in
+++ b/python/pyfory/includes/libflat_hash_map.pxd
@@ -14,26 +14,25 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
 
-@PACKAGE_INIT@
-
-include(CMakeFindDependencyMacro)
-
-# Check for Abseil (optional)
-find_package(absl CONFIG QUIET)
-
-include("${CMAKE_CURRENT_LIST_DIR}/ForyTargets.cmake")
-
-# Provide convenient component targets
-# Users can use:
-#   find_package(Fory REQUIRED)
-#   target_link_libraries(myapp fory::serialization)  # For serialization only
-#   target_link_libraries(myapp fory::row_format)     # For row format
-#   target_link_libraries(myapp fory::fory)           # For everything
-
-check_required_components(Fory)
+from libcpp.utility cimport pair
 
-# Print found message
-if(NOT Fory_FIND_QUIETLY)
-    message(STATUS "Found Fory: ${CMAKE_CURRENT_LIST_DIR}")
-endif()
+cdef extern from "fory/thirdparty/flat_hash_map.h" namespace "fory" nogil:
+    cdef cppclass flat_hash_map[T, U]:
+        ctypedef T key_type
+        ctypedef U mapped_type
+        ctypedef pair[T, U] value_type
+        flat_hash_map() except +
+        flat_hash_map(flat_hash_map&) except +
+        U& operator[](const T&)
+        void clear()
+        bint empty()
+        pair[T, U]* find(const T&)
+        size_t size()
+        void swap(flat_hash_map&)
+        void max_load_factor(float)
+        float max_load_factor()
+        void rehash(size_t)
+        void reserve(size_t)
+        size_t bucket_count()
diff --git a/python/pyfory/serialization.pyx b/python/pyfory/serialization.pyx
index c9e85de3c..375fa9882 100644
--- a/python/pyfory/serialization.pyx
+++ b/python/pyfory/serialization.pyx
@@ -34,7 +34,7 @@ from cpython.dict cimport PyDict_Next
 from cpython.list cimport PyList_New, PyList_SET_ITEM
 from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM
 from cpython.ref cimport Py_INCREF, Py_XDECREF
-from pyfory.includes.libabsl cimport flat_hash_map
+from pyfory.includes.libflat_hash_map cimport flat_hash_map
 from pyfory.includes.libutil cimport FlatIntMap
 from pyfory._fory import (
     NO_USER_TYPE_ID,
@@ -315,8 +315,11 @@ cdef class TypeResolver:
         self._populate_type_info(typeinfo)
 
     cpdef inline TypeInfo get_type_info(self, cls, create=True):
-        cdef PyObject * typeinfo_ptr = self._c_types_info[<uintptr_t> 
<PyObject *> cls]
+        cdef pair[uint64_t, PyObject *] *entry = 
self._c_types_info.find(<uintptr_t> <PyObject *> cls)
+        cdef PyObject * typeinfo_ptr = NULL
         cdef TypeInfo typeinfo
+        if entry != NULL:
+            typeinfo_ptr = deref(entry).second
         if typeinfo_ptr != NULL:
             typeinfo = <TypeInfo> typeinfo_ptr
             if typeinfo.serializer is None:
@@ -388,6 +391,7 @@ cdef class TypeResolver:
         cdef object ns_metabytes
         cdef object type_metabytes
         cdef PyObject * typeinfo_ptr = NULL
+        cdef pair[uint32_t, PyObject *] *entry
         if (
             type_id == <uint8_t>TypeId.COMPATIBLE_STRUCT
             or type_id == <uint8_t>TypeId.NAMED_COMPATIBLE_STRUCT
@@ -417,10 +421,10 @@ cdef class TypeResolver:
             return self._load_bytes_to_type_info(ns_metabytes, type_metabytes)
         if reg_kind == TypeRegistrationKind.BY_ID:
             user_type_id = buffer.read_var_uint32()
-            typeinfo_ptr = self._c_user_type_id_to_type_info[user_type_id]
-            if typeinfo_ptr == NULL:
+            entry = self._c_user_type_id_to_type_info.find(user_type_id)
+            if entry == NULL or deref(entry).second == NULL:
                 raise ValueError(f"Unexpected user_type_id {user_type_id}")
-            return <TypeInfo>typeinfo_ptr
+            return <TypeInfo>deref(entry).second
         if type_id >= self._c_registered_id_to_type_info.size():
             raise ValueError(f"Unexpected type_id {type_id}")
         typeinfo_ptr = self._c_registered_id_to_type_info[type_id]
@@ -468,7 +472,7 @@ cdef class TypeResolver:
         cdef uint8_t type_id
         cdef object type_def
         cdef uint64_t type_addr
-        cdef flat_hash_map[uint64_t, int32_t].iterator it
+        cdef pair[uint64_t, int32_t] *entry
         cdef int32_t index
         if meta_context is None:
             raise AssertionError(
@@ -481,9 +485,9 @@ cdef class TypeResolver:
             write_context.write_bytes(typeinfo.type_def.encoded)
             return
         type_addr = <uint64_t> <PyObject *> type_cls
-        it = meta_context.class_map.find(type_addr)
-        if it != meta_context.class_map.end():
-            write_context.write_var_uint32((deref(it).second << 1) | 1)
+        entry = meta_context.class_map.find(type_addr)
+        if entry != NULL:
+            write_context.write_var_uint32((deref(entry).second << 1) | 1)
             return
         index = meta_context.class_map.size()
         meta_context.class_map[type_addr] = index
@@ -526,21 +530,17 @@ cdef class TypeResolver:
         return typeinfo
 
     cdef inline TypeInfo _load_bytes_to_type_info(self, object ns_metabytes, 
object type_metabytes):
-        cdef PyObject * typeinfo_ptr = self._c_meta_hash_to_type_info[
-            pair[int64_t, int64_t](
-                ns_metabytes.hashcode,
-                type_metabytes.hashcode,
-            )
-        ]
+        cdef pair[int64_t, int64_t] hash_key = pair[int64_t, int64_t](
+            ns_metabytes.hashcode,
+            type_metabytes.hashcode,
+        )
+        cdef pair[pair[int64_t, int64_t], PyObject *] *entry = 
self._c_meta_hash_to_type_info.find(hash_key)
         cdef TypeInfo typeinfo
-        if typeinfo_ptr != NULL:
-            return <TypeInfo>typeinfo_ptr
+        if entry != NULL and deref(entry).second != NULL:
+            return <TypeInfo>deref(entry).second
         typeinfo = self.resolver._load_metabytes_to_type_info(ns_metabytes, 
type_metabytes)
         self._c_meta_hash_to_type_info[
-            pair[int64_t, int64_t](
-                ns_metabytes.hashcode,
-                type_metabytes.hashcode,
-            )
+            hash_key
         ] = <PyObject *>typeinfo
         return typeinfo
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to