• Non ci sono risultati.

Laboratorio di Programmazione aa 2012/2013 Tipi Astratti

N/A
N/A
Protected

Academic year: 2022

Condividi "Laboratorio di Programmazione aa 2012/2013 Tipi Astratti"

Copied!
15
0
0

Testo completo

(1)

Laboratorio di Programmazione aa 2012/2013

Tipi Astratti

Giorgio Grisetti

email:grisettidis.uniroma1.it April 15, 2014

Fino ad ora abbiamo sviluppato programmi che manipolano entita’ relativamente semplici, quali matrici, vettori o stringhe. Le specifiche di tali programmi sono state fornite a basso livello, e le descrizioni delle entita’ da manipolare erano facilmente traducibili in C/C++.

Nello sviluppo di programmi, capita spesso di avere a che fare con realta’ complesse, che richiedono accurate riflessioni per essere modellate. In questa lezione, avvalendoci di un esempio, introdurremo una metodologia generale che ci permettera’ di catturare tali realta’: la specifica per tipo astratto.

1 Tipo Astratto di Dato

Un tipo astratto di dato e’ caratterizzato da

• uno o piu’ domini di interesse

• un insieme di operazioni che su questi domini operano, ciascuna operazione e’ caratterizzata da una precondizione ed una postcondizione

– Una precondizione e’ una condizione che deve essere verificata affinche’ l’operazione possa essere eseguita.

– Una postcondizione e’ una condizione che sussiste al termine dell’operazione ed indica il risul- tato della funzione.

Ad esempio, la specifica del tipo astratto Vec, e’ la seguente:

• Domini di interesse:

– Rn: Dominio dei vettori di n dimensioni sul campo dei reali – N : Dominio dei numeri naturali

– R : Dominio dei reali

– Stream : Stream di input output

• Operazioni:

– V ec(n) → v: N → Rn

∗ Pre: n > 0

∗ Post: v ∈ Rn e’ un vettore di dimensione n.

– resize(v1, m) → v2: Rn× N → Rm

∗ Pre: n > 0

(2)

∗ Post: v2 ∈ Rn e’ un vettore di dimensione m, i cui primi min(n, m) elementi sono gli stessi di v1. 1

– print(v, s1) → s2: Rn× Stream → Stream

∗ Pre: nessuna

∗ Post: s2 e’ lo stream ottenuto da s1, stampando v.

– read(s) → v: Stream → v

∗ Pre: s contiene un input valido che rappresenta un vettore.

∗ Post: v e’ il vettore letto dallo stream.

– scale(v1, a) → v2: Rn× R → Rn

∗ Pre: nessuna

∗ Post: v2= a · v1

– scaledSum(v1, v2, a) → v3: Rn× Rn× R → Rn

∗ Pre: dim(v1) == dim(v2)

∗ Post: v3= v1+ a · v2

– setElement(v1, n, a) → v2: Rn× N × R → Rn

∗ Pre: n < dim(v1)

∗ Post: v2 e’ il vettore ottenuto da v1, settando la componente in posizione n ad a.

– getElement(v1, n) → a: Rn× N → Rn

∗ Pre: n < dim(v1)

∗ Post: a = v1[n].

– dot(v1, v2) → d: Rn× Rn→ R

∗ Pre: dim(v1) == dim(v2)

∗ Post: d = v1˙v2

– convolve(v1, v2, a) → v3: Rn× Rm→ Rm+n

∗ Pre: nessuna

∗ Post: v3= v1∗ v2 (convoluzione discreta) – compare(v1, v2) → c: Rn× Rn → N

∗ Pre: nessuna

∗ Post: c =

−1 se v1< v2in ordine lessicografico +1 se v1> v2in ordine lessicografico

0 altrimenti Nella specifica data di sopra noterete due cose:

• Si sono specificate solo le operazioni da compiere, non come compierle.

• Non e’ stato specificato alcun linguaggio di programmazione. Tale specifica e’ sodfdisfatta da tutte le implementazioni della “classe” Vec fatte fino ad ora 2.

1questa specifica e’ leggermente diversa dalle implementazioni viste fino ad ora, in quanto non solo ridimensiona il vettore, ma lo copia anche gli elementi contenuti.

