views:

255

answers:

2

I have a data structure defined as

struct myDataStruct
{
   int32_t header;
   int16_t data[8];
}

and I want to take a character stream and turn it into a myData stream. What stream class should I extend? I would like to create a custom stream class so that I can do things like

myDataStruct myData;
myDataStruct myDataArray[10];

myDataStream(ifstream("mydatafile.dat"));
myDataStream.get(myData);
myDataStream.read(myDataArray, 10);
+4  A: 

Instead of myDataStream.get(myData), what you do is overload operator>> for your data type:

std::istream& operator>>(std::istream& is, myDataStruct& obj)
{
  // read from is into obj
  return is;
}

If you want to read into an array, just write a loop:

for( std::size_t idx=0; idx<10; ++idx ) 
{
   myDataStruct tmp;
   if( is >> tmp )
     myDataArray[idx] = tmp;
   else
     throw "input stream broken!";
}

Using a function template, you should also able to overload the operator for arrays on the right-hand side (but this I have never tried):

template< std::size_t N >
std::istream& operator>>(std::istream& is, myDataStruct (&myDataArray)[N])
{
  // use loop as above, using N instead of the 10
}

But I can't decide whether this is gorgeous or despicable.

sbi
Eugene
@Eugene: Thanks for the comment, I extended my posting about an idea that comment gave me.
sbi
Since we are adding ideas (and even if I believe that the question deals with binary representation and not formatted input/output), you could try std::copy / std::copy_n algorithms if you trust the correctness of the input.
David Rodríguez - dribeas
@dribeas: I'm not sure what you mean, but I have made the answer cw, so go ahead and edit it in!
sbi
A: 

If you are working with unformatted input, you should probably read directly in binary form. Usually you would use some compiler specific directive to create data structures with no padding and then just read/write from a file.

// Gcc
#pragma pack(1) // option 1: pragmas
struct frame {
   std::uint32_t header;
   std::uint16_t data[8];
} __attribute((packed)); // option 2: packed attribute
#pragma pack(0)

bool operator==( data const & lhs, data const & rhs )
{
   bool result = lhs.header == rhs.header;
   for ( int i = 0; i < 8; ++i )
   {
      result &= lhs.data[i] == rhs.data[i];
   }
   return result;
}

int main()
{
   frame data = { 10, 1, 2, 3, 4, 5, 6, 7, 8 };

   std::ofstream out( "data.bin", ofstream::binary );
   out.write( reinterpret_cast<char*>(&data), sizeof(data) );
   out.close();

   std::ifstream in( "data.bin", ifstream::binary );
   frame readed;
   in.read( reinterpret_cast<char*>(&readed), sizeof(readed) );
   in.close();

   std::cout << (readed == data) << std::endl; // 1
}

The compiler directive to disable padding for VS might be different (I believe the pragma directive works both in gcc and VS, but I have always used the attribute).

David Rodríguez - dribeas