buffer: Penyimpanan byte yang dapat dikembangkan

Buffer Menjelaskan aturan inisialisasi, penambahan, penyelidikan, kapasitas dan rilis.

Wave Foundation

Arti Buffer

Buffer di std::buffer::types memiliki data: ptr<u8>, len: i64, dan cap: i64. len adalah jumlah byte yang diinisialisasi dan digunakan, dan cap adalah jumlah total byte yang dialokasikan. Selalu pertahankan 0 <= len <= cap. String NUL tidak secara otomatis menjamin penghentian.

Dasar API

modul deklarasi artinya
std::buffer::alloc buffer_init(out_buf: ptr<Buffer>, capacity: i64) -> i64 Inisialisasi repositori baru. Jangan mengingat ke dalam buffer yang sudah dimiliki
modul yang sama buffer_free(buf: ptr<Buffer>) -> i64 Batalkan alokasi. Kosongkan jika berhasil
modul yang sama buffer_reserve(buf: ptr<Buffer>, required_cap: i64) -> i64 Pastikan kapasitas penuh minimum. len Terpelihara
modul yang sama buffer_clear(buf: ptr<Buffer>) -> i64 Pertahankan kapasitas dan len=0
modul yang sama buffer_resize(buf: ptr<Buffer>, new_len: i64, value: u8) -> i64 Ubah panjangnya, isi byte baru dengan value
std::buffer::write buffer_push(buf: ptr<Buffer>, value: u8) -> i64 tambahkan satu byte
modul yang sama buffer_append(buf: ptr<Buffer>, src: ptr<u8>, size: i64) -> i64 sizeSalin dan tambahkan byte
modul yang sama buffer_append_str(buf: ptr<Buffer>, s: str) -> i64 Tambahkan byte string kecuali NUL
std::buffer::read buffer_get(buf: ptr<Buffer>, index: i64, out_value: ptr<u8>) -> i64 Baca satu byte dalam jangkauan

Pengembalian status API mengembalikan BUFFER_OK(0) jika berhasil. Bedakan antara kesalahan INVALID, BOUNDS, OVERFLOW, dan ALLOC dari std::buffer::error. Angka tersebut tidak diartikan sebagai OS errno. buffer_new mewakili kegagalan alokasi sebagai Buffer kosong, jadi ketika Anda perlu membedakan kegagalan, gunakan buffer_init.

Contoh berjalan

import("std::buffer::alloc")::{
    Buffer, buffer_init, buffer_free
};
import("std::buffer::write")::{
    buffer_append_str, buffer_push
};
import("std::buffer::read")::{
    buffer_get
};

fun main() -> i32 {
    var data: Buffer;
    if (buffer_init(&data, 0) < 0) {
        return 1;
    }
    if (buffer_append_str(&data, "Hi") < 0 || buffer_push(&data, 33) < 0) {
        buffer_free(&data);
        return 2;
    }

    var value: u8 = 0;
    if (buffer_get(&data, 2, &value) < 0) {
        buffer_free(&data);
        return 3;
    }

    println("{} {}", data.len, value);
    if (buffer_free(&data) < 0) {
        return 4;
    }

    return 0;
}

Hasil eksekusi:

3 33

Simpan sebagai main.wave dan jalankan sebagai wavec run main.wave. Kapasitas awal 0 bukanlah kegagalan, namun buffer kosong yang valid. Mengosongkan ruang selama pemrosesan lebih lanjut.

Umur dan Kegagalan

Menumbuhkan buffer dapat mengubah data. Jangan gunakan alamat yang dipinjam sebelumnya setelah operasi yang dapat direalokasi. Menyalin struktur Buffer tidak menduplikasi alokasinya, jadi berikan alokasi tersebut kepada satu pemilik.

buffer_get tidak mengubah argumen keluaran jika gagal. Di sisi lain, fungsi kemudahan buffer_at juga mewakili kesalahan sebagai 0, jadi gunakan buffer_get untuk membedakan antara 0 byte aktual dan kegagalan. Hindari membuat len/cap yang tidak valid dengan langsung mengubah kolom publik.

Memori API · Berlatih membaca file sebagai Buffer

Amati panjang dan kapasitas secara terpisah

