Skip to content

Commit

Permalink
WIP Added methods to a variety of types from the binary data stream.
Browse files Browse the repository at this point in the history
Refs #11056
  • Loading branch information
martyngigg committed Dec 1, 2015
1 parent 10b3d68 commit 79b4d4a
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 4 deletions.
27 changes: 24 additions & 3 deletions Framework/Kernel/inc/MantidKernel/BinaryStreamReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@
// Includes
//------------------------------------------------------------------------------
#include "MantidKernel/DllConfig.h"

#include <cstdint>
#include <cfloat>
#include <iosfwd>
#include <string>

namespace Mantid {
namespace Kernel {

/**
* Assists with reading a binary file by providing standard overloads for the
* istream operators (>>) to given types (and vectors of those types)
* istream operators (>>) to given types (and vectors of those types). It
* only allows for reading fixed-width integer types to avoid cross-platform
* differences on the sizes of various types.
*
* Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
* National Laboratory & European Spallation Source
Expand All @@ -36,10 +42,25 @@ namespace Kernel {
*/
class MANTID_KERNEL_DLL BinaryStreamReader {
public:
BinaryStreamReader(std::istream & istrm);
BinaryStreamReader(std::istream &istrm);
~BinaryStreamReader();

///@name Stream operators
/// @{
BinaryStreamReader &operator>>(int32_t &value);
BinaryStreamReader &operator>>(int64_t &value);
BinaryStreamReader &operator>>(float &value);
BinaryStreamReader &operator>>(double &value);
BinaryStreamReader &operator>>(std::string &value);
/// @}

private:
std::istream & m_istrm;
/// Reference to the stream being read
std::istream &m_istrm;
/// The default size in bytes of the type used to encode the length
/// of a string in the file. Used by operator>>(std::string&). Use largest
/// fixed-width unsigned integer as sizeof(size_t) varies
uint64_t m_strLengthSize;
};

} // namespace Kernel
Expand Down
82 changes: 81 additions & 1 deletion Framework/Kernel/src/BinaryStreamReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,38 @@

#include <istream>

//------------------------------------------------------------------------------
// Anonymous functions
//------------------------------------------------------------------------------
namespace {

/**
* Read a value from the stream based on the template type
* @param stream The open stream on which to perform the read
* @param value An object of type T to fill with the value from the file
*/
template<typename T>
inline void readFromStream(std::istream & stream, T &value) {
stream.read(reinterpret_cast<char*>(&value), sizeof(T));
}

}

namespace Mantid {
namespace Kernel {

//------------------------------------------------------------------------------
// Public members
//------------------------------------------------------------------------------

/**
* Constructor taking the stream to read.
* @param istrm An open stream from which data will be read. The object does
* not take ownership of the stream. The caller is responsible for closing
* it.
*/
BinaryStreamReader::BinaryStreamReader(std::istream &istrm) : m_istrm(istrm) {
BinaryStreamReader::BinaryStreamReader(std::istream &istrm)
: m_istrm(istrm), m_strLengthSize(static_cast<uint64_t>(sizeof(int32_t))) {
if (!istrm) {
throw std::runtime_error(
"BinaryStreamReader: Input stream is in a bad state. Cannot continue.");
Expand All @@ -29,5 +51,63 @@ BinaryStreamReader::BinaryStreamReader(std::istream &istrm) : m_istrm(istrm) {
*/
BinaryStreamReader::~BinaryStreamReader() {}

/**
* Read a int32_t from the stream
* @param value The value is stored in the given stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::operator>>(int32_t &value) {
readFromStream(m_istrm, value);
return *this;
}

/**
* Read a int64_t from the stream
* @param value The value is stored in the given stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::operator>>(int64_t &value) {
readFromStream(m_istrm, value);
return *this;
}

/**
* Read a float (4-bytes) from the stream
* @param value The value is stored in the given stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::operator>>(float &value) {
readFromStream(m_istrm, value);
return *this;
}

/**
* Read a double (8-bytes) from the stream
* @param value The value is stored in this object
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::operator>>(double &value) {
readFromStream(m_istrm, value);
return *this;
}

/**
* Read a string of characters into given object. This method assumes that
* the stream currently points at a type specifying the length followed directly
* by the string itself.
* @param value The string value is stored in the given object. It is resized
* to the appropriate length
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::operator>>(std::string &value) {
// First read the size.
decltype(m_strLengthSize) length(0);
m_istrm.read(reinterpret_cast<char *>(&length), m_strLengthSize);
// Now the value
value.resize(static_cast<std::string::size_type>(length));
m_istrm.read(const_cast<char *>(value.data()), static_cast<size_t>(length));
return *this;
}

} // namespace Kernel
} // namespace Mantid
49 changes: 49 additions & 0 deletions Framework/Kernel/test/BinaryStreamReaderTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class BinaryFileReaderTest : public CxxTest::TestSuite {
openTestFile();
}

void setUp() { resetStreamToStart(); }

//----------------------------------------------------------------------------
// Successes cases
//----------------------------------------------------------------------------
Expand All @@ -35,6 +37,31 @@ class BinaryFileReaderTest : public CxxTest::TestSuite {
TS_ASSERT_EQUALS(std::ios_base::beg, m_stream.tellg());
}

void test_Read_int32_t_Gives_Correct_Value() {
doReadTest<int32_t>(6, sizeof(int32_t));
}

void test_Read_int64_t_Gives_Correct_Value() {
moveStreamToPosition(677763);
doReadTest<int64_t>(580, sizeof(int64_t));
}

void test_Read_float_Gives_Correct_Value() {
// Move to where a float should be
moveStreamToPosition(166);
doReadTest<float>(787.0f, sizeof(float));
}

void test_Read_double_Gives_Correct_Value() {
moveStreamToPosition(10);
doReadTest<double>(2.0, sizeof(double));
}

void test_Read_String_Gives_Expected_String() {
const size_t offset = sizeof(int32_t) + 6;
doReadTest<std::string>("horace", offset);
}

//----------------------------------------------------------------------------
// Failure cases
//----------------------------------------------------------------------------
Expand All @@ -48,6 +75,18 @@ class BinaryFileReaderTest : public CxxTest::TestSuite {
}

private:

template <typename T>
void doReadTest(T expectedValue, size_t expectedStreamOffset) {
BinaryStreamReader reader(m_stream);
auto streamPosBeg = m_stream.tellg();
T value;
reader >> value;
TS_ASSERT_EQUALS(expectedValue, value);
TS_ASSERT_EQUALS(expectedStreamOffset, m_stream.tellg() - streamPosBeg);

}

void openTestFile() {
using Mantid::Kernel::ConfigService;
// The test file should be in the data search path
Expand All @@ -72,6 +111,16 @@ class BinaryFileReaderTest : public CxxTest::TestSuite {
}
}

void resetStreamToStart() {
m_stream.clear();
m_stream.seekg(std::ios_base::beg);
}

/// Move the stream nbytes from the beginning
void moveStreamToPosition(size_t nbytes) {
m_stream.seekg(nbytes, std::ios_base::beg);
}

std::string m_filename;
std::ifstream m_stream;
};
Expand Down

0 comments on commit 79b4d4a

Please sign in to comment.