Skip to content

Commit

Permalink
WIP Add overloads for read arrays of values from a stream
Browse files Browse the repository at this point in the history
Refs #11056
  • Loading branch information
martyngigg committed Dec 2, 2015
1 parent 79b4d4a commit 2e052a3
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 14 deletions.
16 changes: 15 additions & 1 deletion Framework/Kernel/inc/MantidKernel/BinaryStreamReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <cfloat>
#include <iosfwd>
#include <string>
#include <vector>

namespace Mantid {
namespace Kernel {
Expand Down Expand Up @@ -45,7 +46,7 @@ class MANTID_KERNEL_DLL BinaryStreamReader {
BinaryStreamReader(std::istream &istrm);
~BinaryStreamReader();

///@name Stream operators
///@name Single-value stream operators
/// @{
BinaryStreamReader &operator>>(int32_t &value);
BinaryStreamReader &operator>>(int64_t &value);
Expand All @@ -54,6 +55,19 @@ class MANTID_KERNEL_DLL BinaryStreamReader {
BinaryStreamReader &operator>>(std::string &value);
/// @}

///@name std::vector-reader methods
/// @{
BinaryStreamReader & read(std::vector<int32_t> &value, const size_t nvals);
BinaryStreamReader & read(std::vector<int64_t> &value, const size_t nvals);
BinaryStreamReader & read(std::vector<float> &value, const size_t nvals);
BinaryStreamReader & read(std::vector<double> &value, const size_t nvals);
/// @}

///@name std::string methods for specifying number of characters
/// @{
BinaryStreamReader & read(std::string &value, const size_t length);
/// @}

private:
/// Reference to the stream being read
std::istream &m_istrm;
Expand Down
86 changes: 81 additions & 5 deletions Framework/Kernel/src/BinaryStreamReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,26 @@ namespace {
* @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));
}

template <typename T>
inline void readFromStream(std::istream &stream, T &value) {
stream.read(reinterpret_cast<char *>(&value), sizeof(T));
}

/**
* Overload to read an array of values from the stream based on the template
* type for the element of the array.
* @param stream The open stream on which to perform the read
* @param value An object of type std::vector<T> to fill with the value from
* the file
* @param nvals The number of values to read
*/
template <typename T>
inline void readFromStream(std::istream &stream, std::vector<T> &value,
size_t nvals) {
if (value.size() < nvals)
value.resize(nvals);
stream.read(reinterpret_cast<char *>(value.data()), nvals * sizeof(T));
}
}

namespace Mantid {
Expand Down Expand Up @@ -109,5 +124,66 @@ BinaryStreamReader &BinaryStreamReader::operator>>(std::string &value) {
return *this;
}

/**
* Read an array of int32_t into the given vector.
* @param value The array to fill. Its size is increased if necessary
* @param nvals The number values to attempt to read from the stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::read(std::vector<int32_t> &value,
const size_t nvals) {
readFromStream(m_istrm, value, nvals);
return *this;
}

/**
* Read an array of int64_t into the given vector.
* @param value The array to fill. Its size is increased if necessary
* @param nvals The number values to attempt to read from the stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::read(std::vector<int64_t> &value,
const size_t nvals) {
readFromStream(m_istrm, value, nvals);
return *this;
}

/**
* Read an array of float balues into the given vector.
* @param value The array to fill. Its size is increased if necessary
* @param nvals The number values to attempt to read from the stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::read(std::vector<float> &value,
const size_t nvals) {
readFromStream(m_istrm, value, nvals);
return *this;
}

/**
* Read an array of double values into the given vector.
* @param value The array to fill. Its size is increased if necessary
* @param nvals The number values to attempt to read from the stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::read(std::vector<double> &value,
const size_t nvals) {
readFromStream(m_istrm, value, nvals);
return *this;
}

/**
* Read a series of characters into a string object.
* @param value The string to fill. Its size is increased if necessary
* @param nvals The number values to attempt to read from the stream
* @return A reference to the BinaryStreamReader object
*/
BinaryStreamReader &BinaryStreamReader::read(std::string &value,
const size_t length) {
value.resize(length);
m_istrm.read(const_cast<char *>(value.data()), length);
return *this;
}

} // namespace Kernel
} // namespace Mantid
107 changes: 99 additions & 8 deletions Framework/Kernel/test/BinaryStreamReaderTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <Poco/File.h>
#include <Poco/Path.h>

