98 lines
2.4 KiB
C++
98 lines
2.4 KiB
C++
|
/** Implement the genetic code as a thread-safe GeneticCode.
|
||
|
*
|
||
|
* @see https://refactoring.guru/design-patterns/GeneticCode/cpp/example#example-1
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <complex>
|
||
|
#include <fstream>
|
||
|
#include <sstream>
|
||
|
#include <iostream>
|
||
|
#include <stdexcept>
|
||
|
#include <unordered_map>
|
||
|
#include <vector>
|
||
|
#include <mutex>
|
||
|
|
||
|
#include "Sequence.hpp"
|
||
|
#include "strutils.hpp"
|
||
|
|
||
|
|
||
|
class GeneticCode {
|
||
|
|
||
|
|
||
|
private:
|
||
|
|
||
|
static GeneticCode *pinstance_;
|
||
|
static std::mutex mutex_;
|
||
|
|
||
|
protected:
|
||
|
|
||
|
std::unordered_map<std::string, char> 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<std::string> 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<std::mutex> lock(mutex_);
|
||
|
if (pinstance_ == nullptr)
|
||
|
{
|
||
|
pinstance_ = new GeneticCode();
|
||
|
}
|
||
|
return pinstance_;
|
||
|
}
|
||
|
|
||
|
GeneticCode *GeneticCode::GetInstance(std::string input_filename)
|
||
|
{
|
||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||
|
if (pinstance_ == nullptr)
|
||
|
{
|
||
|
pinstance_ = new GeneticCode(input_filename);
|
||
|
}
|
||
|
return pinstance_;
|
||
|
}
|