[simdjson] 填充字符串 | `document` 對象 | on-demand 模式

第二章:填充字符串

在第一章解析器中,我們學習了simdjson::dom::parsersimdjson::ondemand::parser作為可復用內存的JSON解析工具

本章將深入解析JSON數據輸入的核心要求——“填充字符串”。

為何需要填充?

simdjson通過SIMD(單指令多數據)指令實現高性能解析。

這些指令要求以固定字節塊(如32或64字節)處理數據,可能越界訪問內存。

若JSON數據位于內存末尾且未預留空間,將導致段錯誤。

為此,simdjson要求輸入數據必須包含SIMDJSON_PADDING(默認為64字節)的填充空間。

// 來自include/simdjson/base.h
/*** JSON解析所需的填充字節數*/
constexpr size_t SIMDJSON_PADDING = 64;

例如:100字節的JSON數據需要至少164字節的緩沖區,前100字節存儲數據,后64字節為填充(通常置零)。

填充數據管理

simdjson提供兩種核心類型處理填充:

1. simdjson::padded_string

內存自主管理型,保證數據尾部包含填充空間。創建時會自動分配新緩沖區并復制數據。

#include <simdjson.h>int main() {// 從C風格字符串創建const char* json_cstr = "{\"name\":\"simdjson\"}";simdjson::padded_string s1(json_cstr, strlen(json_cstr));// 從std::string創建std::string json_std = "{\"count\":42}";simdjson::padded_string s2(json_std);// 使用_padded字面量(推薦)auto s3 = R"({"active":true})"_padded;// 數據訪問std::cout << "數據長度:" << s3.size() << std::endl;  // 實際JSON長度return 0;
}

注意:

  • size()返回原始數據長度(不含填充)
  • 屬于移動語義類型,不可復制
  • _padded字面量簡化創建過程

2. simdjson::padded_string_view

非擁有型視圖,適用于已有填充緩沖區的情況。需開發者保證緩沖區有效性。

#include <simdjson.h>
#include <vector>int main() {// 手動創建填充緩沖區std::string source = "{\"value\":99}";std::vector<char> buffer(source.size() + SIMDJSON_PADDING, 0);memcpy(buffer.data(), source.data(), source.size());// 創建視圖simdjson::padded_string_view view(buffer.data(), source.size(), buffer.size());// 使用pad()工具處理std::stringstd::string dynamic_str = "{\"id\":123}";auto padded_view = simdjson::pad(dynamic_str);  // 修改原字符串容量// 解析示例simdjson::dom::parser parser;auto doc = parser.parse(view);return 0;
}

注意:

  • pad()會修改原字符串,追加空格至滿足填充要求
  • 必須確保底層緩沖區在視圖使用期間有效

解析器集成

兩種類型均可直接用于解析方法:

// DOM解析示例
simdjson::dom::parser parser;
auto json = R"({"key":"value"})"_padded;
auto result = parser.parse(json);// On-Demand解析(強制要求填充)
simdjson::ondemand::parser ondemand_parser;
auto doc = ondemand_parser.iterate(json);

內存模型

在這里插入圖片描述

類型對比指南

