#ifndef SEQARRAY_H // voorkomt dat dit bestand meerdere keren #define SEQARRAY_H // ge-include wordt #include "variant.h" #include "deletie.h" #include "insertie.h" #include "inversie.h" #include "delinsertie.h" #include "substitutie.h" #include <cstdint> #include <iostream> #include <string> #include <vector> template <typename T> class SeqArray { public: // Constructor voor leeg object SeqArray(); // Initialisatie constructor array SeqArray(T* const sequentie, int const sizeArray0, int const rest0); // Initialisatie constructor string SeqArray(std::string const sequentie); // Initialisatie constructor voor SeqArray SeqArray(SeqArray<T> const &sequentie); // Default destructor ~SeqArray(); // Kopieer functie void copy(SeqArray<T> const &sequentie); // Geeft de lengte van de sequentie terug int length() const; // Geeft karakter terug op plek symbool in het vakje op positie pos char char_at(int const positie) const; // Retourneert waar in de array het symbool op positie "positie" ligt int vindVakje(int const positie) const; // Concateneert de huidige sequentie met een andere sequentie: 'other' SeqArray<T> concat(SeqArray const &other) const; // Geeft een nieuwe sequentie met de symbolen [start, end) SeqArray<T> slice(int const start, int const eind) const; // Checkt of de twee sequenties hetzelfde zijn bool equal(SeqArray<T> const &other) const; // Drukt de sequentie af op het scherm void drukAf() const; // Past de varianten in de meegegeven vector één voor één toe aan de sequentie SeqArray<T> apply(std::vector<Variant const*> varianten) const; private: // Data van sequentie T* data; // grootte van de array int sizeArray; // Grootte van een vakje (T) in bits int grootte; // Hoeveel DNA-symbolen er in een vakje kunnen int maxGrootte; // De rest van het laatste vakje van de sequentie, als dit er is, anders 0 int rest; // Hulpfunctie voor het concateneren. void aanvullen(T& eerste, T& laatste, int& restEerste, int& restLaatste) const; // Hulpfunctie voor de variant inversie SeqArray<T> inverse(SeqArray<T> const inside) const; }; // Constructor van een leeg SeqArray object template<typename T> SeqArray<T>::SeqArray(): data(nullptr), sizeArray(0), grootte(sizeof(T)*8), maxGrootte(grootte / 2), rest(0) { } // SeqArray::SeqArray // Intialisatie constructor voor een vector template <typename T> SeqArray<T>::SeqArray(T* const sequentie, int const sizeArray0, int const rest0): SeqArray() { sizeArray = sizeArray0; rest = rest0; data = new T[sizeArray]; std::copy(sequentie, sequentie + sizeArray, data); // kopieert alles behalve het laatste vakje } // SeqArray::SeqArray // Initialisatie constructor voor een string template <typename T> SeqArray<T>::SeqArray(std::string const sequentie): SeqArray() { if(sequentie == "") { return; } // lege string int sequentieSize = sequentie.size(); // aantal karakters in sequentie int teller = 0; // teller voor hoeveel symbolen er al in een vakje is gedaan data = new T[(sequentieSize / maxGrootte) + (sequentieSize % maxGrootte)]; // initialisatie van data T info = T(); // Hierin wordt het vakje opgebouwd for(int i = 0; i < sequentieSize; i++) { teller++; char kar = sequentie.at(i); if(kar == 'A' || kar == 'C' || kar == 'G' || kar == 'T') { info = info << 2; switch(kar) { case 'A': info = info | 0b00; break; case 'C': info = info | 0b01; break; case 'G': info = info | 0b10; break; case 'T': info = info | 0b11; break; } // Voegt het symbool toe aan info } // Checkt of het wel een DNA-symbool is else { std::cerr << "Geen geldige DNA-type in de string" << std::endl; delete[] data; data = nullptr; return; } // Geen geldige type DNA (A, C, G T) if(teller == maxGrootte) { data[sizeArray] = info; teller = 0; // Reset teller sizeArray++; info = T(); } // Voegt info op een nieuwe plek achteraan in de array data } // Maakt van de string een vector<T> if(teller != 0) { rest = grootte - (teller * 2); info = info << rest; data[sizeArray] = info; sizeArray++; } // Het is het laatste vakje en teller is niet 0, dus er is een vakje met rest } // SeqArray<T>::SeqArray template <typename T> SeqArray<T>::SeqArray(SeqArray<T> const &sequentie): SeqArray() { sizeArray = sequentie.sizeArray; data = new T[sizeArray]; for(int i = 0; i < sizeArray; i++) { data[i] = sequentie.data[i]; } rest = sequentie.rest; } // Default destructor template <typename T> SeqArray<T>::~SeqArray() { delete[] data; } // SeqArray<T>::~SeqArray // Kopieer functie, die de meegegeven SeqArray de huidige SeqArray maakt template <typename T> void SeqArray<T>::copy(SeqArray<T> const &sequentie) { sizeArray = sequentie.sizeArray; data = new T[sizeArray]; for(int i = 0; i < sizeArray; i++) { data[i] = sequentie.data[i]; } rest = sequentie.rest; } // SeqArray<T>::copy // Geeft de lengte van de sequentie in integers template <typename T> int SeqArray<T>::length() const { return (sizeArray * maxGrootte) - (rest / 2); } // SeqArray::length // Geeft karakter terug op plek symbool in het vakje op positie "positie". Als positie // buiten de sequentie ligt dan wordt X geretourneerd template <typename T> char SeqArray<T>::char_at(int const positie) const { if(positie < 0 || positie >= ((sizeArray * maxGrootte) - rest / 2)) { std::cerr << "Positie pos ligt buiten de grenzen van de sequentie." << std::endl; return 'X'; } T seq = data[vindVakje(positie)] >> ((maxGrootte * 2) - 2 - ((positie % maxGrootte) * 2)); // Aan het begin het symbool switch(seq & 0b11) { case 0b00: return 'A'; break; case 0b01: return 'C'; break; case 0b10: return 'G'; break; case 0b11: default: return 'T'; break; } } // SeqArray::char_at // Hulpfunctie voor het concateneren en slice. // Schuift het vakje laatste zo aan dat het vakje eerste geen rest meer heeft. // Zo wordt de rest in het eerste vakje opgeschoven naar het laatste vakje. template <typename T> void SeqArray<T>::aanvullen(T& eerste, T& laatste, int& restEerste, int& restLaatste) const { int opschuiven = grootte - restEerste; // Hoe veel er moet worden opgeschoven eerste = eerste >> restEerste; eerste = eerste << restEerste; // zorgt ervoor dat de rest ook echt nullen zijn if(restEerste == 0 || restLaatste == 8) { return; } else if(restLaatste + restEerste > grootte) { opschuiven = grootte - restEerste; restEerste -= grootte - restLaatste; restLaatste = grootte; } // Dit kan alleen bij het laatste vakje van de andere sequentie else { restLaatste += restEerste; restEerste = 0; } // De rest van eerste schuift op naar het vakje laatste T hulp = laatste >> opschuiven; // stukje dat bij eerste moet eerste |= hulp; // eerste + hulp laatste = laatste << (grootte - opschuiven); // laatste - hulp } // SeqArray<T>::aanvullen // Concateneert sequentie met gegeven sequentie template <typename T> SeqArray<T> SeqArray<T>::concat(SeqArray<T> const &other) const { if(other.length() == 0) { return SeqArray<T>(data, sizeArray, rest); } // Concat met niks (other is leeg) int newSizeArray = sizeArray + other.sizeArray - ((rest + other.rest) / grootte); int rest0 = other.rest; T* newData = new T[newSizeArray]; // Hierom komt de nieuwe geconcatteneerde data vector if(rest == 0) { std::copy(data, data + sizeArray, newData); // kopieert alles behalve het laatste vakje std::copy(other.data, other.data + other.sizeArray, newData + sizeArray); // kopieert alles behalve het laatste vakje } // Als de huidige sequentie geen rest heeft, dan kan other gewoon erachter worden toegevoegd else { std::copy(data, data + sizeArray - 1, newData); // kopieert alles behalve het laatste vakje int restEerste = rest; // rest van eerste vakje int restLaatste = 0; // rest van het vakje daarna T eerste = data[sizeArray - 1]; for(int i = 0; i < other.sizeArray; i++) { T laatste = other.data[i]; if(i + 1 == other.sizeArray) { aanvullen(eerste, laatste, restEerste, rest0); newData[sizeArray - 1 + i] = eerste; if(rest0 < grootte) { newData[newSizeArray - 1] = laatste; } // Er is nog een laatste vakje over met rest else { rest0 = restEerste; } // Er is een vakje afgevallen } // Dit is het laatste vakje, dus er moet worden opgelet op de rest van other else { aanvullen(eerste, laatste, restEerste, restLaatste); newData[sizeArray - 1 + i] = eerste; } restEerste = restLaatste; restLaatste = 0; eerste = laatste; // laatste wordt het nieuwe eerste vakje } } // Concateneert de sequentie met other SeqArray<T> newSeq(newData, newSizeArray, rest0); delete[] newData; return newSeq; } // SeqArray::concat // Geeft het vakje waarin positie bevindt template <typename T> int SeqArray<T>::vindVakje(int const positie) const { return positie / maxGrootte; } // SeqArray<T>::vindVakje // Geeft een nieuwe sequentie met de symbolen [start, end) template <typename T> SeqArray<T> SeqArray<T>::slice(int const start, int const eind) const { if(start > eind || start < 0 || eind > length() ) { std::cerr << "Start en eind voldoen niet aan de eisen." << std::endl; return SeqArray<T>(); } if(start == eind) { return SeqArray<T>(); } int startVakje = vindVakje(start); int eindVakje = vindVakje(eind); int restEerste = grootte - ((maxGrootte - (start % maxGrootte)) * 2); int restEind = grootte - ((eind % maxGrootte) * 2); int newSizeArray = (eind - start) / maxGrootte; T eerste = data[startVakje] << restEerste; // de rest achteraan if((eind - start) % maxGrootte > 0) { newSizeArray++; } // komt nog een vakje erbij met rest T* newData = new T[newSizeArray]; if(restEerste == 0 && (newSizeArray == 1 || newSizeArray == 2)) { if(newSizeArray == 2) { newData[0] = eerste; } if(restEind == 8) { restEind = 0; eindVakje--; } eerste = data[eindVakje] >> restEind; newData[newSizeArray - 1] = eerste << restEind; // verschilt: moet 0 zijn voor size 1 en 1 voor size 2 return SeqArray<T>(newData, newSizeArray, restEind); } // start is bij 0de symbool van vakje en de nieuwe array bestaat maar uit 1 vakje newData[0] = eerste; int restLaatste = 0; for(int i = 0; i < newSizeArray - 1; i++) { T laatste = data[startVakje + 1 + i]; aanvullen(eerste, laatste, restEerste, restLaatste); newData[i] = eerste; restEerste = restLaatste; restLaatste = 0; eerste = laatste; // laatste wordt het nieuwe eerste vakje } // Voegt alle vakjes in het 'midden' toe aanvullen(eerste, data[eindVakje], restEerste, restEind); // het laatste vakje newData[newSizeArray - 1] = eerste; if(restEind == 8) { restEind = restEerste; } SeqArray<T> newSeq(newData, newSizeArray, restEind); delete[] newData; return newSeq; } // SeqArray<T>::slice // Checkt of deze sequentie overeenkomt met de gegeven sequentie template <typename T> bool SeqArray<T>::equal(SeqArray<T> const &other) const { if(rest == other.rest && std::equal(data, data + sizeArray, other.data)) { return true; } return false; } // SeqArray<T>::equal // Drukt de sequentie af op het scherm template <typename T> void SeqArray<T>::drukAf() const { for(int i = 0; i < sizeArray; i++) { int restTemp = 0; if(i + 1 == sizeArray) { restTemp = rest; } // Laatste vakje for(int j = grootte - 2; j >= restTemp; j -= 2) { T temp = data[i] >> j; // zet het gewilde symbool vooraan switch(temp & 0b11) { case 0b00: std::cout << "A"; break; case 0b01: std::cout << "C"; break; case 0b10: std::cout << "G"; break; case 0b11: default: std::cout << "T"; break; } // print het symbool af } // Loopt het vakje af van achter naar voor (voor naar achter in de sequentie) } // Loopt de vector af std::cout << std::endl; } // SeqArray<T>::drukAf // Hulpfunctie voor inversie. // Maakt van de meegegeven SeqArray een reverse complement SeqArray. template <typename T> SeqArray<T> SeqArray<T>::inverse(SeqArray<T> const inside) const{ T* newData = new T[inside.sizeArray]; int teller = 0; // Teller voor de lengte van hoe veel er in een vakje is gestopt T hulp = T(); // Hulp T, waarin de nieuwe vakjes worden opgebouwd int tempSize = grootte - inside.rest; // Grootte van laatste vakje (houdt rekening met rest) int vakjesTeller = 0; for(int i = inside.sizeArray - 1; i >= 0; i--) { T info = inside.data[i]; if(i == inside.sizeArray - 1) { info = info >> inside.rest; } for(int j = 0; j < tempSize; j += 2) { T temp = info >> j; hulp = hulp << 2; teller++; switch(temp & 0b11) { case 0b00: hulp = hulp | 0b11; break; case 0b01: hulp = hulp | 0b10; break; case 0b10: hulp = hulp | 0b01; break; case 0b11: default: hulp = hulp | 0b00; break; } // Complement van temp komt in hulp if(teller == maxGrootte) { newData[vakjesTeller] = hulp; hulp = T(0); teller = 0; vakjesTeller++; } // Hulp zit vol, dus komt in de vector en wordt gerest } // Gaat door elke vakje van achter naar voor in de sequentie (oftewel van voor naar achter) tempSize = grootte; // reset tempSize } // Gaat door elk vakje van achter naar voor if(teller != 0) { hulp = hulp << inside.rest; newData[vakjesTeller] = hulp; } // Teller is nog niet 0, dus er is nog een rest over in hulp SeqArray<T> newSeq(newData, inside.sizeArray, inside.rest); delete[] newData; return newSeq; } // SeqArray<T>::inverse // Past de varianten in de meegegeven vector één voor één toe aan de sequentie // en retourneerd uiteindelijk de resultaat sequentie-array template <typename T> SeqArray<T> SeqArray<T>::apply(std::vector<Variant const*> varianten) const { int vectorSize = varianten.size(); SeqArray<T> product = SeqArray<T>(data, sizeArray, rest); for(int k = 0; k < vectorSize; k++) { Variant const* var = varianten.at(k); // Variant op plek k var->write(); if(var->get_eind() > product.length()) { std::cerr << "Deze variant komt buiten de grenzen van de sequentie" << std::endl; return SeqArray(); } SeqArray<T> const prefix(product.slice(0, var->get_start())); SeqArray<T> const suffix(product.slice(var->get_eind(), product.length())); if(var->get_type() == "inv") { SeqArray<T> temp(prefix.concat(inverse(product.slice(var->get_start(), var->get_eind())))); // prefix + inverse product.copy(temp.concat(suffix)); // temp + suffix } // inversie else { SeqArray<T> const insert(var->get_inserted()); SeqArray<T> temp = prefix.concat(insert); // prefix + insert product.copy(temp.concat(suffix)); // temp + suffix } // Deletie, Deletie-Insertie, substitutie, Insertie: kan allemaal met hetzelfde algoritme delete var; // Delete de pointer in var } // Voert steeds de variant uit op de sequentie in product varianten.clear(); return product; } // SeqArray<T>::apply #endif