Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add std.meta #1662

Merged
merged 20 commits into from Oct 19, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions std/index.zig
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
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))
{
tgschultz marked this conversation as resolved.
Show resolved Hide resolved
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"));
}