特性padded_stringpadded_string_view
內存所有權自主管理依賴外部緩沖區
填充保證自動創建預先存在
適用場景新數據創建已有緩沖區復用
性能影響可能內存拷貝零拷貝
易用性高(推薦新手中(需內存管理經驗)

核心要點

  1. 安全第一SIMD指令越界訪問可能引發段錯誤,填充是必須的
  2. 性能權衡:padded_string簡化開發但可能內存拷貝,padded_string_view適合高性能場景
  3. 生命周期管理:解析結果依賴原始緩沖區,需確保數據持續有效
  4. 工具鏈整合_padded字面量和pad()函數提升開發效率

掌握填充字符串機制是使用simdjson的關鍵下一步,我們將在第三章文檔結構中學習如何訪問解析后的數據。

下一章:文檔結構


第三章:文檔(Document)

在前幾章中,我們學習了用于解析 JSON 的核心工具:解析器(Parser),以及如何通過填充字符串(Padded String)格式準備 JSON 數據以實現安全快速處理。

現在我們已經準備好解析器并將 JSON 數據放入填充字符串中,執行解析操作會得到什么?在按需(On-Demand)API 中,這就是 simdjson::ondemand::document 的用武之地。

可以document 對象視為初始解析步驟(iterate 調用)的結果

這是探索所提供 JSON 數據的入口點。

什么是按需模式中的文檔?

與可能立即在內存中構建完整 JSON 文檔樹結構的傳統 JSON 解析器不同,simdjson 按需 API 采用了不同的方法。

當調用 parser.iterate(padded_string) 時,我們得到的是 simdjson::ondemand::document 對象。

這個 document 并非整個 JSON 的完全解析表示,而更像是定位在 JSON 數據起始位置的智能迭代器游標。它持有導航 JSON 結構和按需解析值所需的必要信息。

  • 想象你的 JSON 數據是裝滿嵌套在盒子和袋子里的物品的大型寶箱。document 不是寶箱內所有內容的描述,而是打開寶箱的鑰匙和指示第一個主容器(JSON 根值)位置的地圖。

  • 我們使用這張地圖(document 的方法)找到第一個容器,然后通過進一步指令打開它并發現內部物品,僅在需要時挖掘寶物。

這種"按需挖掘"的特性使得按需 API 內存效率極高,尤其適用于只需少量數據的大型 JSON 文件。

獲取第一個文檔

讓我們回顧前幾章的簡單示例,重點觀察獲得的 document 對象:

#include <simdjson.h>
#include <iostream>int main() {// 1. 創建解析器實例(我們的工具)simdjson::ondemand::parser parser;// 2. 準備填充字符串格式的 JSON 數據(我們的原材料)// 按需模式需要填充輸入simdjson::padded_string json_data = R"({"message": "hello world", "status": true})"_padded;// 3. 使用解析器"遍歷"填充數據// 返回需要檢查錯誤的結果對象simdjson::simdjson_result<simdjson::ondemand::document> result = parser.iterate(json_data);// 4. 檢查遍歷步驟是否成功if (result.error()) {std::cerr << "解析初始化失敗: " << result.error() << std::endl;return EXIT_FAILURE;}// 5. 從結果中獲取文檔對象simdjson::ondemand::document doc = std::move(result.value()); // 使用 std::move 提高效率std::cout << "成功獲取文檔對象!" << std::endl;// 現在'doc'是我們進入 JSON 的入口// 實際上還未真正*解析*內容,只是設置了迭代器return EXIT_SUCCESS;
}

代碼解析:

  • parser.iterate(json_data) 是關鍵函數調用,接收包含 JSON 的填充字符串
  • 返回 simdjson::simdjson_result<simdjson::ondemand::document>,這是 simdjson 處理潛在錯誤的方式
  • 檢查 result.error() 確保文檔迭代器設置成功,此步驟包括快速掃描 JSON 的基本結構有效性并構建內部索引(有時稱為"tape")
  • 成功時通過 std::move(result.value()) 獲取 simdjson::ondemand::document 對象

獲得 doc 對象后,我們即可開始用它訪問 JSON 數據。

探索文檔根節點

document 對象表示 JSON 結構的根節點。JSON 文檔的根可以是任意有效 JSON 值:對象 {}、數組 []、字符串 "abc"、數值 123、布爾值 truenull

document 提供以下方法判斷根值類型:

  • doc.type():返回根 JSON 值的類型(如 json_type::object, json_type::array 等)
  • doc.get_object():嘗試以 JSON 對象形式訪問根節點
  • doc.get_array():嘗試以 JSON 數組形式訪問根節點
  • doc.get_string(), doc.get_int64(), doc.get_double(), doc.get_bool(), doc.is_null():嘗試以標量值形式訪問根節點

當調用這些 get_...() 方法時,simdjson 才會真正執行根節點的解析。讓我們擴展示例來檢查類型并訪問根對象:

