libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
stats_output.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_STATS_OUTPUT_HPP
2 #define LIBJMMCG_CORE_STATS_OUTPUT_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2017 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #include "config.h"
23 
24 #include <cassert>
25 #include <fstream>
26 #include <memory>
27 #include <string>
28 #include <vector>
29 
30 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace stats_to_csv {
31 
32 namespace private_ {
33 
34 inline auto
35 find_run_num(char const * const stats_name) noexcept(false) {
36  std::ifstream os(stats_name);
37  std::string line;
38  std::vector<std::string> lines;
39  while (std::getline(os, line)) {
40  lines.emplace_back(std::move(line));
41  }
42  if (lines.empty()) {
43  return 1ul;
44  } else {
45  const auto &last_entry=lines.rbegin();
46  assert(!last_entry->empty());
47  const auto slash_at=last_entry->find("\\");
48  assert(slash_at<last_entry->size());
49  auto end=std::next(&*last_entry->begin(), slash_at);
50  const unsigned long last_number=std::strtoul(last_entry->data(), &end, 10);
51  return last_number+1u;
52  }
53 }
54 
55 struct file_wrapper final {
56  std::ofstream stats;
57 
58  file_wrapper(char const * const stats_name, unsigned run_number) noexcept(false)
60  stats
62  }
63  ~file_wrapper() noexcept(true) {
64  stats<<std::endl;
65  }
66 };
67 
68 }
69 
70 /**
71  This file must only be included once, otherwise there should be obvious ODR issues (the linker will complain about multiple definitions of this variable.
72  This variable is managed by other means.
73 
74  \see setup(), teardown(), wrapper
75 */
76 static std::unique_ptr<private_::file_wrapper> handle;
77 
78 /**
79  This can be used in this manner:
80 
81  boost::unit_test::fixture(boost::bind(&stats_to_csv::setup, "count_setbits.csv"), &stats_to_csv::teardown)
82 
83  or:
84 
85  *boost::unit_test::fixture<libjmmcg::stats_to_csv::wrapper>(std::string("count_setbits.csv"))
86 
87  or:
88 
89  *make_fixture("count_setbits.csv")
90 
91  \see handle, teardown(), make_fixture(), BOOST_AUTO_TEST_SUITE
92 */
93 inline void
94 setup(char const * const stats_name) noexcept(false) {
95  handle.reset(new private_::file_wrapper(stats_name, private_::find_run_num(stats_name)));
96 }
97 
98 /**
99  \see setup()
100 */
101 inline void
102 teardown() noexcept(true) {
103  handle.reset();
104 }
105 
106 /**
107  \see handle, setup(), teardown(), make_fixture()
108 */
109 struct wrapper final {
110  explicit wrapper(char const *stats_name) noexcept(false) {
111  setup(stats_name);
112  }
113  explicit wrapper(std::string const &stats_name) noexcept(false) {
114  setup(stats_name.c_str());
115  }
116  ~wrapper() noexcept(true) {
117  teardown();
118  }
119 };
120 
121 
122 #ifdef BOOST_TEST_INCLUDED
123 /**
124  This file needs to be included after: <boost/test/included/unit_test.hpp> or an equivalent for this function to work.
125 
126  \see wrapper, BOOST_AUTO_TEST_SUITE
127 */
128 inline auto
129 make_fixture(char const *stats_name) noexcept(false) {
130  return boost::unit_test::fixture<wrapper>(stats_name);
131 }
132 #endif
133 
134 } } }
135 
136 #endif