zig/test/behavior/slice.zig
Andrew Kelley a0e195120d stage2: implement slicing
* New AIR instruction: slice, which constructs a slice out of a pointer
   and a length.
 * AstGen: use `coerced_ty` for start and end expressions, use `none`
   for the sentinel, and don't try to load the result of the slice
   operation because it returns a by-value result.
 * Sema: pointer arithmetic is extracted into analyzePointerArithmetic
   and it is used by the implementation of slice.
   - Also I implemented comptime pointer addition.
 * Sema: extract logic into analyzeSlicePtr, analyzeSliceLen and use them
   inside the slice semantic analysis.
   - The approach in stage2 is much cleaner than stage1 because it uses
     more granular analysis calls for obtaining the slice pointer, doing
     arithmetic on it, and checking if the length is comptime-known.
 * Sema: use the slice Value Tag for slices when doing coercion from
   pointer-to-array.
 * LLVM backend: detect when emitting a GEP instruction into a
   pointer-to-array and add the extra index that is required.
 * Type: ptrAlignment for c_void returns 0.
 * Implement Value.hash and Value.eql for slices.
 * Remove accidentally duplicated behavior test.
2021-10-20 21:45:11 -07:00

112 lines
2.9 KiB
Zig

const std = @import("std");
const expect = std.testing.expect;
const expectEqualSlices = std.testing.expectEqualSlices;
const expectEqual = std.testing.expectEqual;
const mem = std.mem;
// comptime array passed as slice argument
comptime {
const S = struct {
fn indexOfScalarPos(comptime T: type, slice: []const T, start_index: usize, value: T) ?usize {
var i: usize = start_index;
while (i < slice.len) : (i += 1) {
if (slice[i] == value) return i;
}
return null;
}
fn indexOfScalar(comptime T: type, slice: []const T, value: T) ?usize {
return indexOfScalarPos(T, slice, 0, value);
}
};
const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong };
const list: []const type = &unsigned;
var pos = S.indexOfScalar(type, list, c_ulong).?;
if (pos != 1) @compileError("bad pos");
}
test "slicing" {
var array: [20]i32 = undefined;
array[5] = 1234;
var slice = array[5..10];
if (slice.len != 5) unreachable;
const ptr = &slice[0];
if (ptr.* != 1234) unreachable;
var slice_rest = array[10..];
if (slice_rest.len != 10) unreachable;
}
test "const slice" {
comptime {
const a = "1234567890";
try expect(a.len == 10);
const b = a[1..2];
try expect(b.len == 1);
try expect(b[0] == '2');
}
}
test "comptime slice of undefined pointer of length 0" {
const slice1 = @as([*]i32, undefined)[0..0];
try expect(slice1.len == 0);
const slice2 = @as([*]i32, undefined)[100..100];
try expect(slice2.len == 0);
}
test "implicitly cast array of size 0 to slice" {
var msg = [_]u8{};
try assertLenIsZero(&msg);
}
fn assertLenIsZero(msg: []const u8) !void {
try expect(msg.len == 0);
}
test "access len index of sentinel-terminated slice" {
const S = struct {
fn doTheTest() !void {
var slice: [:0]const u8 = "hello";
try expect(slice.len == 5);
try expect(slice[5] == 0);
}
};
try S.doTheTest();
comptime try S.doTheTest();
}
test "comptime slice of slice preserves comptime var" {
comptime {
var buff: [10]u8 = undefined;
buff[0..][0..][0] = 1;
try expect(buff[0..][0..][0] == 1);
}
}
test "slice of type" {
comptime {
var types_array = [_]type{ i32, f64, type };
for (types_array) |T, i| {
switch (i) {
0 => try expect(T == i32),
1 => try expect(T == f64),
2 => try expect(T == type),
else => unreachable,
}
}
for (types_array[0..]) |T, i| {
switch (i) {
0 => try expect(T == i32),
1 => try expect(T == f64),
2 => try expect(T == type),
else => unreachable,
}
}
}
}