Code:
#include "stdafx.h"
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <numeric>
#include <boost/lexical_cast.hpp> //MR Added to cast from double to string
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
static bool testFailure(false);
static size_t testCount(0);
#define TEST_REQUIRE_EQUAL(a, b) \
{ \
++testCount; \
if (a != b) { \
std::cout << "ERROR: TEST ABORTING (" #a " != " #b ")" << std::endl; \
exit(1); \
} \
}
#define TEST_CHECK_EQUAL(a, b) \
{ \
++testCount; \
if (a != b) { \
std::cout << "ERROR: TEST FAILURE (" #a " != " #b ")" << std::endl; \
testFailure=true; \
} \
}
#define TEST_CHECK_EQUAL_AS_STR(a, b) \
{ \
++testCount; \
std::stringstream lhs, rhs; \
lhs << a; \
rhs << b; \
if (lhs.str() != rhs.str()) { \
std::cout << "ERROR: TEST FAILURE (" \
<< lhs.str() \
<< " != " \
<< rhs.str() \
<< ")" \
<< std::endl \
; \
testFailure=true; \
} \
}
//Function for challenge 1, for when recursion hits last tuple element
inline void set_to_val_over_ten(const boost::tuples::null_type&, double){};
//Challenge 1 - populates tuple recursively
template<typename H, typename T>
inline void set_to_val_over_ten(boost::tuples::cons<H, T>& x, double V )
{
x.get_head() = V;
set_to_val_over_ten(x.get_tail(), V/10);
}
//Challenge 2 - specialisation for strings
template< typename T>
inline void set_to_val_over_ten(boost::tuples::cons<std::string, T>& x, double V )
{
x.get_head() = boost::lexical_cast<std::string>(V);
set_to_val_over_ten(x.get_tail(), V/10);
}
//Challenge 1 - Provided function template
template <typename CONTAINER>
void populateData(CONTAINER& container, size_t count)
{
for(size_t i=0 ; i<count ; i++)
{
typename CONTAINER::value_type tupleToAdd(i);
set_to_val_over_ten(tupleToAdd.get_tail(), double(i)/10.0);
container.push_back(tupleToAdd);
};
}
template<typename ITERATOR_TYPE>
typename ITERATOR_TYPE::value_type sum(const ITERATOR_TYPE& first, const ITERATOR_TYPE& last)
{
typedef typename ITERATOR_TYPE::value_type value_type;
value_type count(static_cast<value_type>(std::distance(first,last)));
if(count==0)
throw std::exception("Cannot calculate the sum of empty series.");
return std::accumulate(first, last, value_type(), std::plus<value_type>());
}
template<typename ITERATOR_TYPE>
typename ITERATOR_TYPE::value_type mean(const ITERATOR_TYPE& first, const ITERATOR_TYPE& last)
{
typedef typename ITERATOR_TYPE::value_type value_type;
value_type count(static_cast<value_type>(std::distance(first,last)));
return sum(first, last)/count;
}
template<typename CONTAINER>
typename CONTAINER::value_type mean(const CONTAINER& container)
{
return mean(container.begin(), container.end());
}
int main()
{
// challenge 1 - pass the following tests
typedef boost::tuple<int, double> row1_t;
typedef std::vector<row1_t> vec1_t;
vec1_t vec1;
populateData(vec1, 100);
TEST_REQUIRE_EQUAL(vec1.size(), 100);
TEST_CHECK_EQUAL_AS_STR(vec1[1],"(1 0.1)");
TEST_CHECK_EQUAL_AS_STR(vec1[99],"(99 9.9)");
typedef boost::tuple<int, double, double> row2_t;
typedef std::vector<row2_t> vec2_t;
vec2_t vec2;
populateData(vec2, 100);
TEST_REQUIRE_EQUAL(vec2.size(), 100);
TEST_CHECK_EQUAL_AS_STR(vec2[1],"(1 0.1 0.01)");
TEST_CHECK_EQUAL_AS_STR(vec2[99],"(99 9.9 0.99)");
// challenge 2 - create a specialisation for strings
typedef boost::tuple<int, double, std::string> row3_t;
typedef std::vector<row3_t> vec3_t;
vec3_t vec3;
populateData(vec3, 100);
TEST_REQUIRE_EQUAL(vec3.size(), 100);
TEST_CHECK_EQUAL_AS_STR(vec3[1],"(1 0.1 1/100)");
TEST_CHECK_EQUAL_AS_STR(vec3[99],"(99 9.9 99/100)");
// challenge 3 - create a generalised view on the series - ideal solution should not copy data
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec1)), 49);
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec1)), 4.95);
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec2)), 49);
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec2)), 4.95);
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<2>(vec2)), 0.495);
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<0>(vec3)), 49);
//TEST_CHECK_EQUAL_AS_STR( mean(columnViewOfTuple<1>(vec3)), 4.95);
TEST_CHECK_EQUAL_AS_STR(testCount, 17);
if (!testFailure) {
std::cout << "Congratulations!\n";
}
}