Tag: zig
35 รายการ
Blog
Zig splitScalar: เก็บช่องว่างใน CSV เล็ก ๆ ไม่ให้ข้อมูลเลื่อน
ใช้ std.mem.splitScalar แยก field ด้วย delimiter หนึ่งไบต์โดยรักษาช่องว่าง พร้อม zig test ตรวจ missing และ extra fields
Zig tokenizeSequence: แยกข้อมูลด้วย delimiter หลายไบต์แบบไม่ตัดกลาง
ใช้ std.mem.tokenizeSequence แยก record ด้วย delimiter ทั้งชุด ข้ามช่องว่างซ้ำ และทดสอบ edge case ด้วย zig test
Zig std.mem.replace: คำนวณขนาดก่อนแทนข้อความโดยไม่เดา buffer
ใช้ replacementSize คู่กับ replace เพื่อจองปลายทางพอดี ตรวจจำนวนครั้ง และกัน output โตเกินเพดาน
Zig std.mem.tokenizeAny: แยกคำเมื่อ delimiter มีหลายตัว
ใช้ tokenizeAny แยกข้อความด้วยช่องว่าง comma slash หรือ pipe โดยไม่คืน token ว่าง พร้อมเทียบ tokenizeScalar และ splitAny
Zig std.mem.findMinMax: หา index ค่าน้อยสุดและมากสุดในรอบเดียว
ใช้ findMinMax บน slice ที่ไม่ว่าง พร้อมจัดการ empty input และ tie behavior ด้วย test บน Zig 0.17
Zig splitBackwardsSequence: แยก path จากด้านท้ายโดยไม่ reverse ข้อมูล
ใช้ std.mem.splitBackwardsSequence ดึงชื่อไฟล์และโฟลเดอร์จากท้าย slice พร้อมรู้ empty field, delimiter หลายไบต์ และ lifetime
Zig std.mem.rotate: หมุน slice in-place สำหรับคิวแบบวงแหวน
เข้าใจทิศทาง amount, ค่าเกินความยาว และ trade-off ของการหมุนข้อมูลจริงเทียบกับเก็บ head index
Zig indexOfScalarPos: ค้นตัวคั่นต่อจาก cursor โดยไม่ตัด slice ซ้ำ
ใช้ std.mem.indexOfScalarPos ทำ parser แบบเดิน cursor พร้อมเข้าใจ null และขอบเขตเริ่มค้นหา
Zig std.mem.reverse: กลับลำดับในที่เดิม พร้อมเข้าใจ slice และ mutation
ทดลอง reverse slice แบบ in-place ใน Zig 0.16 และระวังเรื่องข้อมูลต้นฉบับถูกแก้
Zig 0.16 Socket.createPair: สร้างช่องสื่อสารสองปลายสำหรับงานในโปรเซส
ทดลอง API socket pair ใหม่ใน std.Io พร้อมอธิบาย ownership, การปิด handle และจังหวะที่ควรเลือก pipe
Zig 0.16 renamePreserve: ย้ายไฟล์โดยไม่เขียนทับปลายทางเงียบ ๆ
ใช้ Io.Dir.renamePreserve ทำ publish แบบ fail-closed และแยกกรณีปลายทางมีอยู่จากการ replace
Zig 0.16 เทียบ packed union ตาม backing integer: สะดวกแต่ต้องอ่าน representation
ทดลอง equality ของ packed union และอธิบายว่าทำไม field คนละชื่ออาจเท่ากันได้
Zig std.mem.window: ทำ Sliding Window โดยคืน Slice ไม่คัดลอกข้อมูล
ใช้ std.mem.window สร้าง moving window, chunk และ sampling พร้อมระวัง tail slice กับ size/advance ที่ห้ามเป็นศูนย์
Zig splitSequence: แยก delimiter หลายไบต์โดยยังเห็นช่องว่างระหว่างคู่ติดกัน
ใช้ std.mem.splitSequence ทำ parser รูปแบบเล็ก ๆ พร้อมเข้าใจ empty field, lifetime และความต่างจาก splitAny

