Files
ta-splitting/antclass.c
2019-02-22 17:33:33 +00:00

756 lines
15 KiB
C

/** antclass.c **/
/*
* Manipulacje klasami abstrakcyjnymi, tworzenie nowych,
* modyfikowanie ich parametrow, sprawdzanie, etc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include "antclass.h"
#include "anpsmod.h"
#include "anproc.h"
#include "antypes.h"
#include "anmacro.h"
#include "macro.h"
#include "dbm.h"
/*
* Tworzenie klasy
*/
TimedClass_set *
tclass_create(ProdLoc_set *loc, DBM_elem *zone, DBM_elem *cor, dpt_t depth)
{
TimedClass_set *new_tclass;
new_tclass = tclass_create_nd(loc, zone, cor);
new_tclass->depth = depth;
return new_tclass;
}
/*
* Tworzenie klasy bez okreslania glebokosci
*/
TimedClass_set *
tclass_create_nd(ProdLoc_set *loc, DBM_elem *zone, DBM_elem *cor)
{
TimedClass_set *new_tclass;
new_tclass = smalloc(sizeof(TimedClass_set));
new_tclass->dbm = zone;
new_tclass->cor_dbm = cor;
/*new_tclass->depth = depth;*/
new_tclass->loc_set = loc;
new_tclass->rs = NULL;
new_tclass->stable_pre = NULL;
new_tclass->stable_succ = NULL;
new_tclass->next = NULL;
return new_tclass;
}
/*
* Tworzenie domyslnej klasy wyjsciowej dla odkrytej lokacji
*/
TimedClass_set *
tclass_create_base(ProdLoc_set *loc)
{
/* Nowa klasa rowna niezmiennikowi (z cor rownym rowniez niezmiennikowi) */
return tclass_create(loc, NULL, NULL, DEPTH_INF);
}
/*
* Dodawanie klasy do zbioru klas (przyczepianie do odpowiedniej lokacji)
*/
void
tclass_add(TimedClass_set *tclass)
{
ProdLoc_set *loc;
#ifdef TC_VERBOSE
printf("tclass_add (%p): ", tclass); tclass_print(tclass); printf("\n");
#endif
loc = tclass->loc_set;
if (!loc->classes)
loc->classes = tclass;
else
loc->last_class->next = tclass;
loc->last_class = tclass;
}
/*
* Usuwanie klasy ze zbioru wszystkich klas nalezacych do podzialu
*
* przez koniecznosc szukania poprzedniego elementu listy moze byc
* nieco bolesne, ale oszczedzamy troche pamieci ;)
*
* W praktyce na razie funkcja okazuje sie raczej nieprzydatna, bo
* wykorzystujemy istniejace klasy i zmieniamy w nich strefy.
*
* UWAGA: brakuje usuwania informacji o klasach stabilnych (trzeba
* zwolnic pamiec).
*/
// void
// tclass_del(TimedClass_set *tclass)
// {
// ProdLoc_set *loc;
// TimedClass_set *tmp, *prev = NULL;
//
// loc = tclass->loc_set;
//
// for (tmp = loc->classes; tmp; prev = tmp, tmp = tmp->next)
// {
// if (tmp == tclass)
// {
// if (prev) /* usuwamy dalej niz z poczatku */
// {
// prev->next = tmp->next;
//
// /* usuwamy z konca */
// if (tmp == loc->last_class)
// loc->last_class = prev;
// }
// else /* usuwamy z poczatku */
// {
// loc->classes = tmp->next;
// /* tutaj nie aktualizujemy last_class, bo jak korzen
// * bedzie NULL, to nie patrzymy na last_class.
// */
// }
//
// if (tmp->dbm) dbm_destroy(tmp->dbm);
// if (tmp->cor_dbm) dbm_destroy(tmp->cor_dbm);
// free(tmp);
//
// return;
// }
// }
//
// assert(0); /* jesli jestesmy tutaj, to nie znalezlismy klasy do usuniecia */
// }
void
tclass_print(TimedClass_set *tc)
{
printf("{"); prod_loc_show(tc->loc_set->loc);
printf(" Z=");
dbm_xprint(tclass_readZoneDBM(tc), dbm_size);
if (!tc->dbm) printf("=(inv)");
printf(" Cor=");
if (tc->cor_dbm)
dbm_xprint(tc->cor_dbm, dbm_size);
else
printf("(zone)");
printf(" dpt=");
if (tc->depth != DEPTH_INF)
printf("%u", tc->depth);
else
printf("inf");
printf("} ");
}
/*
* Funkcja zwracajaca adres DBM ze strefa klasy w celu jego ODCZYTANIA
* UWAGA: nie jest tworzona kopia, uwazac zeby nie zmodyfikowac!
*/
DBM_elem *
tclass_readZoneDBM(TimedClass_set *tclass)
{
if (!tclass->dbm) return tclass->loc_set->inv;
else return tclass->dbm;
}
/*
* Funkcja zwracajaca adres DBM z cor klasy w celu jego ODCZYTANIA
* UWAGA: nie jest tworzona kopia, uwazac zeby nie zmodyfikowac!
*/
DBM_elem *
tclass_readCorDBM(TimedClass_set *tclass)
{
/* jesli cor == NULL, to jest taki sam jak zone */
if (!tclass->cor_dbm) return tclass_readZoneDBM(tclass);
else return tclass->cor_dbm; /* cor ustawiony jawnie (niedomyslny) */
}
/*
* Funkcja zwracajaca strefe klasy gotowa do modyfikowania
*/
DBM_elem *
tclass_writeZoneDBM(TimedClass_set *tclass)
{
if (!tclass->dbm) tclass->dbm = dbm_copy(tclass->loc_set->inv, dbm_size);
return tclass->dbm;
}
/*
* Funkcja zwracajaca cor klasy gotowy do modyfikowania
*/
DBM_elem *
tclass_writeCorDBM(TimedClass_set *tclass)
{
if (!tclass->cor_dbm) tclass->cor_dbm = dbm_copy(tclass_readZoneDBM(tclass), dbm_size);
return tclass->cor_dbm;
}
/*
* Funkcje pomocnicze do przenoszenia DBM-ow do nowych klas
* (unikanie kopiowania)
*
* Po uzyciu ktorejs z nich klasa jest zdegenerowana,
* tzn. cor i zone moga nie odpowiadac wlasciwej klasie.
*/
/*
DBM_elem *
tclass_consumeZoneDBM(TimedClass_set *tclass)
{
DBM_elem *rlt;
rlt = tclass_writeZoneDBM(tclass);
tclass->dbm = NULL;
return rlt;
}
DBM_elem *
tclass_consumeCorDBM(TimedClass_set *tclass)
{
DBM_elem *rlt;
rlt = tclass_writeCorDBM(tclass);
tclass->cor_dbm = NULL;
return rlt;
}
*/
/*
* Podmienianie strefy klasy, cor domyslnie taki sam jak calosc klasy
*/
void
tclass_replaceZoneDBM(TimedClass_set *tclass, DBM_elem *new_dbm)
{
DBM_elem *tmp;
assert(!dbm_empty(new_dbm, dbm_size));
#ifdef TC_VERBOSE
printf("tclass_replaceZoneDBM: nowy zone dla klasy (%p) ", tclass); tclass_print(tclass);
printf("; nowy zone: "); dbm_xprint(new_dbm, dbm_size); printf("\n");
#endif
tmp = tclass->dbm;
tclass->dbm = dbm_copy(new_dbm, dbm_size);
if (tmp) dbm_destroy(tmp);
if (tclass->cor_dbm) dbm_destroy(tclass->cor_dbm);
tclass->cor_dbm = NULL;
}
/*
* Podmienianie cor klasy
*/
void
tclass_replaceCorDBM(TimedClass_set *tclass, DBM_elem *new_cor)
{
DBM_elem *tmp;
assert(!dbm_empty(new_cor, dbm_size));
tmp = tclass->cor_dbm;
tclass->cor_dbm = dbm_copy(new_cor, dbm_size);
if (tmp) dbm_destroy(tmp);
}
void
tclass_depthUpdateIncr(TimedClass_set *tclass, TimedClass_set *pre_tclass)
{
dpt_t new_depth;
if (pre_tclass->depth < DEPTH_INF-1)
{
new_depth = pre_tclass->depth+1;
if (new_depth < tclass->depth)
{
tclass->depth = new_depth;
}
}
else
{
FERROR("Depth overflow!");
}
}
/*
* Ustawianie glebokosci klasy na inf jesli nie zawiera
* ona stanu poczatkowego q0
*/
void
tclass_depthUpdateInf(TimedClass_set *tclass)
{
if (!tclass_hasInit(tclass))
{
assert(!tclass->rs); /* jak inf, to nie moze byc w RS */
tclass->depth = DEPTH_INF;
}
}
/*
* Sprawdzanie czy klasa zawiera stan poczatkowy q0
*/
bool
tclass_hasInit(TimedClass_set *tclass)
{
DBM_elem *tmp;
bool has_init = false;
if (tclass->loc_set == init_loc_set) /* zgodnosc lokacji */
{
/*dbm_print(tclass_readZoneDBM(tclass), dbm_size);*/
assert(dbm_is_canonical(tclass_readZoneDBM(tclass), dbm_size));
tmp = dbm_intersection_cf(tclass_readZoneDBM(tclass), zeroDBM, dbm_size);
if (!dbm_empty(tmp, dbm_size)) has_init = true;
dbm_destroy(tmp);
}
return has_init;
}
/*
* Do poprawy. Trzeba troche zmienic struktury danych, bo to szukanie jest mordercze.
*/
bool
tclass_is_in_ReachStable(TimedClass_set *tclass)
{
if (tclass->rs) return true;
else return false;
}
/*
* Dodawanie klasy do zbioru reachable+stable klas
*/
void
tclass_ReachStable_add(TimedClass_set *new_class, TimedClassRS_set **root, TimedClassRS_set **cur)
{
assert(new_class->depth != DEPTH_INF);
assert(tclass_ReachStable_is_sorted(*root));
if (!tclass_is_in_ReachStable(new_class))
{
TimedClassRS_set *new, *pred;
new = smalloc(sizeof(TimedClassRS_set));
new->tclass = new_class;
new->stable = false;
new_class->rs = new;
if (!*root)
{
new->prev = NULL;
new->next = NULL;
*root = *cur = new;
}
else
{
/* cofamy sie do elementu o glebokosci nie wiekszej od naszej (po ktorym chcemy dodac nowy element) > */
for (pred = *cur; pred->tclass->depth > new_class->depth; pred = pred->prev);
new->next = pred->next;
new->prev = pred; /* poprzedni element to ostatnio dodany */
if (pred->next) {
pred->next->prev = new;
}
pred->next = new;
if (pred == *cur) *cur = new;
}
}
assert(tclass_ReachStable_is_sorted(*root));
}
/*
* Dodawanie klasy zawierajacej stan q0 do zbioru
*/
void
tclass_ReachStable_addInit(TimedClass_set *new_class, TimedClassRS_set **root, TimedClassRS_set **cur)
{
TimedClassRS_set *new;
if (!tclass_is_in_ReachStable(new_class))
{
assert(new_class->depth != DEPTH_INF);
new = smalloc(sizeof(TimedClassRS_set));
new->tclass = new_class;
new->stable = false;
new->next = *root; /* pod nowy element podczepiamy korzen */
new->prev = NULL; /* bo dodajemy na poczatku */
new_class->rs = new;
if (!*root) /* jesli lista byla pusta, to trzeba zaktualizowac cur, bo nowy bedzie ostatni */
{
*cur = new;
}
else
{
assert(*root != NULL);
(*root)->prev = new;
}
*root = new; /* lista zaczyna sie od nowego elementu */
assert(tclass_ReachStable_is_sorted(*root));
}
}
/*
* Usuwanie klasy ze zbioru klas
*/
void
tclass_ReachStable_delete(TimedClass_set *del_class, TimedClassRS_set **root, TimedClassRS_set **cur)
{
#ifdef TC_VERBOSE
printf("Usuwam klase (%p) ze zbioru ReachStable: ", del_class);
tclass_print(del_class);
#endif
if (tclass_is_in_ReachStable(del_class))
{
TimedClassRS_set *tmpRS;
tmpRS = del_class->rs;
if (tmpRS->next)
tmpRS->next->prev = tmpRS->prev;
if (tmpRS->prev)
tmpRS->prev->next = tmpRS->next;
if (tmpRS == *root)
*root = NULL;
else
if (tmpRS == *cur) *cur = tmpRS->prev;
free(tmpRS);
del_class->rs = NULL;
#ifdef TC_VERBOSE
printf("faktycznie usuwana\n");
tclass_ReachStable_print(*root);
#endif
}
#ifdef TC_VERBOSE
else
{
printf("nie bylo co usuwac\n");
}
#endif
}
/*
* Zwalnianie pamieci przydzielonej na strukture zbioru (bez faktycznych klas)
*/
/*void
tclass_ReachStable_free(TimedClassRS_set **root)
{
}*/
/*
* Oznaczanie klasy jako osiagalna i niestabilna (czyli dodawanie do zbioru)
*/
void
tclass_mark_reach_unst(TimedClass_set *tclass, TimedClassRS_set **root, TimedClassRS_set **cur)
{
tclass_ReachStable_add(tclass, root, cur);
}
/*
* Oznaczanie klasy jako osiagalna (dodawanie klasy do zbioru reachable)
*/
void
tclass_rs_mark_stable(TimedClassRS_set *tclass_rs)
{
tclass_rs->stable = true;
}
/*
* Znajdowanie klasy tclass i oznaczanie jako stabilna
*/
void
tclass_mark_stable(TimedClass_set *tclass)
{
assert(tclass->rs != NULL);
tclass->rs->stable = true;
}
/*
* Znajdowanie klasy tclass i oznaczanie jako niestabilna
*/
void
tclass_mark_unstable(TimedClass_set *tclass)
{
if (tclass->rs)
tclass->rs->stable = false;
}
/*
* Oznaczanie wszystkich poprzednikow danej klasy jako niestabilne
*/
void
tclass_mark_preds_unstable(TimedClass_set *tclass)
{
SrcLoc_set *src_loc;
TimedClass_set *tclass_src;
ProdTrans_set *trans_e;
for (src_loc = tclass->loc_set->src_locs; src_loc; src_loc = src_loc->next)
{
for (tclass_src = src_loc->loc_set->classes; tclass_src; tclass_src = tclass_src->next)
{
for (trans_e = src_loc->trans; trans_e; trans_e = trans_e->next)
{
if (!psmodel_pre_empty(trans_e, src_loc->loc_set, tclass->loc_set,
tclass_readZoneDBM(tclass_src), tclass_readZoneDBM(tclass)))
{
tclass_mark_unstable(tclass_src);
}
}
}
}
}
TimedClassRS_set *
tclass_pickReachUnst(TimedClassRS_set *root)
{
TimedClassRS_set *curRS;
assert(tclass_ReachStable_is_sorted(root));
/* szukamy pierwszego niestabilnego elementu (od korzenia) */
for (curRS = root; curRS; curRS = curRS->next)
{
if (curRS->stable == false)
{
return curRS;
}
}
return NULL;
}
/*
* Sprawdzanie czy lista ReachStable jest posortowana
*/
bool
tclass_ReachStable_is_sorted(TimedClassRS_set *root)
{
TimedClassRS_set *curRS;
dpt_t min_depth = 0;
for (curRS = root; curRS; curRS = curRS->next)
{
if (curRS->tclass->depth < min_depth)
return false;
min_depth = curRS->tclass->depth;
}
return true;
}
/*
* Wyswietlanie wszystkich stabilnych klas nalezacych do zbioru RS
*/
void
tclass_ReachStable_print(TimedClassRS_set *root)
{
TimedClassRS_set *curRS;
idx_t i;
for (curRS = root, i = 1; curRS; curRS = curRS->next, i++)
{
printf("(%u) (%p) ", i, curRS->tclass); tclass_print(curRS->tclass);
if (!curRS->stable) printf("UNSTABLE!!!");
printf("\n");
}
}
/*
* Zapamietywanie stabilnego nastepnika
*/
void
tclass_saveStable(TimedClass_set *tcX, TimedClass_set *tcY)
{
TClassPtr_set *new;
assert(tclass_isReallyStableSucc(tcX, tcY));
if (!tclass_is_in_tcPtrs(tcY, tcX->stable_succ))
{
new = smalloc(sizeof(TClassPtr_set));
new->tclass = tcY;
new->next = tcX->stable_succ;
tcX->stable_succ = new;
}
if (!tclass_is_in_tcPtrs(tcX, tcY->stable_pre))
{
new = smalloc(sizeof(TClassPtr_set));
new->tclass = tcX;
new->next = tcY->stable_pre;
tcY->stable_pre = new;
}
}
/*
* Usuwanie informacji o poprzednikach stabilnych
* wzgledem danej klasy tcY.
*/
void
tclass_forgetPreStability(TimedClass_set *tcY)
{
TClassPtr_set *tcptr;
if (tcY->stable_pre)
{
for (tcptr = tcY->stable_pre; tcptr; )
{
TClassPtr_set *tmp;
/* zagladamy do kazdego poprzednika i usuwamy sie z jego stable_succ */
tclass_tcPtrDel(tcY, &tcptr->tclass->stable_succ);
tmp = tcptr;
tcptr = tcptr->next;
free(tmp);
}
tcY->stable_pre = NULL;
}
}
/*
* Usuwanie informacji o nastepnikach wzgledem
* ktorych jest stabilna dana klasa tcX.
*/
void
tclass_forgetSuccStability(TimedClass_set *tcX)
{
TClassPtr_set *tcptr;
if (tcX->stable_succ)
{
for (tcptr = tcX->stable_succ; tcptr; )
{
TClassPtr_set *tmp;
/* zagladamy do kazdego nastepnika i usuwamy sie z jego stable_pre */
tclass_tcPtrDel(tcX, &tcptr->tclass->stable_pre);
tmp = tcptr;
tcptr = tcptr->next;
free(tmp);
}
tcX->stable_succ = NULL;
}
}
void
tclass_tcPtrDel(TimedClass_set *tc, TClassPtr_set **tcptr)
{
TClassPtr_set *tmp, *prev = NULL;
for (tmp = *tcptr; tmp; prev = tmp, tmp = tmp->next)
{
if (tmp->tclass == tc)
{
if (prev)
prev->next = tmp->next;
else
*tcptr = tmp->next;
free(tmp);
return;
}
}
}
bool
tclass_is_in_tcPtrs(TimedClass_set *tc, TClassPtr_set *tcptr)
{
TClassPtr_set *tmp;
for (tmp = tcptr; tmp; tmp = tmp->next)
if (tmp->tclass == tc) return true;
return false;
}
/*
* Sprawdzanie czy klasa tcY jest stabilnym nastepnikiem tcX
*/
bool
tclass_isStableSucc(TimedClass_set *tcX, TimedClass_set *tcY)
{
if(tclass_is_in_tcPtrs(tcY, tcX->stable_succ))
{
assert(tclass_isReallyStableSucc(tcX, tcY));
return true;
}
else
{
return false;
}
}
/*
* Sprawdzanie czy faktycznie mamy wlasciwie zapamietana stabilnosc
*/
bool
tclass_isReallyStableSucc(TimedClass_set *tcX, TimedClass_set *tcY)
{
ProdTrans_set *trans_h;
/* W rzeczywistosci interesuje nas tylko istnienie jakiegos przejscia dla ktorego jest AE */
for (trans_h = trans_get(tcX->loc_set, tcY->loc_set); trans_h; trans_h = trans_h->next)
{
if (psmodel_pre_eq(tclass_readCorDBM(tcX), trans_h, tcX->loc_set, tcY->loc_set,
tclass_readCorDBM(tcX), tclass_readCorDBM(tcY)))
return true;
}
return true;
}
unsigned int
tclass_count(ProdLoc_set *locs)
{
ProdLoc_set *loc;
unsigned int nclasses = 0;
for (loc = locs; loc; loc = loc->next)
{
TimedClass_set *tclass;
for (tclass = loc->classes; tclass; tclass = tclass->next)
{
nclasses++;
}
}
return nclasses;
}