Search code examples
windows-phone-8datareaderc++-cx

Efficient read some bytes from DataReader?


I have a stream with ANSI string. It is prefixed with bytes length. How can I read it into std::string?

Something like:

short len = reader.readInt16();
char[] result = reader.readBytes(len); // ???
std::string str = std::copy(result, result + len);

but there is no method readBytes(int).

Side question: is it slow to read with readByte() from DataReader one byte at a time?


Solution

  • According to MSDN, DataReader::ReadBytes exists and is what you are looking for: http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.streams.datareader.readbytes

    It takes an Platform::Array<unsigned char> as an argument, which presumably you'll initialize using the prefixed length, which on returning will contain your bytes. From there it's a tedious-but-straightforward process to construct the desired std::string.

    The basic usage will look something like this (apologies, on a Mac at the moment, so precise syntax might be a little off):

    auto len = reader->ReadInt16();
    auto data = ref new Platform::Array<uint8>(len);
    reader->ReadBytes(data);
    
    // now data has the bytes you need, and you can make a string with it
    

    Note that the above code is not production-ready - it's definitely possible that reader does not have enough data buffered, and so you'll need to reader.LoadAsync(len) and create a continuation to process the data when it is available. Despite that, hopefully this is enough to get you going.

    EDIT:

    Just noticed your side question. The short answer is, yes, it is much slower to read a byte at a time, for the reason that it is much more work.

    The long answer: Consider what goes in to each byte:

    1. A function call happens - stack frame allocation
    2. Some logic of reading a byte from the buffer happens
    3. The function returns - stack frame is popped, result is pushed, control returns
    4. You take the byte, and push it into a std::string, occasionally causing dynamic re-allocation (unless you've already str.resize(len), that is)

    Of all the things that happen, the dynamic reallocation is the really performance killer. That being said, if you have lots of bytes the work of function-calling will dominate the work of reading a byte.

    Now, consider what happens when you read all the bytes at once:

    1. A function call happens - stack frame, push the result array
    2. (in the happy path where all requested data is there) memcpy from the internal buffer to your pre-allocated array
    3. return
    4. memcpy into the string

    This is of course quite a bit faster - your allocations are constant with respect to the number of bytes read, as are the number of function calls.