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