Successivo: , Precedente: , Su: Descrizione dell'estensione API   [Contenuti][Indice]


17.4.2 I tipi di dati di impiego generale

Ho un vero rapporto di amore/odio con le unioni.

Arnold Robbins

Questo è ciò che contraddistingue le unioni: il compilatore è in grado di accomodare le cose in modo da far coesistere amore e odio.

Chet Ramey

L’estensione API definisce un certo numero di semplici tipi di dato e strutture di uso generale. Ulteriori strutture di dati, più specializzate, saranno introdotte nelle successive sezioni, insieme alle funzioni che ne fanno uso.

I tipi di dati e le strutture di uso generale sono le seguenti:

typedef void *awk_ext_id_t;

Un valore di questo tipo è trasmesso da gawk a un’estensione nel momento in cui viene caricata. Tale valore dev’essere restituito a gawk come primo parametro di ogni funzione API.

#define awk_const …

Questa macro genera delle ‘costanti’ nel momento in cui si compila un’estensione, e non genera nulla quando si compila il comando gawk vero e proprio. Ciò rende alcuni campi nelle strutture dei dati dell’API non alterabili dal codice sorgente dell’estensione, ma consente al comando gawk di usarle secondo necessità.

typedef enum awk_bool {
    awk_false = 0,
    awk_true
} awk_bool_t;

Un semplice tipo di variabile booleana.

typedef struct awk_string {
    char *str;     /* dati veri e propri */
    size_t len;    /* lunghezza degli stessi, in caratteri */
} awk_string_t;

Questo rappresenta una stringa modificabile. gawk è responsabile per la gestione della memoria utilizzata, se ha fornito il valore della stringa. Altrimenti, assume il possesso della memoria in questione. Questa memoria dev’essere resa disponibile chiamando una delle funzioni gawk_malloc(), gawk_calloc() o gawk_realloc()!

Come già detto, la rappresentazione delle stringhe in memoria usa la codifica multibyte corrente.

typedef enum {
    AWK_UNDEFINED,
    AWK_NUMBER,
    AWK_STRING,
    AWK_REGEX,
    AWK_STRNUM,
    AWK_ARRAY,
    AWK_SCALAR,         /* accesso opaco a una variabile */
    AWK_VALUE_COOKIE    /* per aggiornare un valore
                        già creato */
} awk_valtype_t;

L’elenco enum indica di che tipo è un certo valore. È usato nella seguente struttura struct.

typedef struct awk_value {
    awk_valtype_t val_type;
    union {
        awk_string_t       s;
        awknum_t           n;
        awk_array_t        a;
        awk_scalar_t       scl;
        awk_value_cookie_t vc;
    } u;
} awk_value_t;

Un “valore di awk”. Il campo val_type indica che tipo di valore union contiene, e ogni campo è del tipo appropriato.

#define str_value      u.s
#define strnum_value   str_value
#define regex_value    str_value
#define num_value      u.n.d
#define num_type       u.n.type
#define num_ptr        u.n.ptr
#define array_cookie   u.a
#define scalar_cookie  u.scl
#define value_cookie   u.vc

L’uso di queste macro rende più facile da seguire l’accesso ai campi di awk_value_t.

enum AWK_NUMBER_TYPE {
    AWK_NUMBER_TYPE_DOUBLE,
    AWK_NUMBER_TYPE_MPFR,
    AWK_NUMBER_TYPE_MPZ
};

La lista enum è usata nella struttura seguente per definire il tipo di valore numerico con cui si ha a che fare. Va dichiarata al livello più alto del file, in modo da poter essere usata sia con il linguaggio C++ che con il C.

typedef struct awk_number {
    double d;
    enum AWK_NUMBER_TYPE type;
    void *ptr;
} awk_number_t;

Questo rappresenta un valore numerico. Internamente, gawk memorizza ogni numero o come una variabile C di tipo double, o come un numero intero GMP, o come un numero MPFR in virgola mobile di precisione arbitraria. Per consentire alle estensioni di supportare valori numerici GMP ed MPFR, i valori numerici sono trasmessi utilizzando questa struttura.

L’elemento in doppia-precisione d è sempre presente nei dati ricevuti da gawk. Inoltre, esaminando il membro type, un’estensione è in grado di determinare se il membro puntato da ptr sia un numero intero GMP (tipo mpz_ptr), o un numero MPFR in virgola mobile (tipo mpfr_ptr_t), e trasformarlo a seconda delle necessità.

typedef void *awk_scalar_t;

La variabili scalari possono essere rappresentate da un tipo opaco. Questi valori sono ottenuti da gawk e in seguito gli vengono restituiti. Questo argomento è discusso in maniera generale nel testo che segue questa lista, e più in dettaglio in Accedere alle variabili per “cookie” e aggiornarle.

typedef void *awk_value_cookie_t;

