summaryrefslogtreecommitdiff
path: root/bstates.ha
diff options
context:
space:
mode:
Diffstat (limited to 'bstates.ha')
-rw-r--r--bstates.ha107
1 files changed, 107 insertions, 0 deletions
diff --git a/bstates.ha b/bstates.ha
new file mode 100644
index 0000000..bf329f2
--- /dev/null
+++ b/bstates.ha
@@ -0,0 +1,107 @@
+use types;
+use strings;
+
+type BstateId = u32;
+type BlockPropId = u32;
+
+type BlockBstates = struct {
+ state0: BstateId,
+ nstates: u32,
+ props: [](str, []str),
+ prop_moduli: []u32,
+};
+
+type BstateInfo = struct {
+ block: BlockId,
+};
+
+let BLOCKS_BSTATES: []BlockBstates = [];
+let BSTATES_INFO: []BstateInfo = [];
+
+fn bstates_handle_blocks_onregister(blk: BlockId) void = {
+ append(BLOCKS_BSTATES, BlockBstates { ... });
+};
+
+fn block_addprop(blk: BlockId, name: str, values: []str) BlockPropId = {
+ assert(len(values) != 0, "Block property must have at least 1 value");
+ const bstates = &BLOCKS_BSTATES[blk];
+ assert(len(bstates.props) < types::U32_MAX - 1,
+ "Too many block properties");
+ append(bstates.props, (strings::dup(name), strings::dupall(values)));
+ return len(bstates.props): u32 - 1;
+};
+
+fn init_bstates() void = {
+ for (let blk: BlockId = 0; blk < blocks_count(); blk += 1) {
+ const bstates = &BLOCKS_BSTATES[blk];
+
+ bstates.prop_moduli = alloc([], len(bstates.props));
+ let mod = 1u32;
+ for (let j = 0z; j < len(bstates.props); j += 1) {
+ // TODO: overflow...
+ mod *= len(bstates.props[j].1): u32;
+ static append(bstates.prop_moduli, mod);
+ };
+ bstates.state0 = len(BSTATES_INFO): u32;
+ bstates.nstates = mod;
+
+ assert(bstates.state0 + bstates.nstates > bstates.state0,
+ "Too many blockstates");
+
+ for (let j = 0u32; j < mod; j += 1) {
+ append(BSTATES_INFO, BstateInfo {
+ block = blk,
+ });
+ };
+ };
+};
+
+fn destroy_bstates() void = {
+ for (let blk: BlockId = 0; blk < blocks_count(); blk += 1) {
+ const bstates = &BLOCKS_BSTATES[blk];
+ for (let i = 0z; i < len(bstates.props); i += 1) {
+ free(bstates.props[i].0);
+ strings::freeall(bstates.props[i].1);
+ };
+ free(bstates.prop_moduli);
+ };
+ free(BLOCKS_BSTATES);
+ free(BSTATES_INFO);
+};
+
+fn block_propcount(blk: BlockId) u32 =
+ len(BLOCKS_BSTATES[blk].props): u32;
+
+fn block_propname(blk: BlockId, prop: BlockPropId) str =
+ BLOCKS_BSTATES[blk].props[prop].0;
+
+fn block_findprop(blk: BlockId, name: str) (BlockPropId | void) = {
+ for (let prop: BlockPropId = 0;
+ prop < block_propcount(blk); prop += 1) {
+ if (block_propname(blk, prop) == name)
+ return prop;
+ };
+};
+
+fn block_propvalcount(blk: BlockId, prop: BlockPropId) u32 =
+ len(BLOCKS_BSTATES[blk].props[prop].1): u32;
+
+fn block_propvalname(blk: BlockId, prop: BlockPropId, val: u32) str =
+ BLOCKS_BSTATES[blk].props[prop].1[val];
+
+fn block_findpropval(blk: BlockId, prop: BlockPropId, name: str)
+ (u32 | void) = {
+ for (let val = 0u32; val < block_propvalcount(blk, prop); val += 1) {
+ if (block_propvalname(blk, prop, val) == name)
+ return val;
+ };
+};
+
+fn bstate_getblock(bstate: BstateId) BlockId =
+ BSTATES_INFO[bstate].block;
+
+fn bstate_getprop(bstate: BstateId, blk: BlockId, prop: BlockPropId) u32 = {
+ const bstates = &BLOCKS_BSTATES[blk];
+ return (bstate - bstates.state0) % bstates.prop_moduli[prop]
+ / (if (prop == 0) 1u32 else bstates.prop_moduli[prop - 1]);
+};