DNA-sequences / include / seqarray.h
seqarray.h
Raw
#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