Zig Workshop #6: 1 ล้านบรรทัดใน 62 มิลลิวินาที และส่งขึ้นทุกแพลตฟอร์ม
บทจบของ workshop zlog — เก็บข้อมูลแบบ struct-of-arrays เพื่อคำนวณ percentile, เทียบเวลา Debug กับ Release ที่ต่างกัน 14 เท่า, คอมไพล์ binary ให้ห้าแพลตฟอร์มจากเครื่องเดียว และ benchmark เทียบกับ awk และ Python บนไฟล์ 94 MB เดียวกันที่ reproduce ได้

Zig Workshop #5: ให้ comptime สร้างตัวเลือกของ CLI จาก struct
เพิ่มฟิลด์ใน struct หนึ่งบรรทัด แล้ว --by, ข้อความ --help และตัวแปลงค่าของ CLI รองรับให้เองทันที — ใช้ @typeInfo กับ inline for อ่านโครงสร้าง LogLine ตอนคอมไพล์ และ @compileError ดักชื่อฟิลด์ผิดตั้งแต่ยังไม่ได้รัน

Zig Workshop #4: บั๊ก slice ที่ชี้ไปในอากาศ และวิธีแก้ด้วย arena
เก็บสถิติจาก log ที่อ่านมาแบบไม่ copy — สร้างบั๊ก dangling slice ขึ้นมาจริงแล้วแก้ด้วย arena interning, ใช้ getOrPut ให้ hash ครั้งเดียวแทนสามครั้ง, เรียง top-N ด้วย sort.pdq และให้ std.testing.allocator จับ leak ให้อัตโนมัติ

Zig Workshop #3: แยกวิเคราะห์ log โดยไม่ขอหน่วยความจำแม้แต่ไบต์เดียว
เขียน parser สำหรับ nginx combined log ที่ไม่ copy อะไรเลย — ทุกฟิลด์เป็น slice ที่ชี้กลับเข้าไปในบรรทัดต้นทาง, error set ที่บอกได้ว่าผิดตรงไหน, โหมด --strict และบทเรียนเรื่องอายุของข้อมูลที่คอมไพเลอร์ Zig ไม่ได้ตรวจให้

Zig Workshop #2: อ่านไฟล์ 94 MB ด้วยแรม 1.8 MB
อ่าน log ทีละบรรทัดแบบ streaming ด้วย Io.Reader ของ Zig 0.16 — ทำไม buffer ถึงเป็นพารามิเตอร์, takeDelimiter ทำงานยังไง, จัดการบรรทัดแบบ Windows และผลวัดจริงที่ streaming ใช้แรม 1.8 MB เทียบกับอ่านทั้งไฟล์ที่ใช้ 100 MB บนไฟล์เดียวกัน

Zig Workshop #1: วางโครง CLI ที่รันได้จริงด้วย build.zig ของ 0.16
เริ่ม workshop สร้าง zlog เครื่องมือวิเคราะห์ nginx access log — zig init ของจริงใน 0.16, build.zig.zon ที่บังคับ fingerprint, main ที่รับ std.process.Init, อ่าน argument, buffered stdout พร้อม flush และรหัสจบโปรแกรมที่ถูกต้อง

Zig เด่นตรงไหน เทียบกับ C, C++, Rust, Go, C# และ Java แบบไม่เชียร์
บทยาวว่าด้วยจุดเด่นจริงของ Zig 0.16 — ไม่มีอะไรเกิดขึ้นลับหลัง, comptime กลไกเดียวแทนสี่อย่าง, toolchain ที่คอมไพล์ข้ามแพลตฟอร์มได้จากเครื่องเดียว (ผมวัดขนาด binary จริงทุก target), ความปลอดภัยแบบเลือกได้ พร้อมข้อจำกัดที่ต้องรู้ก่อนเอาไปใช้งานจริงและคำเตือนว่าเมื่อไหร่ไม่ควรเลือก Zig

