Print Buffer (printbuf)
Relevant source files
The following files were used as context for generating this wiki page:
The Print Buffer (printbuf) is a core utility module within libfastjson designed to provide a dynamic, growable string buffer. Its primary purpose is to facilitate efficient string construction and concatenation, particularly during the serialization of JSON objects into formatted strings. By managing memory allocations internally, it shields other modules from the complexities of manual buffer management and reallocations.
This module is extensively used by the JSON printing logic and the tokener to accumulate characters and strings during parsing or dumping. It supports various operations including formatted printing (printf-style), raw memory appending, and specialized performance-optimized appending for internal library use.
Data Structure and Lifecycle
The printbuf structure is simple, consisting of a pointer to the character data, a position indicator for the current end of the buffer, and the total allocated size.
The printbuf Struct
| Field | Type | Description |
|---|---|---|
buf | char * | Pointer to the allocated memory buffer. |
bpos | int | Current position in the buffer (length of data). |
size | int | Total allocated size of the buffer. |
Sources: printbuf.h:26-30
Lifecycle Management
The lifecycle of a print buffer involves initialization with a configurable size, iterative expansion as data is added, and final deallocation.
The diagram shows the standard progression of a printbuf object from creation to deletion.
Sources: printbuf.c:42-100, printbuf.c:203-210
Key Functions
printbuf_new(): Allocates a newprintbufand initializes its buffer based on the globalprintbuf_initial_size(default is 32). Sources: printbuf.c:35-40, printbuf.c:42-56fjson_global_set_printbuf_initial_size(int size): Allows users to globally change the starting capacity for all new buffers. Sources: printbuf.c:37-40printbuf_reset(struct printbuf *p): Resets the buffer position to zero and null-terminates the start, effectively clearing the buffer without deallocating memory. Sources: printbuf.c:197-201printbuf_free(struct printbuf *p): Frees the internal character buffer and theprintbufstructure itself. Sources: printbuf.c:203-210
Buffer Expansion Logic
The printbuf_extend function handles the internal logic for resizing the buffer when current capacity is exceeded. It implements a growth strategy to minimize frequent reallocations.
Growth Strategy
- If the current size is less than half of
INT_MAX, the buffer size is doubled. - If the buffer is already very large, it increments by the requested minimum size plus a small constant (8 bytes).
- It includes checks to prevent signed integer overflows during calculation.
Sources: printbuf.c:66-91
The diagram represents the decision logic used to determine the new size of a buffer during an extension.
Sources: printbuf.c:75-98
Data Insertion Operations
The module provides several ways to add data, ranging from high-level formatted strings to low-level character appending.
Appending Methods
| Function / Macro | Description |
|---|---|
sprintbuf | A printf-style function that formats and appends a string. It uses a stack-based buffer (128 bytes) for speed, falling back to dynamic allocation via vasprintf for larger strings. |
printbuf_memappend | Appends a raw memory block of a specific size and ensures the result is null-terminated. |
printbuf_memappend_fast | A macro that checks for available space and performs a memcpy directly if room exists; otherwise, it calls the heavier printbuf_memappend. |
printbuf_memappend_no_nul | Appends data without adding a null terminator, optimized for successive appends. |
printbuf_memappend_char | Appends a single character. |
printbuf_memset | Sets a range of bytes in the buffer to a specific character value, extending the buffer if necessary. |
Sources: printbuf.h:46-77, printbuf.c:102-140, printbuf.c:170-195
Formatted Printing Sequence
The sequence shows how sprintbuf optimizes for small strings while safely handling large outputs.
Sources: printbuf.c:170-195
Integration in libfastjson
The printbuf is a foundational component used across the library:
- JSON Printing:
fjson_object_to_json_string_extuses aprintbufattached to thefjson_objectto generate the JSON representation. Sources: json_object.c:451-467 - Tokenizing: The
fjson_tokenerstructure contains aprintbuf(pb) used to accumulate string literals and escape sequences during parsing. Sources: json_tokener.c:134-142, json_tokener.c:354-360 - Utility Functions: Functions like
fjson_object_from_fduse aprintbufto read raw data from a file descriptor before passing it to the parser. Sources: json_util.c:64-77
Example: Escape String Logic
When escaping strings in json_object.c, the library uses printbuf_memappend_no_nul to efficiently build the escaped string piece-by-piece.
if(str != start_offset)
printbuf_memappend_no_nul(pb, start_offset, str - start_offset);
switch(*str) {
case '\b': printbuf_memappend_no_nul(pb, "\\b", 2); break;
// ... other cases
}
Sources: json_object.c:139-160
Conclusion
The printbuf module provides the necessary infrastructure for efficient string manipulation in libfastjson. By utilizing a combination of macros for fast-path operations and robust growth logic for large data sets, it enables the library to handle JSON serialization and parsing with high performance and minimal memory overhead. Its design emphasizes speed through reduced null-terminator writes and stack-based formatting for common small-scale string operations.