/** Implement the genetic code as a thread-safe GeneticCode. * * @see https://refactoring.guru/design-patterns/GeneticCode/cpp/example#example-1 */ #pragma once #include #include #include #include #include #include #include #include #include #include "Sequence.hpp" #include "strutils.hpp" class GeneticCode { private: static GeneticCode *pinstance_; static std::mutex mutex_; protected: std::unordered_map codon_table; GeneticCode(): GeneticCode("./resources/codons.txt") {} GeneticCode(std::string input_filename) { std::ifstream input(input_filename); if (!input.good()) { throw std::invalid_argument("Error: could not read codon table from " + input_filename + " file."); } load_genetic_code(input); } void load_genetic_code(std::ifstream &input) { if (!input.good()) { throw std::invalid_argument("Error: Could not read the codon table from the text file."); } std::string line; while(input.good()) { std::getline(input, line); std::vector fields = split_string(line, '\t'); std::string codon = fields.at(0); char amino_acid = fields.at(2)[0]; GeneticCode::codon_table.insert({codon, amino_acid}); } } public: GeneticCode(GeneticCode &other) = delete; void operator=(const GeneticCode &) = delete; static GeneticCode *GetInstance(); static GeneticCode *GetInstance(std::string input_filename); char get_amino_acid(std::string codon) { replace_all(codon, 'U', 'T'); if (codon_table.find(codon) != codon_table.end()) { return codon_table.at(codon); } else { throw std::invalid_argument("Error: codon '" + codon + "' not found in genetic code"); } } }; GeneticCode* GeneticCode::pinstance_{nullptr}; std::mutex GeneticCode::mutex_; GeneticCode *GeneticCode::GetInstance() { std::lock_guard lock(mutex_); if (pinstance_ == nullptr) { pinstance_ = new GeneticCode(); } return pinstance_; } GeneticCode *GeneticCode::GetInstance(std::string input_filename) { std::lock_guard lock(mutex_); if (pinstance_ == nullptr) { pinstance_ = new GeneticCode(input_filename); } return pinstance_; }