2a parte la funzione resize(...), che abbiamo ridefinito

(3)

2 Implementazioni funzionali e non

Confrontando ora le diverse implementazioni, ed alle specifiche stese nella descrizione del tipo astratto, osserrveremo che le prime possono “differire” dalla seconda in termini di lista di argomeni e di tipo di dato.

Ad esempio si osservi la specifica dell’operazione scaledSum, che ha come parametri due vettori ed un intero, e ritorna un vettore modificato. Nella nostra implemenazione abbiamo deciso di fare side effect su uno dei parametri della funzione (ovvero il primo), modificandolo in maniera dietta. La nostra definizione della scaledSum era la seguente:

class Vec { ...

void scaledSum(const Vec& other, double scale);

};

ed il risultato veniva messo nell’oggetto di invocazione (this). Informalmente, l’operazione eseguita era *this = scaledSum( *this, other, scale). Nell’implementare tale funzione, nessuno ci vieta di aderire in modo piu’ stretto alla specifica per tipo astratto, ad esempio scrivendo una definizione:

class Vec { ...

Vec scaledSum(const Vec& other, double scale) const;

};

Che ritorna un nuovo vettore v2 tale che v2 = scaledSum( *this,scale). Tale specifica, che non modifica l’oggetto di invocazione e’ detta funzionale. Tale implementazione si contrappone alla specifica con side effect, che invece modifica l’oggetto di invocazione, quindi:

• implementazione funzionale: non modifica l’oggetto di invocazione

• implementazione con side-effect: modifica l’oggetto di invocazione

Una specifica per tipo astratto viene solitamente data in termini funzionali. Nel momento in cui la si implementa, occorre fare una scelta per ogni operazione, decidendo se ha senso o meno un’implementazione funzionale. Il buon senso e la conoscenza del contesto in cui la classe verra’ usata sono determinanti per la scelta. In genere le implementazioni funzionali sono piu’ pulite e sicure, in quanto non modificano mai l’oggetto di invocazione, ma sono piu’ inefficienti in quanto comportano la creazione di nuovi oggetti ogni volta che si altera uno dei valori. La nostra classe Vec e’ stata implementata con side effect. Se volessimo rendere l’implementazione completamente funzionale, occorre reimplementare i seguenti metodi:

#ifndef _LP_VECTOR_H_

#define _LP_VECTOR_H_

class Vec{

...

//void setElement (int i, double d);

// questa ritorna un nuovo vettore!

Vec setElement (int i, double d) const;

//void void scale(double d);

// anche questa

Vec scale(double d) const;

//void scaledSum(const Vec& src, double d);

// vedi sopra

Vec scaledSum(const Vec& src, double d); //

//void setZero(); (questa non ha bisogno dell’oggetto di invocazione)

(4)

// non c’e’ niente da settare nell’implementazione funzionale, basta sapere la dimensione.

static Vec zero(int n);

// void resize(int size) const Vec resize(int size) const;

//void void read(); (questa non ha bisogno dell’oggetto di invocazione) static Vec read(); //

//non cambia

void print() const;

double dot(const Vec& b);

// void Vec convolve(const Vec& src1, const Vec& src2);

// questa cambia semantica e ritorna la convoluzione di due vettori.

// la convoluzione si fa con src1.colvolve(src2), e ritorna un nuovo vettore.

void Vec convolve(const Vec& src1, const Vec& src2) const;

// questa non cambia

int compare(const Vec& v2) const;

};

#endif

3 Astrazioni di Tipi e di Entita’

Nell’implementazione di un tipo astratto occorre tenere presente il contesto in cui il tipo di dato svilup- pato verra’ utilizzato e le sue caratteristiche. Un tipo di dato astratto puo’ rappresentare sia valori (ad esempio interi, vettori, matrici), che entita’ (ad esempio l’archivio degli studenti della Sapienza). In genere implementazioni funzionali si prestano bene per i primi, mentre implementazioni con side effect sono migliori per i secondi. Una tipico tipo di dato che rappresenta un’entita’ e’ un file. Quando com- piamo operazioni su un file. Un file non e’ il suo valore, ma e un insieme di dati che puo’ essere letto, scritto o modificato. E’ poco pratico definire un nuovo file ogni volta che leggiamo o scriviamo qualcosa su di esso.

