オフィスアワーがそろそろ始まるよ!()

mem

std.memはプリミティブなメモリ操作を提供します。いくつか有用なものを紹介します。

copy

fn copy(comptime T: type, dst: []T, src: []const T) void

srcスライスをdstスライスへコピーします。

呼び出し側は、次のことを保証しなければなりません。

  • dstsrc以上のサイズのスライスであること、つまり、src.len <= dst.lenを満たすこと
  • 2つのスライスのメモリ領域が重なっている場合、dst.ptr <= src.ptrであること

examples/ch09-std/mem/src/mem.zen:5:13

const mem = std.mem;

test "mem.copy" {
    const src = "hello";
    var dest = [_]u8 {0} ** 5;

    mem.copy(u8, &dest, &src);
    equalSlices(u8, &dest, "hello");
}

copyBackwards

fn copyBackwards(comptime T: type, dst: []T, src: []const T) void

srcスライスをdstスライスへコピーしますが、スライスを後ろから順番にコピーします。

呼び出し側は、次のことを保証しなければなりません。

  • dstsrc以上のサイズのスライスであること、つまり、src.len <= dst.lenを満たすこと
  • 2つのスライスのメモリ領域が重なっている場合、dst.ptr >= src.ptrであること

set

fn set(comptime T: type, src: []T, value: T) void

スライス (src) の全ての要素にvalueを書き込みます。

secureZero

fn secureZero(comptime T: type, s: []T) void

スライス (s) の全ての領域に0を書き込みます。

examples/ch09-std/mem/src/mem.zen:15:26

test "mem.secureZero" {
    const Point = struct {
        x: u64,
        y: u64,
    };
    // x => 10, y => 20 の Point が10個連続する配列
    var p = [_]Point { Point { .x = 10, .y = 20 } } ** 10;

    mem.secureZero(Point, &p);
    ok(p[0].x == 0);
    ok(p[9].y == 0);
}

equal

pub fn equal(comptime T: type, a: []const T, b: []const T) bool

abが同じ内容を含むスライスかどうか比較します。Tは整数型、浮動小数点型、ブール型、型です。

実行時のメモリ比較はもちろん、コンパイル時であれば、次のような比較も可能です。

examples/ch09-std/mem/src/mem.zen:28:34

test "mem.equal" {
    comptime {
        var a = [_]type {f64, f32};
        var b = [_]type {f64, f32, f16};
        _ = mem.equal(type, a[0..1], b[0..1]);
    }
}

swap

fn swap(comptime T: type, a: *T, b: *T) void

abが指しているメモリの内容を交換します。

reverse

fn reverse(comptime T: type, items: []T) void

スライスの中身を前後、逆にします。

examples/ch09-std/mem/src/mem.zen:36:41

test "mem.reverse" {
    var arr = [_]i32{ 1, 2, 3, 4, 5 };
    mem.reverse(i32, arr[0..]);

    equalSlices(i32, arr, [_]i32{ 5, 4, 3, 2, 1 });
}

startsWith

fn startsWith(comptime T: type, haystack: []const T, needle: []const T) bool

haystackが、needleから始まるスライスかどうかを調べます。

endsWith

fn endsWith(comptime T: type, haystack: []const T, needle: []const T) bool

haystackが、needleで終わるスライスかどうかを調べます。

len

fn len(comptime T: type, ptr: [*]const T) usize

NULL文字終端された配列の長さを求めます。C言語との相互運用のための関数です。

toSlice

fn toSlice(comptime T: type, ptr: [*]T) []T
fn toSliceConst(comptime T: type, ptr: [*]const T) []const T

NULL文字終端された配列をスライスに変換します。C言語との相互運用のための関数です。

separate

fn separate(buffer: []const u8, delimiter: []const u8) SplitIterator

バイト列 (buffer) をデリミタ (delimiter) で区切ります。戻り値型は、区切られたバイト列を順にアクセスできるイテレータです。

examples/ch09-std/mem/src/mem.zen:43:50

test "mem.separate" {
    var it = mem.separate("abc|def||ghi", "|");
    equalSlices(u8, it.next().?, "abc");
    equalSlices(u8, it.next().?, "def");
    equalSlices(u8, it.next().?, "");
    equalSlices(u8, it.next().?, "ghi");
    ok(it.next() == null);
}

デリミタは、複数バイトでもかまいません。

tokenize

pub fn tokenize(buffer: []const u8, delimiter_bytes: []const u8) TokenIterator

バイト列 (buffer) をデリミタ (delimiter) のいずれかのバイトで区切ります。戻り値型は、区切られたバイト列を順にアクセスできるイテレータです。

examples/ch09-std/mem/src/mem.zen:52:59

test "mem.tokenize" {
    var it = mem.tokenize("a|b,c/d", "/,|");
    equalSlices(u8, it.next().?, "a");
    equalSlices(u8, it.next().?, "b");
    equalSlices(u8, it.next().?, "c");
    equalSlices(u8, it.next().?, "d");
    ok(it.next() == null);
}

writeInt

fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void

整数型 (T) をendianのエンディアンで、配列へのポインタ (buffer) に書き込みます。ビット表現は2の補数表現です。

examples/ch09-std/mem/src/mem.zen:62:81