Zig 0.16 บทที่ 9: เลือก allocator ให้ถูกงาน และของที่หายไปใน 0.16
สวนสัตว์ allocator ของ Zig 0.16 — arena ที่ทำให้โค้ดคืนหน่วยความจำหายไปเกือบหมด (วัดได้ว่าลดการขอจาก 50 ครั้งเหลือ 5), FixedBufferAllocator, MemoryPool, stackFallback พร้อมทางย้ายสู่ BufferFirstAllocator ใน 0.17, DebugAllocator vs smp_allocator และรายชื่อ allocator ที่ถูกลบทิ้งใน 0.16

Zig 0.16 บทที่ 8: allocator คืออะไร และใครเป็นเจ้าของหน่วยความจำ
หัวใจของ Zig คือไม่มี allocator ตั้งต้น — ทำความเข้าใจ interface ที่มีแค่สี่ฟังก์ชัน, ธรรมเนียมว่าใครเป็นเจ้าของผลลัพธ์, เขียน allocator ของตัวเองที่นับการใช้งานได้, และรายงาน leak จริงจาก DebugAllocator ที่ผมรันให้ดูทั้ง output และรหัสจบโปรแกรม

Zig 0.16 บทที่ 7: error ไม่มีข้อมูลแนบ แล้วจะบอกรายละเอียดยังไง
งานจริงของ error handling ใน Zig — รูปแบบ diagnostics struct ที่ standard library ใช้เอง, ทดสอบทุกจุดที่หน่วยความจำเต็มด้วย checkAllAllocationFailures, ตาราง safety ต่อ build mode ที่ผมรันจริงทั้งสามโหมด และการเขียน panic handler เองแบบ 0.16

Zig 0.16 บทที่ 6: error ที่คอมไพเลอร์ไม่ยอมให้คุณเมิน
ระบบ error ของ Zig ไม่มี exception ไม่มีการคลี่ stack และเมินไม่ได้ — error set เป็นชนิดข้อมูล, try/catch/errdefer, switch บน error ที่ต้องครบทุกกรณี และ error return trace ที่ผมรันจริงแล้วพบว่า ReleaseSafe ปิดไว้ ต่างจากที่เอกสารส่วนใหญ่บอก พร้อมเทียบกับ C++, Java, C#, Go และ Rust

Zig 0.16 บทที่ 5: comptime กลไกเดียวที่แทน macro, template และ reflection ทั้งหมด
comptime คือการรันภาษา Zig เองตอนคอมไพล์ — สร้างตาราง lookup ล่วงหน้า, เขียน generic ด้วยฟังก์ชันที่คืน type, อ่านโครงสร้าง struct ด้วย @typeInfo และ inline for, ตรวจความถูกต้องด้วย @compileError และ @Int ที่มาแทน @Type ใน 0.16 พร้อมตัวอย่างที่รันผ่านจริง

Zig 0.16 บทที่ 4: ทำไม I/O ต้องส่ง io ไปทุกที่ และข้อความที่เขียนไม่เหมือนเดิม
หัวใจของการเปลี่ยนแปลงใน Zig 0.16 — I/O กลายเป็นพารามิเตอร์เหมือน allocator, writer ที่คุณต้องส่ง buffer ให้เองและต้อง flush, อ่านไฟล์ทีละบรรทัดด้วย takeDelimiter, จัดการ CRLF ของ Windows และ format method ที่เปลี่ยน signature จนโค้ดเก่าใช้ไม่ได้

Zig 0.16 บทที่ 3: struct, enum, union และคอนเทนเนอร์ที่เปลี่ยนไปทั้งหมด
ประกอบข้อมูลเป็นก้อนใหญ่ใน Zig 0.16 — struct กับ decl literal, enum ที่ switch ครบทุกกรณีหรือคอมไพล์ไม่ผ่าน, tagged union แทน inheritance, การจัดวางหน่วยความจำที่คอมไพเลอร์เรียงให้เอง และ ArrayList/HashMap/MultiArrayList แบบ 0.16 ที่ใช้ไม่เหมือนเดิม

