ساختن یه فرمت باینری از صفر با C++
خلاصهٔ کاملتر
نویسنده تو این پست با لحن شوخ تعریف میکنه که چطور برای اینکه «برنامهنویس واقعی» باشه و داده رو JSON ذخیره نکنه، رفت سراغ باینری و آخرش jBin رو ساخت: یه زبان schema که به گفتهی خودش payloadهای JSON رو تا ۸۰٪ کوچیکتر میکنه. پیادهسازی با C++ انجام شده و شامل lexer، parser، AST، تحلیلگر معنایی، codegen و یه CLI میشه.
مسیر طراحی قدمبهقدم جلو میره. اول هر مقدار یه بایت نوع و یه بایت طول داره. بعد برای صرفهجویی از varint استفاده میکنه، یعنی عددی با طول متغیر که بیت آخر (MSB) هر بایت میگه «بایت بعدی هم مال همین عدده». اینطوری عددهای کوچیک فقط یه بایت جا میگیرن. ترتیب بایتها هم little-endian هست، یعنی ۷ بیت کمارزشتر اول میان:
void encodeVariant(std::vector<uint8_t> &buffer, uint64_t value) {
while (value >= 128) {
uint8_t lower = value & 127; // 127 = 01111111
lower |= 128;
buffer.push_back(lower);
value >>= 7;
}
uint8_t lower = value & 127;
buffer.push_back(lower);
}قدم بعدی schema هست: وقتی ساختار داده از قبل معلومه (مثل یه struct تو C)، دیگه لازم نیست نوع کنار هر مقدار ذخیره بشه. نویسنده میگه protobuf هم همین کارو میکنه. بعد فقط چهار نوع رمزگذاری میمونه (varint، f32، f64 و delimited برای رشتهها) که تو ۲ بیت جا میشن. این ۲ بیت با شیفت به چپ کنار شمارهی فیلد میشینن، و حتی طول هم داخل همون varint هدر بستهبندی میشه.
برای سینتکس، نویسنده عمداً از protobuf فاصله گرفته. فیلدها مثل لیست خرید شماره میخورن (1. name: string)، بلوکها با end تموم میشن، تورفتگی مهم نیست و نقطهویرگول هم لازم نیست. مقدار پیشفرض با = میاد، و list، map، enum و union شکل تابع دارن. پیشفرض یه union کنار نوع خودش نوشته میشه تا ابهام نداشته باشه. چون کامپایلر دو بار فایل رو میخونه، ترتیب تعریفها مهم نیست و یه message میتونه به خودش ارجاع بده:
message Player:
1. name: string
2. health: i32 = 100
4. connections: list(Player)
7. balance: union(string="empty", i32)
end
نکات کلیدی:
- jBin به گفتهی سازندهش حجم payloadهای JSON رو تا ۸۰٪ کم میکنه.
- عددها و boolها به شکل varint ذخیره میشن؛ MSB هر بایت نشون میده عدد ادامه داره یا نه.
- فقط چهار نوع رمزگذاری هست (varint، f32، f64، delimited) که تو ۲ بیت کنار شمارهی فیلد جا میشن.
- سینتکس بدون آکولاد و نقطهویرگوله، با end بسته میشه و enumها لازم نیست از ۰ شروع بشن (برخلاف protobuf).
- کامپایلر با C++ نوشته شده و lexer، parser، AST، تحلیل معنایی، codegen و CLI داره.




