-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmax_by_key.zig
57 lines (47 loc) · 1.83 KB
/
max_by_key.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
const zignite = @import("../zignite.zig");
const std = @import("std");
const expect = std.testing.expect;
const ConsumerType = @import("consumer_type.zig").ConsumerType;
test "max_by_key: len" {
const Str = []const u8;
const len = struct {
fn len(str: Str) usize {
return str.len;
}
}.len;
const x = zignite.fromSlice(Str, &[_]Str{ "one", "two", "three", "four", "12345" }).maxByKey(usize, len).?;
try expect(std.mem.eql(u8, x, "three"));
try expect(zignite.empty(Str).maxByKey(usize, len) == null);
}
pub fn MaxByKey(comptime S: type, comptime T: type, comptime transformer: fn (value: S) T) type {
return struct {
key: ?T,
value: ?S,
pub const Type = ConsumerType(S, @This(), ?S);
pub const init = _init(null, null);
pub fn next(event: Type.Event) Type.Action {
const k = event.state.key;
const v = event.state.value;
return switch (event.tag) {
._yield => |w| by_key(k, v, w),
._continue => Type.Action._await(_init(k, v)),
._break => Type.Action._return(_init(k, v), v),
};
}
pub const deinit = Type.nop;
inline fn _init(key: ?T, value: ?S) Type.State {
return .{ .key = key, .value = value };
}
inline fn t(value: S) T {
return @call(.{ .modifier = .always_inline }, transformer, .{value});
}
inline fn by_key(key1: ?T, value1: ?S, value2: S) Type.Action {
if (value1 == null) {
return Type.Action._await(_init(null, value2));
}
const k1 = if (key1 == null) t(value1.?) else key1.?;
const k2 = t(value2);
return Type.Action._await(if (k1 < k2) _init(k2, value2) else _init(k1, value1));
}
};
}