2009-09-23 8 views
16

Je suis à la recherche d'un "équivalent" C++ de Java ByteBuffer.C++ équivalent de Java ByteBuffer?

Je manque probablement l'évidence ou ai juste besoin d'un exemple d'utilisation isolé pour clarifier. J'ai regardé à travers la famille iostream & il semble que cela puisse fournir une base. Spécifiquement, je veux pouvoir:

  • construire un tampon à partir d'un tableau/point d'octets et d'obtenir des primitives du tampon, par ex. getByte, getInt
  • construire un tampon en utilisant des primitives, par ex. putByte, putInt puis récupère le byte array/pointeur.
+0

Il est important de noter que dans 'obtenir (T) et' 'mettre (T)', 'T' est * pas *' byte'. Il s'agit de * autres * types primitifs, tels que 'int',' float' et 'short'. –

+0

Oui, c'était un mauvais choix de nommer de ma part. Je l'ai fait plus clair. – hplbsh

Répondre

14

Vous avez stringbuf, filebuf ou vous pouvez utiliser vector<char>.


Ceci est un exemple simple en utilisant 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 

Merci @Pete Kirkham pour l'idée des fonctions génériques.

#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

Ce serait un meilleur exemple si la chose extraite du tampon n'était pas un autre tableau de char. 'ByteBuffer' permet d'extraire * autres * types primitifs du tampon d'octets, pas seulement des octets. http://java.sun.com/j2se/1.4.2/docs/api/java/nio/ByteBuffer.html –

+0

Mon choix de get (T) et put (T) comme exemples était plutôt pauvre; Je voudrais extraire des tailles variables du tampon. Std :: stringbuf se sent comme dans la bonne direction. Merci. – hplbsh

+0

Son caractère non-basé. Peut-être que std :: streambuf est un meilleur choix dans ce cas, même si les deux devraient être réalisables. – 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 fournit des opérations de base non formatées get et write pour écrire des blocs de caractères. Pour se spécialiser sur T soit sous-classe ou envelopper, ou fournir des fonctions de modèle autonome pour utiliser la mémoire get/write de taille appropriée.

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

Vous pouvez écrire ces modèles pour tout autre flux ou un vecteur que vous voulez - dans le cas du vecteur, il faudrait utiliser insert plutôt que d'écrire.

+0

Belle solution :) Je pense que les flux sont plus un outil pour lire et écrire * des données formatées *. Pourquoi devrais-je utiliser un flux comme un tampon, où à l'intérieur du flux il y a un tampon. Pourtant, je pense que vos fonctions génériques sont une excellente idée. – AraK

+0

J'ai tendance à préférer les flux comme j'aime la coercition à la booléenne et l'idiome de retourner le flux pour le chaînage, plutôt que le retour du nombre d'octets écrit par le tampon et le fait de tester cela. –

1

Merci pour toutes les entrées, il a conduit à cette solution assez 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); 
    } 
}; 

Pour utiliser par exemple:


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: Je n'aime vraiment pas l'idée que vous sous-classez un std :: stringbuf. Utilisez la composition à la place. La plupart des types dans cet espace de noms ne sont pas conçus pour cela. Aussi, pourquoi utilisez-vous size_t comme ça? – Arafangion

4

j'ai écrit un certain temps ce retour à faire exactement ce que vous demandez pour. Donnez un coup de feu:

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

+0

Cela ne semble pas concerner les différences d'ordre des octets pour les types entiers si l'auteur et le lecteur s'exécutent sur des architectures différentes. Je pense que ByteBuffer de Java est un gros endian par défaut, mais offre la possibilité de changer l'ordre des octets. Des alternatives? – Hoobajoob