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

mem

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

copy

fn copy(comptime T: type, dest: []mut T, source: []T) void

sourceスライスをdestスライスへコピーします。

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

  • destsource以上のサイズのスライスであること、つまり、source.len <= dest.lenを満たすこと
  • 2つのスライスのメモリ領域が重なっている場合、dest.ptr <= source.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, &mut dest, src);
    equalSlices(u8, &dest, "hello");
}

copyBackwards

fn copyBackwards(comptime T: type, dest: []mut T, source: []T) void

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

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

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

set

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

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

secureZero

fn secureZero(comptime T: type, s: []mut 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, &mut p);
    ok(p[0].x == 0);
    ok(p[9].y == 0);
}

equal

fn equal(comptime T: type, a: []T, b: []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: *mut T, b: *mut T) void

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

reverse

fn reverse(comptime T: type, items: []mut 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: []T, needle: []T) bool

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

endsWith

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

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

len

fn len(ptr: anytype) usize

ptr に指定したデータの要素数を返します。 ptr には配列、配列へのポインタ、終端値付き配列へのポインタ、スライスが指定できます。

終端値付き配列の場合は終端値を含まない要素数を返します。C言語の文字列のポインタを指定した場合は終端値がNULL文字の終端値付き配列として扱います。

slice

fn slice(ptr: anytype) Slice(@TypeOf(ptr))

ptr に指定したポインタをスライスに変換します。 ptr には配列へのポインタ、終端値付き配列へのポインタ、スライスが指定できます。

主に C言語との相互運用時にNULL文字終端された配列をスライスに変換する場合などに使用します。

separate

fn separate(buffer: []u8, delimiter: []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

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

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

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: *mut [@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, &mut buf1, 0x12345678, .Little);
    equalSlices(u8, &buf1, &[_]u8{ 0x78, 0x56, 0x34, 0x12 });
    mem.writeInt(u32, &mut buf1, 0x12345678, .Big);
    equalSlices(u8, &buf1, &[_]u8{ 0x12, 0x34, 0x56, 0x78 });
    // x86_64 is big endian
    mem.writeInt(u32, &mut buf1, 0x12345678, builtin.endian);
    equalSlices(u8, &buf1, &[_]u8{ 0x78, 0x56, 0x34, 0x12 });

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

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

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

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

readInt

fn readInt(comptime T: type, bytes: *[@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, &mut buf, 0x12345678, .Little);

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

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

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

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

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

trim

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

スライスの先頭、末尾から指定した値を取り除きます。trimLefttrimRighttrim はそれぞれ、スライスの先頭から、スライスの末尾から、スライスの先頭、末尾の両側から values_to_strip に指定した値を取り除いたスライスを返す関数です。

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

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"));

    // 先頭、末尾以外には影響しない
    equalSlices(u8, "foo bar", mem.trim(u8, " foo bar\n ", " \n"));
}

indexOf

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

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

examples/ch09-std/mem/src/mem.zen:110:122

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: []mut T, amount: usize) void

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

examples/ch09-std/mem/src/mem.zen:124:129

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:131:134

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:136:139

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

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

  • littleToNative
  • bigToNative

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6

Chapter 7

Chapter 8

Chapter 9

Chapter 10

Chapter 11

Chapter 12

Chapter 13

Chapter 14

Chapter 15

Appendix

Error Explanation

☰ 人の生きた証は永遠に残るよう ☰
Copyright © 2018-2020 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.