4 Specifiche di Tipo Astratto Articolate

Spesso per modellare una realta’ occorre “far interagire” piu’ tipi. Una specifica per tipo astratto puo’

includere molti domini di interesse. Nel seguito, illustreremo un esempio piu’ complesso: il tipo astratto

“NavigatorMap”, che contiene la mappa di un navigatore satellitare. Vogliamo sviluppare la specifica per tipo astratto di una di tali mappe, che permetta una rapida ricerca di strade e luoghi (e percorsi minimi).

Una “NavigatorMap” rappresenta luoghi e tratti di strada che connettono questi luoghi. Un luogo e’ identificato da una stringa e potenzialmente da altre informazioni (longitudine, latitudine etc,)3. Un tratto di strada connette due luoghi. Un luogo e’ raggiunto da tanti tratti di strada.

Iniziamo dalla specifica per tipo astratto di NavigatorMap

• Domini di interesse:

– Maps: Dominio delle mappe – Places : Dominio dei luoghi

3In questa descrizione ometteremo tali potenziali altre informazioni per alleggerire la trattazione.

(5)

– SegmentContainer : Dominio degli insiemi di tratti di strada – Strings : Dominio delle stringhe

– Stream : Stream di input output

• Operazioni:

– f indP lace(m, s) → p: Maps × Strings → Places

∗ Pre: nessuna

∗ Post: p e’ un luogo in m con nome s. Se il luogo non e’ presente p = null.

– addP lace(m1, p) → m2: Maps × Places → Maps

∗ Pre: non esiste in m1 un luogo con lo stesso nome di p.

∗ Post: m2 e ’ una mappa ottenuta da m1, aggiungendo il luogo p.

– addSegment(m1, s) → m2: Maps × Segments → Maps

∗ Pre: I luoghi di arrivo e destinazione del segmento sono contenuti in m.

∗ Post: m2 e ’ una mappa ottenuta da m1, aggiungendo il segmento s.

– removeSegment(m1, s) → m2: Maps × Segments → Maps

∗ Pre: m1 contiene s.

∗ Post: m2 e ’ una mappa ottenuta da m1, rimuovendo il segmento s.

– print(m, s1) → s2: < Maps × Stream → Stream

∗ Pre: nessuna

∗ Post: s2 e’ lo stream ottenuto da s1, stampando v.

∗ Post: s2 e’ lo stream ottenuto da s1, stampando m. La stampa avviene stampando i luoghi, e per ciascun luogo, l’insieme di segmenti che lo raggiungono.

Nella specifica di sopra abbiamo implicitamente definito due tipi di dato a noi sconosiuti: i luoghi ed i segmenti. Occorre caratterizzare tali oggetti. Iniziamo dai segmenti:

– Segment(p1, p2, l) → s: Places × Places × R → Segments

∗ Pre: nessuna

∗ Post: s e’ un tratto di strada che congiunge i segmenti p1 e p2, di lunghezza l.

– getLenght(s) → l: Segments → R

∗ Pre: nessuna

∗ Post: l e’ la lunghezza della strada l.

– getF rom(s) → p: Segments → Places

∗ Pre: nessuna

∗ Post: p e’ il luogo da cui il segmento s parte.

– getT o(s) → p: Segments → Places

∗ Pre: nessuna

∗ Post: p e’ il luogo a cui il segmento s arriva.

Caratterizziamo ora gli insiemi di tratti di strada

– SegmentContainer() → ss: void → SegmentContainer

∗ Pre: nessuna

∗ Post: ss e’ container vuoto.

(6)

– addSegment(ss1, s) → ss2: SegmentContainer × Segments → SegmentContainer

∗ Pre: s non e’ contenuto in ss

∗ Post: ss2 e’ il set ottenuto da ss1 aggoingendo il segmento s.

– removeSegment(ss1, s) → ss2: SegmentContainer × Segments → SegmentContainer

∗ Pre: s e’ contenuto in ss

∗ Post: ss2 e’ il set ottenuto da ss1 rimuovendo il segmento s.