reserve mengosongkan ruang penyimpanan, tetapi tidak menambah len. resize mengubah panjang sebenarnya yang digunakan dan menginisialisasi bagian yang diperluas ke byte yang ditentukan. clear hanya menyetel panjang yang digunakan ke 0, sehingga alokasi dapat digunakan kembali.

Simpan program berikut sebagai main.wave dan jalankan. Hal ini tidak bergantung pada pertumbuhan kapasitas yang berlipat ganda; itu hanya memastikan bahwa Anda memiliki ruang yang Anda butuhkan.

import("std::buffer::alloc")::{
    Buffer,
    buffer_init,
    buffer_reserve,
    buffer_resize,
    buffer_clear,
    buffer_free
};

fun main() -> i32 {
    var data: Buffer;

    if (buffer_init(&data, 0) < 0) {
        return 1;
    }

    if (buffer_reserve(&data, 20) < 0) {
        buffer_free(&data);
        return 2;
    }

    println("reserved length={}", data.len);

    if (buffer_resize(&data, 3, 7) < 0) {
        buffer_free(&data);
        return 3;
    }

    println("resized length={} first={}", data.len, deref data.data[0]);

    if (buffer_clear(&data) < 0) {
        buffer_free(&data);
        return 4;
    }

    println("cleared length={}", data.len);

    if (buffer_free(&data) < 0) {
        return 5;
    }

    return 0;
}

Hasil eksekusi:

reserved length=0
resized length=3 first=7
cleared length=0

Ketika meningkat menjadi resize, kita meneruskan value=7, jadi ketiga byte baru yang kita lihat adalah 7. Spasi yang hanya diamankan dengan reserve tidak dibaca sebagai data yang diinisialisasi. cap akan tetap ada setelah clear dan dapat ditambahkan lagi ke Buffer yang sama.

Bedakan antara nol byte dan kegagalan pencarian

buffer_get mengembalikan status dan menulis byte sebenarnya sebagai argumen keluaran. Sekalipun datanya 0, itu adalah keberhasilan yang normal.

import("std::buffer::alloc")::{Buffer, buffer_init, buffer_free};
import("std::buffer::write")::{buffer_push};
import("std::buffer::read")::{buffer_get};
import("std::buffer::error")::{BUFFER_ERR_BOUNDS};

fun main() -> i32 {
    var data: Buffer;

    if (buffer_init(&data, 0) < 0) {
        return 1;
    }

    if (buffer_push(&data, 0) < 0) {
        buffer_free(&data);
        return 2;
    }

    var value: u8 = 99;

    if (buffer_get(&data, 0, &value) < 0) {
        buffer_free(&data);
        return 3;
    }

    println("stored={}", value);
    value = 99;

    if (buffer_get(&data, 1, &value) == BUFFER_ERR_BOUNDS) {
        println("outside, preserved={}", value);
    }

    if (buffer_free(&data) < 0) {
        return 4;
    }

    return 0;
}

Hasil eksekusi:

stored=0
outside, preserved=99

Pukulan pertama adalah keberhasilan yang bernilai 0, pukulan kedua adalah kegagalan di luar batas. Bahkan jika value=99 tetap ada setelah kegagalan, itu tidak berarti bahwa itu adalah nilai yang dibaca dari buffer. Pastikan untuk memeriksa statusnya bersama-sama.

Solusi latihan: Akumulasi byte

Untuk menjumlahkan angka 0 hingga 9, ulangi buffer_push dan periksa setiap hasilnya. Simpan jumlahnya di i64 dan baca hanya rentangnya 0 <= index < data.len. Setelah menangani buffer, kami memanggil buffer_free pada jalur berhasil dan gagal.

import("std::buffer::alloc")::{Buffer, buffer_init, buffer_free};
import("std::buffer::write")::{buffer_push};

fun main() -> i32 {
    var data: Buffer;

    if (buffer_init(&data, 0) < 0) {
        return 1;
    }

    for (var value: i32 = 0; value < 10; value += 1) {
        if (buffer_push(&data, value as u8) < 0) {
            buffer_free(&data);
            return 2;
        }
    }

    var total: i64 = 0;

    for (var index: i64 = 0; index < data.len; index += 1) {
        total += deref data.data[index] as i64;
    }

    println("sum={}", total);

    if (buffer_free(&data) < 0) {
        return 3;
    }

    return 0;
}

Hasil eksekusi:

sum=45