test:zig
This commit is contained in:
122
guide/standard-libaray/01-allocator.zig
Normal file
122
guide/standard-libaray/01-allocator.zig
Normal file
@@ -0,0 +1,122 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
// The Zig standard library provides a pattern for allocating memory,
|
||||
// which allows the programmer to choose precisely how memory allocations are done within the standard library
|
||||
// - no allocations happen behind your back in the standard library.
|
||||
// Zig 표준 라이브러리는 메모리 할당 패턴을 하나만 제공하며,
|
||||
// 이를 통해 프로그래머는 표준 라이브러리 내부에서 메모리 할당을 어떻게 할지 선택할 수 있습니다.
|
||||
// 사용자가 모르는 사이에 메모리 할당이 발생하지 않습니다.
|
||||
|
||||
// The most basic allocator is `std.heap.page_allocator`.
|
||||
// Whenever this allocator makes an allocation, it will ask your OS for entire pages of memory;
|
||||
// an allocation of a single byte will likely reserve multiple kibibytes(`KiB`).
|
||||
// As asking the OS for memory requires a system call, this is also extremely inefficient for speed.
|
||||
// 가장 기본적인 할당자는 `std.heap.page_allocator`입니다. 이 할당자는 메모리를 할당할 때 OS에게 전체 페이지의 메모리를 요청합니다.
|
||||
// 하나의 바이트를 할당하더라도 여러 `키비바이트`(`KiB`)를 예약할 수 있습니다.
|
||||
// OS에게 메모리를 요청하는 것은 시스템 호출을 필요로 하므로, 이는 매우 비효율적입니다.
|
||||
|
||||
// Here, we allocate 100 bytes as a []u8.
|
||||
// Notice how defer is used in conjunction with a free - this is a common pattern for memory management in Zig.
|
||||
// 여기서는 []u8로 100바이트를 할당합니다. defer와 free가 함께 사용되는 것을 주목하세요.
|
||||
// - 이는 Zig에서 메모리 관리에 일반적인 패턴입니다.
|
||||
|
||||
test "allocation" {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
const memory = try allocator.alloc(u8, 100);
|
||||
defer allocator.free(memory);
|
||||
|
||||
try expect(memory.len == 100);
|
||||
try expect(@TypeOf(memory) == []u8);
|
||||
}
|
||||
|
||||
// The `std.heap.FixedBufferAllocator` is an allocator
|
||||
// that allocates memory into a fixed buffer and does not make any heap allocations.
|
||||
// This is useful when heap usage is not wanted, for example, when writing a kernel.
|
||||
// It may also be considered for performance reasons.
|
||||
// - It will give you the error `OutOfMemory` if it has run out of bytes.
|
||||
// 이 할당자는 고정된 버퍼에 메모리를 할당하며, 힙 할당을 하지 않습니다.
|
||||
// 이는 힙 사용을 원하지 않을 때, 예를 들어 커널을 작성할 때 유용합니다.
|
||||
// - 성능 이유로 고려될 수 있습니다. 메모리가 부족할 경우 `OutOfMemory` 오류를 발생시킵니다.
|
||||
|
||||
test "fixed buffer allocator" {
|
||||
var buffer: [1000]u8 = undefined;
|
||||
var fba = std.heap.FixedBufferAllocator.init(&buffer);
|
||||
const allocator = fba.allocator();
|
||||
|
||||
const memory = try allocator.alloc(u8, 100);
|
||||
defer allocator.free(memory);
|
||||
|
||||
try expect(memory.len == 100);
|
||||
try expect(@TypeOf(memory) == []u8);
|
||||
}
|
||||
|
||||
// `std.heap.ArenaAllocator` takes in a child allocator and allows you to allocate many times and only free once.
|
||||
// Here, `.deinit()` is called on the arena, which frees all memory.
|
||||
// Using allocator.free in this example would be a no-op (i.e. does nothing).
|
||||
// `std.heap.ArenaAllocator`는 자식 할당자를 포함하고, 여러 번 할당을 할 수 있으며, 한 번에 해제할 수 있습니다.
|
||||
// 여기서, `.deinit()`는 arena 할당자에서 호출하여 모든 메모리를 해제합니다.
|
||||
// 이 예제에서는 `allocator.free`를 사용하면 아무 것도 하지 않습니다(`no-op`).
|
||||
test "arena allocator" {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = arena.allocator();
|
||||
|
||||
_ = try allocator.alloc(u8, 1);
|
||||
_ = try allocator.alloc(u8, 10);
|
||||
_ = try allocator.alloc(u8, 100);
|
||||
// allocator.free(); // no-op, no declaration `allocator.free` at zig-1.15.2`
|
||||
}
|
||||
|
||||
// alloc and free are used for slices. For single items, consider using create and destroy.
|
||||
// `alloc`과 `free`는 슬라이스에 사용됩니다. 단일 항목에 대해서는 `create`와 `destroy`를 사용하세요.
|
||||
test "allocator create/destroy" {
|
||||
const byte = try std.heap.page_allocator.create(u8);
|
||||
defer std.heap.page_allocator.destroy(byte);
|
||||
byte.* = 128;
|
||||
|
||||
try expect(byte.* == 128);
|
||||
}
|
||||
|
||||
// The Zig standard library also has a general-purpose allocator.
|
||||
// This is a safe allocator that can prevent double-free, use-after-free and can detect leaks.
|
||||
// Safety checks and thread safety can be turned off via its configuration struct (left empty below).
|
||||
// Zig's GPA is designed for safety over performance, but may still be many times faster than page_allocator.
|
||||
|
||||
// Zig 표준 라이브러리에는 일반적인 목적의 할당자도 있습니다.
|
||||
// 이는 이중 free, free 후 사용, 메모리 누수를 방지할 수 있는 안전한 할당자입니다.
|
||||
// 안전성 검사와 스레드 안전성은 구성 구조체를 통해 끌 수 있습니다 (left empty below).
|
||||
// - `std.heap.GeneralPurposeAllocator(.{}){};`, `{}`는 구성 구조체입니다.
|
||||
// Zig의 GPA는 성능보다 안전성을 우선시하도록 설계되었지만, `page_allocator`보다 여러 배 더 빠를 수 있습니다.
|
||||
const print = std.debug.print;
|
||||
test "GPA" {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
defer {
|
||||
const deinit_status = gpa.deinit();
|
||||
//fail test; can't try in defer as defer is executed after we return
|
||||
if (deinit_status == .leak) expect(false) catch @panic("TEST FAIL");
|
||||
}
|
||||
|
||||
const bytes = try allocator.alloc(u8, 100);
|
||||
// const sample_text = "Hello, GPA!";
|
||||
// for (bytes, 0..) |*byte, i| {
|
||||
// byte.* = @as(u8, sample_text.ptr[i]);
|
||||
// }
|
||||
// bytes[sample_text.len] = @as(u8, 0);
|
||||
// const bytes_slice = bytes[0 .. sample_text.len + 1 :@as(u8, 0)];
|
||||
// print("bytes: {s}\n", .{bytes_slice});
|
||||
defer allocator.free(bytes);
|
||||
}
|
||||
|
||||
// For high performance (but very few safety features!), std.heap.c_allocator may be considered.
|
||||
// This,however, has the disadvantage of requiring linking `Libc`, which can be done with `-lc`.
|
||||
// 높은 성능(하지만 매우 적은 안전성 기능!)을 위해 `std.heap.c_allocator`를 고려할 수 있습니다.
|
||||
// 그러나, `Libc`를 링크해야 하는 단점이 있으며, `-lc`로 수행할 수 있습니다.
|
||||
|
||||
// Benjamin Feng's talk `What's a Memory Allocator Anyway?` goes into more detail on this topic,
|
||||
// and covers the implementation of allocators.
|
||||
// Benjamin Feng의 토크 `What's a Memory Allocator Anyway?`는 이 주제에 대해 더 자세히 설명하고,
|
||||
// 할당자의 구현을 다룹니다.
|
||||
37
guide/standard-libaray/02-array-list.zig
Normal file
37
guide/standard-libaray/02-array-list.zig
Normal file
@@ -0,0 +1,37 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
// The `std.ArrayList` is commonly used throughout Zig, and serves as a buffer that can change in size.
|
||||
// `std.ArrayList(T)` is similar to C++'s `std::vector<T>` and Rust's `Vec<T>`.
|
||||
// The `deinit()` method frees all of the `std.ArrayList`'s memory.
|
||||
// The memory can be read from and written to via its slice field - `.items`.
|
||||
// `std.ArrayList` 는 Zig 에서 많이 사용되는 버퍼로, 크기를 변경할 수 있는 버퍼를 제공합니다.
|
||||
// `std.ArrayList(T)` 는 C++의 `std::vector<T>` 와 Rust의 `Vec<T>` 와 유사합니다.
|
||||
// `deinit()` 메서드는 `std.ArrayList`의 모든 메모리를 해제합니다.
|
||||
// 메모리는 `.items` 필드를 통해 읽거나 쓸 수 있습니다.
|
||||
|
||||
// Here we will introduce the usage of the testing allocator.
|
||||
// This is a special allocator that only works in tests and can detect memory leaks.
|
||||
// In your code, use whatever allocator is appropriate.
|
||||
// 여기서는 테스트 할당자(testing allocator)의 사용법을 소개합니다.
|
||||
// 이 할당자는 테스트에서만 동작하며 메모리 누수를 감지할 수 있는 특별한 할당자입니다.
|
||||
// 실제 코드에서는 상황에 맞는 할당자를 사용하면 됩니다.
|
||||
const eql = std.mem.eql;
|
||||
const ArrayList = std.ArrayList;
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
test "arraylist" {
|
||||
var list: ArrayList(u8) = .empty;
|
||||
defer list.deinit(allocator);
|
||||
try list.append(allocator, 'H');
|
||||
try list.append(allocator, 'e');
|
||||
try list.append(allocator, 'l');
|
||||
try list.append(allocator, 'l');
|
||||
try list.append(allocator, 'o');
|
||||
try list.appendSlice(allocator, " World!");
|
||||
|
||||
try expect(eql(u8, list.items, "Hello World!"));
|
||||
}
|
||||
|
||||
// Coming from C++?
|
||||
// Zig's std.ArrayList is very comparable to C++'s std::vector.
|
||||
// Zig의 std.ArrayList는 C++의 std::vector와 매우 비슷합니다.
|
||||
75
guide/standard-libaray/03-filesystem.zig
Normal file
75
guide/standard-libaray/03-filesystem.zig
Normal file
@@ -0,0 +1,75 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const eql = std.mem.eql;
|
||||
|
||||
// Let's create and open a file in our current working directory, write to it, and then read from it.
|
||||
// Here we have to use `.seekTo` to go back to the start of the file before reading what we have written.
|
||||
// 현재 작업 디렉터리에서 파일을 생성하고 열어, 그 안에 내용을 기록한 후 다시 읽어 봅시다.
|
||||
// 여기서 기록한 내용을 읽기 전에 파일의 시작 부분으로 돌아가기 위해 `.seekTo`를 사용해야 합니다.
|
||||
test "createFile, write, seekTo, read" {
|
||||
const file = try std.fs.cwd().createFile(
|
||||
"junk_file.txt",
|
||||
.{ .read = true },
|
||||
);
|
||||
defer file.close();
|
||||
|
||||
try file.writeAll("Hello File!");
|
||||
|
||||
var buffer: [100]u8 = undefined;
|
||||
try file.seekTo(0);
|
||||
const bytes_read = try file.readAll(&buffer);
|
||||
|
||||
try expect(eql(u8, buffer[0..bytes_read], "Hello File!"));
|
||||
}
|
||||
|
||||
// The functions `std.fs.openFileAbsolute` and similar absolute functions exist, but we will not test them here.
|
||||
// We can get various information about files by using `.stat()` on them.
|
||||
// `Stat` also contains fields for `.inode` and `.mode`, but they are not tested here as they rely on the current OS' types.
|
||||
// When the Enum type is known from context, it can be omitted, so we can compare `stat.kind` to `.file` instead of `Kind.file`.
|
||||
// 함수 `std.fs.openFileAbsolute` 와 같은 절대 경로 함수가 존재하지만, 여기서는 테스트하지 않습니다.
|
||||
// 파일에 대한 다양한 정보를 얻기 위해 `.stat()` 함수를 사용할 수 있습니다.
|
||||
// `Stat` 에는 `.inode` 와 `.mode` 필드가 포함되어 있지만, 현재 OS의 타입에 의존하므로 여기서는 테스트하지 않습니다.
|
||||
// Enum 타입이 컨텍스트에서 알려져 있을 때, 타입을 생략할 수 있고, `stat.kind` 를 `.file` 과 비교하는 대신 `Kind.file` 과 비교할 수 있습니다.
|
||||
test "file stat" {
|
||||
const file = try std.fs.cwd().createFile(
|
||||
"junk_file2.txt",
|
||||
.{ .read = true },
|
||||
);
|
||||
defer file.close();
|
||||
const stat = try file.stat();
|
||||
try expect(stat.size == 0);
|
||||
try expect(stat.kind == .file);
|
||||
try expect(stat.ctime <= std.time.nanoTimestamp());
|
||||
try expect(stat.mtime <= std.time.nanoTimestamp());
|
||||
try expect(stat.atime <= std.time.nanoTimestamp());
|
||||
}
|
||||
|
||||
// We can make directories and iterate over their contents.
|
||||
// Here we will use an iterator (discussed later).
|
||||
// This directory (and its contents) will be deleted after this test finishes.
|
||||
// 디렉터리를 생성하고 그 내용을 반복할 수 있습니다.
|
||||
// 여기서는 이터레이터(나중에 설명)를 사용합니다.
|
||||
// 이 디렉터리(와 그 내용)는 이 테스트가 완료된 후 삭제됩니다.
|
||||
test "make dir" {
|
||||
try std.fs.cwd().makeDir("test-tmp");
|
||||
var iter_dir = try std.fs.cwd().openDir(
|
||||
"test-tmp",
|
||||
.{ .iterate = true },
|
||||
);
|
||||
defer {
|
||||
iter_dir.close();
|
||||
std.fs.cwd().deleteTree("test-tmp") catch unreachable;
|
||||
}
|
||||
|
||||
_ = try iter_dir.createFile("x", .{});
|
||||
_ = try iter_dir.createFile("y", .{});
|
||||
_ = try iter_dir.createFile("z", .{});
|
||||
|
||||
var file_count: usize = 0;
|
||||
var iter = iter_dir.iterate();
|
||||
while (try iter.next()) |entry| {
|
||||
if (entry.kind == .file) file_count += 1;
|
||||
}
|
||||
|
||||
try expect(file_count == 3);
|
||||
}
|
||||
Reference in New Issue
Block a user