visto che implementeremo la classe SegmentContainer mediante un array, avremo bisogno di qualche metodo ausiliario per scandirla (questo fa parte dell’implementazione e non e’ necessario ma tornera’

utile).

– numSegments(ss) → n: SegmentContainer → N

∗ Pre: nessuna

∗ Post: n e’ il numero di segmenti in ss.

– getIndex(ss, s) → n: SegmentContainer × Segments → N

∗ Pre: nessuna

∗ Post: n e’ l’indice dell’array in ss alla cui posizione si trova s. Se s non e’ in ss, n = −1 – segmentAt(ss, n) → s: SegmentContainer × N → Segments

∗ Pre: n > 0 and n < numSegments(ss)

∗ Post: s = ss[n]

Ora andiamo ai luoghi

– P lace(name, ss) → p: Strings × SegmentContainer → Places

∗ Pre: tutti i segmenti in ss partono o terminano in p

∗ Post: p e’ un luogo di nome name.

– getN ame(p) → s: Places → Strings

∗ Pre: nessuna

∗ Post: s e’ il nome di p.

– getSegments(p) → ss: Places → Strings

∗ Pre: nessuna

∗ Post: s e’ l’insieme di luoghi di p.

Per simmetria (e semplicita’ di implementazione) aggiungeremo ai domini di interesse anche l’insieme di luoghi

• numP laces(ps) → n: PlaceContainer → N – Pre: nessuna

– Post: n e’ il numero di Placei in ps.

• getIndex(ps, p) → n: PlaceContainer × Places → N – Pre: nessuna

– Post: n e’ l’indice dell’array in ps alla cui posizione si trova p. Se p non e’ in ps, n = −1

• P laceAt(ps, n) → p: PlaceContainer × N → Places – Pre: n > 0 and n < numP laces(ps)

– Post: p = ps[n]

(7)

Abbiamo ora caratterizzato tutti i tipi e le loro operazioni. Nell’uso che faremo con la mappa, e’ improbabile che faremo operazioni con questa, ma e’ probabile che ne scandiremo e modificheremo la struttura. Una mappa e’ un’astrazione di entita’, ed una implementazione con side effect e’ piu’

appropriata.

Nell’implementazione c’e una questione importante da risolvere che e’ la ownership dei tratti di strada (segments). I segmenti sono infatti “posseduti” sia dalla mappa (navigatormap), sia dai places.

Per una implementazione pulita, solo una delle due entita’ potra’ “possedere” i tipi e sara’ incaricata di distruggerli quando questi non sono piu’ necessari. Come regola generale e’ bene che tale entita’ sia la piu’ “grande”, ovvero la “NavigatorMap”, che ha una visione globale delle strutture. Il possessore sara’

colui che compirera’ la distruzione dell’oggetto quando questo non e’ piu’ refrenziato. Le implementazioni di SegmentContainer e PlaceContainer saranno tramite array di puntatori.

Per implementare il programma si consiglia di partire sempre dalla classe piu’ semplice e testare ogni singolo passo dell’implementazione mediante un main di prova.

segment.h

#ifndef _SEGMENT_H_

#define _SEGMENT_H_

// forward declaration class Place;

class Segment { public:

Segment(Place* from_, Place* to_, float length_);

//~Segment(); the degailt destructor is ok, we do not need any;

Place* getFrom();

Place* getTo();

float getLength();

void setLenght(float l);

// prints a segment on the stream, preceded by numSpaces blanks

// the segment is "name of the from location, name of the to location, lenght";

void print(int numSpaces);

private:

Place* _from, *_to;

float _length;

};

// implements a container of segments through an array of pointers to segments.

// each segment is stored by a pointer to the corresponding object class SegmentContainer{

public:

// initializes a place container with 0 elements SegmentContainer();

// deletes a segmentContainer, but it does not deallocate the objects in te pool. To this end you should call the clear() method;

~SegmentContainer();

// adds a segment to the segment container.

// returns false if the segment with the same pointer is already contained in the pool, false othrwise bool addSegment(Segment* p);

// removes a segment pointed by p from the place container

// if erasePointer is true, also the pointer to the object is erased // returns false if the element is not in the array of places;

