Newsgroup: it.comp.lang.c++
Titolo: ancora con le sfide strane sui template

come si potrebbe fare una cosa simile alla seguente :
vorrei creare un template che come argomento prendesse un 
istanza ENUM (sarà settata con valori contenenti un numero 
prefissato di bit, tipo 8, 16, 32 o 64) e una sua 
dichiarazione interna e/ una funzione di interfaccia, a 
seconda di tale valore dovrebbero allocare / ritornare un 
tipo integrale con la suddetta ampiezza di bit (il tutto 
risolto a compile time possibilmente, senza switch e senza 
tipi UNION che non consentirebbero il risparmio di spazio 
dei tipi integrali a minore dimensione).
Certo, la soluzione ovvia (che per certi versi ho già 
pensato e non mi interessa) è passare anche un typename 
corrispettivo al tipo che voglio allocare o ritornare.
Solo che questa soluzione manuale da il fianco a possibili 
dichiarazioni non coerenti, tipo istanziare
Integral <Enum_8_bit, unsigned long> Var;
in cui si intuisce che la dimensione in bit passata nella 
enum non combacia con il typename richiesto. Vorrei poter 
passare solo la Enum e poter desumere il primo tipo integral 
che la comprenda.
Se vi chiedete perché non faccia il contrario, tipo passare 
il typename e usare sizeof per capire quanti bit contiene 
.... allora la dico tutta : vorrei implementare tramite 
campi di bit anche interi a profondità di bit arbitraria (ma 
sempre inferiore o uguale alla massima grandezza di un tipo 
integral intrinseco, niente stringhe di bit più lunghe).
Allora il vero problema è desumere, a compile time, dal 
valore della Enum, qual'è il primo tipo integral che possa 
includere la dimensione richiesta.
Se passo una Enum_12_Bit, il tipo allocato/ritornato 
dovrebbe essere uno short integer;
Se passo una Enum_24_Bit, il tipo allocato/ritornato 
dovrebbe essere un long integer;
Temo che non riuscirò a venirne a capo da solo, ma se avete 
dritte, sono assai gradite.
ciao
Soviet_Mario


-- 
-riko

 astratto e sfruttando i campi di bit.
I campi di bit non garantiscono *niente*. Tipicamente un campo di un bit
occupa un byte, due ne occupano due. Tipicamente vuole dire che "il
compilatore può fare come vuole, e in molti casi fa così".
Devi usare keywords non standard per forzare impacchettamento e
allineamento. Ottieni software possibilmente non portabile e meno
efficiente. 
Poi fai come vuoi.
-- 
-riko

   
Mica vero ;-) Anche se lo standard specica che i bit-field sono 
implementation dependend
ricordo che i bit field sono nati perche' "when a memory is a 
premium...(K&R)" , c'era la necessita'
di impaccare informazioni di pochi bit in poco spazio senza sprecare 
memoria.
*tipicamente* i bit field sono impaccati nel tipo utilizzato e qundi in 
in BYTE ci stanno
8 bit field. Fino al C89 c'era il vincolo che i campi a bit dovessero 
stare nel tipo
indicato (no crossing-word boundaries), che nel C99 non c'e' piu.
Sui processori con operazioni ai bit le operazioni per l' accesso ai bit 
field sono
molto efficienti, su altre achitetture i vari campi sono gestiti con 
maschere binarie
per selezionare il campo (and / or).
ciao,
B.

 implementation dependend
Si, in effetti il compilatore sembra (per lo meno qua su x86)
lavorarseli come ci si aspetta. Comunque IMHO il metodo standard di
avere campi interi di dimensione in bit arbitraria sono i bitsets.
Anche perchè C++ offre direttamente funzioni per metterci dentro ed
estrarci valori integrali standard, input output, alcune pratiche
funzioni di verifica operazioni logiche e shift (il che facilita
alquanto se bisogna implementarci sopra operazioni aritmetiche).
-- 
-riko

 B.

 avere campi interi di dimensione in bit arbitraria sono i bitsets.
Ah, i bitset ...
ne ho letto l'interfaccia sull'help, ma non sono riuscito a 
capire se possano essere impaccati come vorrei.
Voglio dire, se creassi un array di 3 bitset ciascuno da 4 
bit, potrei presumere che possano essere stiparli tutti in 
un intero a 16 bit (lasciando come mancia i 4 bit non 
usati), oppure ciascuna istanza di bitset si prende 
singolarmente il suo overspace e mi fa sfumare via la 
compattificazione ?
P.S. l'help di .net e msdn non sono troppo generosi con le 
librerie standard, ho notato :-\
riciao
Soviet_mario


 compattificazione ?
% cat bitsets2.cc
#include <bitset>
#include <iostream>
using std::bitset;
int main (int argc, char const *argv[])
{
    bitset<4> barr[3];
    std::cout << sizeof(barr) << std::endl;
    return 0;
}
% g++ -o bitsets2 bitsets2.cc && ./bitsets2
12
Non hai tuttavia nessuna garanzia che *debba* essere cosě.
Sulla mia piattaforma non fa quello che vuoi. Magari con altre opzioni
di compilazione e/o un'altra libreria standard.
-- 
-riko

 in effetti mi scassa la minchia, eh he he)
