aboutsummaryrefslogtreecommitdiff
path: root/lib/std/mem.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-03-19 18:06:16 -0400
committerGitHub <noreply@github.com>2020-03-19 18:06:16 -0400
commitdc04e97098010f590d109e6e70d4afe79cd8f01b (patch)
treebed11818fd80fe7b4557f4253c8d5562de773624 /lib/std/mem.zig
parent555a2c03286507ffe4bd3bea2154dbfb719ebef1 (diff)
parent160367e0ddcb36b6957e603d869507b9d7542edc (diff)
downloadzig-dc04e97098010f590d109e6e70d4afe79cd8f01b.tar.gz
zig-dc04e97098010f590d109e6e70d4afe79cd8f01b.zip
Merge pull request #4752 from ziglang/slice-array
slicing with comptime start and end indexes results in pointer-to-array
Diffstat (limited to 'lib/std/mem.zig')
-rw-r--r--lib/std/mem.zig113
1 files changed, 46 insertions, 67 deletions
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 438c15c2eb..2f7a21c6b6 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -560,7 +560,7 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) {
test "span" {
var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
- const ptr = array[0..2 :3].ptr;
+ const ptr = @as([*:3]u16, array[0..2 :3]);
testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
}
@@ -602,7 +602,7 @@ test "len" {
testing.expect(len(&array) == 5);
testing.expect(len(array[0..3]) == 3);
array[2] = 0;
- const ptr = array[0..2 :0].ptr;
+ const ptr = @as([*:0]u16, array[0..2 :0]);
testing.expect(len(ptr) == 2);
}
{
@@ -824,8 +824,7 @@ pub const readIntBig = switch (builtin.endian) {
pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
const n = @divExact(T.bit_count, 8);
assert(bytes.len >= n);
- // TODO https://github.com/ziglang/zig/issues/863
- return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr));
+ return readIntNative(T, bytes[0..n]);
}
/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
@@ -863,8 +862,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en
pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
const n = @divExact(T.bit_count, 8);
assert(bytes.len >= n);
- // TODO https://github.com/ziglang/zig/issues/863
- return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian);
+ return readInt(T, bytes[0..n], endian);
}
test "comptime read/write int" {
@@ -1586,24 +1584,24 @@ pub fn nativeToBig(comptime T: type, x: T) T {
}
fn AsBytesReturnType(comptime P: type) type {
- if (comptime !trait.isSingleItemPtr(P))
+ if (!trait.isSingleItemPtr(P))
@compileError("expected single item pointer, passed " ++ @typeName(P));
- const size = @as(usize, @sizeOf(meta.Child(P)));
- const alignment = comptime meta.alignment(P);
+ const size = @sizeOf(meta.Child(P));
+ const alignment = meta.alignment(P);
if (alignment == 0) {
- if (comptime trait.isConstPtr(P))
+ if (trait.isConstPtr(P))
return *const [size]u8;
return *[size]u8;
}
- if (comptime trait.isConstPtr(P))
+ if (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.
+/// 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);
@@ -1750,34 +1748,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
}
pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {
- const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes;
-
// let's not give an undefined pointer to @ptrCast
// it may be equal to zero and fail a null check
- if (bytesSlice.len == 0) {
+ if (bytes.len == 0) {
return &[0]T{};
}
- const bytesType = @TypeOf(bytesSlice);
- const alignment = comptime meta.alignment(bytesType);
+ const Bytes = @TypeOf(bytes);
+ const alignment = comptime meta.alignment(Bytes);
- const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T;
+ const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T;
- return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))];
+ return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))];
}
test "bytesAsSlice" {
- const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
- const slice = bytesAsSlice(u16, bytes[0..]);
- testing.expect(slice.len == 2);
- testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
- testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
+ {
+ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
+ const slice = bytesAsSlice(u16, bytes[0..]);
+ testing.expect(slice.len == 2);
+ testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
+ testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
+ }
+ {
+ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
+ var runtime_zero: usize = 0;
+ const slice = bytesAsSlice(u16, bytes[runtime_zero..]);
+ testing.expect(slice.len == 2);
+ testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
+ testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
+ }
}
test "bytesAsSlice keeps pointer alignment" {
- var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
- const numbers = bytesAsSlice(u32, bytes[0..]);
- comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
+ {
+ var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
+ const numbers = bytesAsSlice(u32, bytes[0..]);
+ comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
+ }
+ {
+ var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
+ var runtime_zero: usize = 0;
+ const numbers = bytesAsSlice(u32, bytes[runtime_zero..]);
+ comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
+ }
}
test "bytesAsSlice on a packed struct" {
@@ -1813,21 +1827,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {
}
pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {
- const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice;
- const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer;
+ const Slice = @TypeOf(slice);
// let's not give an undefined pointer to @ptrCast
// it may be equal to zero and fail a null check
- if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) {
+ if (slice.len == 0 and comptime meta.sentinel(Slice) == null) {
return &[0]u8{};
}
- const sliceType = @TypeOf(actualSlice);
- const alignment = comptime meta.alignment(sliceType);
+ const alignment = comptime meta.alignment(Slice);
- const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8;
+ const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8;
- return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))];
+ return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
}
test "sliceAsBytes" {
@@ -1897,39 +1909,6 @@ test "sliceAsBytes and bytesAsSlice back" {
testing.expect(bytes[11] == math.maxInt(u8));
}
-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.
-/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
-pub fn subArrayPtr(
- ptr: var,
- comptime start: usize,
- comptime length: usize,
-) SubArrayPtrReturnType(@TypeOf(ptr), length) {
- 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 "subArrayPtr" {
- const a1: [6]u8 = "abcdef".*;
- const sub1 = subArrayPtr(&a1, 2, 3);
- testing.expect(eql(u8, sub1, "cde"));
-
- var a2: [6]u8 = "abcdef".*;
- var sub2 = subArrayPtr(&a2, 2, 3);
-
- testing.expect(eql(u8, sub2, "cde"));
- sub2[1] = 'X';
- testing.expect(eql(u8, &a2, "abcXef"));
-}
-
/// Round an address up to the nearest aligned address
/// The alignment must be a power of 2 and greater than 0.
pub fn alignForward(addr: usize, alignment: usize) usize {