test "mem.writeInt" {
    var buf1: [4]u8 = undefined;

    mem.writeInt(u32, &buf1, 0x12345678, .Little);
    equalSlices(u8, &buf1, [_]u8 { 0x78, 0x56, 0x34, 0x12 });
    mem.writeInt(u32, &buf1, 0x12345678, .Big);
    equalSlices(u8, &buf1, [_]u8 { 0x12, 0x34, 0x56, 0x78 });
    // x86_64 is big endian
    mem.writeInt(u32, &buf1, 0x12345678, builtin.endian);
    equalSlices(u8, &buf1, [_]u8 { 0x78, 0x56, 0x34, 0x12 });

    // 2の補数表現で格納する。`-1`は`0xffff_ffff`
    mem.writeInt(i32, &buf1, -1, .Little);
    equalSlices(u8, &buf1, [_]u8 { 0xff, 0xff, 0xff, 0xff });

    // 8ビットで割り切れるビット幅であればOK
    var buf2: [3]u8 = undefined;
    mem.writeInt(u24, &buf2, 0x123456, .Little);
    equalSlices(u8, &buf2, [_]u8 { 0x56, 0x34, 0x12 });
}

下の関数は、エンディアンを引数として指定せずに使える関数です。

  • writeIntNative: ネイティブエンディアン (ストア命令になる)
  • writeIntForeign: ネイティブとは逆のエンディアン (@byteSwap後ストア)
  • writeIntLittle: リトルエンディアン (コンパイル時にwriteIntNativewriteIntForeignをエイリアスする)
  • writeIntBig: ビッグエンディアン (コンパイル時にwriteIntNativewriteIntForeignをエイリアスする)

readInt

fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T

配列へのポインタ (buffer) から endianのエンディアネスで、整数型 (T) を読み込みます。

examples/ch09-std/mem/src/mem.zen:83:98

test "mem.readInt" {
    var buf: [4]u8 = undefined;
    mem.writeInt(u32, &buf, 0x12345678, .Little);

    var result = mem.readInt(u32, &buf, .Little);
    ok(result == 0x12345678);
    result = mem.readInt(u32, &buf, .Big);
    ok(result == 0x78563412);

    mem.writeInt(i32, &buf, -1, .Little);
    result = mem.readInt(u32, &buf, .Little);
    ok(result == 0xffff_ffff);

    var signed = mem.readInt(i32, &buf, .Little);
    ok(signed == -1);
}

下の関数は、エンディアンを引数として指定せずに使える関数です。

  • readIntNative: ネイティブエンディアン (ロード命令になる)
  • readIntForeign: ネイティブとは逆のエンディアン (ロード後@byteSwap)
  • readIntLittle: リトルエンディアン (コンパイル時にreadIntNativereadIntForeignをエイリアスする)
  • readIntBig: ビッグエンディアン (コンパイル時にreadIntNativereadIntForeignをエイリアスする)

trim

fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T
fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T
fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T

slice から、values_to_strip に含まれるバイトを取り除きます。戻り値はsliceの一部を参照するスライスです。

examples/ch09-std/mem/src/mem.zen:100:105

test "mem.trim" {
    // それぞれスペースと改行を取り除く
    equalSlices(u8, "foo\n ", mem.trimLeft(u8, " foo\n ", " \n"));
    equalSlices(u8, " foo", mem.trimRight(u8, " foo\n ", " \n"));
    equalSlices(u8, "foo", mem.trim(u8, " foo\n ", " \n"));
}

indexOf

fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize
fn lastIndexOfScalar(comptime T: type, slice: []const T, value: T) ?usize
fn indexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
fn lastIndexOf(comptime T: type, haystack: []const T, needle: []const T) ?usize
fn indexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize
fn lastIndexOfAny(comptime T: type, slice: []const T, values: []const T) ?usize

スライスに、スカラ値またはサブスライスが含まれているかどうかを探し、見つかった場合にはそのインデックスを、見つからなかった場合にはnullを返します。

examples/ch09-std/mem/src/mem.zen:107:119

test "mem.indexOf" {
    // 見つからない場合、`null`が返る
    ok(mem.indexOfScalar(u8, "boo", 'a') == null);

    ok(mem.indexOfScalar(u8, "boo", 'o').? == 1);
    ok(mem.lastIndexOfScalar(u8, "boo", 'o').? == 2);

    ok(mem.indexOf(u8, "one two three four", "four").? == 14);
    ok(mem.lastIndexOf(u8, "one two three two four", "two").? == 14);

    ok(mem.indexOfAny(u8, "boo, cat", "abo").? == 0);
    ok(mem.lastIndexOfAny(u8, "boo, cat", "abo").? == 6);
}

rotate

fn rotate(comptime T: type, items: []T, amount: usize) void

スライス (items) の中身を、amount分、回転させます。amount <= items.lenであることを前提としています。

examples/ch09-std/mem/src/mem.zen:121:126

test "mem.rotate" {
    var array = [_]i32 { 1, 2, 3, 4, 5 };
    mem.rotate(i32, array[0..], 2);

    equalSlices(i32, [_]i32 { 3, 4, 5, 1, 2 }, array);
}

nativeTo

fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T

Tの値をネイティブエンディアンから、desired_endiannessに変換します。Tは整数型でなければなりません。

examples/ch09-std/mem/src/mem.zen:128:131

test "nativeTo" {
    const native: u32 = 0x12345678;
    ok(mem.nativeTo(u32, native, .Big) == 0x78563412);
}

エンディアンを引数として渡さなく良い関数もあります。

  • nativeToLittle
  • nativeToBig

toNative

fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T

Tの値をendianness_of_xから、ネイティブエンディアンに変換します。Tは整数型でなければなりません。

examples/ch09-std/mem/src/mem.zen:133:136

test "toNative" {
    const native: u32 = 0x78563412;
    ok(mem.toNative(u32, native, .Big) == 0x12345678);
}

エンディアンを引数として渡さなく良い関数もあります。

  • littleToNative
  • bigToNative

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2019 connectFree Corporation. All rights reserved.
Zen, the Zen three-circles logo and The Zen Programming Language are trademarks of connectFree corporation in Japan and other countries.