2009-09-23 15 views
16

Estoy buscando un "equivalente" de C++ de Java ByteBuffer.C++ equivalente de Java ByteBuffer?

Probablemente me falta lo obvio o simplemente necesito un ejemplo de uso aislado para aclarar. He buscado en la familia iostream &, parece que puede proporcionar una base. Específicamente, deseo poder:

  • crear un búfer a partir de una matriz/punto de bytes y obtener primitivas del búfer, p. getByte, getInt
  • construye un buffer utilizando primitivas, p. putByte, putInt y luego obtener la matriz/puntero de bytes.
+0

Es importante señalar que en 'get (T)' y 'puesto (T)', 't' * no *' byte'. Son * otros * tipos primitivos, como 'int',' float' y 'short'. –

+0

Sí, fue una elección desafortunada de nombrar de mi parte. Lo he dejado más claro. – hplbsh

Respuesta

14

Tienes stringbuf, filebuf o puede utilizar vector<char>.


Este es un simple ejemplo usando 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 

Gracias @Pete Kirkham para la idea de funciones genéricas.

#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

Este sería un mejor ejemplo si la cosa que se extrae del búfer no fuera otra matriz de char. 'ByteBuffer' permite extraer * otros * tipos primitivos del búfer de bytes, no solo bytes. http://java.sun.com/j2se/1.4.2/docs/api/java/nio/ByteBuffer.html –

+0

Mi elección de get (T) y put (T) como ejemplos fue bastante pobre; Me gustaría extraer tamaños variables del buffer. std :: stringbuf se siente como la dirección correcta. Gracias. – hplbsh

+0

Su carácter no basado. Quizás std :: streambuf es una mejor opción en este caso, aunque ambos deberían ser viables. – 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 proporciona operaciones básicas sin formato get y write para escribir bloques de caracteres. Para especializarse en T ya sea una subclase o envolverla, o proporcionar funciones de plantilla independientes para usar la memoria de obtención/escritura de tamaño apropiado.

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; 
} 

Se puede escribir este tipo de plantillas para cualquier otra corriente o vector que desee - en el caso del vector, se tendría que usar inserto en lugar de escribir.

+0

Buena solución :) Creo que las transmisiones son más una herramienta para leer y escribir * datos formateados *. ¿Por qué usaría una secuencia como un buffer, donde dentro de la secuencia hay un buffer? Aún así, creo que sus funciones genéricas son una excelente idea. – AraK

+0

que tienden a preferir corrientes como me gusta la coacción a bool y el lenguaje de devolver la corriente de encadenamiento, en lugar de la memoria intermedia de devolver el número de bytes escritos y tener que tocar el violín alrededor probar eso. –

1

Gracias por toda la entrada, que ha llevado a esta solución bastante simple:


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); 
    } 
}; 

Para utilizar por ejemplo:


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: Realmente no me gusta la idea de que esté subclasando un std :: stringbuf. Usa la composición en su lugar. La mayoría de los tipos en ese espacio de nombres no están diseñados para eso. Además, ¿por qué estás usando size_t de esa manera? – Arafangion

4

de escribir este un tiempo atrás para hacer exactamente lo que estás pidiendo para. Darle un tiro:

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

+0

Esto no parece tratar con las diferencias de ordenamiento de bytes para tipos integrales si el escritor y el lector se ejecutan en arquitecturas diferentes. Creo que ByteBuffer de Java es un gran endian por defecto, pero ofrece la posibilidad de cambiar el orden de bytes. Alguna alternativa? – Hoobajoob