bool removeSegment(Segment* p, bool erasePointer);

// returns the place at position i in the array. ) otherwise;

Segment* getSegmentAt(int i);

(8)

// returns the index of a place in the pool, -1 if the element is not present in the pool int getIndex(Segment* p);

// returns the number of places in the pool int getNumSegments();

// clears all elements in the vector, and sets te size to 0 // if erasePointer is true, it deletes also the objects pointed // by the elements in the vector;

void clear(bool erasePointer);

protected:

Segment** _segments;

int _numSegments;

};

#endif

segment.cpp

#include "stdio.h"

#include "segment.h"

#include "place.h"

Segment::Segment(Place* from_, Place* to_, float length_) { _from = from_;

_to = to_;

_length = length_;

}

void Segment::print(int numSpaces) { for (int i =0; i<numSpaces; i++)

printf (" ");

printf ("%s %s %f\n", _from->getName(), _to->getName(), _length);

}

Place* Segment::getFrom() { return _from;

}

Place* Segment::getTo() { return _to;

}

float Segment::getLength() { return _length;

}

void Segment::setLenght(float length_){

_length = length_;

}

// implements a container of segments through an array of pointers to segments.

// each segment is stored by a pointer to the corresponding object SegmentContainer::SegmentContainer(){

_numSegments = 0;

_segments = 0;

}

(9)

SegmentContainer::~SegmentContainer(){

clear(false);

}

bool SegmentContainer::addSegment(Segment* p){

if (getIndex(p)>=0) return false;

Segment** newSegments = new Segment*[_numSegments+1];

for (int i=0; i<_numSegments; i++) newSegments[i] = _segments[i];

if (_segments) delete _segments;

_segments = newSegments;

_segments [_numSegments] = p;

_numSegments ++;

return true;

}

bool SegmentContainer::removeSegment(Segment* p, bool erasePointer){

int k = getIndex(p);

if (k<0) return false;

if (erasePointer) delete p;

// special case the vector has only one element and it is the one we have to delete, // we clear all the vector;

if (_numSegments==1) { delete [] _segments;

_numSegments = 0;

_segments = 0;

return true;

}

// create a new array of segments large _numSegments-1;

Segment** newSegments = new Segment*[_numSegments-1];

for (int i=0; i<k; i++)

newSegments[i] = _segments [i];

for (int i=k; i<_numSegments-1; i++) newSegments[i] = _segments [i+1];

delete [] _segments;

_segments = newSegments;

_numSegments--;

return true;

}

Segment* SegmentContainer::getSegmentAt(int i){

if (i>=0 && i<_numSegments) return _segments[i];

return 0;

}

int SegmentContainer::getIndex(Segment* p) { for (int i=0; i<_numSegments; i++)

if (p == _segments [i]) return i;

return -1;

}

int SegmentContainer::getNumSegments() { return _numSegments;

(10)

}

void SegmentContainer::clear(bool erasePointer){

if (erasePointer) {

for (int i=0; i<_numSegments; i++) delete _segments[i];

}

delete [] _segments;

_segments= 0;

_numSegments = 0;

}

place.h

#ifndef _PLACE_H_

#define _PLACE_H_

#include "segment.h"

// forward declaration of a container of segments class SegmentContainer;

// this class describes a place, which is a location in the map // a place is characterized by name, and a set of segments class Place {

public:

// creates a new place with a name Place(char* name);

// deletes a place

~Place();

char* getName();

// prints the place on the stdout, and also prints the places, numSpaces is the number of spaces to be left // before in the line

// numSpaces = 1 does this: " bla bla bla"

// numSpaces = 5 does this: " bla bla bla"

// the bla bla bla is:

// "name of the place \n"

// " segment 1 // " segment 2 // " segment N

void print(int numSpaces);

SegmentContainer& getSegments();

private:

SegmentContainer _segments;

char* _name;

};

// implements a container of places through an array of pointers to places.

// each place is stored by a pointer to the corresponding object class PlaceContainer{

public:

// initializes a place container with 0 elements PlaceContainer();

// deletes the places from the container, does not delete the pointers

~PlaceContainer();

// adds a place to the place container.

// returns false if the place with the same pointer is already contained in the pool, false othrwise