Un “value cookie” è un tipo di variabile opaca, e rappresenta un valore nascosto. Anche questo argomento è discusso in maniera generale nel testo che segue questa lista, e più in dettaglio in Creare e usare valori nascosti.

I valori di tipo scalare in awk sono numeri, stringhe, strnum o regexp fortemente tipizzate. La struttura awk_value_t rappresenta valori. Il campo val_type indica cosa contiene union.

Rappresentare numeri è facile: l’API usa una variabile C di tipo double. Le stringhe richiedono uno sforzo maggiore. Poiché gawk consente che le stringhe contengano dei byte NUL (a zeri binari) nel valore di una stringa, una stringa dev’essere rappresentata da una coppia di campi che contengono il puntatore al dato vero e proprio e la lunghezza della stringa. È questo è il tipo awk_string_t.

Un valore di tipo strnum (stringa numerica) è rappresentato come una stringa e consiste di dati in input forniti dall’utente che appaiono essere numerici. Quando una funzione di estensione crea un valore di tipo strnum, il risultato è una stringa che viene marcata come immessa dall’utente. La successiva analisi da parte di gawk servirà poi a determinare se la stringa appare essere un numero, e va quindi trattata come strnum, invece che come una normale stringa di caratteri.

Ciò è utile nei casi un cui una funzione di estensione desideri fare qualcosa di paragonabile alla funzione split, la quale imposta l’attributo di strnum agli elementi di vettore che crea. Per esempio, un’estensione che implementi la divisione di record CSV (Comma Separated Values, i cui elementi sono delimitati da virgole) potrebbe voler usare questa funzionalità. Un’altra situazione in cui ciò è utile è quello di una funzione che richieda campi-dati ad una banca di dati. La funzione PQgetvalue() della banca dati PostgreSQ, per esempio, restituisce una stringa che può essere numerica o di tipo carattere, a seconda del contesto.

I valori di regexp fortemente tipizzate (vedi la sezione Costanti regexp fortemente tipizzate non sono molto utili nelle funzioni di estensione. Le funzioni di estensione possono stabilire di averli ricevuti, e crearne, attribuendo valori di tipo scalare. In alternativa, è possibile esaminare il testo della regexp utilizzando campi regex_value.str e regex_value.len.

Identificativi (cioè, nomi di variabili globali) possono essere associati sia a valori scalari che a vettori. Inoltre, gawk consente veri vettori di vettori, in cui ogni singolo elemento di un vettore può a sua volta essere un vettore. La spiegazione dei vettori è rinviata a Manipolazione di vettori.

La varie macro sopra elencate facilitano l’uso degli elementi delle union come se fossero campi in una struttura struct; è questa una pratica comunemente adottata nella scrittura di programmi in C. Questo tipo di codice è più semplice da scrivere e da leggere, ma resta una responsabilità del programmatore assicurarsi che il campo val_type rifletta correttamente il tipo del valore contenuto nella struttura awk_value_t.

Dal punti di vista concettuale, i primi tre campi dell’union (numero, stringa, e vettore) sono sufficienti per lavorare con i valori awk. Tuttavia, poiché l’API fornisce routine per ottenere e modificare il valore di una variabile scalare globale usando solo il nome della variabile, si ha qui una perdita di efficienza: gawk deve cercare la variabile ogni volta che questa è utilizzata e modificata. Questo è un probelma reale, non solo un problema teorico.

Per questo motivo, se si sa che una certa estensione passerà molto tempo a leggere e/o modificare il valore di una o più variabili scalari, si può ottenere uno scalar cookie108 per quella variabile, e poi usare il cookie per ottenere il valore della variabile o per modificarne il valore. Il tipo awk_scalar_t contiene uno scalar cookie, e la macro scalar_cookie fornisce accesso al valore di quel tipo nella struttura awk_value_t. Dato uno scalar cookie, gawk può trovare o modificare direttamente il valore, come richiesto, senza bisogno di andarlo a cercare ogni volta.

Il tipo awk_value_cookie_t e la macro value_cookie sono simili. Se si pensa di dover usare lo stesso valore numerico o la stessa stringa per una o più variabili, si può creare il valore una volta per tutte, mettendo da parte un value cookie per quel valore, e in seguito specificare quel value cookie quando si desidera impostare il valore di una variabile. Ciò consente di risparmiare spazio in memoria all’interno del processo di gawk e riduce il tempo richiesto per creare il valore.


Note a piè di pagina

(108)

Si veda la voce “cookie” nello Jargon file per una definizione di cookie, e la voce “magic cookie” sempre nello Jargon file per un bell’esempio. Si veda anche la voce “Cookie” nel Glossario. [È disponibile in rete anche una traduzione italiana dello Jargon file]


Successivo: , Precedente: , Su: Descrizione dell'estensione API   [Contenuti][Indice]