#include <simdjson.h>
#include <iostream>int main() {simdjson::ondemand::parser parser;simdjson::padded_string json_data = R"({"message": "hello world", "status": true})"_padded;simdjson::simdjson_result<simdjson::ondemand::document> result = parser.iterate(json_data);if (result.error()) {std::cerr << "解析初始化失敗: " << result.error() << std::endl;return EXIT_FAILURE;}simdjson::ondemand::document doc = std::move(result.value());// 6. 檢查文檔根節點類型simdjson::simdjson_result<simdjson::ondemand::json_type> root_type_result = doc.type();if (root_type_result.error()) {std::cerr << "獲取根類型錯誤: " << root_type_result.error() << std::endl;return EXIT_FAILURE;}simdjson::ondemand::json_type root_type = root_type_result.value();if (root_type == simdjson::ondemand::json_type::object) {std::cout << "根節點是 JSON 對象。" << std::endl;// 7. 以對象形式訪問根節點simdjson::simdjson_result<simdjson::ondemand::object> obj_result = doc.get_object();if (obj_result.error()) {std::cerr << "獲取根對象錯誤: " << obj_result.error() << std::endl;return EXIT_FAILURE;}simdjson::ondemand::object root_object = obj_result.value();std::cout << "成功訪問根對象。" << std::endl;// 后續章節將學習如何使用此'root_object'// 訪問"message"和"status"等字段} else {std::cout << "根節點不是對象,類型代碼: " << int(root_type) << std::endl;}// 重要提示:'doc'對象、解析器和 json_data 必須保持有效// 只要仍在使用從'doc'派生的任何數據return EXIT_SUCCESS;
}

源碼安裝庫文件:

git clone https://github.com/simdjson/simdjson.git
cd simdjson
mkdir build && cd build
cmake ..
make -j
sudo make install

編譯:

g++ -std=c++17 -o simdjson_test/test_simdjson simdjson_test/test_simdjson.cpp -lsimdjson

輸出結果:
在這里插入圖片描述

此示例展示了如何獲取文檔、檢查類型并以預期類型(本例為 object)訪問根節點。獲得的 simdjson::ondemand::object 是導航對象內部的入口點,我們將在第五章詳細講解。

注意:即使檢查類型和訪問根值也會返回 simdjson_result。在按需 API 中,驗證和解析是漸進式進行的,在導航或提取數據的任何步驟都可能因 JSON 結構或值無效而產生錯誤。錯誤處理至關重要,后續將有專門章節講解(錯誤處理)。

文檔與依賴關系

必須牢記:simdjson::ondemand::document 對象并非已解析數據的獨立副本,而是原始填充 JSON 字符串的視圖,依賴解析器的內部狀態(如 tape/索引)。

這意味著:

  1. 只要仍在使用從文檔獲得的任何 objectarrayvaluestring_view 實例,simdjson::ondemand::parser 對象必須保持存活且未被修改
  2. 包含 JSON 數據的原始 simdjson::padded_string(或 padded_string_view 指向的緩沖區)必須保持有效且未被修改
  3. 每個解析器對象同一時間只能激活一個文檔對象。若再次調用 parser.iterate(),新文檔將使舊文檔失效

實現原理(簡化版)

調用 parser.iterate(padded_string) 時,解析器會進行初始化工作,主要包括識別大括號、中括號、逗號和引號等結構元素,并構建內部索引(“tape”)。此階段不會完全解析字符串、數值或數組/對象的內容。

返回的 simdjson::ondemand::document 對象本質上是包裝了解析器內部狀態(特別是 json_iterator)和填充輸入字符串起始位置的指針。

