- PureBasic 100%
Codex-Review 2026-05-17 hat 5 RFC-Luecken identifiziert. Alle gefixt: Fix #1: UTF-8 Validation (RFC 3629 / RFC 8259 §8.1) Neuer _IsValidUtf8(*data, len, *errPos) Helper. Parse() validiert jetzt strikt UTF-8 vor _ParseValue. Rejected: overlong-Encodings, stray Continuation-Bytes, Surrogates (U+D800..U+DFFF), Codepoints > U+10FFFF. Bei Fehler: JSON_ERR_UTF8 + exact Byte-Position. Fix #2: Builder State-Machine Neue _CtxAllowsKey/_CtxAllowsValue/_CtxAllowsObjEnd/_CtxAllowsArrEnd Helpers. Builder broken bei: - Key* in Array-Context - Push* in Object-Context (kein Key) - ArrEnd in Object / ObjEnd in Array - Mehrfacher Root-Wert (had_root-Flag) - End-Operation bei depth=0 FinalizeToBytes/String + IsValid pruefen jetzt depth=0 UND had_root. Fix #3: Object-Keys decoded gespeichert (RFC-8259 semantisch) Neuer _DecodeRawToArena(*src, len, arena, *out_ptr, *out_len) Helper (Escape + Surrogate-Pair-Decoding aus AsString extrahiert). _ParseObject dekodiert Keys jetzt beim Parse in die Arena. Damit findet ObjectGet(root, "a/b") jetzt Key "a\/b" semantisch. KeyString liefert dekodierten String. Fix #4: Float Non-Finite Rejection Neuer _IsFiniteFloat(val) Helper (PB-Trick: val*0.0<>0.0 fuer NaN/Inf). KeyFloat/PushFloat setzen broken bei NaN/Infinity statt ungueltiges JSON-Token auszugeben. Fix #5: OOM in _WriteEscaped markiert Builder broken Bei AllocateMemory-Failure jetzt *b\broken = #True (vorher: silent return mit "key": ohne Value). Smoke-Tests: +20 neue Asserts (Section 15) fuer alle 5 Fixes +2 Asserts (Section 10) angepasst (alte laxe Semantik) 102/102 PASS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| DATA | ||
| GUI | ||
| SYS | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
lhs_lib
Includes entwickelt und erweitert aus bestehenden Sourcen um PureBasic-Funktionalitäten zu erweitern.
Module
SYS/
| Modul | Beschreibung | C-Backend |
|---|---|---|
lhs_log.pbi / lhs_log_ext.pbi |
Logging-Modul (single- bzw. multi-threaded Logger) | nein |
lhs_sys_debug_wrapper.pbi |
Debug-Wrapper für PB-Default-Debug, lhs_log, lhs_log_ext | nein |
lhs_uuid.pbi |
UUID-Generator (v1, v3, v4, v5) | nein |
lhs_arena.pbi |
Arena-Allocator mit case-insensitive HashMap und FlatList — Hot-Path-Performance für Result-Sets, HTTP-Header-Maps, Per-Request-Pools | ja |
lhs_atomic.pbi |
Lock-free Atomics über GCC builtins (CAS, AtomicLoad/Store, Increment/Decrement, Add, Memory-Barriers) | ja |
lhs_lockfree_queue.pbi |
MPMC-bounded Queue (Dmitry-Vyukov-Algorithmus), benötigt lhs_atomic |
ja |
GUI/
| Modul | Beschreibung |
|---|---|
lhs_dialog.pbi |
Erweiterte Dialog-Bausteine |
Tests / Benchmarks
Liegen im separaten Wrapper-Repo lhs_lib_full (lhs_lib selbst eingebunden als Git-Submodule). Enthält:
lhs_arena_bench.pb— Performance-Benchmark gegen PB-Native Map/List mit Realworld-Szenarien (HTTP Lifecycle, Mixed Workload, Concurrent, PPQL Result-Sets, Search-Index, Cookie-Parser, Header-Match)lhs_arena_memprof.pb— Memory-Footprint-Profiler (Peak-RSS, Page-Faults)build_csv.sh— Vergleichstabellen-Generator- Bench-Outputs für verschiedene Hardware (Ryzen, Xeon X5650, …)
Build-Hinweise
Module mit C-Backend-Pflicht (lhs_arena, lhs_atomic, lhs_lockfree_queue) müssen mit dem PureBasic-C-Backend gebaut werden:
pbcompilerc dein_programm.pb --thread --optimizer --executable dein_programm
Das C-Backend ist auf Linux, macOS, Windows und ARM verfügbar. Der ASM-Backend wird für diese Module nicht unterstützt (GCC-builtin-Atomics und Inline-C-Hotpaths sind C-spezifisch).
Programming recommendations in this collection
Debugging
Es empfiehlt sich, SYS/lhs_sys_debug_wrapper.pbi zu verwenden statt direkt Debug:
Initial:
Global LoggerUUID.s = ""
Global Log_Level_Info = 0
Global Log_Level_Debug = 0
Global Log_Level_Error = 2
Im Code:
ldl::Logging("Something on Info Log", LoggerUUID, Log_Level_Info)
Arena (HTTP/PPQL Hot-Path)
Pro Request/Query eine Arena, am Ende Reset (Speicher bleibt für nächsten Cycle wiederverwendbar) oder Destroy:
XIncludeFile "lhs_lib/SYS/lhs_arena.pbi"
Define *arena.lhs_arena::Arena = lhs_arena::Create(65536)
; HashMap mit case-insensitive Key-Vergleich (ideal für HTTP-Header)
Define *headers.lhs_arena::HashMap = lhs_arena::MapCreate(*arena, 32)
lhs_arena::MapSet(*headers, "Content-Type", "text/html")
v.s = lhs_arena::MapGet(*headers, "content-type") ; → "text/html"
; Zero-UTF-Boundary für Bytes direkt aus Socket-Buffer (HTTP-Parser-Pfad)
lhs_arena::MapSetBytes(*headers, *key_ptr, key_len, *val_ptr, val_len)
*vp = lhs_arena::MapGetBytes(*headers, *key_ptr, key_len, @vlen)
lhs_arena::Reset(*arena) ; Alles zurück, Chunks behalten
lhs_arena::Destroy(*arena) ; Alles freigeben
Benchmark-Auszug (Ryzen AI 9 HX 370, 24 Cores) gegen PB-Native bei 100 000 Map-Einträgen:
| Test | PB-Native | Arena | Speedup |
|---|---|---|---|
| Map-Lifecycle (Insert + Lookup + Cleanup) | 269 ms | 27.6 ms | 9.7× |
| Concurrent (1000 Threads × 5k ops, 90% read) | 4.62 s | 102 ms | 45× |
| PPQL Result-Set 50k Rows × 10 Cols | 9.89 s | 69 ms | 143× |
| HTTP Header-Match (500 known, Bytes-API) | 1.4 µs/op | 43 ns/op | 32× |
Details, X5650-Vergleich und Memory-Footprint: siehe tests/.
Lock-Free Queue (MPMC)
XIncludeFile "lhs_lib/SYS/lhs_atomic.pbi"
XIncludeFile "lhs_lib/SYS/lhs_lockfree_queue.pbi"
Define *q = lhs_lockfree_queue::Create(1024) ; Power-of-2 capacity
; Producer (mehrere Threads ok)
lhs_lockfree_queue::Push(*q, *work_item)
; Consumer (mehrere Threads ok)
*item = lhs_lockfree_queue::Pop(*q)
If *item
; arbeiten ...
EndIf
lhs_lockfree_queue::Free(*q)
Autoren
René Linder [Ground0]
Lizenz
Sofern in den Sourcen nicht anders erwähnt gilt:
- LGPL v2.1: https://www.gnu.org/licenses/old-licenses/lgpl-2.1
- Commercial: Für proprietary/closed-source Projekte. Kontakt: info@lihaso.ch
SPDX-License-Identifier: LGPL-2.1-or-later OR Commercial