CSVWriter.hpp 6.05 KB
Newer Older
Pietro Incardona's avatar
Pietro Incardona committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
 * CSVWriter.hpp
 *
 *  Created on: Dec 15, 2014
 *      Author: Pietro Incardona
 */

#ifndef CSVWRITER_HPP_
#define CSVWRITER_HPP_

#include <iostream>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <fstream>
Pietro Incardona's avatar
Pietro Incardona committed
15
#include "util/common.hpp"
Pietro Incardona's avatar
Pietro Incardona committed
16
17
18
19
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/for_each.hpp>
#include "csv_multiarray.hpp"
#include "util.hpp"
Pietro Incardona's avatar
Pietro Incardona committed
20
#include "is_csv_writable.hpp"
Pietro Incardona's avatar
Pietro Incardona committed
21

Pietro Incardona's avatar
Pietro Incardona committed
22
23
#define CSV_WRITER 0x30000

Pietro Incardona's avatar
Pietro Incardona committed
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*! \brief this class is a functor for "for_each" algorithm
 *
 * For each element of the boost::vector the operator() is called.
 * Is mainly used to create a string containing all the properties of the object
 *
 * \tparam Tobj object
 *
 */

template<typename Tobj>
struct csv_prp
{
	// String
	std::stringstream & str;

	// Object to write
	Tobj & obj;

	/*! \brief Constructor
	 *
	 * Create a vertex properties list
	 *
	 * \param str streamstring
	 * \param obj object to write
	 *
	 */
	csv_prp(std::stringstream & str, Tobj & obj)
	:str(str),obj(obj)
	{
	};

	//! It call the functor for each member
    template<typename T>
    void operator()(T& t)
    {
		// This is the type of the csv column
Pietro Incardona's avatar
Pietro Incardona committed
60
		typedef decltype(obj.template get<T::value>()) col_type;
Pietro Incardona's avatar
Pietro Incardona committed
61
62
63

		// Remove the reference from the column type
		typedef typename boost::remove_reference<col_type>::type col_rtype;
Pietro Incardona's avatar
Pietro Incardona committed
64
		typedef typename std::remove_all_extents<col_rtype>::type base_col_rtype;
Pietro Incardona's avatar
Pietro Incardona committed
65

Pietro Incardona's avatar
Pietro Incardona committed
66
    	csv_value_str<col_rtype, is_csv_writable<base_col_rtype>::value >(obj.template get<T::value>(),str);
Pietro Incardona's avatar
Pietro Incardona committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    }
};

/*! \brief this class is a functor for "for_each" algorithm
 *
 * For each element of the boost::vector the operator() is called.
 * Is mainly used to create a string containing all the properties of the object
 *
 * \tparam T object
 *
 */

template<typename Tobj, bool attr>
struct csv_col
{
	std::stringstream & str;

	csv_col(std::stringstream & str)
	:str(str)
	{
	};

	//! It call the functor for each member
    template<typename T>
Pietro Incardona's avatar
Pietro Incardona committed
91
    inline void operator()(T& t)
Pietro Incardona's avatar
Pietro Incardona committed
92
93
    {
		// This is the type of the csv column
Pietro Incardona's avatar
Pietro Incardona committed
94
		typedef typename boost::mpl::at<typename Tobj::type,boost::mpl::int_<T::value>>::type col_type;
Pietro Incardona's avatar
Pietro Incardona committed
95

Pietro Incardona's avatar
Pietro Incardona committed
96
    	csv_col_str<col_type>(std::string(Tobj::attributes::name[T::value]),str);
Pietro Incardona's avatar
Pietro Incardona committed
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    }
};

/*! \brief this class is a functor for "for_each" algorithm
 *
 * This class is a functor for "for_each" algorithm. For each
 * element of the boost::vector the operator() is called.
 * Is mainly used to create a string containing all the vertex
 * properties
 *
 * Specialization when we do not have vertex attributes
 *
 * \tparam G graph type
 *
 */

template<typename Tobj>
struct csv_col<Tobj,false>
{
	std::stringstream & str;

	csv_col(std::stringstream & str)
	:str(str)
	{
	};

	//! It call the functor for each member
    template<typename T>
    void operator()(T& t)
    {
		// This is the type of the csv column
		typedef typename boost::fusion::result_of::at_c<typename Tobj::type,T::value>::type col_type;

		// Remove the reference from the column type
		typedef typename boost::remove_reference<col_type>::type col_rtype;

		std::stringstream str2;
		str2 << "column_" << T::value;

		csv_col_str<col_rtype>(str2.str(),str);
    }
};

#define VECTOR 1

