2009-09-23 3 views
16

Sto cercando un "equivalente" C++ di Java ByteBuffer.equivalente in C++ di Java ByteBuffer?

Probabilmente mi manca l'ovvio o ho solo bisogno di un esempio di utilizzo isolato per chiarire. Ho guardato attraverso la famiglia iostream & sembra che possa fornire una base. In particolare, voglio essere in grado di:

  • costruire un buffer da un array di byte/punto e ottenere primitive dal buffer, ad esempio getByte, getInt
  • crea un buffer utilizzando le primitive, ad es. putByte, putInt e quindi ottieni l'array/puntatore di byte.
+0

E 'importante notare che in 'ottenere (T)' e 'mettere (T)', 'T' * non *' byte'. Sono * altri * tipi primitivi, come 'int',' float' e 'short'. –

+0

Sì, è stata una sfortunata scelta di nominare da parte mia. L'ho reso più chiaro. – hplbsh

risposta

14

Hai stringbuf, filebuf o si potrebbe usare vector<char>.


Questo è un semplice esempio utilizzando stringbuf:

std::stringbuf buf; 
char data[] = {0, 1, 2, 3, 4, 5}; 
char tempbuf[sizeof data]; 

buf.sputn(data, sizeof data); // put data 
buf.sgetn(tempbuf, sizeof data); // get data 

Grazie @Pete Kirkham per l'idea di funzioni generiche.

#include <sstream> 

template <class Type> 
std::stringbuf& put(std::stringbuf& buf, const Type& var) 
{ 
    buf.sputn(reinterpret_cast<const char*>(&var), sizeof var); 

    return buf; 
} 

template <class Type> 
std::stringbuf& get(std::stringbuf& buf, Type& var) 
{ 
    buf.sgetn(reinterpret_cast<char*>(&var), sizeof(var)); 

    return buf; 
} 

int main() 
{ 
    std::stringbuf mybuf; 
    char byte = 0; 
    int var; 

    put(mybuf, byte++); 
    put(mybuf, byte++); 
    put(mybuf, byte++); 
    put(mybuf, byte++); 

    get(mybuf, var); 
} 
+1

Questo sarebbe un esempio migliore se la cosa che viene estratta dal buffer non fosse un'altra serie di caratteri. 'ByteBuffer' consente di estrarre * altri * tipi primitivi dal buffer di byte, non solo da byte. http://java.sun.com/j2se/1.4.2/docs/api/java/nio/ByteBuffer.html –

+0

La mia scelta di get (T) e put (T) come esempi era piuttosto scarsa; Vorrei estrarre le dimensioni variabili dal buffer. std :: stringbuf sembra la giusta direzione. Grazie. – hplbsh

+0

Non basato su caratteri. Forse std :: streambuf è una scelta migliore in questo caso, anche se entrambi dovrebbero essere fattibili. – hplbsh

3
std::vector<char> bytes; 

bytes.push_back(some_val); // put 

char x = bytes[N];   // get 

const char* ptr = &bytes[0]; // pointer to array 
8

stringstream fornisce operazioni di base non formattate get e write per scrivere blocchi di caratteri. Per specializzarsi su T sottoclasse o avvolgerlo, o fornire funzioni di template free standing per utilizzare la memoria di opportunamente dimensione get/write.

template <typename T> 
std::stringstream& put (std::stringstream& str, const T& value) 
{ 
    union coercion { T value; char data[ sizeof (T) ]; }; 

    coercion c; 

    c.value = value; 

    str.write (c.data, sizeof (T)); 

    return str; 
} 

template <typename T> 
std::stringstream& get (std::stringstream& str, T& value) 
{ 
    union coercion { T value; char data[ sizeof (T) ]; }; 

    coercion c; 

    c.value = value; 

    str.read (c.data, sizeof (T)); 

    value = c.value; 

    return str; 
} 

Si potrebbe scrivere tali modelli per qualsiasi altro flusso o di un vettore che si desidera - nel caso del vettore, che avrebbe bisogno di usare inserto piuttosto che scrivere.

+0

Soluzione piacevole :) Penso che i flussi siano più uno strumento per leggere e scrivere * dati formattati *. Perché dovrei usare un flusso come un buffer, dove all'interno del flusso c'è un buffer. Comunque, penso che le tue funzioni generiche siano un'idea eccellente. – AraK

+0

Tendo a preferire i flussi come mi piace la coercizione al bool e l'idioma di restituire il flusso per il concatenamento, piuttosto che il ritorno del buffer del numero di byte scritti e di dover smanettare per testarlo. –

1

Grazie per tutti gli input, che ha portato a questa bella soluzione semplice:


class ByteBuffer : std::stringbuf 
{ 
public: 
    template 
    size_t get(T &out) 
    { 
     union coercion { T value; char data[ sizeof (T) ]; }; 

     coercion c; 

     size_t s= xsgetn(c.data, sizeof(T)); 

     out= c.value; 

     return s; 
    } 

    template 
    size_t put(T &in) 
    { 
     union coercion { T value; char data[ sizeof (T) ]; }; 

     coercion c; 

     c.value= in; 

     return xsputn(c.data, sizeof(T)); 
    } 

    size_t get(uint8_t *out, size_t count) 
    { 
     return xsgetn((char *)out, count); 
    } 

    size_t put(uint8_t *out, size_t count) 
    { 
     return xsputn((char *)out, count); 
    } 
}; 

Per utilizzare ad esempio:


void ByteBufferTest(void) 
{ 
    ByteBuffer bb; 

    float f= 4; 
    uint8_t u8= 1; 
    uint16_t u16= 2; 
    uint32_t u32= 4; 
    uint64_t u64= 8; 

    bb.put(f); 
    bb.put(u8); 
    bb.put(u16); 
    bb.put(u32); 
    bb.put(u64); 

    uint8_t array[19]; 

    bb.get(array, 19); 

    // or 

    bb.get(f); 
    bb.get(u8); 
    bb.get(u16); 
    bb.get(u32); 
    bb.get(u64); 
} 
+1

-1: Non mi piace davvero l'idea di creare una sottoclasse di uno std :: stringbuf. Usa invece la composizione. La maggior parte dei tipi in tale spazio dei nomi non sono progettati per questo. Inoltre, perché stai usando size_t è così? – Arafangion

4

Ho scritto questo un po 'indietro a fare esattamente quello che stai chiedendo per. Dare un colpo:

https://code.google.com/p/bytebuffer-cpp/

+0

Questo non sembra gestire le differenze di ordinamento dei byte per i tipi interi se il writer e il lettore sono in esecuzione su architetture diverse. Penso che ByteBuffer di Java sia di grandi dimensioni per impostazione predefinita, ma offre la possibilità di cambiare l'ordine dei byte. Qualche alternativa? – Hoobajoob