當調用 doc.get_object()doc.type() 等方法時,document 對象使用存儲的指針與解析器狀態及原始 JSON 數據進行交互。它利用索引快速跳轉到 JSON 的相關部分,并執行滿足請求所需的最小解析(例如確認根節點是’{',并為對象字段設置迭代器)。

字符串的實際數據(std::string_view)和導航的結構(objectarrayvalue)都是與原始填充字符串和解析器狀態綁定的臨時視圖。

dom::documentondemand::document 對比(簡注)

在第一章中,我們簡要展示了使用 dom::parser::parse 返回 dom::element 的 DOM 示例。雖然 simdjson 在內部確實有 dom::document 類型(simdjson::dom::parser 持有該類型),但 DOM API 中主要面向用戶的結果通常是表示完全解析樹節點的 dom::element

相比之下,simdjson::ondemand::document 是按需 API 中的核心用戶對象,是 iterate 調用的直接結果,也是惰性導航的起點。

不持有完整的解析樹,而是迭代解析過程的句柄。

對于使用按需模式(推薦方式)的初學者,初始階段主要交互對象是 simdjson::ondemand::parsersimdjson::padded_string(或 padded_string_view)和 simdjson::ondemand::document

流程圖:

在這里插入圖片描述


🎢初始階段的on-demand 模式

simdjson 庫在初始階段聚焦于 simdjson::ondemand::parsersimdjson::padded_stringsimdjson::ondemand::document 的設計,主要基于性能優化、內存安全性和接口簡潔性的綜合考量:

  1. 性能導向的解析器設計
    ondemand::parser 采用 SIMD 指令集加速 JSON 解析,直接操作原始數據而非預解析為 DOM 樹。這種延遲加載(lazy parsing)策略避免一次性解析整個文檔,僅當訪問特定字段時才處理對應數據,極大減少內存占用和初始化開銷。

  2. 內存安全的數據容器
    padded_stringpadded_string_view 為 JSON 數據添加尾部填充(padding),確保 SIMD 指令能安全讀取超出實際數據末尾的緩沖區。這種設計消除了邊界檢查開銷,同時防止內存越界訪問。

  3. 按需文檔模型
    ondemand::document 作為輕量級視圖,提供對 JSON 數據的惰性訪問。它不持有數據所有權,而是基于解析器的內部狀態動態生成字段值,避免了傳統 DOM 模型的全量內存分配。

交互流程

解析流程通常遵循以下模式:

  1. 創建 parser 實例并復用(避免重復分配資源)
  2. 加載 JSON 數據到 padded_string(或直接映射為 padded_string_view
  3. 通過 parser.iterate() 生成 document 視圖
  4. document 上執行具體字段訪問
simdjson::ondemand::parser parser;
auto json = simdjson::padded_string::load("data.json");
auto doc = parser.iterate(json);
std::string_view title = doc["title"];

與其他組件的對比

  • 與 DOM API 的區別
    傳統 DOM 解析(如 simdjson::document)需完整解析整個 JSON 到內存樹,而 on-demand 模式將解析延遲到字段訪問時,更適合流式處理或大型文件。

  • 與 SAX 模型的差異
    SAX 需要實現回調函數處理事件,on-demand 則提供更直觀的鍵值訪問接口,同時保留相似的性能特性。

這種設計使初始階段既能保持高性能,又能通過簡潔的接口降低使用復雜度,符合現代 C++ 庫零開銷抽象的原則。

總結

simdjson::ondemand::documentparser.iterate() 的返回對象,代表按需 API 中 JSON 數據的根節點。

  • 關鍵特性在于它并非完全解析的樹結構,而是允許按需解析 JSON 值的迭代器。

我們使用 document 對象作為導航 JSON 數據的起點,通常通過檢查其類型并調用 get_object()get_array() 等方法來開始遍歷結構。

請牢記依賴關系:文檔對象、創建它的解析器以及原始填充字符串數據必須保持有效且在作用域內,才能安全使用從文檔獲得的任何數據。

現在我們已經掌握如何獲取和訪問 JSON 文檔根節點,下一步是理解單個 JSON 值(如字符串、數值或嵌套對象/數組)的表示和訪問方式,這將是下一章數值(Value)的主題。

下一章:數值(Value)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89320.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89320.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89320.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

扭蛋機小程序開發:開啟線上娛樂新風尚

在當今數字化浪潮席卷的時代&#xff0c;娛樂方式正經歷著前所未有的變革。傳統的扭蛋機&#xff0c;那充滿驚喜與期待的實體裝置&#xff0c;曾是無數人童年回憶中的歡樂源泉。如今&#xff0c;隨著科技的飛速發展&#xff0c;扭蛋機小程序開發應運而生&#xff0c;將這份經典…

【React Native】布局和 Stack 、Slot

布局和Stack 點擊鏈接后&#xff0c;頁面切換時最好是有動畫效果。頁面一般都有頭部&#xff0c;里面有頁面的標題之類的東西。 在app目錄里&#xff0c;新建一個_layout.js文件&#xff0c;這是項目的布局文件。 這個名字是固定的&#xff0c;前面必須有一個_ 。 布局的意…

3C電子產品藍光三維掃描檢測方案-中科米堆CASAIM

隨著3C電子產品向輕薄化、精密化方向發展&#xff0c;傳統的二維檢測技術已難以滿足現代制造業對產品精度的高標準要求。特別是在智能手機、平板電腦等消費電子領域&#xff0c;微小的結構偏差都可能導致產品組裝困難或性能下降。當前行業內普遍面臨檢測效率低、數據采集不完整…

Docker 鏡像原理

Union FS(聯合文件系統) Union File System 是一種分層、輕量級并且高性能的文件系統&#xff0c;它支持對文件系統的修改作為一次提交來一層層的疊加&#xff0c;同時可以將不同目錄掛載到同一個虛擬文件系統下。UnionFS 是一種為 Linux&#xff0c;FreeBSD 和 NetBSD 操作系統…

為什么IoTDB成為物聯網場景的技術優選?

在物聯網、工業監控等領域&#xff0c;時序數據的高效管理成為技術架構設計的關鍵環節。時序數據庫作為專門處理帶時間戳數據的系統&#xff0c;其選型需兼顧性能、兼容性與場景適配性。本文將從技術角度解析 IoTDB 的設計理念與實踐方法&#xff0c;為時序數據庫選型提供參考。…

js中的微任務和宏任務的理解

在JavaScript中&#xff0c;微任務&#xff08;Microtask&#xff09;和宏任務&#xff08;Macrotask&#xff09;是異步任務執行機制的重要組成部分&#xff0c;它們共同構成了JavaScript事件循環&#xff08;Event Loop&#xff09;的核心邏輯。理解這兩個概念對于編寫高性能…

Spring-AI系列-AI模型-Model

原文-知識庫&#xff0c;歡迎大家評論互動 AI Model API Portable ModelAPI across AI providers for Chat, Text to Image, Audio Transcription, Text to Speech, and Embedding models. Both synchronous and stream API options are supported. Dropping down to access mo…

MySQL查詢今天、昨天、上周、近30天、去年等的數據的方法

目錄 常用的MySQL查詢今天、昨天、上周、近30天、去年等數據的方法 0、Sql server中DateDiff()用法 1、MySQL的DATE_SUB()函數 定義和用法 語法 實例 2、MySQL的TO_DAYS(date) 3、MySQL的DATE() 函數 定義和用法 4、MySQL NOW() 函數 定義和用法 語法 實例 例子 …

Linux —— B / 基礎開發工具

一、軟件包管理器1.1什么是軟件包1.2 Linux軟件生態1.3 yum具體操作1.3.1 查看軟件包1.3.2 安裝軟件1.3.3 卸載軟件1.3.4 注意事項1.4 安裝源二、編輯器Vim2-1 Linux編輯器-vim使用2-2 vim的基本概念2-3 vim的基本操作2-4 vim正常模式命令集2-5 vim末行模式命令集2-6 vim操作總…

SQL,在join中,on和where的區別

0.結論 兩個表在&#xff0c;join時&#xff0c;首先做一個笛卡爾積&#xff0c;on后面的條件是對這個笛卡爾積做一個過濾形成一張臨時表&#xff0c;如果沒有where就直接返回結果&#xff0c;如果有where就對上一步的臨時表再進行過濾。 先on&#xff0c;再join&#xff0c;再…

SD-WAN在儲能網絡中的應用,傳統方案如何借力智能化升級?(附網絡架構圖)

一、儲能網絡的建設挑戰在儲能項目中&#xff0c;網絡系統通常需要實現以下目標&#xff1a;高可靠性&#xff1a;實時采集和傳輸儲能設備狀態數據&#xff0c;鏈路中斷可能導致系統故障。靈活擴展&#xff1a;分布式站點部署廣泛&#xff0c;傳統網絡擴展需重新鋪設線路&#…

Oracle11.2.0.4 RAC遷移升級Oracle19.3 RAC

問題描述 填寫問題的基礎信息。 系統名稱 Oracle11.2.0.4遷移升級Oracle19.3 IP地址 操作系統 Centos7.5 數據庫 Oracle11.2.0.4遷移升級Oracle19.3 癥狀表現 問題的癥狀表現如下 需要將單機的Oracle11.2.0.4環境升級到Oracle19.3.0RAC環境&#xff0c;采用遷移升級的…

SAP-ABAP:SAP的‘cl_http_utility=>escape_url‘對URL進行安全編碼方法詳解

SAP的’cl_http_utility>escape_url’對URL進行安全編碼方法詳解 核心作用&#xff1a;對 URL 進行安全編碼&#xff0c;將特殊字符轉換為 %XX 格式&#xff0c;確保符合 HTTP 傳輸規范。1. 功能與作用 ? URL 安全編碼 將非安全字符轉換為十六進制 ASCII 碼&#xff08;%XX…

基于HarmonyOS的智能燈光控制系統設計:從定時觸發到動作聯動全流程實戰

摘要 隨著智能家居的快速普及&#xff0c;人們對居住環境的智能化需求越來越高&#xff0c;其中智能燈光控制是最基礎、也是最常用的功能之一。從最初的遠程控制發展到如今能“感知環境、自動響應”的智能燈光系統&#xff0c;背后依賴的是強大的系統聯動能力。鴻蒙系統作為面向…

ROS1/Linux——linux虛擬機主ip地址:網絡信息不可用

ROS1/Linux——linux虛擬機主ip地址&#xff1a;網絡信息不可用 文章目錄ROS1/Linux——linux虛擬機主ip地址&#xff1a;網絡信息不可用參考億點鏈接問題描述最終解決方案參考億點鏈接 Unable to fetch some archives, maybe run apt-get update or try with –fix-missingli…

ssl相關命令生成證書

當前環境 OpenSSL 3.5.1 1 Jul 2025 (Library: OpenSSL 3.5.1 1 Jul 2025) GmSSL 3.1.2 Dev 本地gmssl命令 #生成證書公私鑰對 gmssl sm2keygen -pass 1234 -out sm2.key -pubout sm2pub.pem #使用certgen命令生成自簽名證書cert.crt gmssl certgen -C CN -ST Beijing -L Ha…

TensorFlow深度學習實戰——DCGAN詳解與實現

TensorFlow深度學習實戰——DCGAN詳解與實現0. 前言1. DCGAN 架構2. 構建 DCGAN 生成手寫數字圖像2.1 生成器與判別器架構2.2 構建 DCGAN相關鏈接0. 前言 深度卷積生成對抗網絡 (Deep Convolutional Generative Adversarial Network, DCGAN) 是一種基于生成對抗網絡 (Generati…

SpringBoot 使用MyBatisPlus

引入依賴<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.3.0</version> </dependency>寫一個interface 繼承basemapMapper public in…

Git 中如何查看提交歷史?常用命令有哪些?

回答重點在 Git 中&#xff0c;我們可以使用 git log 命令來查看提交歷史。這個命令會列出所有的提交記錄&#xff0c;顯示每個提交的哈希值、作者信息、提交時間和提交信息。常用的 git log 命令及其選項有&#xff1a;1&#xff09; git log &#xff1a;顯示完整的提交歷史。…

Flink數據流高效寫入MySQL實戰

這段代碼展示了如何使用 Apache Flink 將數據流寫入 MySQL 數據庫&#xff0c;并使用了 JdbcSink 來實現自定義的 Sink 邏輯。以下是對代碼的詳細解析和說明&#xff1a;代碼結構包聲明&#xff1a;package sink定義了代碼所在的包。導入依賴&#xff1a;導入了必要的 Flink 和…