/*! \brief CSV Writer
 *
 * It write in CSV format vector of objects living into an N-dimensional space
 *
 * \tparam v_pos Positional vector
 * \tparam v_prp Property vector
 *
 */
template <typename v_pos, typename v_prp, unsigned int impl = VECTOR>
class CSVWriter
{
	/*! \brief Get the colums name (also the positional name)
	 *
	 */
	std::string get_csv_colums()
	{
		std::stringstream str;

		// write positional columns
Pietro Incardona's avatar
Pietro Incardona committed
161
		for (size_t i = 0 ; i < v_pos::value_type::dims ; i++)
Pietro Incardona's avatar
Pietro Incardona committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
		{
			if (i == 0)
				str << "x[" << i << "]";
			else
				str << "," << "x[" << i << "]";
		}

		// write positional information

		csv_col<typename v_prp::value_type,has_attributes<typename v_prp::value_type>::value> col(str);

		// Iterate through all the vertex and create the vertex list
		boost::mpl::for_each< boost::mpl::range_c<int,0,v_prp::value_type::max_prop> >(col);

		str << "\n";

		return str.str();
	}

	/*! \brief Get the csv data section
	 *
	 * \param v_pos vector that contain the positional information
	 * \param v_prp vector that contain the property information
Pietro Incardona's avatar
Pietro Incardona committed
185
	 * \param offset from where to start
Pietro Incardona's avatar
Pietro Incardona committed
186
187
	 *
	 */
Pietro Incardona's avatar
Pietro Incardona committed
188
	std::string get_csv_data(v_pos & vp, v_prp & vpr, size_t offset)
Pietro Incardona's avatar
Pietro Incardona committed
189
190
191
192
193
194
195
196
197
198
199
	{
		std::stringstream str;

		// The position and property vector size must match
		if (vp.size() != vpr.size())
		{
			std::cerr << "Error: " << __FILE__ << ":" << __LINE__ << " position vector and property vector must have the same size \n";
			return std::string("");
		}

		// Write the data
Pietro Incardona's avatar
Pietro Incardona committed
200
		for (size_t i = offset ; i < vp.size() ; i++)
Pietro Incardona's avatar
Pietro Incardona committed
201
202
203
204
205
206
207
208
209
210
		{
			for (size_t j = 0 ; j < v_pos::value_type::dims ; j++)
			{
				if (j == 0)
					str << vp.template get<0>(i)[j];
				else
					str << "," << vp.template get<0>(i)[j];
			}

			// Object to write
Pietro Incardona's avatar
Pietro Incardona committed
211
			auto obj = vpr.get(i);
Pietro Incardona's avatar
Pietro Incardona committed
212

Pietro Incardona's avatar
Pietro Incardona committed
213
			csv_prp<decltype(obj)> c_prp(str,obj);
Pietro Incardona's avatar
Pietro Incardona committed
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

			// write the properties to the stream string
			boost::mpl::for_each< boost::mpl::range_c<int,0,v_prp::value_type::max_prop> >(c_prp);

			str << "\n";
		}

		return str.str();
	}

public:

	/*! \brief It write a CSV file
	 *
	 * \tparam prp which properties to output [default = -1 (all)]
	 *
	 * \param file path where to write
	 * \param v_pos positional vector
	 * \param v_prp properties vector
Pietro Incardona's avatar
Pietro Incardona committed
233
	 * \param offset from where to start to write
Pietro Incardona's avatar
Pietro Incardona committed
234
235
236
	 *
	 */

Pietro Incardona's avatar
Pietro Incardona committed
237
	bool write(std::string file, v_pos & v , v_prp & prp, size_t offset=0)
Pietro Incardona's avatar
Pietro Incardona committed
238
239
240
241
242
243
244
245
246
247
	{
		// Header for csv (colums name)
		std::string csv_header;
		// Data point
		std::string point_data;

		// Get csv columns
		csv_header = get_csv_colums();

		// For each property in the vertex type produce a point data
Pietro Incardona's avatar
Pietro Incardona committed
248
		point_data = get_csv_data(v,prp,offset);
Pietro Incardona's avatar
Pietro Incardona committed
249
250
251
252
253
254

		// write the file
		std::ofstream ofs(file);

		// Check if the file is open
		if (ofs.is_open() == false)
255
		{std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " cannot create the CSV file: " << file << std::endl;}
Pietro Incardona's avatar
Pietro Incardona committed
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270

		ofs << csv_header << point_data;

		// Close the file

		ofs.close();

		// Completed succefully
		return true;
	}
};


#endif /* CSVWRITER_HPP_ */