(11)

bool addPlace(Place* p);

// removes a place pointed by p from the place container

// if erasePointer is true, also the pointer to the object is erased // returns false if the element is not in the array of places;

bool removePlace(Place* p, bool erasePointer);

// returns the place at position i in the array. ) otherwise;

Place* getPlaceAt(int i);

// returns the index of a place in the pool, -1 if the element is not present in the pool int getIndex(Place* p);

// returns the number of places in the pool int getNumPlaces();

// clears all places. if erasePointer is true, deletes also the pointers void clear(bool erasePointer);

protected:

Place** _places;

int _numPlaces;

};

#endif

place.cpp

#include <stdio.h>

#include <string.h>

#include "place.h"

Place::Place(char* name){

_name = new char[strlen(name)+1];

strcpy(_name, name);

}

char* Place::getName(){

return _name;

}

Place::~Place() { delete [] _name;

}

// prints the place on the stdout, and also prints the places, numSpaces is the number of spaces to be left // before in the line

// numSpaces = 1 does this: " bla bla bla"

// numSpaces = 5 does this: " bla bla bla"

void Place::print(int numSpaces){

for (int i=0; i< numSpaces; i++) printf(" ");

printf ("%s\n",_name);

for (int i=0; i<_segments.getNumSegments(); i++){

_segments.getSegmentAt(i)->print(numSpaces+2);

} }

SegmentContainer& Place::getSegments() {

(12)

return _segments;

}

PlaceContainer::PlaceContainer(){

_numPlaces = 0;

_places = 0;

}

PlaceContainer::~PlaceContainer(){

clear(false);

}

bool PlaceContainer::addPlace(Place* p){

if (getIndex(p)>=0) return false;

Place** newPlaces = new Place*[_numPlaces+1];

for (int i=0; i<_numPlaces; i++) newPlaces[i] = _places[i];

if (_places) delete _places;

_places = newPlaces;

_places [_numPlaces] = p;

_numPlaces ++;

return true;

}

bool PlaceContainer::removePlace(Place* p, bool erasePointer){

int k = getIndex(p);

if (k<0) return false;

if (erasePointer) delete p;

// special case the vector has only one element and it is the one we have to delete, // we clear all the vector;

if (_numPlaces==1) { delete [] _places;

_numPlaces = 0;

_places = 0;

return true;

}

// create a new array of places large _numPlaces-1;

Place** newPlaces = new Place*[_numPlaces-1];

for (int i=0; i<k; i++) newPlaces[i] = _places [i];

for (int i=k; i<_numPlaces-1; i++) newPlaces[i] = _places [i+1];

delete [] _places;

_numPlaces --;

_places = newPlaces;

return true;

}

Place* PlaceContainer::getPlaceAt(int i) { if (i>=0 && i<_numPlaces)

return _places[i];

return 0;

}

int PlaceContainer::getIndex(Place* p) { for (int i=0; i<_numPlaces; i++)

if (p == _places [i])

(13)

return i;

return -1;

}

int PlaceContainer::getNumPlaces() { return _numPlaces;

}

void PlaceContainer::clear(bool erasePointer){

if (erasePointer) {

for (int i=0; i<_numPlaces; i++) delete _places[i];

}

delete [] _places;

_places = 0;

_numPlaces = 0;

}

navigatormap.h

#ifndef _NAVIGATORMAP_H_

#define _NAVIGATORMAP_H_

#include "segment.h"

#include "place.h"

class NavigatorMap{

public:

//NavigatorMap(); the default constructor calls the constructors of all fields

~NavigatorMap();

// adds a place to the pool. Returns false if a place with the same pointer is already present in the pool bool addPlace(Place* p);

// adds a segment to the pool of segments.

// the segment should have the from and to fields set. If they are not set, to valid places in the pool // the method returns false and rejects the insertion.

// if the segment is inserted also the PlaceContainer of the from and to fields are updated.

bool addSegment(Segment* s);

// This removes a place from the pool of places. returnd false if the place is not existing.

// if the place is existing, it removes also all segments entering and leaving the place bool removePlace(Place* p);

// This removes a segment from the pool of segments. returns false if the segment is not existing.

// if the segment is removed also the segmentcontainers in the vertices are updated;

bool removeSegment(Segment*s);

// returns the place at position i in the placecontainer, -1 if out of bounds Place* getPlaceAt( int i);

// returns the index of the place p in the placecontainer int getPlaceIndex( Place * p);

// returns the segment at position i in the segmentcontainer Segment* getSegmentAt( int i);

int getSegmentIndex(Segment* s);

// prints the map by printing all places void print();

protected:

(14)

PlaceContainer _places;

SegmentContainer _segments;

};

