#ifndef SEQPOINTER_H // voorkom dat dit bestand meerdere keren #define SEQPOINTER_H // ge-include wordt #include "variant.h" #include "deletie.h" #include "insertie.h" #include "inversie.h" #include "delinsertie.h" #include "substitutie.h" #include <iostream> #include <cstdint> #include <string> #include <vector> template <typename T> class Vakje { public: Vakje* vorige; Vakje* volgende; T data; int rest; Vakje(); }; template <typename T> Vakje<T>::Vakje():vorige(nullptr), volgende(nullptr), data(T()), rest(0) { } template <typename T> class SeqPointer { private: // Pointer die naar het eerste Vakje van de SeqPointer wijst Vakje<T> *ingang; // Pointer die naar het laatste Vakje van de SeqPointer wijst Vakje<T> *uitgang; // Hoeveel Vakjes de SeqPointer bevat int aantalVakjes; // Maximaal aantal bits dat in T past int grootte; // Maximale aantal symbolen die in T past int maxGrootte; // Zet de string seq om in een variabele van type T en zet in // rest hoeveel rest er over is T vakjeMaken(std::string seq, int &rest) const; // Vult een Vakje "vakje" aan met een Vakje "nieuw" void aanvullen(Vakje<T> *vakje, Vakje<T> *nieuw) const; // Retourneert het Vakje van plek "position" Vakje<T>* vindVakje(int const position) const; // Voegt een nieuw Vakje achteraan de SeqPointer toe void voegachter(T const nieuwVakje, int const rest0); // Verwijdert het voorste Vakje van de SeqPointer void voorVerwijderen(); public: // Constructor voor een lege SeqPointer SeqPointer(); // Constructor die van een string een SeqPointer maakt SeqPointer(std::string const sequentie); // Copy constructor van SeqPointer SeqPointer(SeqPointer<T> const &seqpointer); // Destructor die alle Vakjes verwijderd ~SeqPointer(); // Retourneert de waarde van de private variabele aantalVakjes int getaantalVakjes() const; // Retourneert de waarde van de private variabele ingang Vakje<T>* getIngang() const; // Verwijdert alle Vakjes uit de SeqPointer void vernietig(); // Retourneert de SeqPointer waarmee de functie is aangeroepen SeqPointer<T> copy() const; // Kopieert de SeqPointer sequentie in de SeqPointer waarmee de functie // is aangeroepen void copy2(SeqPointer<T> const &sequentie); // Drukt de symbolen af die in SeqPointer zijn opgeslagen void drukAf() const; // Maakt de Vakjes uit een gegeven string void seqpointerMaken(std::string const &sequentie); // Retourneert hoeveel symbolen zijn opgeslagen in de SeqPointer int length() const; // Retourneert het character dat op position staat char char_at(int const position) const; // Kijkt of de meegegeven SeqPointer gelijk is aan de SeqPointer waarmee // de functie is aangeroepen bool equal(SeqPointer<T> const &sequentie) const; // Geeft een nieuwe SeqPointer met de symbolen [start, end) SeqPointer<T> slice(int const start, int const end) const; // Geeft een nieuwe SeqPointer waarbij de SeqPointer waarmee de functie is // aangeroepen en other zijn geconcateneerd SeqPointer<T> concat(SeqPointer<T> const &other) const; // Retourneert de reverse complement van inside SeqPointer<T> inverse(SeqPointer<T> const inside) const; // Past de meegegeven varianten toe op de SeqPointer waarmee de functie is // aangeroepen en retourneert de nieuwe SeqPointer SeqPointer<T> apply(std::vector<Variant const*> varianten) const; }; // Constructor voor een lege SeqPointer template <typename T> SeqPointer<T>::SeqPointer():ingang(nullptr), uitgang(nullptr), aantalVakjes(0), grootte(sizeof(T)*8), maxGrootte(grootte / 2) { } // SeqPointer<T>::SeqPointer // Copy constructor van de klasse template <typename T> SeqPointer<T>::SeqPointer(SeqPointer<T> const &seqpointer): SeqPointer() { vernietig(); Vakje<T> * hulp = seqpointer.ingang; while(hulp != nullptr) { voegachter(hulp->data, hulp->rest); hulp = hulp->volgende; } // Kopieer de hele pointerlijst } // SeqPointer<T>::SeqPointer // Constructor voor als een string is meegegeven template <typename T> SeqPointer<T>::SeqPointer(std::string const sequentie): SeqPointer() { seqpointerMaken(sequentie); } //SeqPointer<T>::SeqPointer // Retourneert de private variabele aantalVakjes template <typename T> int SeqPointer<T>::getaantalVakjes() const { return aantalVakjes; } // SeqPointer<T>::getaantalVakjes // Retourneert de private variabele ingang template <typename T> Vakje<T>* SeqPointer<T>::getIngang() const { return ingang; } // SeqPointer<T>::getIngang // Retourneert de lengte in symbolen van de SeqPointer waarmee // de functie is aangeroepen template <typename T> int SeqPointer<T>::length() const { Vakje<T> *hulp = ingang; int size = 0; // Hier komt de lengte in te staan while(hulp != nullptr) { if(hulp->rest == 0) { size += maxGrootte; // Vakje is vol } else { size += maxGrootte - (hulp->rest/2); // Rest moet eraf gehaald worden } hulp = hulp->volgende; } return size; } // SeqPointer<T>::length // Zoekt het Vakje waarin het symbool op plek positie zich bevindt en retourneert // dat Vakje template <typename T> Vakje<T>* SeqPointer<T>::vindVakje(int const position) const { Vakje<T> *hulp = ingang; int vakje = position/maxGrootte; // Hoeveelste vakje het is if(position < 0 || position > length()) { vakje = -1; return nullptr; } // Positie is buiten de array for(int i = 0; i < vakje; i++) { if(hulp != nullptr) { hulp = hulp->volgende; } else { vakje = -1; return nullptr; } } return hulp; } // SeqPointer<T>::vindVakje // Retourneert uit de SeqPointer het symbool dat op position staat template <typename T> char SeqPointer<T>::char_at(int const position) const { Vakje<T> *hulp = vindVakje(position); int plek = 0; T extra = T(0); char kar = 'X'; if(vindVakje == nullptr) { std::cerr << "Position bevindt zich buiten de sequentie" << std::endl; return kar; } if(hulp != nullptr) { plek = (position % maxGrootte)*2; // plek van position in het vakje extra = hulp->data >> (grootte - plek - 2); switch(extra & 0b11) { case 0b00: kar = 'A'; break; case 0b01: kar = 'C'; break; case 0b10: kar = 'G'; break; case 0b11: kar = 'T'; } } return kar; } // SeqPointer<T>::char_at // Deze functie retourneert true als de sequentie en de SeqPointer waarmee // de functie is aangeroepen gelijk zijn en anders false template <typename T> bool SeqPointer<T>::equal(SeqPointer<T> const &sequentie) const { Vakje<T> *hulp = ingang; Vakje<T> *hulpSeq = sequentie.ingang; while(hulp != nullptr && hulpSeq != nullptr) { if(hulp->data ^ hulpSeq->data != T()) { return false; } // De sequenties zijn verschillend if(hulp->data ^ hulpSeq->data == T() && hulp->rest != hulpSeq->rest) { return false; } // De sequentie lijken op elkaar omdat de ene allemaal A's heeft aan het // einde en de ander korter is en met nullen is opgevuld maar ze zijn dan // wel verschillend hulp = hulp->volgende; hulpSeq = hulpSeq->volgende; } if(hulp != nullptr || hulpSeq != nullptr) { return false; } // Een van de sequenties is een of meer vakjes langer return true; } // SeqPointer<T>::equal // Voegt een nieuw Vakje toe achteraan de SeqPointer waarmee de functie // is aangeroepen. In data komt nieuwVakje te staan en rest0 wordt de rest // van het nieuwe Vakje template <typename T> void SeqPointer<T>::voegachter(T const nieuwVakje, int const rest0) { Vakje<T> *hulp = new Vakje<T>; hulp->data = nieuwVakje; if(ingang == nullptr) { ingang = hulp; } // De SeqPointer is dan leeg else { uitgang->volgende = hulp; } hulp->vorige = uitgang; uitgang = hulp; hulp->volgende = nullptr; aantalVakjes++; hulp->rest = rest0; } // SeqPointer<T>::voegachter // Verwijdert het voorste vakje van de SeqPointer // als die er is template <typename T> void SeqPointer<T>::voorVerwijderen() { Vakje<T> *hulp = ingang; if(ingang != nullptr) { ingang = ingang->volgende; if(ingang != nullptr) { ingang->vorige = nullptr; } // Als er minstens twee vakjes zijn else { uitgang = nullptr; } // Als er één vakje is delete hulp; hulp = nullptr; aantalVakjes--; } // Er moet minstens één vakje zijn } // SeqPointer<T>::voorVerwijderen // Verwijdert alle vakjes uit de SeqPointer template <typename T> void SeqPointer<T>::vernietig() { while(ingang != nullptr) { voorVerwijderen(); } // Zolang er nog vakjes zijn, doorgaan met verwijderen } // SeqPointer<T>::vernietig // Destructor voor SeqPointer template <typename T> SeqPointer<T>::~SeqPointer() { vernietig(); } // SeQPointer<T>::~SeqPointer // Aan de hand van de string seq wordt bepaald wat de data van het Vakje // moet zijn en wordt die data met type T geretourneerd. In rest komt te staan // wat de rest van het vakje wordt template <typename T> T SeqPointer<T>::vakjeMaken(std::string const seq, int &rest) const { int seqgrootte = seq.length(); int teller = 0; T info = T(); while(teller < seqgrootte) { info = info << 2; // Opschuiven zodat het nieuwe symbool kan worden gezet switch(seq.at(teller)) { case 'A': info = info | 0b00; // A = 00 break; case 'C': info = info | 0b01; // C = 01 break; case 'G': info = info | 0b10; // G = 10 break; case 'T': info = info | 0b11; // T = 11 } // Het nieuwe symbool zetten door eerst te kijken welke het is teller++; } rest = grootte - seqgrootte*2; info = info << rest; // Ervoor zorgen dat de rest aan de rechterkant van info zit return info; } // SeqPointer<T>::vakjeMaken // Zet de string sequentie om in de Vakjes die worden toegevoegd aan de // SeqPointer waarmee de functie is aangeroepen template <typename T> void SeqPointer<T>::seqpointerMaken(std::string const &sequentie) { int sequentieSize = sequentie.size(); char kar; int teller = 0; // Telt hoeveel symbolen voorbij zijn gekomen int rest = 0; std::string seq = ""; // Hier komt de sequentie die in het Vakje zal worden gestopt T info = T(); for(int i = 0; i < sequentieSize; i++) { kar = sequentie.at(i); if(teller < maxGrootte) { if(kar == 'A' || kar == 'C' || kar == 'G' || kar == 'T') { seq += kar; teller++; } // Controleren of het wel een toegestaan symbool is else { std::cerr << "Geen geldige DNA-type in de string" << std::endl; vernietig(); return; } } if(teller == maxGrootte) { info = vakjeMaken(seq, rest); voegachter(info, rest); seq = ""; teller = 0; } // Het maximaal aantal symbolen om het Vakje te vullen, is dan bereikt } if(teller != 0) { info = vakjeMaken(seq, rest); voegachter(info, rest); } // Als de laatste Vakjes nog niet zijn toegevoegd is omdat het niet // een vol Vakje maakt } // SeqPointer<T>::seqpointerMaken template <typename T> void SeqPointer<T>::drukAf() const { Vakje<T> *hulp = ingang; T temp = T(); while(hulp != nullptr) { int tempsize = grootte-2; for(int i = tempsize; i >= 0; i--) { temp = hulp->data >> i; i--; 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; } } hulp = hulp->volgende; } std::cout << std::endl; } // Vult de data van Vakje "vakje" aan met de data van Vakje "nieuw". De data van "nieuw" // die niet in "vakje" pas wordt naar links in de integer geschoven. De rest van beide Vakjes // wordt ook aangepast template <typename T> void SeqPointer<T>::aanvullen(Vakje<T> *vakje, Vakje<T> *nieuw) const { if(nieuw == nullptr) { return; } // Er hoeft dan niks te gebeuren else if(vakje == nullptr) { vakje = nieuw; nieuw->data = T(0); nieuw->rest = grootte; return; } // Als vakje een nullptr is, wordt alles van nieuw in vakje gezet int opschuiven = (grootte - vakje->rest); // Hoeveel de data in nieuw moet opschuiven T hulp = nieuw->data >> opschuiven; // Data van nieuw dat bij vakje gaat worden toegevoegd vakje->data |= hulp; vakje->rest -= (grootte - nieuw->rest); if(vakje->rest < 0) { nieuw->data = nieuw->data << (grootte - opschuiven); nieuw->rest = grootte + vakje->rest; vakje->rest = 0; } // Dan zijn er nog symbolen over die in nieuw blijven staan else { nieuw->data = T(0); nieuw->rest = grootte; } } // SeqPointer<T>::aanvullen // Retourneert de SeqPointer waarmee de functie is aangeroepen template <typename T> SeqPointer<T> SeqPointer<T>::copy() const { Vakje<T> *hulp = ingang; SeqPointer<T> resultaat; while(hulp != nullptr) { resultaat.voegachter(hulp->data, hulp->rest); hulp = hulp->volgende; } return resultaat; } // SeqPointer<T>::copy // De meegegeven sequentie wordt gekopieerd in de SeqPointer waarmee de functie is aangeroepen template <typename T> void SeqPointer<T>::copy2(SeqPointer<T> const &sequentie) { Vakje<T> *hulp = sequentie.ingang; // Houdt de Vakjes van sequentie bij vernietig(); // Als er nog iets in zat dan moet dat eerst weg while(hulp != nullptr) { voegachter(hulp->data, hulp->rest); hulp = hulp->volgende; } } // SeqPointer<T>::copy // Maakt een nieuwe SeqPointer resultaat waarbij de de SeqPointer other wordt geplakt // achter de SeqPointer waarmee de functie is aangeroepen template <typename T> SeqPointer<T> SeqPointer<T>::concat(SeqPointer<T> const &other) const { SeqPointer<T> resultaat = copy(); SeqPointer<T> ander(other); // Zodat other niet wordt aangepast Vakje<T> *hulp = ander.ingang; while(resultaat.uitgang != nullptr && hulp != nullptr) { aanvullen(resultaat.uitgang, hulp); if(hulp->rest != grootte) { resultaat.voegachter(hulp->data, hulp->rest); } hulp = hulp->volgende; } return resultaat; } // SeqPointer<T>::concat // Retouneert een nieuwe SeqPointer resultaat met een sequentie die van start // tot end loopt van de SeqPointer waarmee de functie is aangeroepen template <typename T> SeqPointer<T> SeqPointer<T>::slice(int const start, int const end) const { SeqPointer<T> resultaat; SeqPointer<T> temp = copy(); int laatste = 0; Vakje<T> *eersteVakje = temp.vindVakje(start); Vakje<T> *endVakje = temp.vindVakje(end); Vakje<T> *hulp = eersteVakje; T info = T(0); int plekEerst = (start % maxGrootte)*2; // Plek in het Vakje in resultaat van start int plekLaatst = ((end - start - 1) % maxGrootte)*2; // Plek in het Vakje in resultaat van end int rest = 0; laatste = (end - start - 1)/maxGrootte; // Wordt het laatste Vakje in resultaat if(eersteVakje == nullptr || endVakje == nullptr || start > end) { std::cerr << "Start en eind voldoen niet aan de eisen." << std::endl; return SeqPointer<T>(); } if(start == end) { return SeqPointer<T>(); } // Dan zitten er geen symbolen in de SeqPointer info = eersteVakje->data << plekEerst; rest = eersteVakje->rest + plekEerst; resultaat.voegachter(info, rest); // Eerste Vakje alvast toevoegen hulp = hulp->volgende; for(int i = 0; i < laatste; i++) { aanvullen(resultaat.uitgang, hulp); resultaat.voegachter(hulp->data, hulp->rest); hulp = hulp->volgende; } if((resultaat.length() % maxGrootte)*2 <= plekLaatst) { aanvullen(resultaat.uitgang, hulp); } info = resultaat.uitgang->data >> (grootte - plekLaatst - 2); // Vanaf end resultaat.uitgang->data = info << (grootte - plekLaatst - 2); // alles weghalen resultaat.uitgang->rest = grootte - ((end - start) % maxGrootte)*2; if(resultaat.uitgang->rest == grootte) { resultaat.uitgang->rest = 0; } // Anders zou rest = grootte zijn bij een vol Vakje while(resultaat.uitgang->rest < 0) { resultaat.uitgang->rest += grootte; } // Rest kan negatief zijn maar door herhaald grootte op te tellen // krijg je de goede rest return resultaat; } // SeqPointer<T>::slice // Hulpfunctie voor inversie. // Maakt van de meegegeven SeqPointer een reverse complement SeqPointer. template <typename T> SeqPointer<T> SeqPointer<T>::inverse(SeqPointer<T> const inside) const{ SeqPointer<T> resultaat; Vakje<T> *nieuw = inside.uitgang; 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 - nieuw->rest; // Grootte van laatste vakje (houdt rekening met rest) int rest = 0; while(nieuw != nullptr) { T info = nieuw->data; if(nieuw == inside.uitgang) { info = info >> nieuw->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) { resultaat.voegachter(hulp, 0); hulp = T(0); teller = 0; } // 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 nieuw = nieuw->volgende; } // Gaat door elk vakje van achter naar voor if(teller != 0) { rest = (maxGrootte-teller)*2; hulp = hulp << rest; resultaat.voegachter(hulp, rest); } // Teller is nog niet 0, dus er is nog een rest over in hulp return resultaat; } // SeqPointer<T>::inverse // Past de varianten in de meegegeven vector één voor één toe aan de sequentie // en retourneert uiteindelijk de resultaat sequentie-pointer template <typename T> SeqPointer<T> SeqPointer<T>::apply(std::vector<Variant const*> varianten) const { int vectorSize = varianten.size(); SeqPointer<T> product = copy(); for(int k = 0; k < vectorSize; k++) { Variant const* var = varianten.at(k); // Variant op plek k if(var->get_eind() > product.length()) { std::cerr << "Deze variant komt buiten de grenzen van de sequentie" << std::endl; return SeqPointer<T>(); } SeqPointer<T> const prefix = product.slice(0, var->get_start()); SeqPointer<T> const suffix = product.slice(var->get_eind(), product.length()); if(var->get_type() == "inv") { SeqPointer<T> temp(prefix.concat(inverse(product.slice(var->get_start(), var->get_eind())))); // prefix + inverse product.copy2(temp.concat(suffix)); // temp + suffix } // inversie else { SeqPointer<T> const insert(var->get_inserted()); SeqPointer<T> temp = prefix.concat(insert); // prefix + insert product.copy2(temp.concat(suffix)); // temp + suffix } // Deletie, Deletie-Insertie, Insertie: kan allemaal methetzelfde algoritme delete var; } varianten.clear(); return product; } // SeqPointer<T>::apply #endif