Per compilare un programma C++ con questa libreria devi aggiungere lo switch
-I /usr/src/classliballa linea di comando del tuo compilatore C++ e
-lclassliballa linea di comando del linker.
La classlib e' una shared libray e puo' essere inclusa in formato binario nei tuoi programmi.
Per poter utilizzare la libreria all'interno dei programmi C++ e' stato realizzato un metodo semplice per l'inclusione degli header; tutte le componenti della libreria possono essere incluse in un programma utilizzando l'include del file usclslib.h. Questo file a sua volta include tutte le componenti necessarie e nel corretto ordine, secondo la dichiarazione di una serie di simboli che controllano l'inclusione.
#define _Use_Arrays // per l'uso degli array (TArray, TIArray, TSArray...)
#define _Use_FixString // per l'uso di FixedString
#define _Use_SQueues // per l'uso di TSIQueue
#define _Use_Prop // per l'uso di PropertyContainer
#include <usclslib.h>
...
...
TArray<FixedString> arStrings(10,0,10);
...
...
Una ispezione del file usclslib.h e' necessaria per il corretto uso della libreria.
Le classi container rappresentanto il corpo principale della libreria. Un nutrito numero di container coprono all'incirca qualsiasi esigenza per la scrittura di programmi in C++.
Ogni oggetto che si voglia inserire nelle classi container deve possedere un valido operatore == per le funzioni di base della libreria. La funzione Find() principalmente usa questo operatore.
Le versioni sortate degli array (TSArray e TISArray) richiedono anche un operatore < per poter riconoscere un ordine fra gli oggetti inseriti.
Per poter utilizzare le forme dirette dei container e' richiesto inoltre che esista un valido operatore = per copiare dati fra le istanze degli oggetti.
In generale per ogni tipo di container due forme sono presenti: diretto e indiretto.
Le classi container dirette mantengono copie di istanze degli oggetti. Questo significa che deve esistere un operatore di copia (operator=) per poter leggere e inserire i dati nei container.
...
// questo va bene: tutti i tipi base hanno operator= e operator==
TArray<double> arDbl(100, 0, 10);
arDbl.add(123.45);
...
...
class myClass
{
public:
int var1, var2, var3;
myClass& operator=(const myClass& c) {
var1 = c.var1;
var2 = c.var2;
var3 = c.var3;
return *this;
}
int operator==(const myClass& c) const { return &c == this; }
};
...
...
TArray<myClass> arMC(10, 0, 10);
myClass c1;
c1.var1 = 10;
c1.var2 = 20;
c1.var3 = 30;
...
// inserice una istanza (NON UN POINTER) nell'array
// l'entry dell'array sara' copiata dall'oggetto c1 tramite l'operatore =
arMC.add(c1);
...
...
I container indiretti mantengono puntatori a oggetti del tipo dichiarato. Un pointer ha sempre una sematica di copia, assicurata dal compilatore, per cui non e' necessario definire un operator= in questo caso.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
myClass c1 = new myClass;
c1->var1 = 10;
c1->var2 = 20;
c1->var3 = 30;
...
// inserisce il puntatore nell'array
// NON CHIAMARE delete SUL PUNTATORE c1
arMC.add(c1);
...
...
Ogni container indiretto supporta un concetto di appartenenza degli oggetti in esso contenuti. Se l'appartenenza e' attiva (questo e' il default per tutti i container indiretti) alla distruzione del container verranno distrutti tutti gli oggetti in esso contenuti, chiamando l'apposito operatore delete. Il comportamento di default puo' essere cambiato utilizzando il metodo
OwnsElements(int own)Se 'own' e' zero l'appartenenza viene disattivata, alrimenti attivata.
In tutte (o quasi) le classi container sono implementate le queste funzioni:
GetItemsInContainer() ritorna il numero di oggetti nel container
IsEmpty() ritorna vero se il container e' vuoto
ForEach() auto iteratore per tutti gli oggetti contenuti
FirstThat() auto iteratore per la ricerca di un elemento
LastThat() auto iteratore per la ricerca di un elemento
Flush() svuota il container
Gli auto iteratori sono particolarmente comodi per eseguire dei task per gli elementi contenuti nei container.
La funzione 'void ForEach( IterFunc iter, void *args )' consente di eseguire una operazione su tutti gli elementi contenuti nel container. Il primo parametro e' una funzione del tipo 'void IterFunc(T&, void *);' che viene chiamata per ogni elemento dell'array passato come primo parametro. Il secondo parametro e' un puntatore ad un dato qualsiasi.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
...
...
void PutValues(myClass& c, void* args)
{
c.var1 = c.var2 = c.var3 = *((int*)(args));
}
...
...
int val = 0;
arMC.ForEach(PutValues, &val);
...
...
ATTENZIONE: se la funzione di iterazione viene dichiarata all'interno di una classe DEVE essere dichiarata static.
La funzione 'T *FirstThat( CondFunc cond, void *args ) const' consente di definire un confronto ad hoc per la ricerca del primo elemento nell'array che la soddisfi. In modo analogo 'T *LastThat( CondFunc cond, void *args ) const' ritorna l'ultimo elemento del container. Entrambe le funzioni utilizzano come primo parametro una funzione con un prototipo del tipo 'int CondFunc(const T&, void *);'.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
...
...
int searchEqualValues(const myClass& c, void* args)
{
return c.var1 == *((int*)(args));
}
...
...
int val = 0;
myClass* ptMy = arMC.FirstThat(searchEqualValues, &val);
if(ptMy != NULL) {
// ptMy punta al primo elemento che soddisfa la condizione var1 == 0
...
}
...
...
int val = 0;
myClass* ptMy = arMC.LastThat(searchEqualValues, &val);
if(ptMy != NULL) {
// ptMy punta all'ultimo elemento che soddisfa la condizione var1 == 0
...
}
...
...
ATTENZIONE: se la funzione di iterazione viene dichiarata all'interno di una classe DEVE essere dichiarata static.
Per ogni classe container esiste un equivalente iteratore per scorrere gli elementi contenuti nel container. Il nome della classe iteratore e' lo stesso della classe container con l'aggiunta di 'Iterator' alla fine. Ogni iteratore ha un operatore int che ritorna diverso da zero fino a quando ci sono elementi da iterare e un operatore ++ per avanzare all'elemento successivo. Un metodo Current() restituisce l'elemento corrente dell'iterazione. Un metodo Restart() fa ripartire l'iterazione dal primo elemento.
...
class myClass
{
public:
int var1, var2, var3;
int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
...
...
TIArrayIterator<myClass> itrMC(arMC);
while(itrMC) {
const myClass* c = itrMC.Current();
...
...
itrMC++;
}
...
...
for(itrMC.Restart() ; itrMC ; itrMC++)
{
const myClass* c = itrMC.Current();
...
...
}
...
...
Una serie di classi di utilita' offrono una serie di semplici soluzioni a problemi frequenti nella programmazione:
1) PropertyContainer lettura/scrittura di parametri da file di configurazione (chiave=valore).
2) Funzioni template per uso generale.
3) Socket comunicazioni client/server TCP, UDP, UNIX domain socket.
4) Multitask semplice implementazione di mutex, semafori, ecc. per la programmazione multitask.
La classe PropertyContainer implementa il reperimento di valore associato a chiave. Essa consente di gestire facilemente file di configurazione in formato ASCII, potendo leggere direttamente un file formattato secondo la classica sintassi UNIX dei files di configurazione.
La classe PropertyContainer utilizza un dizionario con tabella di hashing per l'implementazione.
#
# QUESTO E' IL MIO FILE DI CONFIGURAZIONE (/etc/mio.conf)
#
# imposta il valore della proprita' host e port
host=www.winada.it
port=8080
Questo file puo' essere letto cosi':
PropertyContainer p;
p.loadFile("/etc/mio.conf");
FixString hostName = p.getProperty("host", "localhost");
int port = p.getPropertyInt("port", 7000);
...
...
Una serie di comode funzioni template per ottenere il massimo, il minimo (anche fra tre valori) e similari sono presenti nel file stdtempl.h. Vedi il file per ulteriori dettagli.
Vedi l'apposita sezione piu' avanti.
Nella programmazione multithread sono necessari alcuni oggetti comunemente noti com mutex, semafori, eventi. Per ognuno di questi esiste una apposita classe illustrata piu' avanti con specifiche caratteristiche.
Una corposa parte della libreria racchiude una serie di funzioni matematiche implementate sotto forma di classi di oggetti, per la manipolazione di dati e strutture geometriche in 2D e 3D.
Le classi Punto2D e Punto3D implementano un concetto di punto nello spazio bidibmensionale e tridimensionale. Le Linea2D e Linea3D rappresentano un concetto di linea nello spazio 2D e 3D. La classe Matrix3 viene utilizzata per elaborare le trasformazioni (calcolo matriciale) da applicare ai punti e alle linee.
Vedi l'apposita sezione per i dattagli.