2009-09-23 16 views
16

Szukam "odpowiednika" języka Java ByteBuffer w C++.C++ odpowiednik Java ByteBuffer?

Prawdopodobnie brakuje mi oczywistego lub po prostu trzeba wyizolowanego przykładu użycia, aby wyjaśnić. Sprawdziłem rodzinę iostream & wygląda na to, że może stanowić podstawę. W szczególności chcę móc:

  • zbudować bufor z tablicy/punktu bajtów i uzyskać prymitywy z bufora, np. getByte, getInt
  • zbuduj bufor, używając prymitywów np. putByte, putInt, a następnie pobierz tablicę/wskaźnik bajtów.
+0

Ważne jest, aby pamiętać, że w 'get (T)' i 'put (T)', 'T' * nie *' byte'. Jest to * inne * typy pierwotne, takie jak 'int',' float' i 'short'. –

+0

Tak, to był niefortunny wybór nazywania z mojej strony. Uczyniłem to jaśniejszym. – hplbsh

Odpowiedz

14

Masz stringbuf, filebuf lub możesz użyć vector<char>.


To jest prosty przykład za pomocą 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 

Dzięki @Pete Kirkham dla idei funkcji generycznych.

#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

Byłby to lepszy przykład, jeśli rzeczą wyodrębnioną z bufora nie była kolejna tablica znaków. 'ByteBuffer' pozwala na wyodrębnienie * innych * typów pierwotnych z bufora bajtów, a nie tylko bajtów. http://java.sun.com/j2se/1.4.2/docs/api/java/nio/ByteBuffer.html –

+0

Mój wybór get (T) i put (T) jako przykłady był raczej słaby; Chciałbym wyodrębnić zmienne rozmiary z bufora. std :: stringbuf czuje się właściwym kierunkiem. Dzięki. – hplbsh

+0

Nie jest oparty na znakach. Być może std :: streambuf jest lepszym wyborem w tym przypadku, chociaż oba powinny być wykonalne. – 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 udostępnia podstawowe niesformatowane operacje get i write do pisania bloków znaków. Aby specjalizować się na T dowolnej podklasie lub owinąć ją, lub zapewnić bezpłatne funkcje szablonów do korzystania z odpowiednio zapisanej pamięci/zapisu.

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

Można napisać takie szablony dla cokolwiek innego wektora strumienia lub chcesz - w przypadku nosiciela, to trzeba użyć wkładkę zamiast pisać.

+0

Przyjemne rozwiązanie :) Myślę, że strumienie są bardziej narzędziem do odczytywania i zapisywania * sformatowanych danych *. Dlaczego miałbym używać strumienia takiego jak bufor, gdzie wewnątrz strumienia znajduje się bufor. Mimo to, myślę, że twoje ogólne funkcje są doskonałym pomysłem. – AraK

+0

Ja preferuję strumienie, ponieważ podoba mi się wymuszenie bool i idiom zwracania strumienia do łączenia, zamiast powrotu bufora liczby zapisanych bajtów i konieczności błądzenia przy testowaniu tego. –

1

Dzięki za wszystkie wejścia, ma doprowadzić do tego dość proste rozwiązanie:


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

Aby użyć np:


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: Naprawdę nie podoba mi się pomysł, że podklasy std :: stringbuf. Zamiast tego użyj kompozycji. Większość typów w tej przestrzeni nazw nie jest do tego zaprojektowana. Ponadto, dlaczego używasz size_t's w ten sposób? – Arafangion

4

Napisałem to chwilę z powrotem robić dokładnie to, o co prosisz dla. Daj mu szansę:

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

+0

Nie wydaje się, aby dotyczyło różnic w porządkowaniu bajtów dla typów integralnych, jeśli pisarz i czytnik działają na różnych architekturach. Myślę, że Java ByteBuffer jest domyślnie dużym endianem, ale zapewnia możliwość zmiany kolejności bajtów. Jakieś alternatywy? – Hoobajoob