#include <algorithm>
#include <fstream>

using Mantid::Kernel::BinaryStreamReader;
Expand Down Expand Up @@ -38,28 +39,106 @@ class BinaryFileReaderTest : public CxxTest::TestSuite {
}

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

void test_Read_int64_t_Gives_Correct_Value() {
moveStreamToPosition(677763);
doReadTest<int64_t>(580, sizeof(int64_t));
doReadSingleValueTest<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));
doReadSingleValueTest<float>(787.0f, sizeof(float));
}

void test_Read_double_Gives_Correct_Value() {
moveStreamToPosition(10);
doReadTest<double>(2.0, sizeof(double));
doReadSingleValueTest<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);
doReadSingleValueTest<std::string>("horace", offset);
}

void test_Read_Vector_int32_t() {
moveStreamToPosition(466);
const size_t nvals(2);
std::vector<int32_t> expectedValue(nvals);
expectedValue[0] = 4;
expectedValue[1] = 7;

doReadArrayValueTest(nvals, expectedValue, nvals * sizeof(int32_t));
}

void test_Read_Vector_int64_t() {
moveStreamToPosition(677427);
const size_t nvals(36);
std::vector<int64_t> expectedValue(nvals, 0);
expectedValue[4] = 1288490188800;
expectedValue[22] = 386547056640;
expectedValue[23] = 816043786240;

doReadArrayValueTest(nvals, expectedValue, nvals * sizeof(int64_t));
}

void test_Read_Vector_float() {
using std::fill;
moveStreamToPosition(646);
const size_t nvals(31);
std::vector<float> expectedValue(nvals, 0.0f);
float accumulator(0.0f);
std::generate(begin(expectedValue) + 1, end(expectedValue),
[&accumulator]() {
accumulator += 5.0f;
return accumulator;
});

doReadArrayValueTest(nvals, expectedValue, nvals * sizeof(float));
}

void test_Read_Vector_double() {
using std::fill;
moveStreamToPosition(10);
const size_t nvals(1);
std::vector<double> expectedValue(nvals, 2.0);

doReadArrayValueTest(nvals, expectedValue, nvals * sizeof(double));
}

// Only test this for a single type assuming it is the same for all
void test_Read_Vector_With_Bigger_Vector_Leaves_Size_Untouched() {
moveStreamToPosition(466);
BinaryStreamReader reader(m_stream);
auto streamPosBeg = m_stream.tellg();

const size_t nvals(2);
std::vector<int32_t> values(nvals + 2, 0);
reader.read(values, nvals);

std::vector<int32_t> expectedValue(nvals + 2, 0);
expectedValue[0] = 4;
expectedValue[1] = 7;
TS_ASSERT_EQUALS(expectedValue, values);
TS_ASSERT_EQUALS(nvals + 2, values.size());
auto expectedStreamOffset = nvals * sizeof(int32_t);
TS_ASSERT_EQUALS(expectedStreamOffset, m_stream.tellg() - streamPosBeg);
}

void test_Read_String_Of_Given_Size() {
moveStreamToPosition(677015);

BinaryStreamReader reader(m_stream);
auto streamPosBeg = m_stream.tellg();
std::string value;
const size_t nchars(7);
reader.read(value, nchars);

TS_ASSERT_EQUALS(nchars, value.length());
TS_ASSERT_EQUALS("QQQE___", value);
TS_ASSERT_EQUALS(nchars, m_stream.tellg() - streamPosBeg);
}

//----------------------------------------------------------------------------
Expand All @@ -75,16 +154,28 @@ class BinaryFileReaderTest : public CxxTest::TestSuite {
}

private:

template <typename T>
void doReadTest(T expectedValue, size_t expectedStreamOffset) {
void doReadSingleValueTest(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);

}

template <typename T>
void doReadArrayValueTest(const size_t nvals,
const std::vector<T> &expectedValue,
size_t expectedStreamOffset) {
BinaryStreamReader reader(m_stream);
auto streamPosBeg = m_stream.tellg();

std::vector<T> values;
reader.read(values, nvals);
TS_ASSERT_EQUALS(expectedValue, values);
TS_ASSERT_EQUALS(nvals, values.size());
TS_ASSERT_EQUALS(expectedStreamOffset, m_stream.tellg() - streamPosBeg);
}

void openTestFile() {
Expand Down

0 comments on commit 2e052a3

Please sign in to comment.