authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-11 22:25:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-11 22:25:13-07:00
log0ae9023832584e256aa3b6df0f0829026141d21a
tree78b989a47e93169227a1d08d7b1da1499a04ee87
parent0a482bbbfe1dbabaab6b7a5c26ec4f29f0c618d9

add CBuf to standard library

and fix ability to take address of variables from other namespaces

8 files changed, 206 insertions(+), 72 deletions(-)

src/analyze.cpp+1
......@@ -2688,6 +2688,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
26882688 return node->data.field_access_expr.type_struct_field->type_entry;
26892689 } else if (wrapped_in_fn_call) {
26902690 BlockContext *container_block_context = get_container_block_context(bare_struct_type);
2691 assert(container_block_context);
26912692 auto entry = container_block_context->decl_table.maybe_get(field_name);
26922693 AstNode *fn_decl_node = entry ? entry->value : nullptr;
26932694 if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
src/codegen.cpp+13-3
......@@ -1243,6 +1243,11 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
12431243
12441244 AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
12451245
1246 *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry;
1247 if (!type_has_bits(*out_type_entry)) {
1248 return nullptr;
1249 }
1250
12461251 LLVMValueRef struct_ptr;
12471252 if (struct_expr_node->type == NodeTypeSymbol) {
12481253 VariableTableEntry *var = get_resolved_expr(struct_expr_node)->variable;
......@@ -1272,8 +1277,6 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
12721277 int gen_field_index = node->data.field_access_expr.type_struct_field->gen_index;
12731278 assert(gen_field_index >= 0);
12741279
1275 *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry;
1276
12771280 set_debug_source_node(g, node);
12781281 return LLVMBuildStructGEP(g->builder, struct_ptr, gen_field_index, "");
12791282}
......@@ -1490,7 +1493,14 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
14901493 zig_unreachable();
14911494 }
14921495 } else if (node->type == NodeTypeFieldAccessExpr) {
1493 target_ref = gen_field_ptr(g, node, out_type_entry);
1496 AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
1497 TypeTableEntry *struct_type = get_expr_type(struct_expr_node);
1498 if (struct_type->id == TypeTableEntryIdNamespace) {
1499 target_ref = gen_field_access_expr(g, node, true);
1500 *out_type_entry = get_expr_type(node);
1501 } else {
1502 target_ref = gen_field_ptr(g, node, out_type_entry);
1503 }
14941504 } else if (node->type == NodeTypePrefixOpExpr) {
14951505 assert(node->data.prefix_op_expr.prefix_op == PrefixOpDereference);
14961506 AstNode *target_expr = node->data.prefix_op_expr.primary_expr;
std/cstr.zig+121-2
......@@ -1,3 +1,11 @@
1const List = @import("list.zig").List;
2const mem = @import("mem.zig");
3const Allocator = mem.Allocator;
4const debug = @import("debug.zig");
5const assert = debug.assert;
6
7const strlen = len;
8
19// TODO fix https://github.com/andrewrk/zig/issues/140
210// and then make this able to run at compile time
311#static_eval_enable(false)
......@@ -17,10 +25,121 @@ pub fn cmp(a: &const u8, b: &const u8) -> i32 {
1725}
1826
1927pub fn to_slice_const(str: &const u8) -> []const u8 {
20 return str[0...len(str)];
28 return str[0...strlen(str)];
2129}
2230
2331pub fn to_slice(str: &u8) -> []u8 {
24 return str[0...len(str)];
32 return str[0...strlen(str)];
33}
34
35
36/// A buffer that allocates memory and maintains a null byte at the end.
37pub struct CBuf {
38 list: List(u8),
39
40 /// Must deinitialize with deinit.
41 pub fn init(self: &CBuf, allocator: &Allocator) {
42 self.list.init(allocator);
43 // This resize is guaranteed to not have an error because we use a list
44 // with preallocated memory of at least 1 byte.
45 %%self.resize(0);
46 }
47
48 /// Must deinitialize with deinit.
49 pub fn init_from_mem(self: &CBuf, allocator: &Allocator, m: []const u8) -> %void {
50 self.init(allocator);
51 %return self.resize(m.len);
52 mem.copy(u8, self.list.items, m);
53 }
54
55 /// Must deinitialize with deinit.
56 pub fn init_from_cstr(self: &CBuf, allocator: &Allocator, s: &const u8) -> %void {
57 self.init_from_mem(allocator, s[0...strlen(s)])
58 }
59
60 /// Must deinitialize with deinit.
61 pub fn init_from_cbuf(self: &CBuf, cbuf: &const CBuf) -> %void {
62 self.init_from_mem(cbuf.list.allocator, cbuf.list.items[0...cbuf.len()])
63 }
64
65 /// Must deinitialize with deinit.
66 pub fn init_from_slice(self: &CBuf, other: &const CBuf, start: usize, end: usize) -> %void {
67 self.init_from_mem(other.list.allocator, other.list.items[start...end])
68 }
69
70 pub fn deinit(self: &CBuf) {
71 self.list.deinit();
72 }
73
74 pub fn resize(self: &CBuf, new_len: usize) -> %void {
75 %return self.list.resize(new_len + 1);
76 self.list.items[self.len()] = 0;
77 }
78
79 pub fn len(self: &const CBuf) -> usize {
80 return self.list.len - 1;
81 }
82
83 pub fn append_mem(self: &CBuf, m: []const u8) -> %void {
84 const old_len = self.len();
85 %return self.resize(old_len + m.len);
86 mem.copy(u8, self.list.items[old_len...], m);
87 }
88
89 pub fn append_cstr(self: &CBuf, s: &const u8) -> %void {
90 self.append_mem(s[0...strlen(s)])
91 }
92
93 pub fn append_char(self: &CBuf, c: u8) -> %void {
94 %return self.resize(self.len() + 1);
95 self.list.items[self.len() - 1] = c;
96 }
97
98 pub fn eql_mem(self: &const CBuf, m: []const u8) -> bool {
99 if (self.len() != m.len) return false;
100 return mem.cmp(u8, self.list.items[0...m.len], m) == mem.Cmp.Equal;
101 }
102
103 pub fn eql_cstr(self: &const CBuf, s: &const u8) -> bool {
104 self.eql_mem(s[0...strlen(s)])
105 }
106
107 pub fn eql_cbuf(self: &const CBuf, other: &const CBuf) -> bool {
108 self.eql_mem(other.list.items[0...other.len()])
109 }
110
111 pub fn starts_with_mem(self: &const CBuf, m: []const u8) -> bool {
112 if (self.len() < m.len) return false;
113 return mem.cmp(u8, self.list.items[0...m.len], m) == mem.Cmp.Equal;
114 }
115
116 pub fn starts_with_cbuf(self: &const CBuf, other: &const CBuf) -> bool {
117 self.starts_with_mem(other.list.items[0...other.len()])
118 }
119
120 pub fn starts_with_cstr(self: &const CBuf, s: &const u8) -> bool {
121 self.starts_with_mem(s[0...strlen(s)])
122 }
25123}
26124
125#attribute("test")
126fn test_simple_cbuf() {
127 var buf: CBuf = undefined;
128 buf.init(&debug.global_allocator);
129 assert(buf.len() == 0);
130 %%buf.append_cstr(c"hello");
131 %%buf.append_char(' ');
132 %%buf.append_mem("world");
133 assert(buf.eql_cstr(c"hello world"));
134 assert(buf.eql_mem("hello world"));
135
136 var buf2: CBuf = undefined;
137 %%buf2.init_from_cbuf(&buf);
138 assert(buf.eql_cbuf(&buf2));
139
140 assert(buf.starts_with_mem("hell"));
141 assert(buf.starts_with_cstr(c"hell"));
142
143 %%buf2.resize(4);
144 assert(buf.starts_with_cbuf(&buf2));
145}
std/debug.zig+26-1
......@@ -1,10 +1,11 @@
1const Allocator = @import("mem.zig").Allocator;
12const io = @import("io.zig");
23
34pub fn assert(b: bool) {
45 if (!b) unreachable{}
56}
67
7pub fn print_stack_trace() {
8pub fn printStackTrace() {
89 var maybe_fp: ?&const u8 = @frame_address();
910 while (true) {
1011 const fp = maybe_fp ?? break;
......@@ -14,3 +15,27 @@ pub fn print_stack_trace() {
1415 maybe_fp = *(&const ?&const u8)(fp);
1516 }
1617}
18
19pub var global_allocator = Allocator {
20 .alloc_fn = globalAlloc,
21 .realloc_fn = globalRealloc,
22 .free_fn = globalFree,
23 .context = null,
24};
25
26var some_mem: [10 * 1024]u8 = undefined;
27var some_mem_index: usize = 0;
28
29fn globalAlloc(self: &Allocator, n: usize) -> %[]u8 {
30 const result = some_mem[some_mem_index ... some_mem_index + n];
31 some_mem_index += n;
32 return result;
33}
34
35fn globalRealloc(self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8 {
36 const result = %return globalAlloc(self, new_size);
37 @memcpy(result.ptr, old_mem.ptr, old_mem.len);
38 return result;
39}
40
41fn globalFree(self: &Allocator, old_mem: []u8) { }
std/hash_map.zig+7-32
......@@ -1,4 +1,5 @@
1const assert = @import("debug.zig").assert;
1const debug = @import("debug.zig");
2const assert = debug.assert;
23const math = @import("math.zig");
34const mem = @import("mem.zig");
45const Allocator = mem.Allocator;
......@@ -9,7 +10,7 @@ const debug_u32 = if (want_modification_safety) u32 else void;
910pub fn HashMap(inline K: type, inline V: type, inline hash: fn(key: K)->u32,
1011 inline eql: fn(a: K, b: K)->bool) -> type
1112{
12 SmallHashMap(K, V, hash, eql, 8)
13 SmallHashMap(K, V, hash, eql, @sizeof(usize))
1314}
1415
1516pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)->bool, STATIC_SIZE: usize) {
......@@ -63,9 +64,8 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
6364 hm.allocator = allocator;
6465 hm.size = 0;
6566 hm.max_distance_from_start_index = 0;
66 for (hm.entries) |*entry| {
67 entry.used = false;
68 }
67 hm.prealloc_entries = zeroes; // sets used to false for all entries
68 hm.modification_count = zeroes;
6969 }
7070
7171 pub fn deinit(hm: &Self) {
......@@ -162,7 +162,7 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
162162
163163 fn increment_modification_count(hm: &Self) {
164164 if (want_modification_safety) {
165 hm.modification_count += 1;
165 hm.modification_count +%= 1;
166166 }
167167 }
168168
......@@ -231,35 +231,10 @@ pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b
231231 }
232232}
233233
234var global_allocator = Allocator {
235 .alloc_fn = global_alloc,
236 .realloc_fn = global_realloc,
237 .free_fn = global_free,
238 .context = null,
239};
240
241var some_mem: [200]u8 = undefined;
242var some_mem_index: usize = 0;
243
244fn global_alloc(self: &Allocator, n: usize) -> %[]u8 {
245 const result = some_mem[some_mem_index ... some_mem_index + n];
246 some_mem_index += n;
247 return result;
248}
249
250fn global_realloc(self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8 {
251 const result = %return global_alloc(self, new_size);
252 @memcpy(result.ptr, old_mem.ptr, old_mem.len);
253 return result;
254}
255
256fn global_free(self: &Allocator, old_mem: []u8) {
257}
258
259234#attribute("test")
260235fn basic_hash_map_test() {
261236 var map: HashMap(i32, i32, hash_i32, eql_i32) = undefined;
262 map.init(&global_allocator);
237 map.init(&debug.global_allocator);
263238 defer map.deinit();
264239
265240 %%map.put(1, 11);
std/list.zig+16-33
......@@ -1,22 +1,25 @@
1const assert = @import("debug.zig").assert;
1const debug = @import("debug.zig");
2const assert = debug.assert;
23const mem = @import("mem.zig");
34const Allocator = mem.Allocator;
45
56pub fn List(inline T: type) -> type {
6 SmallList(T, 8)
7 SmallList(T, @sizeof(usize))
78}
89
10// TODO: make sure that setting STATIC_SIZE to 0 codegens to the same code
11// as if this were programmed without STATIC_SIZE at all.
912pub struct SmallList(T: type, STATIC_SIZE: usize) {
1013 const Self = SmallList(T, STATIC_SIZE);
1114
1215 items: []T,
13 length: usize,
16 len: usize,
1417 prealloc_items: [STATIC_SIZE]T,
1518 allocator: &Allocator,
1619
1720 pub fn init(l: &Self, allocator: &Allocator) {
1821 l.items = l.prealloc_items[0...];
19 l.length = 0;
22 l.len = 0;
2023 l.allocator = allocator;
2124 }
2225
......@@ -27,10 +30,15 @@ pub struct SmallList(T: type, STATIC_SIZE: usize) {
2730 }
2831
2932 pub fn append(l: &Self, item: T) -> %void {
30 const new_length = l.length + 1;
33 const new_length = l.len + 1;
3134 %return l.ensure_capacity(new_length);
32 l.items[l.length] = item;
33 l.length = new_length;
35 l.items[l.len] = item;
36 l.len = new_length;
37 }
38
39 pub fn resize(l: &Self, new_len: usize) -> %void {
40 %return l.ensure_capacity(new_len);
41 l.len = new_len;
3442 }
3543
3644 pub fn ensure_capacity(l: &Self, new_capacity: usize) -> %void {
......@@ -50,35 +58,10 @@ pub struct SmallList(T: type, STATIC_SIZE: usize) {
5058 }
5159}
5260
53var global_allocator = Allocator {
54 .alloc_fn = global_alloc,
55 .realloc_fn = global_realloc,
56 .free_fn = global_free,
57 .context = null,
58};
59
60var some_mem: [200]u8 = undefined;
61var some_mem_index: usize = 0;
62
63fn global_alloc(self: &Allocator, n: usize) -> %[]u8 {
64 const result = some_mem[some_mem_index ... some_mem_index + n];
65 some_mem_index += n;
66 return result;
67}
68
69fn global_realloc(self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8 {
70 const result = %return global_alloc(self, new_size);
71 @memcpy(result.ptr, old_mem.ptr, old_mem.len);
72 return result;
73}
74
75fn global_free(self: &Allocator, old_mem: []u8) {
76}
77
7861#attribute("test")
7962fn basic_list_test() {
8063 var list: List(i32) = undefined;
81 list.init(&global_allocator);
64 list.init(&debug.global_allocator);
8265 defer list.deinit();
8366
8467 {var i: usize = 0; while (i < 10; i += 1) {
std/math.zig+6
......@@ -1,3 +1,9 @@
1pub enum Cmp {
2 Equal,
3 Greater,
4 Less,
5}
6
17pub fn f64_from_bits(bits: u64) -> f64 {
28 *(&f64)(&bits)
39}
std/mem.zig+16-1
......@@ -3,6 +3,8 @@ const math = @import("math.zig");
33const os = @import("os.zig");
44const io = @import("io.zig");
55
6pub const Cmp = math.Cmp;
7
68pub error NoMem;
79
810pub type Context = u8;
......@@ -40,7 +42,20 @@ pub struct Allocator {
4042
4143/// Copy all of source into dest at position 0.
4244/// dest.len must be >= source.len.
43pub fn copy(inline T: type, dest: []T, source: []T) {
45pub fn copy(inline T: type, dest: []T, source: []const T) {
4446 assert(dest.len >= source.len);
4547 @memcpy(dest.ptr, source.ptr, @sizeof(T) * source.len);
4648}
49
50/// Return < 0, == 0, or > 0 if memory a is less than, equal to, or greater than,
51/// memory b, respectively.
52pub fn cmp(inline T: type, a: []const T, b: []const T) -> Cmp {
53 const n = math.min(usize, a.len, b.len);
54 var i: usize = 0;
55 while (i < n; i += 1) {
56 if (a[i] == b[i]) continue;
57 return if (a[i] > b[i]) Cmp.Greater else if (a[i] < b[i]) Cmp.Less else Cmp.Equal;
58 }
59
60 return if (a.len > b.len) Cmp.Greater else if (a.len < b.len) Cmp.Less else Cmp.Equal;
61}