#endif

navigatormap.cpp

#include <stdio.h>

#include "navigatormap.h"

NavigatorMap::~NavigatorMap(){

_places.clear(true);

_segments.clear(true);

}

bool NavigatorMap::addPlace(Place* p) { return _places.addPlace(p);

}

bool NavigatorMap::addSegment(Segment* s){

int idFrom = _places.getIndex(s->getFrom());

int idTo = _places.getIndex(s->getTo());

int idSegment = _segments.getIndex(s);

if (idFrom <0 || idTo <0 || idSegment >=0) // the places are not in the pool return false;

s->getFrom()->getSegments().addSegment(s);

s->getTo()->getSegments().addSegment(s);

_segments.addSegment(s);

return true;

}

bool NavigatorMap::removePlace(Place* p){

int index = _places.getIndex(p);

if (index<0) return false;

// remove all segments in the place to be removed while (p->getSegments().getNumSegments()>0) {

p->getSegments().getSegmentAt(0)->print(3);

removeSegment(p->getSegments().getSegmentAt(0));

}

_places.removePlace(p,true);

return true;

}

// This removes a segment from the pool of segments. returns false if the segment is not existing.

// if the segment is removed also the segmentcontainers in the vertices are updated;

bool NavigatorMap::removeSegment(Segment*s){

int index = _segments.getIndex(s);

if (index<0) return false;

s->getFrom()->getSegments().removeSegment(s,false);

s->getTo()->getSegments().removeSegment(s,false);

return _segments.removeSegment(s,true);

}

// returns the place at position i in the placecontainer, -1 if out of bounds Place* NavigatorMap::getPlaceAt( int i) {

return _places.getPlaceAt(i);

}

// returns the index of the place p in the placecontainer

(15)

int NavigatorMap::getPlaceIndex( Place * p) { return _places.getIndex(p);

}

// returns the segment at position i in the segmentcontainer Segment* NavigatorMap::getSegmentAt( int i){

return _segments.getSegmentAt(i);

}

int NavigatorMap::getSegmentIndex(Segment* s){

return _segments.getIndex(s);

}

// remove all segments in the place to be removed void NavigatorMap::print() {

printf ("the map has %d places and %d segments\n", _places.getNumPlaces(), _segments.getNumSegments());

for (int i=0; i<_places.getNumPlaces(); i++) _places.getPlaceAt(i)->print(0);

}

Riferimenti

Documenti correlati

Methods Five hundred sixty-four cisgender heterosexual and sexual and gender minority individuals, ranging from 18 to 77 years of age (M = 34.66, SD = 11.13), were recruited in 2020

All the information required to build the Markov chain transition matrix can be extracted from the list of trips: in particular, every trip stores the ID of the bike, the time at

If the global trend persists in the next 15 years, China and India will account for almost half of the expected 300 million 25-34 year-olds with tertiary education in 2030 while the

The encapsulation of RK into chitosan microspheres gives an increase in the drug dissolution rate regardless polymer used, except for C B microspheres whose release

The dominant medical model employed in contemporary medical research and clinical practice is grounded an empiricist theory of language. Disea- ses are conceived as

Il refettorio e il capitolo del monastero maschile di Santa Chiara: l’impianto topografico e le scelte decorative, in Committenza artistica, vita religiosa e progettualità

L’espressione – coniata dall’antropologo inglese Gregory Bateson – estende l’idea stessa di ‘ecosistema’ dalla sfera natu- rale all’intelletto umano, dove

Il tramonto apparentemente de- finitivo di questo scenario, a fine Ottocento, in seguito al pensiero epocale di Nietzsche, da un lato frantuma l’orizzonte della disciplina, che si