1 #ifndef IO_UTILS_HPP
2 #define IO_UTILS_HPP
3
4 #include "utils.hpp"
5 #include <fstream>
6 #include <ostream>
7 #include <terraces/errors.hpp>
8
9 namespace terraces {
10 namespace utils {
11
12 template <typename T>
13 struct comma_separated_output {
14 const T* data;
15 };
16
17 template <typename T>
operator <<(std::ostream & stream,comma_separated_output<T> output)18 std::ostream& operator<<(std::ostream& stream, comma_separated_output<T> output) {
19 bool first = true;
20 for (auto el : *output.data) {
21 if (not first) {
22 stream << ",";
23 }
24 stream << el;
25 first = false;
26 }
27 return stream;
28 }
29
30 template <typename T1, typename T2>
31 struct comma_separated_mapped_output {
32 const T1* data;
33 const T2* names;
34 };
35
36 template <typename T1, typename T2>
operator <<(std::ostream & stream,comma_separated_mapped_output<T1,T2> output)37 std::ostream& operator<<(std::ostream& stream, comma_separated_mapped_output<T1, T2> output) {
38 bool first = true;
39 for (auto el : *output.data) {
40 if (not first) {
41 stream << ",";
42 }
43 stream << (*output.names)[el];
44 first = false;
45 }
46 return stream;
47 }
48
49 template <typename T1, typename T2, typename T3>
50 struct comma_separated_mapped_subset_output {
51 const T1* subset;
52 const T2* data;
53 const T3* names;
54 };
55
56 template <typename T2, typename T3>
57 struct named_output {
58 const typename T2::value_type entry;
59 const T3* names;
60 };
61
62 template <typename T1, typename T2, typename T3>
operator <<(std::ostream & stream,comma_separated_mapped_subset_output<T1,T2,T3> output)63 std::ostream& operator<<(std::ostream& stream,
64 comma_separated_mapped_subset_output<T1, T2, T3> output) {
65 bool first = true;
66 for (auto el : *output.subset) {
67 if (not first) {
68 stream << ",";
69 }
70 stream << named_output<T2, T3>{(*output.data)[el], output.names};
71 first = false;
72 }
73 return stream;
74 }
75
76 // helpers because c++14 can't deduce class template types
77 template <typename T>
as_comma_separated_output(const T & data)78 comma_separated_output<T> as_comma_separated_output(const T& data) {
79 return {&data};
80 }
81
82 template <typename T1, typename T2>
as_comma_separated_output(const T1 & data,const T2 & names)83 comma_separated_mapped_output<T1, T2> as_comma_separated_output(const T1& data, const T2& names) {
84 return {&data, &names};
85 }
86
87 template <typename T1, typename T2, typename T3>
88 comma_separated_mapped_subset_output<T1, T2, T3>
as_comma_separated_output(const T1 & subset,const T2 & data,const T3 & names)89 as_comma_separated_output(const T1& subset, const T2& data, const T3& names) {
90 return {&subset, &data, &names};
91 }
92
open_ifstream(const std::string & filename)93 inline std::ifstream open_ifstream(const std::string& filename) {
94 auto stream = std::ifstream{filename};
95 utils::ensure<file_open_error>(stream.is_open(), "failed to open " + filename);
96 return stream;
97 }
98
read_ifstream_full(std::istream & stream)99 inline std::string read_ifstream_full(std::istream& stream) {
100 using it = std::istreambuf_iterator<char>;
101 return {it{stream}, it{}};
102 }
103
read_file_full(const std::string & filename)104 inline std::string read_file_full(const std::string& filename) {
105 auto file = open_ifstream(filename);
106 return read_ifstream_full(file);
107 }
108
109 } // namespace utils
110 } // namespace terraces
111
112 #endif // IO_UTILS_HPP
113