Per "cross-boundary" si intende l' uso della rimanenza di bit nell' 
integral type che usi.
Fino al C89, nel tipo usato possono essere impaccati solo i bit-field 
che sono completamente
contenibili nel campo:
Come esempio (ipotetico) :
struct bf8{
  unsigned char bf1:2;   /* Occupa 2bit nel byte[0], ad es. bit[0,1] */
  unsigned char bf2:2;   /* Occupa 2bit nel byte[0], ad es. bit[2,3] */
  unsigned char bf3:3;   /* Occupa 3bit nel byte[0], ad es. bit[4,5,6] */
  unsigned char bf4:2;   /* Occupa 2bit nel byte[1], ad es. bit[0,1] - 
il bit 7 in byte0 rimane 'spare' */
  unsigned char bf4:7;   /* Occupa 7bit nel byte[2], ad es. bit[0..6] - 
i bit 2..7 in byte1 rimangono 'spare' */
};
Come si vede, in totale userei 16bit (2 byte da 8bit) ma in realta' 
occupo 3 byte perche'
non e' possibile allocare i bit-field a cavallo di un byte e l' altro.
Questo in C99 invece sarebbe permesso: ovvero l'ipotetico compilatore C99
potrebbe, se l'implementazione lo consente, utilizzare i bit spare per
allocare i bit-field anche a cavallo di piu' locazioni e avresti:
struct bf8C99{
  unsigned char bf1:2;   /* Occupa 2bit nel byte[0], ad es. bit[0,1] */
  unsigned char bf2:2;   /* Occupa 2bit nel byte[0], ad es. bit[2,3] */
  unsigned char bf3:3;   /* Occupa 3bit nel byte[0], ad es. bit[4,5,6] */
  unsigned char bf4:2;   /* Occupa 1bit nel byte[0], ad es. bit[bit7]  e 
un bit in byte[1]- ad es bit0' */
  unsigned char bf4:7;   /* Occupa 7bit nel byte[1], ad es. bit[1..7]   */
};
Ovviamente il codice di gestione del cross-boundary sarebbe piu' ciccio 
che non
quello del C89 ;-)
Invece per le librerie bitset va notato che non sono la stessa cosa 
delle strutture bit-field:
il loro scopo e' quello di manipolare bit, non quello di ottimizzare l' 
impaccamento.
Logicamente, le due cose vanno utilizzate per scopi diversi .
Ciao,
B.


Ma va ? Ho fatto qualcosa del genere utilizzando delle bit map:
La gestione di un singolo blocco e' abbastanza semplice:
   map_index = (block_num/8);                  // Index of  element in 
the bit map array
   bit_mask    = (1<< (block_num%8) );    // Bit mask
.................. 
   bit_map[map_index] &=( ~bit_mask);    // Free block
........................
   bit_map[map_index] |=(~bit_mask);      // reserve block
con piu' blocchi contemponei da gestire la cosa e' leggermente piu' 
complicata ;-)
B.

 Ma va ? Ho fatto qualcosa del genere utilizzando delle bit map:
mmm, si, anche se non visualizzata, e lineare invece che 2D, 
il concetto è quello.
Ma se non ho capito male presumo che tu stessi usando la tua 
bitmap con profondità di 1 singolo bit (lo feci per un 
allocatore FAT-based, e fungeva QUASI sempre bene salvo in 
casi che non sono riuscito a debuggare .... mah, è rimasto 
un mistero, dove contava solo lo stato libero vs. assegnato, 
regardless a chi si assegnava un blocco) ossia bitmap 
monocromatica. Distinguere solo spazio usato e libero.
Stavo invece sondando l'idea di assegnare ad ogni singolo 
cluster una certa profondità di bit (variabile e a scelta 
dell'utente dei template), in modo che non solo un cluster 
risultasse in uso, ma anche contenesse un valore che 
corrispondesse ad un indice di file-entry in una tavola di 
descrittori. Quindi non mi bastava più un bit ma ci vogliono 
vari bit, tanti più quanti più files diversi al massimo può 
supportare tale FAT (16, 256, 4096, 65536 etc .... ho optato 
per una granularità di un nibble, come compromesso tra 
massima flessibilità e un po' di semplificazione).
Ma non voglio niente di hard-coded, dovrei potermi 
agganciare a parametri template (evitando ridondanza e 
possibile incoerenza dei medesimi).
Come mi piacerebbe poter passare non solo tipi e valori 
interi, ma istanze effettive di tipi arbitrari ai template.
Se potessi passargli un oggetto classe opportuno (e 
costante, ossia contenente solo membri costanti e statici, 
ovviamente, non chiedo l'impossibile di passare variabili 
indefinite a compile time), ci metterei dentro tutti i 
parametri, e avrei risolto una parte ... non tutto cmq, 
ancora non so come parametrizzare dei TIPI dentro il 
template (come accadrebbe con parametri typename) attraverso 
parametri di tipo VALUE (degli enum).
ciao
Soviet_Mario