Zig 0.16 บทที่ 2: ชนิดข้อมูลและการควบคุมการทำงาน ที่ไม่มีอะไรซ่อนไว้
เจาะพื้นฐานภาษา Zig 0.16 — จำนวนเต็มความกว้างใดก็ได้, การล้นที่ Zig ถือว่าผิดกฎทั้ง signed และ unsigned, optional ที่แทน null ได้จริง, ความต่างของ array กับ slice, ลูปที่วิ่งหลายชุดพร้อมกัน, labeled switch และ defer พร้อมตัวอย่างที่รันผ่านจริงทุกชิ้น

เริ่มต้น Zig 0.16 ตั้งแต่ติดตั้ง: ทำไม tutorial เก่าที่คุณเจอถึงคอมไพล์ไม่ผ่าน
บทแรกของชุดเรียน Zig ภาษาไทย — ติดตั้ง Zig 0.16.0 บน Windows, macOS และ Linux, เขียนโปรแกรมแรกสองแบบ, ตั้งโปรเจกต์ด้วย zig init และเข้าใจว่าทำไมโค้ดตัวอย่างส่วนใหญ่บนอินเทอร์เน็ตตอนนี้ใช้กับ 0.16 ไม่ได้

Zig Optimization #5: buffer เดียวเปลี่ยน 1,173 ms เป็น 3 ms และของที่แก้แล้วไม่ต่าง
บทปิดของชุด optimization — กราฟขนาด buffer ที่ต่างกัน 375 เท่า, ต้นทุนของ format ที่ต้องแยกให้ออกจากต้นทุน syscall และรวมทุกเคสที่ผมวัดแล้วพบว่าแก้ไปก็ไม่ดีขึ้น ซึ่งมีค่าพอ ๆ กับเคสที่ดีขึ้น

Zig Optimization #4: pointer chasing ช้ากว่า array 247 เท่า แต่ SoA ชนะแค่ 9%
วัดการจัดวางข้อมูลบน 2 ล้านแถว — struct-of-arrays ชนะน้อยกว่าที่คนเล่ากันเยอะ, การเปลี่ยน usize เป็น u32 ไม่ได้ช่วยเลยแม้แต่นิดเดียว แต่การเดิน linked list ที่ node กระจัดกระจายช้ากว่า array 247 เท่า

Zig Optimization #3: เลิก copy ข้อความ และใช้ hash map ให้ถูกวิธี
วัดจริงบนงานนับความถี่ 200,000 ครั้ง — การสร้างข้อความใหม่ทุกรอบช้ากว่า interning 4 เท่า, contains+get+put ช้ากว่า getOrPut เกือบ 3 เท่า และการแปลง key เป็น u32 handle เร็วกว่าทุกวิธี 40 เท่า พร้อมผลตามความยาว key ที่ 16, 64 และ 256 ไบต์

Zig Optimization #2: การขอหน่วยความจำสองแสนครั้ง เหลือสองครั้ง
วัดจริงว่านิสัยขอหน่วยความจำที่ติดมาจาก Java, Go และ Python แพงแค่ไหนใน Zig — create ในลูปช้ากว่า arena 3 เท่า, การจองล่วงหน้าลดการขยายจากยี่สิบกว่ารอบเหลือศูนย์ และเคสที่ MemoryPool กลับไม่ชนะ arena เลยทั้งที่ทฤษฎีบอกว่าควรชนะ

Zig Optimization #1: ก่อนจะปรับให้เร็ว ต้องวัดให้ถูกก่อน
std.time.Timer หายไปจาก Zig 0.16 แล้ว และการเทียบ Debug กับ Release ตรง ๆ ให้ตัวเลขที่เกินจริงหกเท่า เพราะ init.gpa สลับ allocator ตาม build mode — บทนี้สร้าง harness ที่ใช้ได้จริงและพิสูจน์ว่าตัวเลขที่คนแชร์กันหลอกตรงไหน