From 513c30655521bbab4aab5991bf9100be05aa4b88 Mon Sep 17 00:00:00 2001 From: Madeline Busig Date: Tue, 18 Feb 2025 05:14:49 -0800 Subject: [PATCH] Implement generator.add_* methods --- include/fractal.hpp | 6 +- src/fractal.cpp | 158 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 4 deletions(-) diff --git a/include/fractal.hpp b/include/fractal.hpp index ef9178d..df69ce9 100644 --- a/include/fractal.hpp +++ b/include/fractal.hpp @@ -146,7 +146,7 @@ public: * * After all tokens, groups, and rules have been added, the generator's groups * must be processed by calling preprocess(). Once this is done, no new - * groups may be added. + * groups may be added. If an exception occurs, no data is modified. * * @param factor The number of times the group is repeated. Treats the group as if @p tokens was repeated @p factor number of times. * @param tokens @c etl::ivector of @token_id_t that describe how the group functions. Processed in order, front to back. @@ -156,7 +156,7 @@ public: * @pre preprocess() has not been called on this generator. * * @exception mtl::system_error If the generator has already been preprocessed. - * @exception mtl::invalid_argument If no tokens were supplied, or an invalid token was encountered. + * @exception mtl::invalid_argument If an invalid token was encountered. * @exception mtl::length_error If the maximum number of groups is reached. */ group_id_t add_group_characteristic(uint32_t factor, const etl::ivector& tokens); @@ -172,7 +172,7 @@ public: * * Adds weighted group of groups, where each subgroup has a * (weight) / (total weight) chance of being selected. Weights - * are represented as @c uint32_t. + * are represented as @c uint32_t. If an exception occurs, no data is modified. * * @param weights @c etl::ivector of @c etl::pair s of @c group_id_it and their corresponding weights. * diff --git a/src/fractal.cpp b/src/fractal.cpp index e86b3c8..3ab8374 100644 --- a/src/fractal.cpp +++ b/src/fractal.cpp @@ -1,32 +1,188 @@ #include "fractal.hpp" #include +#include + +using mtl::endl; +namespace log = mtl::log; namespace fractal { token_id_t generator_t::add_token(token_type_e type, mtl::fixed value) { + log::debug << "Adding token with type " << (int)type << endl; + + if (m_processed) { + log::error << "Failed to add token, already preprocessed" << endl; + throw mtl::system_error(); + } + + if (m_tokens.full()) { + log::error << "Failed to add token, tokens full" << endl; + throw mtl::length_error(); + } + + switch (type) { + case token_type_e::walk: + case token_type_e::rotate: + case token_type_e::generate: + m_tokens.push_back(token_t{type, value}); + return m_tokens.size() - 1; // IDs are simply index into vector + default: + log::error << "Failed to add token, invalid token type" << endl; + throw mtl::invalid_argument(); + } } group_id_t generator_t::add_group_characteristic(uint32_t factor, const etl::ivector& tokens) { + if (m_processed) { + log::error << "Failed to add characteristic, already preprocessed" << endl; + throw mtl::system_error(); + } + + if (m_group_characteristics.full()) { + log::error << "Failed to add characteristic, vector full" << endl; + throw mtl::length_error(); + } + + // We need to look for invalid tokens AOT, because we only modify the + // generator if the supplied data is valid. + size_t num_tokens = m_tokens.size(); + for (token_id_t token : tokens) { + if (token >= num_tokens) { + log::error << "Failed to add characteristic, invalid token found: " << token << " >= " << num_tokens << endl; + throw mtl::invalid_argument(); + } + } + + m_group_characteristics.push_back(group_characteristic_t()); + + group_characteristic_t& characteristic = m_group_characteristics.back(); + characteristic.m_factor = factor; + characteristic.m_token_ids.assign(tokens.begin(), tokens.end()); + + return m_group_characteristics.size() - 1; // IDs are just the index into vector } group_id_t generator_t::add_group_characteristic(const etl::ivector& tokens) { + return add_group_characteristic(1, tokens); } weighted_group_id_t generator_t::add_weighted_group(const etl::ivector>& group_weights) { + if (m_processed) { + log::error << "Failed to add weighted group, already preprocessed" << endl; + throw mtl::system_error(); + } + + if (m_weighted_groups.full()) { + log::error << "Failed to add weighted group, vector full" << endl; + throw mtl::length_error(); + } + + size_t num_groups = m_group_characteristics.size(); + for (etl::pair pair : group_weights) { + if (pair.first >= num_groups) { + log::error << "Failed to add weighted group, invalid group found: " << pair.first << " >= " << num_groups << endl; + throw mtl::invalid_argument(); + } + } + + m_weighted_groups.push_back(weighted_group_t()); + + weighted_group_t& wgroup = m_weighted_groups.back(); + + uint32_t weight_total = 0; + + for (etl::pair pair : group_weights) { + wgroup.m_groups.push_back(pair.first); + wgroup.m_weights.push_back(pair.second); + wgroup.m_weight_total += pair.second; + } + + wgroup.m_weight_total = weight_total; + + return m_weighted_groups.size() - 1; } weighted_group_id_t generator_t::add_weighted_group(group_id_t group) { + if (m_processed) { + log::error << "Failed to add weighted group, already preprocessed" << endl; + throw mtl::system_error(); + } + + if (m_weighted_groups.full()) { + log::error << "Failed to add weighted group, vector full" << endl; + throw mtl::length_error(); + } + + if (group >= m_group_characteristics.size()) { + log::error << "Failed to add weighted group, invalid group encountered" << endl; + throw mtl::invalid_argument(); + } + + m_weighted_groups.push_back(weighted_group_t()); + + weighted_group_t& wgroup = m_weighted_groups.back(); + wgroup.m_groups.push_back(group); + wgroup.m_weights.push_back(1); // We still need to supply a weight + wgroup.m_weight_total = 1; + + return m_weighted_groups.size() - 1; } branch_rule_basic_id_t generator_t::add_basic_branch_rule(token_id_t match, weighted_group_id_t wgroup) { + if (m_processed) { + log::error << "Failed to add basic branch rule, already preprocessed" << endl; + throw mtl::system_error(); + } + + if (m_basic_branch_rules.full()) { + log::error << "Failed to add basic branch rule, vector full" << endl; + throw mtl::length_error(); + } + + if (match >= m_tokens.size()) { + log::error << "Failed to add basic branch rule, invalid match token" << endl; + throw mtl::invalid_argument(); + } + + if (wgroup >= m_weighted_groups.size()) { + log::error << "Failed to add basic branch rule, invalid weighted group" << endl; + throw mtl::invalid_argument(); + } + + m_basic_branch_rules.push_back(branch_rule_basic_t{match, wgroup}); + + return m_basic_branch_rules.size() - 1; } branch_rule_marking_id_t generator_t::add_marking_branch_rule(token_id_t match, uint32_t marker_id) { + if (m_processed) { + log::error << "Failed to add marking branch rule, already preprocessed" << endl; + throw mtl::system_error(); + } + + if (m_basic_branch_rules.full()) { + log::error << "Failed to add marking branch rule, vector full" << endl; + throw mtl::length_error(); + } + + if (match >= m_tokens.size()) { + log::error << "Failed to add marking branch rule, invalid match token" << endl; + throw mtl::invalid_argument(); + } + + m_marking_branch_rules.push_back(branch_rule_marking_t{match, marker_id}); + + return m_marking_branch_rules.size() - 1; } - void generator_t::set_axiom(weighted_group_id_t wgroup) { + if (wgroup >= m_weighted_groups.size()) { + log::error << "Failed to set axiom, invalid weighted group" << endl; + throw mtl::invalid_argument(); + } + + m_axiom = wgroup; } void generator_t::preprocess() {