/*
=================================================================
Step 4 (for Solution see Step 5)
=================================================================
*/
#include "do_averages.h"
#include <sstream>
// std::istringstream
// std::ostringstream
#ifndef TEST
int main() {
do_averages();
}
#else
#include "pxt.h"
int main() {
{ ////////////////////////////////////////////////////////////
std::istringstream input{
"1 5 7" "\n"
"1.5 7" "\n"
"15.7" "\n"
};
std::ostringstream output{};
PX(do_averages(&input, &output), output.str())
>>= "4.33333" "\n"
"4.25" "\n"
"15.7" "\n";
} ////////////////////////////////////////////////////////////
{ ////////////////////////////////////////////////////////////
std::istringstream input{"\n"};
std::ostringstream output{};
PX(do_averages(&input, &output), output.str()) == "";
} ////////////////////////////////////////////////////////////
{ ////////////////////////////////////////////////////////////
std::istringstream input{
"1 5 7" "\n"
"1 S 7" "\n"
"15.7" "\n"
};
std::ostringstream output{};
PX(do_averages(&input, &output), output.str())
>>= "4.33333" "\n"
"1" "\n"
"15.7" "\n";
} ////////////////////////////////////////////////////////////
}
#endif
# TODO STEP 4
Currently the arguments handed over to `do_average` are pointers.
- Do all the changes necessary to turn them into references.
-----------------------------------------------------------------
TODO (optional - meant for further self-study only):
- Inform yourself (eg. using `cppreference.com`) about the
purpose of the header file `<iosfwd>`.
- In which place were its use more appropriate than the currently
used `<iostream>`?
- Why hadn't that change been possible in the version handing
over the arguments as pointers, using `&std::cin` and
`&std::cout` as default values?
- Why in the current versions wouldn't that change be possible
if the overload with no arguments were defined as `inline`
function?
#include "do_averages.h"
#include <iostream>
// std::cin
// std::cout
// std::istream
// std::ostream
#include <sstream>
// std::istringstream
// std::ostringstream
#include <string>
// std::getline
// std::string
void do_averages(std::istream* in, std::ostream* out) {
std::string line;
while (std::getline(*in, line)) {
float value;
float sum = 0.0f;
int count = 0;
std::istringstream iss{line};
while (iss >> value) {
sum += value;
++count;
}
if (count == 0) return;
*out << sum/count << std::endl;
}
}
void do_averages() {
do_averages(&std::cin, &std::cout);
}
#include <iosfwd>
void do_averages(std::istream*, std::ostream*);
void do_averages();
#ifndef PXT_header_only
#include "pxt.h"
#endif
#include <iostream>
namespace PXT_namespace {
std::ostream& PXT_class::out_stream{PXT_ostream};
PXT_class::Result PXT_class::counter{0, 0};
PXT_class::Result::~Result() {
if (failed > 0) {
PXT_class::out_stream << "** " << failed << " of "
<< total << " tests failed **" << std::endl;
}
else if (total > 0) {
PXT_class::out_stream << "** ALL " << total << " TESTS PASSED **" << std::endl;
}
}
std::ostream& PXT_class::source_location() const {
return out_stream << file_ << ' ' << '[' << func_ << ':' << line_ << ']' << ' ' << texpr_;
}
void PXT_class::plain_output() {
source_location() << " == " << streamed_result.str() << std::endl;
}
void PXT_class::two_line_compare() {
done_ = true;
++counter.total;
if (streamed_result.str() != expected_result.str()) {
++counter.failed;
source_location() << '\n'
<< " = received: " << streamed_result.str() << '\n'
<< " ! expected: " << expected_result.str() << std::endl;
}
}
void PXT_class::multi_line_compare() {
std::string streamed_line{};
std::string expected_line{};
std::ostringstream common{};
while (std::getline(streamed_result, streamed_line),
(expected_result >> std::ws),
std::getline(expected_result, expected_line),
!streamed_result.eof()
&& !expected_result.eof()
&& (streamed_line == expected_line)) {
common << " = " << expected_line << '\n';
}
done_ = true;
++counter.total;
if (streamed_result.eof()
&& expected_result.eof()) return; // no difference
++counter.failed;
if (streamed_result.eof()) { // less streamed than expected
source_location() << '\n'
<< common.str()
<< " + expected: " << expected_line << std::endl;
return;
}
if (expected_result.eof()) { // less expected than streamed
source_location() << '\n'
<< common.str()
<< " + received: " << streamed_line << std::endl;
return;
}
source_location() << '\n' // difference in streamed to expected
<< common.str()
<< " ~ received: " << streamed_line << '\n'
<< " ~ expected: " << expected_line << std::endl;
}
} // namespace
#ifndef PXT_off
#ifndef PXT_ostream
#define PXT_ostream std::cout
#endif
#define PX(...)\
PXT_namespace::PXT_class{__func__, __FILE__, __LINE__, #__VA_ARGS__, (__VA_ARGS__)}
#if defined(PXT_HAVE_BOOST_TYPEINDEX)\
|| defined(__has_include) && __has_include(<boost/type_index.hpp>)
#include <boost/type_index.hpp>
#define PT(...)\
PXT_namespace::PXT_helper(__func__, __FILE__, __LINE__, #__VA_ARGS__,\
boost::typeindex::type_id_with_cvr<__VA_ARGS__>())
#endif
#if !defined(PX)\
|| !defined(PT)
struct PXT_dummy{
template<typename T> void operator==(T const&) const {}
template<typename T> void operator*=(T const&) const {}
template<typename T> void operator>>=(T const&) const {}
template<typename T> void operator%=(T const&) const {}
};
#if !defined(PX)
#define PX(...) PXT_dummy{}
#endif
#if !defined(PT)
#define PT(...) PXT_dummy{}
#endif
#endif
#include <sstream>
#include <iostream>
namespace PXT_namespace {
class PXT_class {
bool done_{};
char const* func_;
char const* file_;
int const line_{};
char const* texpr_;
std::stringstream streamed_result{};
std::stringstream expected_result{};
std::ostream& source_location() const;
void plain_output();
void two_line_compare();
void multi_line_compare();
void glob_pattern_compare();
struct Result {
unsigned long long total;
unsigned long long failed;
~Result();
};
static Result counter;
public:
static std::ostream& out_stream;
static bool ignore_expecations;
template<typename T>
PXT_class(char const* func, char const* file, int line, char const* texpr, T const& expr)
: func_{func}, file_{file}, line_{line}, texpr_{texpr}
{
streamed_result.copyfmt(out_stream);
streamed_result << expr;
}
~PXT_class() {
if (not done_) plain_output();
}
template<typename T>
void operator==(T const& expr) {
expected_result.copyfmt(streamed_result);
expected_result << expr;
two_line_compare();
}
void operator>>=(std::string lines) {
expected_result << lines;
multi_line_compare();
}
void operator*=(std::string smatch) {
glob_pattern_compare();
}
};
} // namespace
#ifdef PXT_header_only
#include "pxt.cpp"
#endif
#endif