Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions std/index.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub const io = @import("io.zig");
pub const json = @import("json.zig");
pub const macho = @import("macho.zig");
pub const math = @import("math/index.zig");
pub const meta = @import("meta/index.zig");
pub const mem = @import("mem.zig");
pub const net = @import("net.zig");
pub const os = @import("os/index.zig");
Expand Down Expand Up @@ -74,6 +75,7 @@ test "std" {
_ = @import("json.zig");
_ = @import("macho.zig");
_ = @import("math/index.zig");
_ = @import("meta/index.zig");
_ = @import("mem.zig");
_ = @import("net.zig");
_ = @import("heap.zig");
Expand Down
179 changes: 179 additions & 0 deletions std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const assert = debug.assert;
const math = std.math;
const builtin = @import("builtin");
const mem = @This();
const meta = std.meta;
const trait = meta.trait;

pub const Allocator = struct.{
pub const Error = error.{OutOfMemory};
Expand Down Expand Up @@ -863,3 +865,180 @@ pub fn endianSwap(comptime T: type, x: T) T {
test "std.mem.endianSwap" {
assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
}



fn AsBytesReturnType(comptime P: type) type
{
if(comptime !trait.isSingleItemPtr(P)) @compileError("expected single item "
++ "pointer, passed " ++ @typeName(P));

const size = usize(@sizeOf(meta.Child(P)));
const alignment = comptime meta.alignment(P);
if(comptime trait.isConstPtr(P)) return *align(alignment) const [size]u8;
return *align(alignment) [size]u8;
}

///Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.
pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr))
{
const P = @typeOf(ptr);
return @ptrCast(AsBytesReturnType(P), ptr);
}

test "std.mem.asBytes"
{
const deadbeef = u32(0xDEADBEEF);
const deadbeef_bytes = switch(builtin.endian)
{
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
};

debug.assert(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes));

var codeface = u32(0xC0DEFACE);
for(asBytes(&codeface).*) |*b| b.* = 0;
debug.assert(codeface == 0);

const S = packed struct.
{
a: u8,
b: u8,
c: u8,
d: u8,
};

const inst = S.{ .a = 0xBE, .b = 0xEF, .c = 0xDE, .d = 0xA1, };
debug.assert(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
}

///Given any value, returns a copy of its bytes in an array.
pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8
{
return asBytes(&value).*;
}

test "std.mem.toBytes"
{
var my_bytes = toBytes(u32(0x12345678));
switch(builtin.endian)
{
builtin.Endian.Big => debug.assert(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")),
builtin.Endian.Little => debug.assert(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")),
}

my_bytes[0] = '\x99';
switch(builtin.endian)
{
builtin.Endian.Big => debug.assert(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")),
builtin.Endian.Little => debug.assert(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")),
}
}


fn BytesAsValueReturnType(comptime T: type, comptime B: type) type
{
const size = usize(@sizeOf(T));

if(comptime !trait.is(builtin.TypeId.Pointer)(B) or meta.Child(B) != [size]u8)
{
@compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B));
}

const alignment = comptime meta.alignment(B);

return if(comptime trait.isConstPtr(B)) *align(alignment) const T else *align(alignment) T;
}

///Given a pointer to an array of bytes, returns a pointer to a value of the specified type
/// backed by those bytes, preserving constness.
pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typeOf(bytes))
{
return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes);
}

test "std.mem.bytesAsValue"
{
const deadbeef = u32(0xDEADBEEF);
const deadbeef_bytes = switch(builtin.endian)
{
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
};

debug.assert(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*);

var codeface_bytes = switch(builtin.endian)
{
builtin.Endian.Big => "\xC0\xDE\xFA\xCE",
builtin.Endian.Little => "\xCE\xFA\xDE\xC0",
};
var codeface = bytesAsValue(u32, &codeface_bytes);
debug.assert(codeface.* == 0xC0DEFACE);
codeface.* = 0;
for(codeface_bytes) |b| debug.assert(b == 0);

const S = packed struct.
{
a: u8,
b: u8,
c: u8,
d: u8,
};

const inst = S.{ .a = 0xBE, .b = 0xEF, .c = 0xDE, .d = 0xA1, };
const inst_bytes = "\xBE\xEF\xDE\xA1";
const inst2 = bytesAsValue(S, &inst_bytes);
debug.assert(meta.eql(inst, inst2.*));
}

///Given a pointer to an array of bytes, returns a value of the specified type backed by a
/// copy of those bytes.
pub fn bytesToValue(comptime T: type, bytes: var) T
{
return bytesAsValue(T, &bytes).*;
}
test "std.mem.bytesToValue"
{
const deadbeef_bytes = switch(builtin.endian)
{
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
};

const deadbeef = bytesToValue(u32, deadbeef_bytes);
debug.assert(deadbeef == u32(0xDEADBEEF));
}


fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type
{
if(trait.isConstPtr(T)) return *const [length]meta.Child(meta.Child(T));
return *[length]meta.Child(meta.Child(T));
}

///Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize)
SubArrayPtrReturnType(@typeOf(ptr), length)
{
debug.assert(start + length <= ptr.*.len);

const ReturnType = SubArrayPtrReturnType(@typeOf(ptr), length);
const T = meta.Child(meta.Child(@typeOf(ptr)));
return @ptrCast(ReturnType, &ptr[start]);
}

test "std.mem.subArrayPtr"
{
const a1 = "abcdef";
const sub1 = subArrayPtr(&a1, 2, 3);
debug.assert(std.mem.eql(u8, sub1.*, "cde"));

var a2 = "abcdef";
var sub2 = subArrayPtr(&a2, 2, 3);

debug.assert(std.mem.eql(u8, sub2, "cde"));
sub2[1] = 'X';
debug.assert(std.mem.eql(u8, a2, "abcXef"));
}
Loading