hash.ha (3970B)
1 // License: MPL-2.0 2 // (c) 2021 Drew DeVault <sir@cmpwn.com> 3 // (c) 2021 Ember Sawady <ecs@d2evs.net> 4 use endian; 5 use hash::fnv; 6 use hash; 7 use strings; 8 use fmt; 9 10 // Keep ordered with respect to bootstrap harec:include/types.h 11 type storage = enum u8 { 12 BOOL, F32, F64, I16, I32, I64, I8, INT, NULL, RUNE, SIZE, STRING, 13 U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, ENUM, FUNCTION, 14 POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION, 15 }; 16 17 fn builtin_storage(b: builtin) u8 = { 18 switch (b) { 19 case builtin::BOOL => 20 return storage::BOOL; 21 case builtin::F32 => 22 return storage::F32; 23 case builtin::F64 => 24 return storage::F64; 25 case builtin::I16 => 26 return storage::I16; 27 case builtin::I32 => 28 return storage::I32; 29 case builtin::I64 => 30 return storage::I64; 31 case builtin::I8 => 32 return storage::I8; 33 case builtin::INT => 34 return storage::INT; 35 case builtin::NULL => 36 return storage::NULL; 37 case builtin::RUNE => 38 return storage::RUNE; 39 case builtin::SIZE => 40 return storage::SIZE; 41 case builtin::STR => 42 return storage::STRING; 43 case builtin::U16 => 44 return storage::U16; 45 case builtin::U32 => 46 return storage::U32; 47 case builtin::U64 => 48 return storage::U64; 49 case builtin::U8 => 50 return storage::U8; 51 case builtin::UINT => 52 return storage::UINT; 53 case builtin::UINTPTR => 54 return storage::UINTPTR; 55 case builtin::VOID => 56 return storage::VOID; 57 }; 58 }; 59 60 fn type_storage(t: *_type) u8 = { 61 match (t.repr) { 62 case alias => 63 return storage::ALIAS; 64 case array => 65 return storage::ARRAY; 66 case let b: builtin => 67 return builtin_storage(b); 68 case _enum => 69 return storage::ENUM; 70 case func => 71 return storage::FUNCTION; 72 case pointer => 73 return storage::POINTER; 74 case slice => 75 return storage::SLICE; 76 case let st: _struct => 77 if (st.kind == struct_union::STRUCT) { 78 return storage::STRUCT; 79 } else { 80 return storage::UNION; 81 }; 82 case tuple => 83 return storage::TUPLE; 84 case tagged => 85 return storage::TAGGED; 86 }; 87 }; 88 89 fn write8(h: *hash::hash, u: u8) void = { 90 let buf = &u: *[*]u8; 91 hash::write(h, buf[..1]); 92 }; 93 94 fn write32(h: *hash::hash, u: u32) void = { 95 static let buf: [size(u32)]u8 = [0...]; 96 endian::leputu32(buf, u); 97 hash::write(h, buf); 98 }; 99 100 fn write64(h: *hash::hash, u: u64) void = { 101 static let buf: [size(u64)]u8 = [0...]; 102 endian::leputu64(buf, u); 103 hash::write(h, buf); 104 }; 105 106 // Returns the hash of a type. These hashes are deterministic and universally 107 // unique: different computers will generate the same hash for the same type. 108 export fn hash(t: *_type) u32 = { 109 // Note that this function should produce the same hashes as harec; see 110 // bootstrap harec:src/types.c:type_hash 111 let id = fnv::fnv32a(); 112 write8(&id, type_storage(t)); 113 write8(&id, t.flags); 114 115 match (t.repr) { 116 case let a: alias => 117 for (let i = len(a.id); i > 0; i -= 1) { 118 hash::write(&id, strings::toutf8(a.id[i - 1])); 119 write8(&id, 0); 120 }; 121 case let a: array => 122 write32(&id, hash(a.member)); 123 writesize(&id, a.length); 124 case builtin => void; 125 case let e: _enum => 126 write8(&id, builtin_storage(e.storage)); 127 for (let i = 0z; i < len(e.values); i += 1) { 128 hash::write(&id, strings::toutf8(e.values[i].0)); 129 write64(&id, e.values[i].1); 130 }; 131 case let f: func => 132 write32(&id, hash(f.result)); 133 write8(&id, f.variadism: u8); 134 write8(&id, f.flags: u8); 135 for (let i = 0z; i < len(f.params); i += 1) { 136 write32(&id, hash(f.params[i])); 137 }; 138 case let p: pointer => 139 write8(&id, p.flags); 140 write32(&id, hash(p.referent)); 141 case let s: slice => 142 write32(&id, hash(s)); 143 case let st: _struct => 144 for (let i = 0z; i < len(st.fields); i += 1) { 145 const field = st.fields[i]; 146 hash::write(&id, strings::toutf8(field.name)); 147 write32(&id, hash(field._type)); 148 writesize(&id, field.offs); 149 }; 150 case let tu: tuple => 151 for (let i = 0z; i < len(tu); i += 1) { 152 write32(&id, hash(tu[i]._type)); 153 }; 154 case let ta: tagged => 155 for (let i = 0z; i < len(ta); i += 1) { 156 write32(&id, hash(ta[i])); 157 }; 158 }; 159 160 return fnv::sum32(&id); 161 };